/* PRD 03 — News Feed Markdown + Inline Media styles. */

/* TYPE: every text size in this file is a step of the platform type scale (custom.css ":root"
   --type-caption 12 / --type-small 13 / --type-title 16 / --type-page 22 / --type-display 28;
   PAGE_COMPOSITION_STANDARDS §5A), and body-sized text inherits the tenant's body size.
   Until 2026-09-24 this file ran its own scale — 9, 10, 11, 11.5, 12.5, 13.5, 14, 14.5, 17px —
   so 44–67% of the Feed, My Posts and My Feeds read off the scale and 400+ characters per page sat
   under the 12px floor (/design-pass communications). Never add a px font-size here: pick a token.
   Icon glyph sizes are not type and stay in px. */

/* ---------- Category left-border accents (one per category + must-read) ---------- */
.news-feed-card--operational {
  border-left: 3px solid var(--bs-primary, #3b7ddd) !important;
}

.news-feed-card--company-news {
  border-left: 3px solid var(--bs-info, #0dcaf0) !important;
}

.news-feed-card--social {
  border-left: 3px solid var(--bs-success, #28a745) !important;
}

.news-feed-card--must-read {
  border-left: 3px solid var(--bs-danger, #dc3545) !important;
}

/* ---------- Card hover lift ---------- */
.card[data-feed-id] {
  transition: box-shadow 0.15s ease;
}

.card[data-feed-id]:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08) !important;
}

/* ---------- Rendered Markdown body ---------- */
.news-feed-rendered {
  line-height: 1.5;
  word-wrap: break-word;
}

.news-feed-rendered p:last-child {
  margin-bottom: 0;
}

.news-feed-rendered img {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
}

/* A picture inserted from the editor toolbar (2026-09-22) sits in the text
   as its own block at the column's width — never mid-line with the prose. */
.news-feed-rendered img.nf-inline-image {
  display: block;
  margin: 0.75rem 0;
  border-radius: 0.5rem;
}

.news-feed-rendered pre {
  background: #f6f8fa;
  padding: 0.75rem;
  border-radius: 6px;
  overflow-x: auto;
  font-size: 0.875rem;
}

.news-feed-rendered code {
  background: #f6f8fa;
  padding: 0.1rem 0.3rem;
  border-radius: 3px;
  font-size: 0.875em;
}

.news-feed-rendered pre code {
  background: transparent;
  padding: 0;
}

.news-feed-rendered blockquote {
  border-left: 3px solid #d0d7de;
  padding-left: 0.75rem;
  color: #57606a;
  margin: 0.5rem 0;
}

/* A Markdown table is the one body element that can be genuinely wider than
   the card: `pre` above already scrolls, and everything else is inline text
   that the container's `word-wrap: break-word` can break. Untreated, a table
   laid out 1688px inside an 880px post card, took the card's own box 833px
   with it and gave the page 659px of horizontal scroll
   (ISS-20260903-353-B1C4BF). Same block-scroll formula GitHub uses for
   rendered Markdown, which is the typography this whole block already
   mirrors (#f6f8fa / #d0d7de).

   `anywhere` rather than `break-word` on the cells: `break-word` is ignored
   when honouring it would change an element's min-content width, which is
   exactly a table cell holding a long unbroken token — so only `anywhere`
   shrinks the table that contains it. The two rules compose: a long token
   wraps and the table fits, and a table that is wide because it has many
   columns scrolls inside the card instead of bursting it. */
.news-feed-rendered table {
  border-collapse: collapse;
  margin: 0.5rem 0;
  font-size: 0.875rem;
  display: block;
  width: max-content;
  max-width: 100%;
  overflow-x: auto;
}

.news-feed-rendered th,
.news-feed-rendered td {
  border: 1px solid #d0d7de;
  padding: 0.35rem 0.6rem;
}

/* Body cells only. `anywhere` drops a cell's min-content width to one
   character, so applying it to the header row too let the table squeeze a
   short heading and break it mid-word ("Colu/mn") whenever a sibling column
   wanted the space. Headers keep their natural minimum; a long token in a
   header instead falls through to the block scroll above. */
.news-feed-rendered td {
  overflow-wrap: anywhere;
}

.news-feed-rendered th {
  background: #f6f8fa;
}

/* Read-More clamp on collapsed body. */
.news-feed-body {
  position: relative;
}

.news-feed-body:not([open]) .news-feed-body__rendered {
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.news-feed-body[open] .news-feed-body__more {
  display: none;
}

.news-feed-body__more {
  display: inline-block;
  margin-top: 0.25rem;
}

.news-feed-body__summary::-webkit-details-marker {
  display: none;
}

/* ---------- Media grid ---------- */
.news-feed-media {
  margin-top: 0.75rem;
}

/* Up to four tiles, each shape capped in height (apps/news_feed/shared/
   _feed_media). --media-cap is the tallest a gallery may be: 600px, 420px on
   a phone-width screen.
     1   the picture's own shape (inline aspect-ratio), fitted whole over a
         blurred copy of itself once the cap bites — never cropped
     2   two squares side by side
     3+  the first across the top (16:9) and the rest in one row under it
     3+ with a portrait first: tall on the left, the rest stacked beside it */
.news-feed-media-grid {
  --media-cap: 600px;
  display: grid;
  gap: 4px;
  border-radius: 6px;
  overflow: hidden;
}

@media (max-width: 575.98px) {
  .news-feed-media-grid {
    --media-cap: 420px;
  }
}

.news-feed-media-grid--1 {
  grid-template-columns: 1fr;
}

.news-feed-media-grid--2 {
  grid-template-columns: 1fr 1fr;
}

.news-feed-media-grid--2 .news-feed-media-tile {
  aspect-ratio: 1 / 1;
  max-height: var(--media-cap);
}

.news-feed-media-grid--3 {
  grid-template-columns: 1fr 1fr;
}

.news-feed-media-grid--4 {
  grid-template-columns: repeat(3, 1fr);
}

/* The row under the first picture is a fixed share of the cap, so the whole
   gallery stays inside it whatever the card's width (a row of 4:3 tiles in a
   wide card grew past it). */
.news-feed-media-grid--3,
.news-feed-media-grid--4 {
  grid-template-rows: auto calc(var(--media-cap) * 0.3);
}

.news-feed-media-grid--3 .news-feed-media-tile,
.news-feed-media-grid--4 .news-feed-media-tile {
  aspect-ratio: auto;
  min-height: 0;
}

/* width: 100% — with a max-height alone, the aspect-ratio would shrink the
   tile's WIDTH to keep 16:9 and leave a gap beside it. */
.news-feed-media-grid--3 .news-feed-media-tile:first-child,
.news-feed-media-grid--4 .news-feed-media-tile:first-child {
  grid-column: 1 / -1;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: calc(var(--media-cap) * 0.69);
}

/* Portrait first: a fixed-height block, the first tile down the left and the
   rest stacked beside it. The rows are stated (one per stacked tile) because
   the first tile's `grid-row: 1 / -1` only spans rows the grid declares. */
.news-feed-media-grid--portrait {
  grid-template-columns: 2fr 1fr;
  height: var(--media-cap);
}

.news-feed-media-grid--3.news-feed-media-grid--portrait {
  grid-template-rows: repeat(2, 1fr);
}

.news-feed-media-grid--4.news-feed-media-grid--portrait {
  grid-template-rows: repeat(3, 1fr);
}

.news-feed-media-grid--portrait .news-feed-media-tile,
.news-feed-media-grid--portrait .news-feed-media-tile:first-child {
  aspect-ratio: auto;
  max-height: none;
  min-height: 0;
}

.news-feed-media-grid--portrait .news-feed-media-tile:first-child {
  grid-column: 1;
  grid-row: 1 / -1;
}

.news-feed-media-tile {
  position: relative;
  background: #f0f0f0;
  cursor: pointer;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}

.news-feed-media-tile img,
.news-feed-media-tile video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* One picture alone: whole, at its own shape up to the cap; past the cap it
   is letterboxed over a blurred copy of itself rather than cropped. */
.news-feed-media-tile--single {
  max-height: var(--media-cap);
}

.news-feed-media-tile--single::before {
  content: "";
  position: absolute;
  inset: -24px;
  background: var(--tile-backdrop, none) center / cover no-repeat;
  filter: blur(24px) brightness(0.92);
}

/* Above the backdrop; the tile's own overlays keep their absolute place. */
.news-feed-media-tile--single > :not(.position-absolute) {
  position: relative;
  z-index: 1;
}

/* !important: the tile's <img> carries an inline object-fit for the grids. */
.news-feed-media-tile--single img,
.news-feed-media-tile--single video {
  object-fit: contain !important;
}

.news-feed-media-tile__badge {
  position: absolute;
  top: 6px;
  left: 6px;
  background: rgba(0, 0, 0, 0.7);
  color: #fff;
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 0.7rem;
  font-weight: 600;
}

.news-feed-media-tile__overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  font-weight: 600;
}

.news-feed-media-tile__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 3rem;
  pointer-events: none;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.6);
}

.news-feed-media-tile__status {
  position: absolute;
  inset: 0;
  background: #f6f8fa;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #57606a;
  font-size: 0.875rem;
  gap: 0.4rem;
}

.news-feed-media-tile__status--failed {
  color: #b42318;
  background: #fef3f2;
}

/* ---------- PRD 09 — Auto-subtitle CC badge & toggle ---------- */
.news-feed-cc-badge {
  bottom: 6px;
  right: 6px;
  padding: 2px 8px;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  border-radius: 3px;
  pointer-events: none;
  z-index: 2;
}

.news-feed-cc-pending {
  opacity: 0.7;
}

.news-feed-cc-failed {
  opacity: 0.55;
  cursor: not-allowed;
}

.news-feed-cc-toggle {
  position: absolute;
  bottom: 16px;
  right: 16px;
  padding: 6px 12px;
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  cursor: pointer;
  z-index: 10;
}

.news-feed-cc-toggle.is-on {
  background: #fff;
  color: #000;
}

.news-feed-cc-toggle:focus-visible {
  outline: 2px solid #4b9eff;
  outline-offset: 2px;
}

/* ---------- File cards ---------- */
.news-feed-file-list {
  margin-top: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.news-feed-file-card {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  background: #fafbfc;
  text-decoration: none;
  color: inherit;
}

.news-feed-file-card:hover {
  background: #f3f4f6;
}

.news-feed-file-card__icon {
  font-size: 1.4rem;
  color: #6b7280;
}

.news-feed-file-card__meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.news-feed-file-card__name {
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.news-feed-file-card__size {
  font-size: 0.75rem;
  color: #6b7280;
}

/* ---------- Link previews ---------- */
.news-feed-link-preview {
  display: flex;
  gap: 0.75rem;
  margin-top: 0.5rem;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  background: #fff;
}

.news-feed-link-preview:hover {
  background: #f9fafb;
}

.news-feed-link-preview__image {
  flex: 0 0 120px;
  background-size: cover;
  background-position: center;
}

.news-feed-link-preview__thumb {
  flex: 0 0 96px;
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: 4px;
}

.news-feed-link-preview__body {
  padding: 0.6rem 0.75rem;
  min-width: 0;
}

.news-feed-link-preview__host {
  font-size: 0.75rem;
  color: #6b7280;
  text-transform: uppercase;
}

.news-feed-link-preview__title {
  font-weight: 600;
  margin: 0.15rem 0;
}

.news-feed-link-preview__desc {
  font-size: 0.85rem;
  color: #4b5563;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ---------- Composer attach list ---------- */
.news-feed-attach-list {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.news-feed-attach-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid #e5e7eb;
  border-radius: 4px;
  background: #fafbfc;
}

.news-feed-attach-item__name {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.news-feed-attach-item__status {
  font-size: 0.75rem;
  color: #6b7280;
}

.news-feed-attach-item__status--ready {
  color: #15803d;
}

.news-feed-attach-item__status--failed {
  color: #b42318;
}

/* ---------- Gallery overlay ---------- */
.news-feed-gallery-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.92);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.news-feed-gallery-stage {
  max-width: 95vw;
  max-height: 90vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.news-feed-gallery-stage img,
.news-feed-gallery-stage video {
  max-width: 95vw;
  max-height: 90vh;
  object-fit: contain;
}

.news-feed-gallery-close,
.news-feed-gallery-prev,
.news-feed-gallery-next {
  position: absolute;
  background: transparent;
  border: none;
  color: #fff;
  font-size: 2rem;
  cursor: pointer;
  padding: 0.5rem 0.75rem;
}

.news-feed-gallery-close {
  top: 12px;
  right: 16px;
  font-size: 2.5rem;
  line-height: 1;
}

.news-feed-gallery-prev {
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 3rem;
}

.news-feed-gallery-next {
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 3rem;
}

.news-feed-gallery-close:hover,
.news-feed-gallery-prev:hover,
.news-feed-gallery-next:hover {
  color: #d1d5db;
}

/* ---------- PRD 04 Phase 15: Reaction bar ---------- */
.sf-reaction-bar {
  padding: 0.5rem 0;
}

.sf-reaction-bar.is-reacting {
  opacity: 0.7;
  pointer-events: none;
}

.sf-reaction-summary {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 2px 8px 2px 4px;
  border-radius: 999px;
  background: #f3f4f6;
  border: 1px solid #e5e7eb;
}

.sf-reaction-summary:hover {
  background: #e9ecef;
}

.sf-reaction-cluster {
  display: inline-flex;
  align-items: center;
}

.sf-reaction-cluster .sf-reaction-glyph:not(:first-child) {
  margin-left: -4px;
}

.sf-reaction-glyph {
  font-size: 1.15rem;
  line-height: 1;
  display: inline-block;
  background: #fff;
  border-radius: 50%;
  padding: 1px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05);
}

.sf-reaction-react-btn {
  color: #57606a;
  transition: background 0.12s ease, color 0.12s ease;
  border-radius: 4px;
}

/* The brand as ink on these fixed light chips: --bs-primary-ink-on-light
   (color_text_fix.css, Console #6311). */
.sf-reaction-react-btn:hover {
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #0d6efd));
  background: #f3f4f6;
  padding: 2px 6px;
  margin: -2px -6px;
}

.sf-reaction-react-btn.is-reacted {
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #0d6efd));
  background: #eff6ff;
  border-radius: 4px;
  padding: 2px 6px;
  margin: -2px -6px;
}

.sf-reaction-react-btn.is-reacted:hover {
  background: #dbeafe;
}

.sf-reaction-react-btn.is-reacted .sf-reaction-label {
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #0d6efd));
}

button.sf-reaction-comment-count {
  transition: background 0.12s ease;
  border-radius: 4px;
  cursor: pointer;
}

button.sf-reaction-comment-count:hover {
  background: #f3f4f6;
  padding: 2px 6px;
  margin: -2px -6px;
}

.sf-reaction-share {
  cursor: default;
}

span.sf-reaction-comment-count {
  cursor: default;
}

/* ---------- Reaction picker popover ---------- */
.sf-reaction-picker-popover {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  z-index: 1050;
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 999px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
  padding: 4px 6px;
  animation: sf-pop-in 120ms ease-out;
}

.sf-reaction-picker-popover.is-below {
  bottom: auto;
  top: calc(100% + 6px);
}

.sf-reaction-picker-row {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  align-items: center;
  /* Seven 36px chips to a row: a palette can be the whole catalog (21). */
  width: max-content;
  max-width: min(264px, calc(100vw - 2rem));
}

.sf-reaction-picker-chip {
  position: relative;
  background: transparent;
  border: none;
  border-radius: 50%;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  line-height: 1;
  transition: transform 100ms ease-out, background 100ms ease-out;
  cursor: pointer;
}

.sf-reaction-picker-chip:hover {
  transform: scale(1.25);
  background: #f3f4f6;
}

.sf-reaction-picker-chip.sf-tier-action {
  box-shadow: inset 0 0 0 2px #0d9488;
  /* teal border per PRD §7.1 */
}

.sf-reaction-picker-chip .sf-tier-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  font-size: 0.65rem;
  color: #0d9488;
}

@keyframes sf-pop-in {
  from {
    opacity: 0;
    transform: translateY(4px) scale(0.96);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* ---------- Admin palette editor (Settings → General → Reactions) ----------
   The chips rendered by apps/news_feed/shared/_reaction_palette_picker.
   Distinct from .sf-reaction-picker-chip above (the reader-facing popover):
   this one is a labelled pill whose whole job is to show which of the 14
   catalog keys are in the business's active palette. Element selectors so
   these win over Bootstrap's .btn / .btn-sm without !important. */
button.sf-reaction-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.75rem;
  border: 1px solid #e5e7eb;
  border-radius: 999px;
  background: #fff;
  color: #57606a;
  font-weight: 500;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

button.sf-reaction-chip:hover {
  background: #f6f8fa;
  border-color: #d0d7de;
  color: #24292f;
}

/* Selected == the reaction is part of the active palette. */
button.sf-reaction-chip.is-selected {
  background: #eff6ff;
  border-color: var(--bs-primary, #0d6efd);
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #0d6efd));
  font-weight: 600;
}

/* A shape cue as well as a colour one, so the on/off state survives
   greyscale printing and the common colour-vision deficiencies. */
button.sf-reaction-chip.is-selected::before {
  content: "\2713";
  font-weight: 600;
  line-height: 1;
}

/* Teal marks action-oriented keys everywhere else in the app
   (.sf-reaction-picker-chip.sf-tier-action) — keep that meaning here, where
   it matters most: an enabled action key is what feeds the Signals pipeline. */
button.sf-reaction-chip.sf-tier-action.is-selected {
  background: #f0fdfa;
  border-color: #0d9488;
  color: #0f766e;
}

/* Off keys read as muted rather than merely uncoloured. */
button.sf-reaction-chip:not(.is-selected) .sf-reaction-glyph {
  opacity: 0.45;
}

/* The shared .sf-reaction-glyph rule paints a white bubble + ring for the
   feed's overlapping reactor cluster; inside a flat editor chip that bubble
   fights the chip's own fill. */
button.sf-reaction-chip .sf-reaction-glyph {
  background: transparent;
  box-shadow: none;
  padding: 0;
}

/* Keyboard focus. AdminKit's `.btn:focus-visible` is (0,2,0) and so OUTRANKS the
   base chip rule (0,1,1) above; it resolves background/border/colour/box-shadow
   against --bs-btn-hover-* custom properties that a bare `.btn` (no colour
   variant — which is exactly what a chip is) never defines, so all four collapse
   to transparent/none, and it finishes with `outline: 0`. Result without these
   rules: tabbing onto an unselected chip makes it dissolve to bare text with no
   focus indicator anywhere in the 14-chip grid. Element+class selectors put us
   back above it. Same remedy as the poll option buttons further down. */
button.sf-reaction-chip:focus-visible {
  background: #fff;
  border-color: #d0d7de;
  color: #24292f;
  outline: 3px solid var(--bs-primary, #0d6efd);
  outline-offset: 2px;
  box-shadow: none;
}

button.sf-reaction-chip.is-selected:focus-visible {
  background: #eff6ff;
  border-color: var(--bs-primary, #0d6efd);
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #0d6efd));
}

button.sf-reaction-chip.sf-tier-action.is-selected:focus-visible {
  background: #f0fdfa;
  border-color: #0d9488;
  color: #0f766e;
}

/* `.is-selected` is later in source than `:hover` and equally specific, so a
   selected chip had no hover feedback at all. Border only — the fill stays in
   its own colour family (blue vs teal). */
button.sf-reaction-chip.is-selected:hover {
  border-color: #0a58ca;
}

button.sf-reaction-chip.sf-tier-action.is-selected:hover {
  border-color: #0f766e;
}

/* Shared by the editor chips and the "Keys marked ⚡" line above them. The
   popover's own rule (which also positions it) keeps its higher specificity. */
.sf-tier-badge {
  color: #0d9488;
  font-size: 0.75rem;
}

/* ---------- Reactor sheet (bottom sheet on mobile / center card desktop) ---------- */
.sf-reactor-sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.sf-reactor-sheet {
  background: #fff;
  border-radius: 12px;
  width: 100%;
  max-width: 420px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.2);
  animation: sf-pop-in 140ms ease-out;
}

.sf-reactor-sheet__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid #e5e7eb;
}

.sf-reactor-sheet__close {
  font-size: 1.5rem;
  line-height: 1;
  padding: 0 0.5rem;
}

.sf-reactor-sheet__tabs {
  display: flex;
  gap: 0.25rem;
  overflow-x: auto;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid #e5e7eb;
}

.sf-reactor-sheet__tab {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  white-space: nowrap;
  cursor: pointer;
}

.sf-reactor-sheet__tab.is-active {
  background: #eff6ff;
  border-color: #bfdbfe;
  color: #1d4ed8;
}

.sf-reactor-sheet__body {
  overflow-y: auto;
}

.sf-reactor-sheet__list {
  padding: 0.5rem 0;
}

.sf-reactor-sheet__row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 1rem;
}

.sf-reactor-sheet__row:hover {
  background: #f9fafb;
}

/* The clickable avatar+name half of a reactor row — opens that person's
   profile card. Rendered as a bare <button> so it keeps the row's own flex
   metrics (the glyph stays pinned right) while carrying real button
   semantics for keyboard and screen-reader users. */
.sf-reactor-sheet__person {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.sf-reactor-sheet__avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  background: #f3f4f6;
}

.sf-reactor-sheet__name {
  flex: 1;
  min-width: 0;
  font-size: 0.9rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sf-reactor-sheet__glyph {
  font-size: 1.1rem;
}

/* Bottom sheet on small viewports */
@media (max-width: 576px) {
  .sf-reactor-sheet-backdrop {
    align-items: flex-end;
    padding: 0;
  }

  .sf-reactor-sheet {
    max-width: 100%;
    width: 100%;
    max-height: 75vh;
    border-radius: 16px 16px 0 0;
    animation: sf-slide-up 180ms ease-out;
  }

  @keyframes sf-slide-up {
    from {
      transform: translateY(100%);
    }

    to {
      transform: translateY(0);
    }
  }
}

/* ---------- Composer: the post body editor (design handoff 2026-06-05) ---------- */


/* Inline card variant — same density adjustments */
.news-feed-composer .form-label {
  font-size: var(--type-small);
  font-weight: 600;
  color: #64748b;
}

.news-feed-composer .form-text {
  font-size: var(--type-small);
  line-height: 18px;
}

.news-feed-composer .mb-3 {
  margin-bottom: 20px !important;
}

/* Focus ring consistency */
.news-feed-composer .form-control:focus,
.news-feed-composer .form-select:focus {
  border-color: var(--bs-primary, #3b82f6);
  box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb, 59, 130, 246), 0.18);
}


/* Section labels — small uppercase headers used above each composer field group.
   Specificity must beat .news-feed-composer .form-label (0,2,0). */
.news-feed-composer .news-feed-composer__section-label,
.news-feed-composer__section-label {
  font-size: var(--type-caption);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #8a929c;
  margin-bottom: 10px;
}


/* Editor header row — section label on the left, Edit/Preview pill on the right */
.news-feed-composer__editor-header {
  margin-bottom: 9px;
}

/* Edit / Preview — compact segmented pill control */
.news-feed-composer__edit-preview {
  display: inline-flex;
  border: 1px solid #dde1e7;
  border-radius: 6px;
  overflow: hidden;
  list-style: none;
  margin: 0;
  padding: 0;
}

.news-feed-composer__edit-preview .nav-link {
  font-size: var(--type-small);
  font-weight: 500;
  color: #6c757d;
  background: #fff;
  padding: 0.3rem 0.68rem;
  border: none;
  border-radius: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.news-feed-composer__edit-preview .nav-item + .nav-item .nav-link {
  border-left: 1px solid #dde1e7;
}

.news-feed-composer__edit-preview .nav-link.active {
  background: #eef3f9;
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #2e63b3));
  font-weight: 600;
}

/* Toolbar — compact, sits inside the editor border (no own border) */
.news-feed-composer-toolbar {
  background: #f8f9fb !important;
  border: none !important;
  border-bottom: 1px solid #e6e9ee !important;
  border-radius: 8px 8px 0 0 !important;
  padding: 6px 8px !important;
  gap: 1px !important;
  flex-wrap: nowrap !important;
  overflow-x: auto;
}

.news-feed-composer-toolbar .btn {
  font-size: var(--type-caption);
  padding: 3px 6px;
  white-space: nowrap;
  color: #5a6572;
}

.news-feed-composer-toolbar .btn:hover {
  background: #e9edf2;
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #2e63b3));
}

/* An attach button the company turned off: aria-disabled, NOT `disabled`, so
   it still takes hover and focus and its tooltip can say why. Looks like
   Bootstrap's disabled button (opacity .65) and does not light up on hover. */
.news-feed-composer-toolbar .btn[aria-disabled="true"] {
  opacity: 0.65;
  cursor: not-allowed;
}

.news-feed-composer-toolbar .btn[aria-disabled="true"]:hover {
  background: transparent;
  color: #5a6572;
}

.news-feed-composer-toolbar__divider {
  display: inline-block;
  width: 1px;
  height: 18px;
  background: #dde1e7;
  margin: 0 5px;
  align-self: center;
  flex-shrink: 0;
}

/* Edit-pane uses flex column so we can reorder the AI strip below the
   editor box without restructuring the DOM (preserves Stimulus targets). */
.news-feed-composer__editor [data-news-feed--markdown-toolbar-target="editPane"] {
  display: flex;
  flex-direction: column;
}

/* AI strip placed last so it always renders below the editor + counter. */
.news-feed-composer__editor [data-news-feed--markdown-toolbar-target="editPane"] .news-feed-composer__ai-strip {
  order: 3;
  margin-top: 12px;
  margin-bottom: 0;
}

.news-feed-composer__editor [data-news-feed--markdown-toolbar-target="editPane"] .news-feed-enhance-diff {
  order: 4;
  margin-top: 8px;
  margin-bottom: 0;
}

.news-feed-composer__editor [data-news-feed--markdown-toolbar-target="editPane"] .news-feed-composer__editor-box {
  order: 1;
}

.news-feed-composer__editor [data-news-feed--markdown-toolbar-target="editPane"] .news-feed-composer__char-counter {
  order: 2;
}

/* The Topics row and the suggested-topics strip follow the counter, under the
   message — where the published post shows its topics. Without an `order`
   they defaulted to 0 and were drawn ABOVE the toolbar. */
.news-feed-composer__editor [data-news-feed--markdown-toolbar-target="editPane"] .news-feed-topic-suggestions {
  order: 2;
}

/* Editor box — wraps toolbar + textarea in a single bordered container */
.news-feed-composer__editor-box {
  border: 1px solid #ced4da;
  border-radius: 8px;
  background: #fff;
}

/* Floating mic — 34x34 circle at bottom-right of the textarea (design handoff). */
.news-feed-composer__mic-slot {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 2;
}

.news-feed-composer__mic-slot .btn,
.news-feed-composer__mic-slot button[data-news-feed--voice-recorder-target="triggerButton"] {
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid #ced4da;
  background: #fff;
  color: #6c757d;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.news-feed-composer__mic-slot .btn:hover,
.news-feed-composer__mic-slot button[data-news-feed--voice-recorder-target="triggerButton"]:hover {
  background: #eef3f9;
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #2e63b3));
  border-color: var(--bs-primary, #2e63b3);
}

/* Char counter — text below the editor box, right-aligned; the autosave
   status ("Draft saved"), when the composer passes one, sits at its left.
   #6c757d, not #adb5bd: the lighter grey measured 2.07:1 on white, so the
   count was the hardest text on the page to read (WCAG AA wants 4.5:1). */
.news-feed-composer__char-counter {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 0.75rem;
  font-size: var(--type-small);
  color: #6c757d;
  margin-top: 6px;
}

.news-feed-composer__char-counter small {
  font-size: var(--type-small);
  color: #6c757d;
}

/* Textarea — seamless join with toolbar, no border, full padding */
.news-feed-composer__editor textarea.form-control {
  border: none !important;
  border-radius: 0 !important;
  resize: vertical;
  min-height: 156px;
  padding: 13px 52px 13px 15px;
  font-size: inherit;
  line-height: 1.6;
}

.news-feed-composer__editor textarea.form-control:focus {
  box-shadow: none !important;
  border-color: transparent !important;
}

/* (Old char-overlay removed — counter now sits below the editor box.) */


/* Bootstrap's `d-flex` defeats the HTML `hidden` attribute (display: flex
   wins over display: none from the user-agent style). Restore the
   expected hide-when-hidden behavior for composer rows.
   `d-block` (display: block !important) defeats it the same way, so the
   AI-enhance error banner is listed here too — its 5s auto-dismiss only sets
   `hidden`, leaving the red message on screen forever without this rule.
   The voice recorder's warning line is the same shape (`.d-block` + a JS
   `hidden` toggle in _showWarning), so it holds its margin-top gap open under
   the transcript on every recording. */
.news-feed-composer__media-count[hidden],
[data-news-feed--enhance-target="error"][hidden],
[data-news-feed--voice-recorder-target="warning"][hidden] {
  display: none !important;
}

/* ---------- Audience chip multi-select (design handoff) ---------- */
.news-feed-audience-picker {
  position: relative;
}

.news-feed-audience-picker__control {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-height: 42px;
  border: 1px solid #ced4da;
  border-radius: 8px;
  padding: 6px 40px 6px 10px;
  background: #fff;
  cursor: pointer;
  position: relative;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.news-feed-audience-picker__control:focus,
.news-feed-audience-picker__control.is-open {
  outline: none;
  border-color: #86b7fe;
  box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb, 13, 110, 253), 0.18);
}

.news-feed-audience-picker__chips {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  flex: 1;
}

.news-feed-audience-picker__placeholder {
  color: #adb5bd;
  font-size: inherit;
  padding: 4px 0;
}

.news-feed-audience-picker__chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #e7eefb;
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #2e63b3));
  font-size: var(--type-small);
  font-weight: 500;
  padding: 4px 9px;
  border-radius: 6px;
}

.news-feed-audience-picker__chip i {
  font-size: var(--type-caption);
}

.news-feed-audience-picker__chip-remove {
  cursor: pointer;
  margin-left: 1px;
  opacity: 0.7;
  line-height: 1;
}

.news-feed-audience-picker__chip-remove:hover {
  opacity: 1;
}

.news-feed-audience-picker__caret {
  position: absolute;
  right: 13px;
  top: 50%;
  transform: translateY(-50%);
  color: #6c757d;
  font-size: var(--type-caption);
  pointer-events: none;
  transition: transform 0.15s;
}

.news-feed-audience-picker__control.is-open .news-feed-audience-picker__caret {
  transform: translateY(-50%) rotate(180deg);
}

.news-feed-audience-picker__menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  background: #fff;
  border: 1px solid #e6e9ee;
  border-radius: 8px;
  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
  z-index: 20;
  padding: 6px;
  max-height: 280px;
  overflow-y: auto;
}

.news-feed-audience-picker__option {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  background: transparent;
  transition: background 0.1s;
}

.news-feed-audience-picker__option:hover {
  background: #f8f9fb;
}

.news-feed-audience-picker__option.is-selected {
  background: #f4f7fc;
}

.news-feed-audience-picker__check {
  width: 18px;
  height: 18px;
  border-radius: 4px;
  border: 1.5px solid #ced4da;
  background: #fff;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.news-feed-audience-picker__option.is-selected .news-feed-audience-picker__check {
  border-color: var(--bs-primary, #2e63b3);
  background: var(--bs-primary, #2e63b3);
}

.news-feed-audience-picker__option.is-selected .news-feed-audience-picker__check::after {
  content: "\f00c";
  font-family: "Font Awesome 6 Free";
  font-weight: 900;
  color: #fff;
  font-size: var(--type-caption);
}

.news-feed-audience-picker__icon {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: #eef3f9;
  color: var(--bs-primary-ink-on-light, var(--bs-primary, #2e63b3));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 13px;
}

.news-feed-audience-picker__option-body {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.news-feed-audience-picker__option-label {
  font-size: inherit;
  font-weight: 500;
  color: #212529;
}

.news-feed-audience-picker__option-sub {
  font-size: var(--type-caption);
  color: #8a929c;
}

.news-feed-audience-picker__reach {
  font-size: var(--type-small);
  color: #6c757d;
}

.news-feed-audience-picker__reach i {
  font-size: var(--type-caption);
  color: #adb5bd;
}

.news-feed-audience-picker__reach strong {
  color: #495057;
  font-weight: 600;
  margin: 0 3px;
}


/* PRD 05 Unit 6 — reserve vertical space for poll result rows so the
   card doesn't reflow when the live-update handler swaps voting UI for
   results. --sf-poll-rows is set inline by _poll.html.erb to the option
   count; 44px matches the per-row height (label + 6px bar + margin). */
.news-feed-poll {
  min-height: calc(var(--sf-poll-rows, 4) * 44px);
}

/* PRD 05 Unit 11 — Present (FR-05-13): the poll block itself goes full
   screen in place (poll_presenter_controller.js adds .is-presenting and asks
   the Fullscreen API; where that is refused the same rules fill the window).
   Sized for a meeting-room or break-room screen: the question large, the
   results always shown (an author or admin sees them without voting), and
   everything that is for the person at the desk steps aside. Tester round 4,
   rows 19 + 21 (the old <dialog> portal closed itself the moment it opened). */
.news-feed-poll.is-presenting {
  position: fixed;
  inset: 0;
  z-index: 1090;
  margin: 0;
  min-height: 0;
  padding: clamp(1.5rem, 6vh, 4.5rem) clamp(1.5rem, 8vw, 9rem);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* `safe`: a long poll scrolls from its top instead of being cut off. */
  justify-content: safe center;
  background: var(--bs-body-bg, #fff);
  color: var(--bs-body-color, #212529);
  font-size: clamp(1.125rem, 0.75rem + 1.4vw, 2.25rem);
}

.news-feed-poll.is-presenting:fullscreen {
  width: 100%;
  height: 100%;
}

.news-feed-poll.is-presenting .news-feed-poll__not-presented {
  display: none !important;
}

/* Bootstrap's [hidden] is display:none !important; the results block is
   hidden for a presenter who has not voted, and shown here regardless. */
.news-feed-poll.is-presenting [data-news-feed--poll-vote-target="results"][hidden] {
  display: block !important;
}

.news-feed-poll__presenting-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: 1.25em;
}

.news-feed-poll__presenting-title {
  font-size: 1.5em;
  font-weight: 700;
  line-height: 1.2;
  margin: 0;
  overflow-wrap: anywhere;
}

.news-feed-poll__presenting-close {
  flex-shrink: 0;
}

.news-feed-poll.is-presenting .progress {
  height: 0.75em !important;
}

.news-feed-poll.is-presenting [data-news-feed--poll-vote-target="results"] .mb-2,
.news-feed-poll.is-presenting [data-news-feed--poll-vote-target="results"] .mb-3 {
  margin-bottom: 0.9em !important;
}

/* The use case is a projected or wall screen, not a phone. */
@media (max-width: 767.98px) {
  .news-feed-poll .news-feed-poll-present-row { display: none !important; }
}

/* PRD 05 Unit 13 — visible keyboard focus ring for poll option buttons.
   Bootstrap's default :focus ring is dropped on .btn-outline-* when the
   button has .active, so we restore a 3:1-contrast ring via focus-visible
   only (keyboard users only, not mouse click). */
.news-feed-poll [data-news-feed--poll-vote-target="optionButton"]:focus-visible {
  outline: 3px solid var(--bs-primary, #0d6efd);
  outline-offset: 2px;
  box-shadow: none;
}

.news-feed-poll__presenting-close:focus-visible {
  outline: 3px solid var(--bs-primary, #0d6efd);
  outline-offset: 2px;
}

/* PRD 07 — AI Enhance diff highlight colors and toolbar layout. */
.news-feed-enhance__add {
  background: rgba(46, 160, 67, 0.18);
  text-decoration: none;
}
.news-feed-enhance__remove {
  background: rgba(207, 34, 46, 0.18);
  text-decoration: line-through;
}
.news-feed-enhance__diff-body {
  white-space: pre-wrap;
  word-break: break-word;
}
@media (max-width: 575.98px) {
  /* Tone pills scroll horizontally on narrow screens (PRD §7.2). */
  .news-feed-enhance-toolbar .btn-group {
    overflow-x: auto;
    flex-wrap: nowrap;
  }
}

/* PRD 08 Phase 7 — Read Aloud player. Hidden until a feed-card Listen button
   enqueues something; the controller toggles `is-active` to reveal.

   A mini-player DOCKED TO THE BOTTOM of the viewport (tester round
   2026-10-09). It used to stick under the navbar at the top of the column, so
   Listen — at the foot of a post — opened a white bar ABOVE the post, often
   out of sight, on a white page. Docked, it stays in reach while the reader
   scrolls and reads along; it sits over the column of cards it is reading
   (the controller sets --nf-ra-left / --nf-ra-width from that card's box),
   and it is a raised panel: the card surface, a hairline and a real shadow.

   z-index 1025: over the page and the sticky rail and sidebar (1020), under
   the navbar and its dropdowns (1030), drawers and modals (1045+) and the
   toasts (1080/1090), which the rules at the end of this block lift clear of
   it. While it is open the controller puts `nf-read-aloud-open` and its height
   (--nf-read-aloud-height) on <body>. */
.news-feed-read-aloud-player {
  display: none;
  position: fixed;
  z-index: 1025;
  left: var(--nf-ra-left, 16px);
  width: var(--nf-ra-width, calc(100% - 32px));
  max-width: calc(100vw - 16px);
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  background: var(--bs-card-bg, var(--bs-body-bg, #fff));
  color: var(--bs-body-color);
  /* The brand in the hairline: over a card of the same white (or, dark, the
     same grey) a neutral border and the shadow alone left the edge vague. */
  border: 1px solid color-mix(in srgb, var(--bs-primary, #3b7ddd) 40%, var(--nf-line, #dee2e6));
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16), 0 2px 8px rgba(0, 0, 0, 0.08);
  padding: 10px 14px 8px;
}

.news-feed-read-aloud-player.is-active {
  display: block;
}

/* Dark: a shadow barely reads on a dark page, so the panel is also lifted a
   step above the cards it floats over (6% toward white — inside the range the
   dark secondary ink was measured against, #333 to #384350). */
:root[data-theme="dark"] .news-feed-read-aloud-player {
  background: color-mix(in srgb, var(--bs-card-bg, #333) 94%, #fff);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.35);
}

/* The acknowledgement prompt, above the controls when the post asks for one. */
.news-feed-read-aloud-player__ack {
  flex-wrap: wrap;
  margin-bottom: 8px;
}

/* Controls · what is playing · up next · speed · close, on one line. */
.news-feed-read-aloud-player__main {
  display: flex;
  align-items: center;
  gap: 12px;
}
.news-feed-read-aloud-player__controls {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.news-feed-read-aloud-player__play {
  width: 40px;
  height: 40px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* The play triangle's optical centre sits left of its box. */
.news-feed-read-aloud-player__play .fa-play { margin-left: 2px; }
.news-feed-read-aloud-player__skip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.news-feed-read-aloud-player__now {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.news-feed-read-aloud-player__eyebrow {
  font-size: var(--type-caption, 12px);
  line-height: 1.3;
  color: var(--nf-muted, var(--bs-secondary-color));
}
/* One line, cut with an ellipsis; the whole headline is its title attribute. */
.news-feed-read-aloud-player__title {
  font-weight: 600;
  line-height: 1.35;
  color: var(--nf-ink, var(--bs-heading-color));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.news-feed-read-aloud-player__queue {
  flex-shrink: 0;
  padding: 3px 10px;
  border-radius: 50rem;
  font-size: var(--type-caption, 12px);
  font-weight: 600;
  color: var(--nf-muted, var(--bs-secondary-color));
  background: var(--nf-surface, var(--bs-tertiary-bg));
  white-space: nowrap;
}
.news-feed-read-aloud-player__queue[hidden] { display: none; }
.news-feed-read-aloud-player__speed { flex-shrink: 0; }
.news-feed-read-aloud-player__close {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--nf-muted, var(--bs-secondary-color));
  text-decoration: none;
}
.news-feed-read-aloud-player__close:hover,
.news-feed-read-aloud-player__close:focus-visible {
  color: var(--nf-ink, var(--bs-heading-color));
}

/* Elapsed · seek bar · length. */
.news-feed-read-aloud-player__progress {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
}
.news-feed-read-aloud-player__time {
  flex-shrink: 0;
  min-width: 2.75em;
  font-size: var(--type-caption, 12px);
  color: var(--nf-muted, var(--bs-secondary-color));
  font-variant-numeric: tabular-nums;
}
.news-feed-read-aloud-player__time--total { text-align: right; }

/* A native range drawn as the design system's Progress bar (the theme's
   primary over a hairline track) with a thumb to drag: the DS has a progress
   bar but no slider. The controller sets --nf-ra-pct as the audio plays;
   Firefox paints the filled part itself (::-moz-range-progress). 24px tall
   so the whole row is the touch target, not the 6px track. */
.news-feed-read-aloud-player__seek {
  --nf-ra-pct: 0%;
  --nf-ra-track: var(--nf-line, var(--bs-border-color, #dee2e6));
  flex: 1 1 auto;
  min-width: 0;
  height: 24px;
  margin: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.news-feed-read-aloud-player__seek:disabled { cursor: default; opacity: 0.6; }
.news-feed-read-aloud-player__seek:focus { outline: none; }
.news-feed-read-aloud-player__seek:focus-visible {
  outline: 2px solid var(--bs-primary, #3b7ddd);
  outline-offset: 2px;
  border-radius: 4px;
}
.news-feed-read-aloud-player__seek::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 50rem;
  background: linear-gradient(to right, var(--bs-primary, #3b7ddd) var(--nf-ra-pct), var(--nf-ra-track) var(--nf-ra-pct));
}
.news-feed-read-aloud-player__seek::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -5px;
  border-radius: 50%;
  background: var(--bs-primary, #3b7ddd);
  border: 2px solid var(--bs-card-bg, #fff);
  box-shadow: 0 0 0 1px var(--bs-primary, #3b7ddd);
}
.news-feed-read-aloud-player__seek::-moz-range-track {
  height: 6px;
  border-radius: 50rem;
  background: var(--nf-ra-track);
}
.news-feed-read-aloud-player__seek::-moz-range-progress {
  height: 6px;
  border-radius: 50rem;
  background: var(--bs-primary, #3b7ddd);
}
.news-feed-read-aloud-player__seek::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--bs-primary, #3b7ddd);
  border: 2px solid var(--bs-card-bg, #fff);
  box-shadow: 0 0 0 1px var(--bs-primary, #3b7ddd);
}

/* Phone / narrow window: the full width with an 8px gutter, the headline on
   its own line beside close, the controls and speed under it. */
@media (max-width: 575.98px) {
  .news-feed-read-aloud-player {
    left: 8px;
    right: 8px;
    width: auto;
    max-width: none;
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    padding: 10px 12px 8px;
  }
  .news-feed-read-aloud-player__main {
    flex-wrap: wrap;
    row-gap: 8px;
  }
  .news-feed-read-aloud-player__now { order: -1; flex: 1 1 calc(100% - 44px); }
  .news-feed-read-aloud-player__close { order: -1; }
  .news-feed-read-aloud-player__speed { margin-left: auto; }
}

/* While it is open: room under the last post so its Listen, reactions and
   comments can scroll clear of the panel, and the toasts land above it
   rather than over its controls. `.content` carries an !important padding
   at >=992px (custom.css), hence the one here. */
body.nf-read-aloud-open #main-content {
  padding-bottom: calc(var(--nf-read-aloud-height, 96px) + 32px) !important;
}
body.nf-read-aloud-open #globalToastContainer,
body.nf-read-aloud-open #toaster-container {
  bottom: calc(var(--nf-read-aloud-height, 96px) + 8px) !important;
}
body.nf-read-aloud-open .notyf {
  padding-bottom: calc(var(--nf-read-aloud-height, 96px) + 36px);
}

/* PRD 11 §7.1 — topic chip strip. Muted background, 12sp / 0.75rem,
 * min 28px height for touch targets. */
.news-feed-topic-chips {
  padding-left: 0;
}

/* A topic name is authored (admin-created, or a #hashtag lifted out of a post
   body), so a chip can hold one long unbroken token. Untreated the chip is a
   single unshrinkable inline-flex box: measured 1431px inside the 1158px feed
   filter card, which burst the card and took 261px of the page with it
   (ISS-20260903-353-B1C4BF). max-width pins the chip to its container and
   `anywhere` is what actually lets the token break — `break-word` is ignored
   when honouring it would change the box's min-content width, which is exactly
   this case. min-width on the flex line keeps the text run shrinkable. */
/* Fill, size and radius follow the 2026-09-17 feed comp's `.nf-chip` so the
   chips on a post, on a comment and in the rail's Topics panel are one
   component rather than three near-misses. */
.news-feed-topic-chip {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  min-width: 0;
  overflow-wrap: anywhere;
  min-height: 26px;
  padding: 0 10px;
  border-radius: 50rem;
  /* Theme tokens (#4343): the chip followed the dark theme only once the
     June filter rule below stopped shadowing it. */
  background-color: var(--nf-surface);
  color: var(--nf-muted);
  font-size: var(--type-small);
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  border: 1px solid transparent;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.news-feed-topic-chip:hover,
.news-feed-topic-chip:focus-visible {
  background-color: var(--nf-divider);
  color: var(--nf-body-ink);
  text-decoration: none;
  outline: none;
  border-color: #c5cfdb;
}

.news-feed-topic-chip:focus-visible {
  box-shadow: 0 0 0 2px rgba(var(--bs-primary-rgb, 13, 110, 253), 0.25);
}

.news-feed-topic-chip--overflow {
  background-color: transparent;
  color: var(--nf-muted);
  cursor: default;
}

.news-feed-topic-chip--overflow:hover {
  background-color: transparent;
  color: var(--nf-muted);
  border-color: transparent;
}

/* Layer-3 relevance (design-principle doc) — followed-topic star on chips.
   The star is the explainability affordance for the social-tier ordering
   boost: "you follow this, so it surfaced higher". */
.news-feed-topic-chip__followed-star {
  font-size: var(--type-caption);
  margin-left: 4px;
  /* 4.7:1 on the followed chip's hover fill (#f7efd2); #b8860b read 2.8:1. */
  color: #8a6400;
}

/* The tinted fills take the body ink: the muted grey sits near 4.4:1 on a
   tint, under AA. */
.news-feed-topic-chip--followed {
  border-color: #e6d9a8;
  background-color: #fdf8e7;
  color: var(--nf-body-ink);
}

.news-feed-topic-chip--followed:hover,
.news-feed-topic-chip--followed:focus-visible {
  background-color: #f7efd2;
  border-color: #d9c98a;
}

/* App-contributed posts: the contributor topic chip is tinted — immutable, no
   edit affordance. The words "via Contests" are on the byline
   (apps/news_feed/shared/_delegated_byline), not on the chip. */
.news-feed-topic-chip--provenance {
  border-color: #d3dce6;
  background-color: #f4f7fa;
  color: var(--nf-body-ink);
}

/* PRD 11 §7.1 — active-filter chip ribbon at the top of the feed. */
.news-feed-active-filter__chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  background-color: #fff3cd;
  color: #664d03;
  font-size: 0.85rem;
  border: 1px solid #ffe69c;
}

.news-feed-active-filter__clear {
  color: #664d03;
  text-decoration: none;
  font-weight: 600;
  line-height: 1;
  padding: 0 2px;
}

.news-feed-active-filter__clear:hover,
.news-feed-active-filter__clear:focus-visible {
  color: #523c01;
  text-decoration: none;
  outline: none;
}

/* PRD 11 §5.2 — Composer "AI suggests …" chip strip. Sits below the
 * textarea, only visible when the suggestions endpoint returns slugs. */
.news-feed-topic-suggestions {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background-color: #f4f7fb;
  border: 1px dashed #c5cfdb;
  border-radius: 8px;
  font-size: 0.8rem;
}

.news-feed-topic-suggestions__label {
  color: #495057;
  font-weight: 500;
  flex-shrink: 0;
}

.news-feed-topic-suggestions__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  flex: 1 1 auto;
}

.news-feed-topic-suggestion-chip {
  display: inline-flex;
  align-items: center;
  background-color: #fff;
  border: 1px solid #c5cfdb;
  border-radius: 14px;
  padding: 2px 4px 2px 10px;
  font-size: 0.75rem;
  line-height: 1.2;
}

.news-feed-topic-suggestion-chip__label {
  margin-right: 4px;
}

.news-feed-topic-suggestion-chip__close {
  background: transparent;
  border: 0;
  color: #6c757d;
  font-size: 0.95rem;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  border-radius: 50%;
}

.news-feed-topic-suggestion-chip__close:hover,
.news-feed-topic-suggestion-chip__close:focus-visible {
  background-color: #f1f3f5;
  color: #1f2d3d;
  outline: none;
}

.news-feed-topic-suggestions__action {
  flex-shrink: 0;
  padding: 0 6px;
  text-decoration: none;
  color: #6c757d;
  font-size: 0.95rem;
}

.news-feed-topic-suggestions__action:hover {
  color: #1f2d3d;
  text-decoration: none;
}

/* PRD 18 §7.2 — sticky Must-Read CTA on mobile; in-flow on desktop. */
@media (max-width: 767.98px) {
  .news-feed-must-read-cta-sticky {
    position: sticky;
    bottom: 0;
    z-index: 1020;
    background: rgba(255, 255, 255, 0.96);
    padding: 12px;
    border-top: 1px solid #dee2e6;
    margin-left: -1rem;
    margin-right: -1rem;
  }
  .news-feed-must-read-cta-sticky .btn {
    min-height: 48px;
  }
  /* Analytics drawer renders as a bottom sheet on mobile. */
  .offcanvas-bottom.news-feed-analytics-drawer {
    height: 80vh;
    border-top-left-radius: 16px;
    border-top-right-radius: 16px;
  }
}

/* ============================================================================
   Signals dashboard — interactive type pills + filter bar (PRD 10 §7.1)
   ========================================================================== */
.news-feed-signals__types {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* Base pill (shared by the "All types" link and each type label).
   A signal type is a CATEGORY, so every type pill wears the same neutral
   outline: red, amber and green are spent on state (rulebook §5B), and an
   "Idea" in green / "Risk" in red read as a judgement the classifier never
   made. What a pill does carry in colour is the one state it has — selected —
   in the brand fill the "All types" pill already used. */
.news-feed-signals__pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--bs-border-color, #ced4da);
  border-radius: 50rem;
  padding: 0.4rem 0.95rem;
  font-size: var(--type-small);
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
  background: var(--bs-body-bg, #fff);
  color: var(--bs-body-color, #495057);
  transition: box-shadow 0.15s ease, background 0.15s ease, border-color 0.15s ease;
  text-decoration: none;
  user-select: none;
}
.news-feed-signals__pill:hover {
  background: var(--bs-tertiary-bg, #f6f8fb);
  color: var(--bs-body-color, #495057);
}
/* A type with no signals in the window reads quieter — the muted ink and a
   dashed outline, never opacity: 0.6 over the body colour was ~3:1 on white,
   under AA for a label people still click. */
.news-feed-signals__pill.is-empty {
  color: var(--bs-secondary-color, #6c757d);
  border-style: dashed;
}
.news-feed-signals__pill-count {
  font-weight: 600;
}
.news-feed-signals__pill-check {
  display: none;
  font-size: var(--type-caption);
}
.btn-check:checked + .news-feed-signals__pill,
.news-feed-signals__pill--all.is-active {
  background: var(--bs-primary, #2e63b3);
  color: var(--bs-on-primary, #fff);
  border-color: var(--bs-primary, #2e63b3);
}
.btn-check:checked + .news-feed-signals__pill .news-feed-signals__pill-check {
  display: inline-block;
}
.btn-check:focus-visible + .news-feed-signals__pill {
  box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb, 46, 99, 179), 0.35);
}

/* ============================================================================
   Tabbed feed — category tabs, topic-filter chips, verified-only toggle.
   ========================================================================== */
.news-feed-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  border-bottom: 1px solid #e6e9ee;
}
.news-feed-tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 15px;
  margin-bottom: -1px;
  font-size: inherit;
  font-weight: 500;
  color: #6c757d;
  text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.news-feed-tab:hover { color: #495057; }
.news-feed-tab__icon { font-size: 13px; color: #adb5bd; }
.news-feed-tab.is-active {
  color: var(--nf-tab-color, var(--bs-primary, #2e63b3));
  font-weight: 600;
  border-bottom-color: var(--nf-tab-color, var(--bs-primary, #2e63b3));
}
.news-feed-tab.is-active .news-feed-tab__icon { color: var(--nf-tab-color, var(--bs-primary, #2e63b3)); }
.news-feed-tab__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 50rem;
  font-size: var(--type-caption);
  font-weight: 600;
  background: #e9ecef;
  color: #495057;
}
.news-feed-tab.is-active .news-feed-tab__count {
  background: var(--nf-tab-color, var(--bs-primary, #2e63b3));
  color: #fff;
}
.news-feed-tab__count.is-red { background: var(--bs-danger, #dc3545); color: var(--bs-on-danger, #fff); }

/* Topic filter chips (btn-check labels). Scoped to the btn-check label
   (#4343): unscoped, this rule repeated `.news-feed-topic-chip` at the same
   specificity after the comp chip above and won everywhere — every chip on a
   post and comment painted #fff (a white island in the dark theme) and the
   --followed / --provenance / --overflow variants never painted. */
.btn-check + .news-feed-topic-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--nf-line);
  background: var(--bs-body-bg, #fff);
  color: var(--nf-muted);
  border-radius: 50rem;
  padding: 0.3rem 0.8rem;
  font-size: var(--type-small);
  font-weight: 500;
  cursor: pointer;
  line-height: 1.4;
  transition: all 0.15s ease;
}
.btn-check + .news-feed-topic-chip:hover { border-color: #aac0e4; }
.news-feed-topic-chip__check { display: none; font-size: var(--type-caption); }
.btn-check:checked + .news-feed-topic-chip {
  background: var(--bs-primary, #2e63b3);
  border-color: var(--bs-primary, #2e63b3);
  color: var(--bs-on-primary, #fff);
}
.btn-check:checked + .news-feed-topic-chip .news-feed-topic-chip__check { display: inline-block; }

/* "Verified answers only" toggle pill. */
.news-feed-verified-toggle {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--bs-success, #198754);
  background: #fff;
  color: var(--bs-success, #198754);
  border-radius: 50rem;
  padding: 0.38rem 0.85rem;
  font-size: var(--type-small);
  font-weight: 500;
  cursor: pointer;
  line-height: 1.4;
  transition: all 0.15s ease;
}
.news-feed-verified-toggle:hover { background: #f0fdf4; }
.btn-check:checked + .news-feed-verified-toggle {
  background: var(--bs-success, #198754);
  color: var(--bs-on-success, #fff);
}

/* ============================================================================
   Home dashboard — summary metric cards + "Important & unread" list.
   ========================================================================== */
.news-feed-metric { transition: transform 0.15s ease, box-shadow 0.15s ease; }
.news-feed-metric:hover { transform: translateY(-2px); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.1) !important; }
.news-feed-metric__label { font-size: var(--type-caption); letter-spacing: 0.04em; margin-bottom: 6px; }
.news-feed-metric__value { font-size: var(--type-display); font-weight: 600; line-height: 1; color: #212529; }
.news-feed-metric__icon {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  flex-shrink: 0;
}

.news-feed-dash-list .list-group-item { padding: 14px 16px; }
.news-feed-dash-list .list-group-item:hover { background: #f8fafd; }
.news-feed-dash-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: transparent;
  margin-top: 7px;
  flex-shrink: 0;
}
.news-feed-dash-dot.is-unread { background: var(--bs-primary, #3b7ddd); }
.news-feed-dash-headline {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.4;
}
.min-width-0 { min-width: 0; }

/* ============================================================================
   SMEs — managed-topic expert rows.
   ========================================================================== */
.border-dashed { border-style: dashed !important; }
.news-feed-sme-remove { opacity: 0; transition: opacity 0.15s ease; }
.news-feed-sme-expert:hover .news-feed-sme-remove { opacity: 1; }
.news-feed-sme-remove:hover { color: #b02a37 !important; }
@media (hover: none) { .news-feed-sme-remove { opacity: 1; } }

/* ============================================================================
   Composer "New Post" — AI assist now lives in the toolbar as a single "AI"
   dropdown (replaced the old always-on light-blue AI strip).

   The menu uses Popper's fixed strategy (set via data-bs-config on the toggle)
   so it escapes the toolbar's overflow:auto and the scrollable modal-body that
   would otherwise clip it to a single row. The global
   `.dropdown-menu { position: absolute !important }` in
   fixes/dropdown_fixes.css would force it back inside those clips, so this
   higher-specificity rule opts this one menu out.
   ========================================================================== */
.news-feed-composer__ai-menu.dropdown-menu {
  position: fixed !important;
}

/* ============================================================================
   Feed page — approved web comp (2026-09-17).

   The feed's card anatomy, filter card, footer and right rail, as specified by
   the design handed over for this page. Tints and inks are Bootstrap 5.3's
   own subtle/emphasis tokens so a tenant's brand still drives them; the
   fallbacks after each `var()` are the exact values the comp measured on the
   default theme, so an older/overridden token can never blank a surface.

   Everything here is scoped to `nf-` classes rather than Bootstrap's `.card`
   family: `body.mgx-restyle` re-skins `.card`, `.card-header` and
   `.card-footer` app-wide (custom.css), and a feed card that opted into those
   selectors would be re-skinned back out of this design.
   ========================================================================== */

:root {
  --nf-line:      #dee2e6;   /* card + control border */
  /* #4076 (2026-09-27): the fills and the grey inks are the theme's own
     tokens (Bootstrap's secondary/tertiary grounds equal the comp's values in
     the light theme), so the feed follows the dark theme; the dark block at
     the end of this section re-points the rest. #6c757d read 4.44:1 on the
     chip fill and 4.21:1 on the count pill; the theme's secondary ink clears
     4.5:1 on both, in both themes. */
  --nf-divider:   var(--bs-secondary-bg, #f1f3f5);   /* inner hairline */
  --nf-surface:   var(--bs-tertiary-bg, #f8f9fa);   /* chip / placeholder fill */
  --nf-ink:       #000;
  --nf-body-ink:  #495057;
  --nf-muted:     var(--bs-secondary-color, #6c757d);
  --nf-faint:     var(--bs-secondary-color, #6c757d); /* was #adb5bd — 2.07:1 on white; meta text must clear AA (/design-pass communications 2026-09-24) */
  --nf-radius:    0.5rem;
  --nf-radius-sm: 0.2rem;
  --nf-shadow:    0 0.1rem 0.2rem rgba(0, 0, 0, 0.05);
}

/* ---------- Page shell ---------- */
.nf-feed-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  align-items: flex-start;
}
.nf-feed-main {
  flex: 1 1 560px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.nf-feed-rail {
  flex: 1 1 280px;
  max-width: 320px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* Sticky only where there is room to scroll past it; below the wrap point the
   rail is stacked under the feed and sticking it would pin it to the viewport
   for the rest of the page. */
@media (min-width: 992px) {
  .nf-feed-rail { position: sticky; top: 96px; }
}

.nf-page-title { font-size: var(--type-page); line-height: 1.2; color: var(--nf-ink); }
.nf-page-sub   { font-size: var(--type-small); color: var(--nf-muted); margin-top: 4px; }

/* ---------- Card ---------- */
.nf-card {
  background: var(--bs-card-bg, #fff);
  border: 1px solid var(--nf-line);
  border-radius: var(--nf-radius);
  box-shadow: var(--nf-shadow);
  transition: transform 0.15s, box-shadow 0.15s;
}
.nf-card--flush { overflow: hidden; }
.nf-card__body { padding: 18px 20px 16px; }
/* Any strip below the body: the acknowledgement callout, the footer. */
.nf-card__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 16px;
  border-top: 1px solid var(--nf-divider);
}

/* ---------- Badge rail ---------- */
.nf-rail {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}
.nf-rail__spacer { flex: 1 1 0%; }

.nf-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--type-caption);
  font-weight: 600;
  letter-spacing: 0.4px;
  padding: 3px 10px;
  border-radius: 50rem;
  white-space: nowrap;
}
.nf-badge i { font-size: var(--type-caption); }
/* A tone pill's ink is the theme's ink FOR THAT TONE'S TINT (--bs-on-subtle-*,
   BusinessTheme#subtle_on_color_tokens: measured AA on every tint of the
   tenant's colour, per mode). --bs-*-text-emphasis is AdminKit's own shade and
   the theme re-points it only inside the `.text-*-emphasis` utilities, so on a
   branded tenant the pill drew AdminKit navy on the brand's tint — Announcement
   rust-on-rust in Compose and Measure, navy-on-rust here (verify 2026-10-09). */
.nf-badge--danger  { background: var(--bs-danger-bg-subtle,  #fdecec); color: var(--bs-on-subtle-danger,  var(--bs-danger-text-emphasis,  #b02a37)); }
.nf-badge--primary { background: var(--bs-primary-bg-subtle, #e7f0fc); color: var(--bs-on-subtle-primary, var(--bs-primary-text-emphasis, #1c5ba8)); }
.nf-badge--success { background: var(--bs-success-bg-subtle, #e8f8f2); color: var(--bs-on-subtle-success, var(--bs-success-text-emphasis, #12916c)); }
.nf-badge--info    { background: var(--bs-info-bg-subtle,    #e2f4fb); color: var(--bs-on-subtle-info,    var(--bs-info-text-emphasis,    #087990)); }
/* The two message-kind tones the feed lacked (#7693): every kind's pill takes
   its Comms::MessageKinds tone — Post secondary, Must-read warning — so a kind
   looks the same on the Compose tile and in the feed. The theme's own subtle
   pair: #664d03 on #fff3cd and #2b2f32 on #e2e3e5 clear AA, as do the dark twins. */
.nf-badge--warning   { background: var(--bs-warning-bg-subtle,   #fff3cd); color: var(--bs-on-subtle-warning,   var(--bs-warning-text-emphasis,   #664d03)); }
.nf-badge--secondary { background: var(--bs-secondary-bg-subtle, #e2e3e5); color: var(--bs-on-subtle-secondary, var(--bs-secondary-text-emphasis, #2b2f32)); }
/* Amber is stated as an alpha of its own ink rather than the Bootstrap subtle
   token: --bs-warning-bg-subtle is a yellow light enough that #997404 on it
   reads washed out, and this pill is the "Pinned"/"Expires" pair that has to
   stay legible beside the red one. */
.nf-badge--amber   { background: rgba(153, 116, 4, 0.12); color: var(--bs-on-subtle-warning, #997404); font-weight: 600; letter-spacing: normal; padding: 3px 9px; }
.nf-badge--type    { background: var(--nf-divider); color: var(--nf-muted); font-weight: 600; letter-spacing: 0.3px; text-transform: uppercase; padding: 3px 9px; gap: 0; }
.nf-badge--quiet   { background: var(--nf-surface); color: var(--nf-faint); font-weight: 600; letter-spacing: normal; padding: 3px 9px; gap: 0; }

.nf-expiry {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--type-caption);
  color: var(--bs-on-subtle-warning, #997404); /* #997404 read 4.32:1 on the card (#4076) */
  white-space: nowrap;
}
.nf-expiry i { font-size: var(--type-caption); }
.nf-unread-dot {
  width: 8px;
  height: 8px;
  border-radius: 50rem;
  background: var(--bs-primary, #3b7ddd);
  flex-shrink: 0;
}

/* ---------- Byline ---------- */
.nf-byline { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.nf-byline__name { font-size: inherit; font-weight: 600; color: var(--nf-ink); }
.nf-byline__meta { font-size: var(--type-caption); color: var(--nf-faint); margin-top: 1px; }
.nf-byline__menu {
  width: 32px;
  height: 32px;
  border-radius: var(--nf-radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--nf-faint);
  border: 0;
  background: transparent;
}
.nf-byline__menu:hover { background: var(--nf-surface); color: var(--nf-muted); }

/* ---------- Body ---------- */
.nf-title { font-size: var(--type-title); line-height: 1.35; color: var(--nf-ink); margin-bottom: 6px; }
.nf-body  { font-size: inherit; line-height: 1.65; color: var(--nf-body-ink); text-wrap: pretty; }
.nf-body p:last-child { margin-bottom: 0; }

/* ---------- Topic chips ---------- */
.nf-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.nf-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 26px;
  padding: 0 10px;
  border-radius: 50rem;
  background: var(--nf-surface);
  color: var(--nf-muted);
  font-size: var(--type-small);
  font-weight: 500;
  text-decoration: none;
  border: 0;
}
.nf-chip:hover { background: var(--nf-divider); color: var(--nf-body-ink); }
.nf-chip--on { background: var(--bs-primary-bg-subtle, #e7f0fc); color: var(--bs-primary-text-emphasis, #1c5ba8); }
/* No opacity (#4076): at .6 the count read 2.22:1 on the chip. Weight sets it apart. */
.nf-chip__count { font-size: var(--type-caption); font-weight: 600; }

/* ---------- Acknowledgement callout ---------- */
.nf-ack {
  background: rgba(252, 185, 44, 0.12);
  color: var(--bs-on-subtle-warning, #8a6100);
  gap: 11px;
  padding: 11px 16px;
}
.nf-ack i { font-size: var(--type-small); flex-shrink: 0; }
.nf-ack__text { flex: 1 1 0%; min-width: 0; font-size: var(--type-small); line-height: 1.45; }
.nf-ack__btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  min-height: 34px;
  padding: 0 16px;
  border: 0;
  border-radius: var(--nf-radius-sm);
  font-size: var(--type-small);
  font-weight: 600;
  background: var(--bs-warning, #fcb92c);
  color: var(--bs-on-warning, #4a3500);
}
.nf-ack__btn:hover { filter: brightness(0.96); color: var(--bs-on-warning, #4a3500); }
.nf-ack__btn i { font-size: var(--type-caption); }
/* Overdue: the SAME strip in the danger tone — past its acknowledge-by date
   and still asking (Comms::MustReadOverdue). Shared by a Must Read and a
   broadcast (shared/comms/_acknowledge_bar). Declared before --ok so an
   in-place acknowledgement's green wins whichever class is still on it. */
.nf-ack--overdue { background: var(--bs-danger-bg-subtle, #fbe7e9); color: var(--bs-danger-text-emphasis, #842029); }
.nf-ack--overdue .nf-ack__btn { background: var(--bs-danger, #dc3545); color: var(--bs-on-danger, #fff); }
.nf-ack--overdue .nf-ack__btn:hover { color: var(--bs-on-danger, #fff); }
/* Acknowledged: the SAME strip, turned green. The comp keeps the geometry and
   the leading glyph and swaps only the tint, the sentence and the button — so
   the card does not reflow when you answer it, and the answer lands where the
   question was. */
.nf-ack--ok { background: rgba(var(--bs-success-rgb, 28, 187, 140), 0.08); color: var(--bs-success-text-emphasis, #12916c); }
.nf-ack__btn--ok {
  background: var(--bs-success-bg-subtle, #e8f8f2);
  color: var(--bs-success-text-emphasis, #12916c);
  cursor: default;
}
.nf-ack__btn--ok:hover { filter: none; color: var(--bs-success-text-emphasis, #12916c); }
/* The neutral variants of the same strip: already acknowledged, window closed,
   not published yet. Same geometry so a card does not change height when its
   state changes. */
.nf-note { gap: 11px; padding: 11px 16px; font-size: var(--type-small); line-height: 1.45; }
.nf-note--ok    { background: var(--bs-success-bg-subtle, #e8f8f2); color: var(--bs-success-text-emphasis, #12916c); }
.nf-note--quiet { background: var(--nf-surface); color: var(--nf-muted); }
.nf-note--info  { background: var(--bs-primary-bg-subtle, #e7f0fc); color: var(--bs-primary-text-emphasis, #1c5ba8); }

/* ---------- Footer ---------- */
.nf-foot__react { display: flex; align-items: center; gap: 6px; }
.nf-quick {
  width: 30px;
  height: 30px;
  border-radius: 50rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: inherit;
  line-height: 1;
  border: 1px solid #e9ecef;
  background: var(--bs-card-bg, #fff);
  padding: 0;
  transition: transform 0.1s;
}
.nf-quick:hover { transform: scale(1.12); }
.nf-quick.is-mine { border-color: var(--bs-primary, #3b7ddd); background: var(--bs-primary-bg-subtle, #e7f0fc); }
/* A comment's single React button (tester round 4): an outline face in the
   footer's muted ink, darkening on hover — present, never louder than the words. */
.nf-quick--outline { color: var(--nf-muted); font-size: var(--type-small); }
.nf-quick--outline:hover, .nf-quick--outline:focus-visible { color: var(--nf-body-ink); border-color: var(--nf-muted); }
.nf-foot__count { font-size: var(--type-small); color: var(--nf-muted); margin-left: 2px; border: 0; background: none; padding: 0; }
.nf-foot__sep { width: 1px; height: 18px; background: #e9ecef; flex-shrink: 0; }
.nf-foot__action {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--type-small);
  color: var(--nf-muted);
  padding: 4px 8px;
  border: 0;
  border-radius: var(--nf-radius-sm);
  background: none;
  text-decoration: none;
}
.nf-foot__action:hover { background: var(--nf-surface); color: var(--nf-body-ink); }
.nf-foot__action i { font-size: var(--type-small); }
.nf-foot__stats {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-size: var(--type-small);
  color: var(--nf-muted);
  flex-wrap: wrap;
}
.nf-foot__stats b { font-weight: 600; color: var(--nf-body-ink); }
.nf-foot__link {
  font-weight: 600;
  color: var(--bs-link-color, var(--bs-primary, #3b7ddd));
  border: 0;
  background: none;
  padding: 0;
  text-decoration: none;
}
.nf-foot__link[disabled] { color: var(--nf-faint); }

/* ---------- Filter card ---------- */
.nf-filter { padding: 6px 8px; }
.nf-filter__tabs { display: flex; flex-wrap: wrap; gap: 4px; }
.nf-tab2 {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  min-height: 36px;
  padding: 0 14px;
  border-radius: var(--nf-radius-sm);
  font-size: var(--type-small);
  font-weight: 500;
  color: var(--nf-muted);
  background: transparent;
  text-decoration: none;
  white-space: nowrap;
}
.nf-tab2:hover { background: var(--nf-surface); color: var(--nf-body-ink); }
.nf-tab2 i { font-size: var(--type-caption); }
/* The tinted fill, the brand ink and the weight mark the chosen tab; the
   underline it also carried said the same thing a fourth time (tester round
   4, 2026-10-10: "remove the redundant underline"). */
.nf-tab2.is-active {
  font-weight: 600;
  color: var(--bs-primary-text-emphasis, #1c5ba8);
  background: var(--bs-primary-bg-subtle, #e7f0fc);
}
.nf-tab2__count {
  font-size: var(--type-caption);
  font-weight: 600;
  padding: 1px 7px;
  border-radius: 50rem;
  background: var(--nf-divider);
  color: var(--nf-muted);
}
.nf-tab2__count--danger { background: var(--bs-danger-bg-subtle, #fdecec); color: var(--bs-danger-text-emphasis, #b02a37); }

.nf-filter__sort {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 8px 6px 4px;
  border-top: 1px solid var(--nf-divider);
  margin-top: 6px;
}
.nf-filter__label { font-size: var(--type-caption); color: var(--nf-muted); }
/* The feed's ONE filter row: tabs (what needs you) left, Type and Sort right;
   wraps to two lines on a narrow screen instead of scrolling. */
.nf-filter__row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; }
.nf-filter__row .nf-filter__sort { border-top: 0; margin-top: 0; padding: 2px 4px; }
.nf-filter__select { font-size: var(--type-small); min-height: 32px; padding-top: 4px; padding-bottom: 4px; }
.nf-sortchip {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 0 11px;
  border-radius: 50rem;
  font-size: var(--type-small);
  font-weight: 500;
  color: var(--nf-muted);
  background: var(--nf-surface);
  text-decoration: none;
}
.nf-sortchip:hover { background: var(--nf-divider); color: var(--nf-body-ink); }
.nf-sortchip.is-active { color: var(--bs-primary-text-emphasis, #1c5ba8); background: var(--bs-primary-bg-subtle, #e7f0fc); }
.nf-toggle2 {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 30px;
  padding: 0 12px;
  border-radius: 50rem;
  font-size: var(--type-small);
  font-weight: 500;
  border: 1px solid var(--nf-line);
  background: var(--bs-card-bg, #fff);
  color: var(--nf-muted);
  cursor: pointer;
  margin-bottom: 0;
}
.nf-toggle2 i { font-size: var(--type-caption); }
.nf-toggle2:hover { background: var(--nf-surface); }
.btn-check:checked + .nf-toggle2 {
  border-color: var(--bs-primary, #3b7ddd);
  background: var(--bs-primary-bg-subtle, #e7f0fc);
  color: var(--bs-primary-text-emphasis, #1c5ba8);
}

/* ---------- Search box ---------- */
.nf-search { position: relative; flex-shrink: 0; }
.nf-search i {
  position: absolute;
  left: 11px;
  top: 50%;
  transform: translateY(-50%);
  font-size: var(--type-caption);
  color: var(--nf-faint);
  pointer-events: none;
}
.nf-search input {
  width: 240px;
  max-width: 100%;
  box-sizing: border-box;
  height: 34px;
  padding: 0 12px 0 32px;
  border: 1px solid #ced4da;
  border-radius: var(--nf-radius-sm);
  background: var(--bs-card-bg, #fff);
  color: var(--nf-body-ink);
  font-size: var(--type-small);
}
/* Beside the header's Post button, the box stretches to the row the button
   sets, so the two read as one row of controls whatever the theme's sizes. */
.nf-header-actions { align-items: stretch; }
.nf-header-actions .nf-search input { height: 100%; font-size: inherit; }

/* ---------- Right-rail panels ---------- */
.nf-panel__head {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--nf-line);
}
.nf-panel__head i { font-size: var(--type-caption); }
.nf-panel__head--danger { background: rgba(var(--bs-danger-rgb, 220, 53, 69), 0.06); }
.nf-panel__title { flex: 1 1 0%; min-width: 0; font-size: var(--type-small); font-weight: 600; color: var(--nf-ink); }
.nf-panel__count {
  font-size: var(--type-caption);
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 50rem;
  background: var(--bs-danger-bg-subtle, #fdecec);
  color: var(--bs-danger-text-emphasis, #b02a37);
}
.nf-panel__row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 16px;
  border-top: 1px solid var(--nf-divider);
  text-decoration: none;
}
.nf-panel__row:first-of-type { border-top: 0; }
.nf-panel__row:hover { background: var(--nf-surface); }
.nf-panel__row-title { font-size: var(--type-small); line-height: 1.4; color: var(--nf-body-ink); text-wrap: pretty; }
.nf-panel__row-meta { font-size: var(--type-caption); color: var(--bs-on-subtle-warning, #997404); margin-top: 3px; }
.nf-panel__pad { padding: 14px 16px; }
.nf-panel__foot {
  display: block;
  padding: 10px 16px;
  border-top: 1px solid var(--nf-divider);
  font-size: var(--type-small);
  font-weight: 600;
  color: var(--bs-link-color, var(--bs-primary, #3b7ddd));
  text-decoration: none;
}
.nf-panel__foot:hover { background: var(--nf-surface); }
.nf-panel__empty { padding: 14px 16px; font-size: var(--type-small); color: var(--nf-muted); }
.nf-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); padding: 14px 16px; gap: 10px; }
.nf-stat { min-width: 0; }
.nf-stat__value { font-size: var(--type-display); line-height: 1.1; color: var(--nf-ink); }
.nf-stat__label { font-size: var(--type-caption); color: var(--nf-muted); margin-top: 3px; }

/* ---------- Documents ----------
   The comp's attachment card: a white tile with a type-coloured glyph, the
   filename, its size beneath, and the action on the right. Replaces a grey
   `bg-light` slab whose only affordance was a bare text link. Used by a post's
   file attachments AND by the policy a Must-Read asks you to accept, so a
   document looks like a document wherever the feed shows one. */
.nf-docs { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.nf-doc-label {
  font-size: var(--type-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--nf-faint);
  margin-bottom: 7px;
}
.nf-doc {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 13px;
  border: 1px solid var(--nf-line);
  border-radius: var(--nf-radius-sm);
  background: var(--bs-card-bg, #fff);
  text-decoration: none;
  transition: border-color 0.12s ease;
}
/* The whole tile is the link, so it must never take the app's global
   `a:hover { text-decoration: underline }` — a card is not a text link, and the
   underline lands on the filename and its meta line together. */
.nf-doc, .nf-doc:hover, .nf-doc:focus { text-decoration: none; }
.nf-doc:hover { border-color: var(--bs-primary, #3b7ddd); }
.nf-doc:hover .nf-doc__name { color: var(--bs-primary-text-emphasis, #1c5ba8); }
.nf-doc__icon { font-size: 20px; line-height: 1; flex-shrink: 0; }
.nf-doc__body { flex: 1 1 auto; min-width: 0; }
.nf-doc__name {
  font-size: var(--type-small);
  color: var(--nf-body-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nf-doc__meta { font-size: var(--type-caption); color: var(--nf-faint); margin-top: 1px; }
.nf-doc__action { flex-shrink: 0; margin-left: 6px; }
/* The "Edit/View in Microsoft 365" icon beside the download: the same
   thumb-sized target as the download it sits next to. */
.nf-doc__office { min-height: 44px; min-width: 44px; }

/* ---------- Poll ---------- */
.nf-poll { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.nf-poll__row {
  position: relative;
  border: 1px solid var(--nf-line);
  border-radius: var(--nf-radius-sm);
  overflow: hidden;
  background: var(--bs-card-bg, #fff);
  width: 100%;
  padding: 0;
  text-align: left;
}
.nf-poll__row:hover { border-color: var(--bs-primary, #3b7ddd); }
.nf-poll__fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: var(--bs-primary-bg-subtle, #e7f0fc);
}
.nf-poll__face {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
}
.nf-poll__label { flex: 1 1 0%; min-width: 0; font-size: var(--type-small); color: var(--nf-body-ink); }
.nf-poll__pct { font-size: var(--type-small); font-weight: 600; color: var(--bs-primary-text-emphasis, #1c5ba8); flex-shrink: 0; }
.nf-poll__meta { font-size: var(--type-caption); color: var(--nf-faint); margin-top: 10px; }

/* ============================================================================
   My Posts — approved web comp (2026-09-17).

   Reuses the feed comp's filter card wholesale (.nf-card / .nf-filter /
   .nf-tab2 / .nf-sortchip) — the two designs draw the same control — and adds
   only what a lifecycle row needs on top: the status/type pill rail, a meta
   line, and a fixed action column.
   ========================================================================== */

.mp-head { display: flex; align-items: flex-start; justify-content: space-between;
           gap: 20px; flex-wrap: wrap; margin-bottom: 20px; }
.mp-head__title { font-size: var(--type-page); line-height: 1.2; color: var(--nf-ink); font-weight: 600; }
.mp-head__sub { font-size: var(--type-small); color: var(--nf-muted); margin-top: 5px; max-width: 640px; text-wrap: pretty; }

.mp-list { display: flex; flex-direction: column; gap: 12px; }

.mp-row {
  background: var(--bs-card-bg, #fff);
  border: 1px solid var(--nf-line);
  border-radius: var(--nf-radius);
  box-shadow: var(--nf-shadow);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.mp-row:hover { transform: translateY(-2px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.10); }
.mp-row__body { display: flex; align-items: flex-start; gap: 16px; padding: 16px 18px; }
.mp-row__main { flex: 1; min-width: 0; }

/* Pill rail. These are square-ish (.2rem), NOT the feed card's round badges —
   a lifecycle state is a label on a row, not a tag on a post. */
.mp-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 9px; }
.mp-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--type-caption);
  font-weight: 500;
  padding: 2px 9px;
  border-radius: var(--nf-radius-sm);
  border: 1px solid var(--nf-line);
  background: var(--nf-surface);
  color: var(--nf-body-ink);
  white-space: nowrap;
}
.mp-pill i { font-size: var(--type-caption); }
.mp-pill--status { font-weight: 600; }
.mp-pill--draft     { background: var(--nf-surface); color: var(--nf-muted); border-color: var(--nf-line); }
.mp-pill--scheduled { background: var(--bs-primary-bg-subtle, #e7f0fc); color: var(--bs-on-subtle-primary, var(--bs-primary-text-emphasis, #1c5ba8)); border-color: rgba(var(--bs-primary-rgb, 59, 125, 221), 0.25); }
.mp-pill--approval  { background: rgba(252, 185, 44, 0.16); color: var(--bs-on-subtle-warning, #8a6100); border-color: rgba(252, 185, 44, 0.35); }
.mp-pill--published { background: var(--bs-success, #1cbb8c); color: var(--bs-on-success, #fff); border-color: var(--bs-success, #1cbb8c); }
/* A row's kind, in its Compose tile tone (#7693): `mp-pill--tone-<tone>` from
   Comms::MessageKinds — Broadcast red, Must-read amber, Announcement primary,
   Post and Placed only secondary — the feed pill's fill and ink
   (.nf-badge--<tone>). Announcement and Post were the plain grey pill, so
   My Posts disagreed with Compose and the feed on both. */
.mp-pill--tone-danger    { background: var(--bs-danger-bg-subtle, #fdecec);    color: var(--bs-on-subtle-danger, var(--bs-danger-text-emphasis, #b02a37));          border-color: rgba(var(--bs-danger-rgb, 220, 53, 69), 0.25); }
.mp-pill--tone-warning   { background: var(--bs-warning-bg-subtle, #fff3cd);   color: var(--bs-on-subtle-warning, var(--bs-warning-text-emphasis, #664d03));       border-color: rgba(var(--bs-warning-rgb, 255, 193, 7), 0.35); }
.mp-pill--tone-primary   { background: var(--bs-primary-bg-subtle, #e7f0fc);   color: var(--bs-on-subtle-primary, var(--bs-primary-text-emphasis, #1c5ba8));       border-color: rgba(var(--bs-primary-rgb, 59, 125, 221), 0.25); }
.mp-pill--tone-secondary { background: var(--bs-secondary-bg-subtle, #e2e3e5); color: var(--bs-on-subtle-secondary, var(--bs-secondary-text-emphasis, #2b2f32)); border-color: rgba(var(--bs-secondary-rgb, 108, 117, 125), 0.25); }

.mp-row__title { font-size: var(--type-title); line-height: 1.4; color: var(--nf-ink); margin-bottom: 6px; text-wrap: pretty; }
.mp-row__excerpt { font-size: var(--type-small); line-height: 1.6; color: var(--nf-muted); margin-bottom: 9px; text-wrap: pretty; }
.mp-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; font-size: var(--type-small); color: var(--nf-faint); }
.mp-meta span { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.mp-meta i { font-size: var(--type-caption); }

/* Acknowledgement progress. The fill colour is a reading of the number, not
   decoration: amber under 60%, brand blue on the way, green once everyone has
   answered. */
.mp-ack { max-width: 360px; margin-top: 12px; }
.mp-ack__row { display: flex; justify-content: space-between; font-size: var(--type-small); color: var(--nf-muted); margin-bottom: 5px; }
.mp-ack__value { font-weight: 600; color: var(--nf-body-ink); }
.mp-ack__track { height: 6px; border-radius: 50rem; background: #e9ecef; overflow: hidden; }
.mp-ack__fill { display: block; height: 100%; border-radius: 50rem; }

/* Action group: natural-width buttons side by side, right-anchored, never squeezed by a long
   headline (flex-shrink: 0 + nowrap is what keeps "Open" from wrapping under its icon). Was a
   152px column of full-width stacked buttons — a second row-action design beside every other
   list in the app (/design-pass communications 2026-09-24; CLAUDE.md: natural button width). */
.mp-actions { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: flex-end; gap: 8px; align-items: flex-start; flex-shrink: 0; }
.mp-actions .btn,
.mp-actions form { width: auto; }
.mp-actions .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 32px;
  padding: 0 12px;
  border-radius: var(--nf-radius-sm);
  font-size: var(--type-small);
  font-weight: 500;
  white-space: nowrap;
}
@media (max-width: 575.98px) {
  .mp-row__body { flex-direction: column; }
  .mp-actions { width: 100%; flex-direction: row; flex-wrap: wrap; }
  .mp-actions .btn, .mp-actions form { width: auto; flex: 1 1 auto; }
}

/* ============================================================================
   Broadcast composer — approved web comp (2026-09-17).
   The page already had the two-column shape and the settings-row drawers; this
   is the state the comp adds around them: what the draft is, what is stopping
   it, and what it will cost a recipient.
   ========================================================================== */

.bc-state {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--type-caption);
  font-weight: 600;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: var(--nf-radius-sm);
  border: 1px solid var(--nf-line);
  background: var(--nf-surface);
  color: var(--nf-muted);
  white-space: nowrap;
}
.bc-state i { font-size: var(--type-caption); }
.bc-state--scheduled { background: var(--bs-primary-bg-subtle, #e7f0fc); color: var(--bs-primary-text-emphasis, #1c5ba8); border-color: rgba(59, 125, 221, 0.25); }
.bc-state--approval  { background: rgba(252, 185, 44, 0.16); color: var(--bs-on-subtle-warning, #8a6100); border-color: rgba(252, 185, 44, 0.35); }
.bc-state--published { background: var(--bs-success, #1cbb8c); color: var(--bs-on-success, #fff); border-color: var(--bs-success, #1cbb8c); }
.bc-saved { font-size: var(--type-small); color: var(--nf-faint); white-space: nowrap; }

/* The blocking banner: says why the primary action will refuse, in the one
   place the author is already looking. */
.bc-blocker {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 16px;
  margin-bottom: 16px;
  border-radius: var(--nf-radius-sm);
  background: rgba(252, 185, 44, 0.12);
  color: var(--bs-on-subtle-warning, #8a6100);
  font-size: var(--type-small);
  line-height: 1.45;
}
.bc-blocker i { flex-shrink: 0; font-size: var(--type-small); }

/* Under the body: what you have written, and how it will read on a phone. */
.bc-body-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 6px;
  font-size: var(--type-small);
  color: var(--nf-faint);
}
.bc-body-foot__link { font-size: var(--type-small); border: 0; background: none; padding: 0; color: var(--bs-link-color, var(--bs-primary, #3b7ddd)); text-decoration: none; }
.bc-body-foot__link:hover { text-decoration: underline; }

.bc-sms-strip {
  display: flex;
  align-items: center;
  gap: 11px;
  margin-top: 10px;
  padding: 11px 16px;
  border-radius: var(--nf-radius-sm);
  background: rgba(252, 185, 44, 0.12);
  color: var(--bs-on-subtle-warning, #8a6100);
  font-size: var(--type-small);
  line-height: 1.45;
}
.bc-sms-strip > i { flex-shrink: 0; font-size: var(--type-small); }
.bc-sms-strip__text { flex: 1 1 auto; min-width: 0; }
.bc-sms-strip__action {
  flex-shrink: 0;
  border: 0;
  background: none;
  padding: 0;
  font-size: var(--type-small);
  font-weight: 600;
  color: var(--bs-on-subtle-warning, #8a6100);
  text-decoration: underline;
  white-space: nowrap;
}

/* "Before it can go out" — the readiness checklist. */
.bc-check__title { font-size: var(--type-small); font-weight: 600; color: var(--nf-ink); margin-bottom: 10px; }
.bc-check__item {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: var(--type-small);
  color: var(--nf-faint);
  padding: 3px 0;
}
.bc-check__item i { font-size: var(--type-small); width: 14px; text-align: center; }
.bc-check__item.is-done { color: var(--nf-body-ink); }
.bc-check__item.is-done i { color: var(--bs-success, #1cbb8c); }

/* ── X2 (cross-app contrast, 2026-09-27): the feed, My Posts and the broadcast
   comp in the DARK theme (#4076). Their cards painted #fff under the dark
   theme's light link ink (2.11:1) with black titles; the grounds above are
   now var(--bs-card-bg) and the fills/greys are theme tokens, so this block
   re-points only the three inks and the hairlines the light theme keeps as
   the comp's literals. ── */
:root[data-theme="dark"] {
  --nf-line:     var(--bs-border-color, #43494f);
  --nf-ink:      var(--bs-heading-color, #e9ecef);
  --nf-body-ink: var(--bs-body-color, #ced4da);
}
:root[data-theme="dark"] .nf-quick,
:root[data-theme="dark"] .nf-search input { border-color: var(--nf-line); }
:root[data-theme="dark"] .nf-foot__sep,
:root[data-theme="dark"] .mp-ack__track { background: var(--nf-line); }
/* Topic chips (#4343): the hover hairline and the two tinted variants are
   light-theme literals above; their dark twins keep the tint without a light
   block on the dark card. */
:root[data-theme="dark"] .news-feed-topic-chip:hover,
:root[data-theme="dark"] .news-feed-topic-chip:focus-visible { border-color: var(--nf-line); }
:root[data-theme="dark"] .news-feed-topic-chip--followed { background-color: #3a3320; border-color: #6b5a24; }
:root[data-theme="dark"] .news-feed-topic-chip--followed:hover,
:root[data-theme="dark"] .news-feed-topic-chip--followed:focus-visible { background-color: #463d26; border-color: #85712e; }
:root[data-theme="dark"] .news-feed-topic-chip__followed-star { color: #d9a62e; }
:root[data-theme="dark"] .news-feed-topic-chip--provenance { background-color: var(--nf-divider); border-color: var(--nf-line); }
:root[data-theme="dark"] .news-feed-topic-chip--overflow:hover { border-color: transparent; }
/* ── end X2 ── */

/* Post cover image */
/* The composer's "Featured image" (NewsFeed::CoverImage,
   Communications tester round 2026-10-09), drawn after the byline and before
   the title on the feed card, the must-read card, the post page and the
   composer's Preview (apps/news_feed/shared/_post_cover). Never cropped: full
   width at the picture's own shape (the <img> carries width/height, so its box
   is reserved before it loads), and a picture taller than the frame is
   letterboxed on the neutral fill rather than cut. A picture narrower than
   the card is not blown up: the partial caps it at its own width, centred.
   The frame is a SHAPE, not a height — at most 3:2 of the card's own width
   (the shape Generate makes for a featured image), measured with a container
   unit. It was a fixed 420px, which is a 4:3 frame in the 560px Preview and a
   2:1 frame in the 840px feed card: the same landscape picture filled the
   Preview and sat between two grey strips once published (tester round 5,
   2026-10-12). A shape reads the same at every width. */
.nf-cover {
  margin: 0 0 12px;
  border-radius: var(--nf-radius);
  overflow: hidden;
  background: var(--nf-surface);
  container-type: inline-size;
}
.nf-cover__open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: zoom-in;
}
.nf-cover__open:focus-visible {
  outline: 2px solid var(--bs-primary, #0d6efd);
  outline-offset: -2px;
}
/* Two classes, so the Preview pane's `.news-feed-rendered img` rule (the
   composer draws the cover inside it) cannot restyle the published look. */
.nf-cover .nf-cover__img {
  display: block;
  width: 100%;
  height: auto;
  /* 420px for a browser without container units; 67cqw is the 3:2 frame
     (66.67, rounded up so a 3:2 picture is never letterboxed by a pixel). */
  max-height: 420px;
  max-height: 67cqw;
  margin: 0 auto;
  border-radius: 0;
  object-fit: contain;
}

/* The speed select in the docked player, dark theme: `.form-select` carries a
   literal #495057 from the compiled Bootstrap, which read at about 1.8:1 on
   the dark panel ("1×" all but invisible). The theme's body colour instead. */
:root[data-theme="dark"] .news-feed-read-aloud-player__speed {
  color: var(--bs-body-color);
}
