/* ============================================================
   Forum Design System — COMPONENTS
   Reusable forum-content building blocks shared across surfaces:
   topic list, post card, threaded reply tree, right rail, votes,
   badges, avatars, buttons, ad frames. Ported verbatim from the
   approved mockups. Depends on tokens.css.
   ============================================================ */

/* ── AD FRAMES (in-feed + rail) ────────────────────────── */
.in-feed-ad{
  padding:14px 20px;
  display:flex;flex-direction:column;align-items:center;gap:6px;
  background:var(--bg-sunk);
}
.in-feed-ad .ad-label,.top-ad-band .ad-label{
  font-family:var(--font-mono);font-size:9px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ad-label-ink);font-weight:500;
}
.in-feed-ad .ad-frame,.rail-ad .ad-frame{
  border:1px solid var(--ad-frame);background:var(--bg);
  display:grid;place-items:center;
  background-image:repeating-linear-gradient(45deg, var(--bg-muted) 0 8px, color-mix(in srgb, var(--bg-muted) 60%, var(--bg)) 8px 16px);
}
.in-feed-ad .ad-frame{width:728px;max-width:100%;height:90px}
.rail-ad{display:flex;flex-direction:column;align-items:center;gap:6px;margin-bottom:18px}
.rail-ad .ad-frame{width:300px;height:250px}
.in-feed-ad .ad-frame .lbl,.rail-ad .ad-frame .lbl,.top-ad-band .ad-frame .lbl{
  font-family:var(--font-mono);font-size:11px;color:var(--ink-3);letter-spacing:.1em;
  text-transform:uppercase;background:rgba(255,255,255,.7);padding:4px 10px;border-radius:3px;
}

/* ── BADGES ────────────────────────────────────────────── */
.badge{
  display:inline-flex;align-items:center;
  font-family:var(--font-mono);font-size:10px;font-weight:600;
  letter-spacing:.1em;text-transform:uppercase;
  padding:3px 6px;border-radius:3px;
  line-height:1;white-space:nowrap;
  vertical-align:0.12em;position:relative;top:-1px;
}
/* Inside .topic-title the badge trails the subject inline, so it needs its own
   leading — it is no longer a flex item of .topic-title-row picking up that
   row's 10px gap. */
.topic-title .badge{margin-left:.4em}
.badge--nt{background:var(--bg-muted);color:var(--ink-3)}
.badge--link{background:var(--accent-tint);color:var(--accent);display:inline-flex;align-items:center;gap:4px}
.badge--link svg{stroke-width:2.2}

/* ── POST STATE BADGES ─────────────────────────────────── */
/* DELETED / HIDDEN / LOCKED, rendered by components/state_badges.twig.
   Identical on every surface: index rows and their reply previews, the
   threaded reply tree, single post, and View All. Sized to sit on a
   title line without pushing it taller. */
.state-badge{
  display:inline-flex;align-items:center;
  font-family:var(--font-mono);font-size:9px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;
  padding:2px 5px;border-radius:3px;
  line-height:1;white-space:nowrap;flex-shrink:0;
  vertical-align:0.14em;position:relative;top:-1px;
}
.state-badge--deleted{background:var(--danger);color:var(--ink-inverse)}
.state-badge--hidden{background:var(--danger-tint);color:var(--danger)}

/* The states every reader sees are icons, not badges — pinned
   (components/pin_icon.twig) and locked (components/state_badges.twig).
   Only the moderator-only states stay as text pills above. */
/* Same treatment as .lock-icon below, and for the same reason: a fixed 14px
   glyph with a fixed -0.18em offset sits low against a 24-32px serif heading,
   because em resolves against the heading's font-size. The pin's ink runs
   y=2 to y=21 of its 24 viewBox (79%), so a 0.9em box draws it at ~0.71em —
   cap height — and 0.11em drops its foot onto the baseline. */
.pin-icon{color:var(--nd-green);flex-shrink:0;width:0.9em;height:0.9em;vertical-align:-0.11em}
/* Sized AND offset in em, so one rule holds everywhere this appears — from a
   13px reply row to the 32px desktop heading.

   Both numbers fall out of the glyph: its ink runs y=1.3 to y=21.5 of the 24
   viewBox, i.e. 84% of the box. A 0.85em box therefore draws a mark ~0.71em
   tall, which is cap height for this serif. The ink's foot sits 0.104 of the
   box above its bottom edge, so dropping the box 0.09em lands that foot on the
   baseline instead of floating above it.

   It previously borrowed .pin-icon's fixed -0.18em. That is tuned for a 14px
   glyph on small text; against a 24px heading em resolves to 4.3px and pushed
   the lock 5.7px below the text's optical centre, 10px at 32px. */
.lock-icon{color:var(--ink-3);flex-shrink:0;width:0.85em;height:0.85em;vertical-align:-0.09em}

/* Every surface renders the markers inside the title and ahead of the
   subject, so none of them is a flex item of the row and none picks up the
   row's 10px gap. They need their own spacing, and a much smaller one: these
   are icons bound to the words that follow, not peers of the title.

   An em rather than a fixed px so one number holds from a 13px reply row to a
   32px desktop heading — the gap tracks the type it is attached to.

   Held in a property for the same reason --rt-step is: the rule enumerates
   five title selectors times three markers, and a breakpoint that wants a
   different gap should set one value rather than restate all fifteen at a
   higher specificity. It lives here rather than in tokens.css because that
   file is the palette and the type scale; this is one component's metric.

   .18em, not the .3em this started at. Most of the visible gap was never the
   margin: neither glyph fills its 24-unit viewBox — the pin spans about 47%
   of its width, the padlock about 67% — so each icon carries side bearing
   inside its own box, on both sides. At a 32px op-title the old margin alone
   was 9.6px before any of that was counted. */
:root{--marker-gap:.18em}
.topic-title .lock-icon,.pr-title .lock-icon,.rt-title .lock-icon,
.op-title .lock-icon,.va-title .lock-icon,
.topic-title .pin-icon,.pr-title .pin-icon,.rt-title .pin-icon,
.op-title .pin-icon,.va-title .pin-icon,
.topic-title .state-badge,.pr-title .state-badge,.rt-title .state-badge,
.op-title .state-badge,.va-title .state-badge{margin-right:var(--marker-gap)}


/* ── VOTE CONTROLS ─────────────────────────────────────── */
/* SVGs inside vote anchors must not capture pointer events — upvote.js
   reads e.target.id from the <a> element to get forumid/msgid. If the
   SVG intercepts the click, e.target.id is empty and the vote silently
   fails. pointer-events:none passes clicks through to the anchor. */
.vote-col a svg, .vote-pill a svg, .va-vote-mini a svg { pointer-events: none; }
/* The column reads as belonging to the two lines beside it — the arrows bracket
   them, up on the subject and down on the byline. Left to itself it stacked
   arrow + score + arrow from the top of the row and finished well above the
   byline, so the whole cluster floated against the subject with nothing holding
   its bottom.

   It cannot align on all three: the subject's centre and the byline's are
   ~30px apart, while the arrows are only 18px apart centre to centre. So the
   arrows take the two anchors and the score sits in the gap between the lines,
   which is where a value shared by both belongs anyway. Closing the arrows onto
   the anchors is what the gap:0 and the 2px off each arrow's height are for;
   -4px then drops the pair onto the text.

   The numbers hold at every width because the column and the title/byline block
   both hang off the same top padding — measured at 390 / 768 / 1280, the down
   arrow lands within 0.2px of the byline's centre at all three.

   Arrows keep their 28px width and stay at 20px tall; the tap target is still
   comfortably past the 24px the rest of the row's controls use. */
.vote-col{display:flex;flex-direction:column;align-items:center;gap:0;padding-top:0;margin-top:-4px;user-select:none}
.vote-col button,.vote-col a.upvote,.vote-col a.downvote{
  width:28px;height:20px;display:grid;place-items:center;border-radius:4px;cursor:pointer;
  color:var(--ink-4);transition:color .12s ease, background .12s ease;
}
.vote-col button:hover,.vote-col a.upvote:hover{background:var(--accent-tint);color:var(--vote-pos)}
.vote-col a.downvote:hover{background:var(--accent-tint);color:var(--vote-neg)}
.vote-col button.is-pos{color:var(--vote-pos)}
.vote-col button.is-neg{color:var(--vote-neg)}
.vote-col .score{font-family:var(--font-mono);font-size:14px;font-weight:700;color:var(--ink-2);font-variant-numeric:tabular-nums;padding:1px 0;line-height:1}
.vote-col .score.pos{color:var(--vote-pos)}
.vote-col .score.neg{color:var(--vote-neg)}
.vote-col .score.zero{color:var(--ink-3)}

.vote-pill{display:inline-flex;align-items:center;gap:2px;border:1px solid var(--line);background:#fff;border-radius:9999px;padding:3px 4px}
.vote-pill button{width:30px;height:28px;display:grid;place-items:center;color:var(--ink-3);border-radius:9999px;transition:color .12s ease, background .12s ease}
.vote-pill button:hover{color:var(--nd-navy);background:var(--accent-tint)}
.vote-pill .v-score{font-family:var(--font-mono);font-size:13px;font-weight:700;color:var(--ink-2);font-variant-numeric:tabular-nums;padding:0 8px;letter-spacing:.01em}

/* Logged-out guests: arrows stay visible but give no interactive affordance.
   Keep the upvote/downvote classes + u-/d-/v- ids — upvote.js contract;
   the server already no-ops guest votes (forum/pages/upvote.php). */
.is-guest a.upvote,.is-guest a.downvote{cursor:default}
.is-guest a.upvote:hover,.is-guest a.downvote:hover{background:transparent;text-decoration:none}
.vote-col.is-guest a.upvote:hover,.vote-col.is-guest a.downvote:hover{color:var(--ink-4)}
.vote-pill .v-score.pos{color:var(--vote-pos)}
.vote-pill .v-score.neg{color:var(--vote-neg)}
.vote-pill .v-score.zero{color:var(--ink-3)}

/* ── BUTTONS / CTAs ────────────────────────────────────── */
.new-topic-btn{
  display:inline-flex;align-items:center;gap:8px;
  font-family:var(--font-sans);font-size:13px;font-weight:600;letter-spacing:.02em;
  color:#fff;background:var(--nd-green);
  padding:9px 16px;border-radius:6px;
  box-shadow:0 1px 0 oklch(1 0 0 / .25) inset, 0 1px 2px rgba(12,35,64,0.1);
  cursor:pointer;text-decoration:none;transition:background .12s ease;
}
.new-topic-btn:hover{background:var(--nd-green-hover);text-decoration:none;color:#fff}
.new-topic-btn svg{stroke-width:2.4}

/* ── GAME DAY LOCK ─────────────────────────────────────────
   Shown while a board is closed to new topics around a game. The chip takes
   .new-topic-btn's box so the meta row keeps its height when the button is
   replaced, but reads as a state rather than an action: muted surface, no
   hover, default cursor. */
.gameday-chip{
  display:inline-flex;align-items:center;gap:8px;
  font-family:var(--font-sans);font-size:13px;font-weight:600;letter-spacing:.02em;
  color:var(--ink-3);background:var(--bg-muted);
  border:1px solid var(--line-strong);
  padding:8px 15px;border-radius:6px;
  cursor:default;
}
/* The notice carries the .errornote treatment — white card, navy top rule —
   because members already read that box as "the board is telling you
   something". It is left-aligned and full width instead of centered, since
   this one is a standing condition rather than a response to an action. */
.gameday-note{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;
  background:var(--card-raised);
  border:1px solid var(--line);border-top:3px solid var(--nd-navy);
  border-radius:var(--r-card);box-shadow:var(--shadow-sm);
  padding:12px 18px;margin:0 0 14px;
  font-family:var(--font-sans);font-size:14px;line-height:1.5;color:var(--ink-2);
}
.gameday-note__icon{color:var(--nd-navy);flex:none}
.gameday-note b{color:var(--nd-navy)}
/* The run-up to a lock, before it takes effect. Same box, gold top rule
   instead of navy — a "look here" accent already used elsewhere, so nothing
   new is introduced. Deliberately not the danger red: nothing has gone
   wrong, and posting still works. */
.gameday-note.is-warning{border-top-color:var(--nd-gold)}
.gameday-note.is-warning .gameday-note__icon{color:var(--nd-gold)}
.gameday-note__chat{
  display:inline-flex;align-items:center;gap:6px;margin-left:auto;
  font-size:12.5px;font-weight:600;
  color:var(--nd-green-ink);background:var(--nd-green-soft);
  border:1px solid color-mix(in srgb, var(--nd-green) 30%, transparent);
  border-radius:6px;padding:6px 12px;text-decoration:none;white-space:nowrap;
}
.gameday-note__chat:hover{background:var(--nd-green-soft);text-decoration:underline;color:var(--nd-green-ink)}
/* Below the wrap point the link is on its own line, where margin-left:auto
   would strand it against the right edge away from the text it belongs to. */
@media (max-width:640px){
  .gameday-note__chat{margin-left:0}
}
.reply-btn{
  display:inline-flex;align-items:center;gap:8px;
  font-family:var(--font-sans);font-size:13px;font-weight:600;letter-spacing:.02em;
  color:#fff;background:var(--nd-navy);
  padding:9px 16px;border-radius:6px;
  box-shadow:0 1px 0 oklch(1 0 0 / .15) inset, 0 1px 2px rgba(12,35,64,0.12);
  transition:background .12s ease;
}
.reply-btn:hover{background:var(--nd-navy-2);text-decoration:none;color:#fff}
.tool-btn{
  display:inline-flex;align-items:center;gap:6px;
  height:32px;padding:0 12px;border-radius:9999px;border:1px solid var(--line);background:#fff;
  font-family:var(--font-sans);font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--ink-2);
  transition:background .12s ease, color .12s ease, border-color .12s ease;
}
.tool-btn:hover{background:var(--bg-muted);color:var(--nd-navy);text-decoration:none;border-color:var(--line-strong)}
.tool-btn svg{color:var(--ink-3);stroke-width:2}
.tool-btn:hover svg{color:var(--nd-navy)}

/* ── PAGINATION ────────────────────────────────────────── */
.pagination{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 0 8px;font-family:var(--font-sans);font-size:13px;color:var(--ink-3)}
.pagination-pages{display:flex;align-items:center;gap:4px;flex-wrap:wrap}
.pagination-pages a,.pagination-pages span{
  min-width:32px;height:32px;padding:0 10px;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--line);background:#fff;border-radius:4px;
  font-family:var(--font-sans);font-size:13px;font-weight:600;color:var(--ink-2);text-decoration:none;
  font-variant-numeric:tabular-nums;
}
.pagination-pages a:hover{background:var(--bg-muted);text-decoration:none;color:var(--nd-navy)}
.pagination-pages a[aria-current="page"],.pagination-pages span.is-current{background:var(--nd-navy);color:#fff;border-color:var(--nd-navy)}
.pagination-pages .ell{border:0;background:transparent;color:var(--ink-4)}
.pagination .results{font-variant-numeric:tabular-nums}

/* ── TOPIC LIST (Forum Home) ───────────────────────────── */
.topic-list{display:flex;flex-direction:column;background:var(--card-raised);border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--shadow-card);overflow:hidden}
.topic-list .topic + .topic{border-top:1px solid var(--line-soft)}
.topic-list .topic + .in-feed-ad{border-top:1px solid var(--line-soft)}
.in-feed-ad + .topic{border-top:1px solid var(--line-soft)}
.topic{display:grid;grid-template-columns:54px 1fr;gap:18px;padding:12px 20px 12px 14px;position:relative;transition:background .1s ease}
.topic:hover{background:oklch(0.99 0.005 82)}
.topic.is-hot{background:linear-gradient(180deg, color-mix(in srgb, var(--nd-gold) 5%, transparent), transparent 60%)}
.topic-body{min-width:0}
.topic-title-row{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:6px}
.topic-title{font-family:var(--font-serif);font-size:1.2rem;font-weight:600;color:var(--nd-navy);letter-spacing:-.005em;line-height:1.28;margin:0;text-wrap:pretty}
.topic-title a{color:inherit}
.topic-title a:visited{color:var(--link-visited)}
.topic-title a:hover{color:var(--accent-hover);text-decoration:none}

.topic-meta{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-family:var(--font-sans);font-size:12.5px;color:var(--ink-3)}
.topic-meta .author{display:inline-flex;align-items:center;gap:6px;color:var(--ink-2);font-weight:600}
.topic-meta time{font-variant-numeric:tabular-nums}
.topic-meta .dot{width:3px;height:3px;border-radius:50%;background:var(--ink-4);flex-shrink:0}
.topic-meta .replies-chip{display:inline-flex;align-items:center;gap:5px;background:var(--bg-muted);color:var(--ink-2);font-family:var(--font-sans);font-size:11.5px;font-weight:600;padding:3px 8px;border-radius:9999px;letter-spacing:.01em}
.topic-meta .replies-chip svg{color:var(--ink-3);stroke-width:2}
.topic-meta .replies-chip.is-hot{background:color-mix(in srgb, var(--nd-gold) 22%, transparent);color:#5e4a0a}
.topic-meta .replies-chip.is-hot svg{color:#8a6e10}
.topic-meta .view-all{margin-left:auto;font-family:var(--font-sans);font-size:11.5px;font-weight:600;color:var(--nd-navy);letter-spacing:.04em;text-transform:uppercase;display:inline-flex;align-items:center;gap:5px}
.topic-meta .view-all:hover{color:var(--accent-hover);text-decoration:none}
.topic-meta .view-all svg{transition:transform .15s ease}
.topic-meta .view-all:hover svg{transform:translateX(2px)}

/* Avatars (shared; size varies by surface) */
.avatar{
  border-radius:50%;
  background:linear-gradient(135deg, var(--nd-navy), var(--ink-2));color:var(--nd-gold);
  display:grid;place-items:center;font-family:var(--font-serif);font-weight:700;flex-shrink:0;
  object-fit:cover;
}
.topic-meta .avatar{width:18px;height:18px;font-size:9.5px}

/* Inline reply preview (topic list partial tree) */
.reply-preview{margin-top:8px;padding:2px 0 0 14px;border-left:1.5px solid var(--thread-rule);display:flex;flex-direction:column}
.reply-preview .pr-row{display:flex;align-items:baseline;gap:10px;padding:3px 0;font-family:var(--font-sans);font-size:13px;line-height:1.35;min-width:0}
/* Indent steps for preview rows and for the continue links that sit under them,
   so a link shares its row's indent. How many steps are reachable is set by
   index_preview_indent_max_level (the deepest level that gets an indent of its
   own; deeper replies share the last step). Ten is the ceiling the setting is
   clamped to, because indent that grows with depth eventually leaves the row no
   width at all — the invariant in docs/forum-deep-thread-navigation.md §2. */
.reply-preview .is-nested-1{margin-left:18px}
.reply-preview .is-nested-2{margin-left:36px}
.reply-preview .is-nested-3{margin-left:54px}
.reply-preview .is-nested-4{margin-left:72px}
.reply-preview .is-nested-5{margin-left:90px}
.reply-preview .is-nested-6{margin-left:108px}
.reply-preview .is-nested-7{margin-left:126px}
.reply-preview .is-nested-8{margin-left:144px}
.reply-preview .is-nested-9{margin-left:162px}
.reply-preview .is-nested-10{margin-left:180px}
.reply-preview .pr-row.is-nested-1,
.reply-preview .pr-row.is-nested-2,
.reply-preview .pr-row.is-nested-3,
.reply-preview .pr-row.is-nested-4,
.reply-preview .pr-row.is-nested-5,
.reply-preview .pr-row.is-nested-6,
.reply-preview .pr-row.is-nested-7,
.reply-preview .pr-row.is-nested-8,
.reply-preview .pr-row.is-nested-9,
.reply-preview .pr-row.is-nested-10{padding-left:14px;border-left:1.5px solid var(--line);position:relative}
.reply-preview .pr-row.is-nested-3,
.reply-preview .pr-row.is-nested-4,
.reply-preview .pr-row.is-nested-5,
.reply-preview .pr-row.is-nested-6,
.reply-preview .pr-row.is-nested-7,
.reply-preview .pr-row.is-nested-8,
.reply-preview .pr-row.is-nested-9,
.reply-preview .pr-row.is-nested-10{border-left-color:var(--line-soft)}
.reply-preview .pr-row.is-nested-1::before,
.reply-preview .pr-row.is-nested-2::before,
.reply-preview .pr-row.is-nested-3::before,
.reply-preview .pr-row.is-nested-4::before,
.reply-preview .pr-row.is-nested-5::before,
.reply-preview .pr-row.is-nested-6::before,
.reply-preview .pr-row.is-nested-7::before,
.reply-preview .pr-row.is-nested-8::before,
.reply-preview .pr-row.is-nested-9::before,
.reply-preview .pr-row.is-nested-10::before{content:"";position:absolute;left:-1px;top:12px;width:8px;height:1.5px;background:var(--line)}
.reply-preview .pr-row.is-nested-3::before,
.reply-preview .pr-row.is-nested-4::before,
.reply-preview .pr-row.is-nested-5::before,
.reply-preview .pr-row.is-nested-6::before,
.reply-preview .pr-row.is-nested-7::before,
.reply-preview .pr-row.is-nested-8::before,
.reply-preview .pr-row.is-nested-9::before,
.reply-preview .pr-row.is-nested-10::before{background:var(--line-soft)}
/* The subject wraps rather than ellipsising. Truncation is what made the index
   unreadable without clicking through: the reply rows are the only place a
   subject appears on this page, so an ellipsis there hides the post's entire
   content. Wrapping costs a line and gives the whole subject back.
   overflow-wrap so a single unbroken token — a pasted URL in a subject — still
   cannot push the row wider than its column. */
.reply-preview .pr-title{color:var(--ink-2);font-weight:500;flex:1;min-width:0;overflow-wrap:break-word}
.reply-preview .pr-title a{color:inherit}
.reply-preview .pr-title a:visited{color:var(--link-visited)}
.reply-preview .pr-title a:hover{color:var(--nd-navy);text-decoration:none}
/* Leads a byline that has wrapped below its subject, so the two lines do not
   read as one block of text. Hidden by default and switched on in the phone
   breakpoint in pages.css, which is the only place the wrap happens — on a
   byline sitting at the end of its subject's own line it would read as a
   dangling dash. Shared by the index reply previews and the reply tree. */
.by-dash{display:none}
.reply-preview .pr-by{color:var(--ink-3);font-size:11.5px;white-space:nowrap;flex-shrink:0;font-variant-numeric:tabular-nums}
.reply-preview .pr-by .author{font-weight:600;color:var(--ink-2)}
.reply-preview .pr-badge,.rt-badge{font-family:var(--font-mono);font-size:9px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;background:var(--bg-muted);color:var(--ink-3);padding:2px 5px;border-radius:3px;line-height:1;flex-shrink:0}
/* Both badges now sit inline at the end of the subject rather than being flex
   items of their row, so they have to bring their own leading — no row gap
   reaches them any more. inline-flex keeps the padded pill from stretching the
   line box: at 13px it is shorter than the ~1.35 line it sits on, so a row with
   a badge is no taller than one without. */
.reply-preview .pr-badge,.rt-badge{display:inline-flex;align-items:center;margin-left:.45em;vertical-align:.06em}
.reply-preview .pr-badge.is-link{background:var(--accent-tint);color:var(--accent)}
/* margin is set as longhands, never the shorthand: the indent comes from an
   .is-nested-N class at equal specificity, and a `margin:` shorthand here would
   silently zero the margin-left it sets.

   padding-left matches .pr-row's 14px rather than the 12px of the other sides,
   so the link's text lands on exactly the same x as a reply row at its indent
   step — the link is meant to read as occupying the slot of the replies it
   stands in for. */
/* Margins go, padding stays: the padding is the link's own hit area, the
   margins were only holding it off the rows around it -- and the .reply-preview
   rule and the card padding are already doing that at both ends. */
.reply-preview .pr-continue{margin-top:0;margin-bottom:0;padding:4px 12px 4px 14px;border-left:1.5px dashed var(--line);display:flex;align-items:center;gap:7px;font-family:var(--font-sans);font-size:12px;font-weight:600;color:var(--nd-navy);letter-spacing:.02em}
.reply-preview .pr-continue.is-topic-more{margin-top:4px}
/* A pinned topic gets no preview rows at all (WindowIndexPreviews), so its
   Continue link is the only child of .reply-preview and the step above is
   holding it off nothing. :first-child IS that case. Base rule, not phone-only:
   the pinned card sits at the top of every board at every width. */
.reply-preview > .pr-continue.is-topic-more:first-child{margin-top:0}
.reply-preview .pr-continue:hover{color:var(--accent-hover);text-decoration:none}
.reply-preview .pr-continue .count{font-family:var(--font-mono);font-size:11px;color:var(--ink-3);font-weight:500;letter-spacing:.04em}
.reply-preview .pr-continue svg{transition:transform .15s ease}
.reply-preview .pr-continue:hover svg{transform:translateX(2px)}
.reply-preview .pr-more{font-family:var(--font-sans);font-size:12px;font-weight:600;color:var(--nd-navy);letter-spacing:.02em;display:inline-flex;align-items:center;gap:5px;margin-top:6px}
.reply-preview .pr-more:hover{text-decoration:none;color:var(--accent-hover)}
.reply-preview .pr-more svg{transition:transform .15s ease}
.reply-preview .pr-more:hover svg{transform:translateX(2px)}
/* Density modes: threaded (default) / flat / legacy */
body[data-density="flat"] .reply-preview .pr-row.is-nested-1,
body[data-density="flat"] .reply-preview .pr-row.is-nested-2,
body[data-density="flat"] .reply-preview .pr-row.is-nested-3,
body[data-density="flat"] .reply-preview .pr-row.is-nested-4,
body[data-density="flat"] .reply-preview .pr-row.is-nested-5,
body[data-density="flat"] .reply-preview .pr-row.is-nested-6,
body[data-density="flat"] .reply-preview .pr-row.is-nested-7,
body[data-density="flat"] .reply-preview .pr-row.is-nested-8,
body[data-density="flat"] .reply-preview .pr-row.is-nested-9,
body[data-density="flat"] .reply-preview .pr-row.is-nested-10{display:none}
body[data-density="legacy"] .reply-preview{display:none}
body[data-density="legacy"] .topic{padding-top:14px;padding-bottom:14px}

/* ── OP CARD (Single Post) ─────────────────────────────── */
/* Horizontal padding is untouched: 32px is the gutter that holds an 18px serif
   body off the card edge at a comfortable measure. Only the vertical stack
   comes in — that is what a reader scrolls through. */
.op-card{background:var(--card-raised);border:1px solid var(--line);border-radius:var(--r-card);box-shadow:var(--shadow-card);padding:18px 32px 20px}
.op-title{font-family:var(--font-serif);font-weight:600;font-size:clamp(1.5rem, 2.4vw, 2rem);line-height:1.15;letter-spacing:-.012em;color:var(--nd-navy);margin:0 0 12px;text-wrap:pretty}
.op-author-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding:10px 0;border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft)}
.op-author{display:flex;align-items:center;gap:12px}
.op-author .avatar{width:44px;height:44px;font-size:18px}
.op-author .stack{display:flex;flex-direction:column;line-height:1.25}
.op-author .who{font-family:var(--font-sans);font-size:15px;font-weight:600;color:var(--nd-navy)}
.op-author .who a{color:inherit}
.op-author .badges{display:flex;align-items:center;gap:6px;margin-top:3px;flex-wrap:wrap}
.op-badge{font-family:var(--font-sans);font-size:11px;font-weight:500;color:var(--ink-3);display:inline-flex;align-items:center;gap:5px}
.op-badge.is-veteran{background:color-mix(in srgb, var(--nd-gold) 18%, transparent);color:#5e4a0a;font-weight:600;padding:2px 7px;border-radius:9999px;font-family:var(--font-mono);font-size:10px;letter-spacing:.06em;text-transform:uppercase}
.op-badge.is-veteran svg{color:var(--nd-gold)}
.op-badge .dot,.op-author .badges .dot{width:3px;height:3px;border-radius:50%;background:var(--ink-4);margin:0 2px}
.op-posted{margin-left:auto;display:flex;flex-direction:column;align-items:flex-end;line-height:1.25;font-family:var(--font-sans);font-size:12px;color:var(--ink-3)}
.op-posted .when{font-family:var(--font-mono);font-size:11px;color:var(--ink-2);font-variant-numeric:tabular-nums;letter-spacing:.02em;display:flex;align-items:center;gap:5px}
.op-posted .label{font-family:var(--font-mono);font-size:9px;letter-spacing:.16em;color:var(--ink-4);text-transform:uppercase;font-weight:500}
.op-tools{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 0 12px}
.op-tools .reply-btn,.op-tools .vote-pill ~ .reply-btn{margin-left:auto}

/* Post body (serif reading surface) */
/* Post bodies carry user content, and a pasted URL is one unbreakable token —
   long enough to push the whole page sideways on a phone (measured: 467px wide
   against a 390px viewport on single post, 504px on View All). `anywhere` breaks
   only when a token cannot fit on its own line, so ordinary prose is untouched;
   it is preferred over `break-word` because it also shrinks the element's
   min-content contribution, which keeps working if these ever become flex or
   grid children. Titles elsewhere are already protected by overflow:hidden. */
/* Leading is the single biggest lever on how tall a post reads, and 1.7 was
   set for long-form editorial rather than for forum posts. It cost twice over:
   once between the wrapped lines of a paragraph, and again on the blank lines
   themselves — post bodies are bare text with <br> unless the author wrote
   HTML (see .op-body > :last-child below), so a "paragraph break" in most
   posts is literally an empty line box, 30.6px of it at 18px/1.7.

   1.45 is still comfortable for a serif at this size — these are short bursts,
   not articles — and takes ~4.5px off every line and every blank one. The
   paragraph, image and blockquote margins below come down with it so the
   rhythm stays proportional rather than leaving the gaps between blocks
   looking larger than they did against the old leading. */
.op-body{max-width:760px;font-family:var(--font-serif);font-size:18px;line-height:1.4;color:var(--text);margin-top:6px;overflow-wrap:anywhere}
/* .op-tools is conditional — it renders only when the reader has something to
   click. A guest reading a reply gets no vote pill and no actions, so the body
   landed 6px under the author row's rule while sitting ~30px off the bottom of
   the card. That is the common case, not an edge one: most posts are replies and
   most readers are logged out. Where the tools row is absent the body takes the
   gap itself, close to the 18px + 6px it inherits when the tools are there. */
.op-author-row + .op-body{margin-top:14px}
.op-body p{margin:0 0 12px;text-wrap:pretty}
/* Post bodies are bare text with <br> unless the author wrote HTML, so the
   trailing 18px below only appeared for some posts — the gap under the body
   should not depend on how the post was written. */
.op-body > :last-child{margin-bottom:0}
/* A doubled <br> still reaches the page from posts that ParagraphisePostBody()
   hands back untouched — the ones carrying block-level author HTML, where
   wrapping paragraphs would reflow the post rather than tighten it. Left
   alone, the second <br> opens a full empty line box, which is the fault the
   paragraphs were introduced to fix; here it would just fail quietly on the
   posts nobody checks.

   Styling the second one as a zero-height block caps it at a set gap instead.
   The first <br> is untouched and still ends the line; only the one that would
   have drawn a blank line is converted. Three in a row give two gaps, which is
   the right shape for someone leaning on the key. */
.op-body br + br{display:block;height:0;margin-top:8px;content:""}
.va-body br + br{display:block;height:0;margin-top:6px;content:""}
.op-body strong{font-weight:600;color:var(--nd-navy)}
.op-body em{font-style:italic}
.op-body blockquote{margin:12px 0;padding:6px 0 6px 18px;border-left:3px solid var(--nd-gold);font-family:var(--font-serif);font-style:italic;color:var(--ink-2);font-size:17px;line-height:1.4}
.op-body img{margin:12px 0;border:1px solid var(--line);border-radius:6px}
.op-body a{color:var(--nd-green-ink);font-weight:600}
/* The link row is metadata trailing the body, not another body paragraph, and
   the body it follows usually ends in a bare <br>-separated line with no
   bottom margin — so it sat flush against the last line of the post. Each
   container gives it its own paragraph rhythm rather than a shared constant:
   .op-body sets 12px between paragraphs, .va-body 8px. The "Link:" label uses
   <strong>, so it picks up the bold navy the body already gives emphasis
   rather than inventing a second treatment. */
.op-body .post-link{margin-top:12px}
.va-body .post-link{margin-top:8px}

.op-body .timestamp-ref{font-family:var(--font-mono);font-size:14.5px;color:var(--nd-navy);font-weight:600;background:color-mix(in srgb, var(--nd-gold) 14%, transparent);padding:1px 5px;border-radius:3px;letter-spacing:.01em}
.embedded-media{margin:22px 0;padding:16px;border:1px solid var(--line);background:var(--bg);border-radius:6px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;min-height:200px;background-image:repeating-linear-gradient(45deg, var(--bg-muted) 0 8px, color-mix(in srgb, var(--bg-muted) 60%, var(--bg)) 8px 16px);position:relative}
.embedded-media .lbl{font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-3);font-weight:600;background:rgba(255,255,255,.85);padding:5px 12px;border-radius:3px}
.embedded-media .caption{font-family:var(--font-sans);font-size:12px;color:var(--ink-3);text-align:center;max-width:36ch;background:rgba(255,255,255,.85);padding:4px 10px;border-radius:3px}
.embedded-broken{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:4px;background:var(--bg-muted);color:var(--ink-3);font-family:var(--font-mono);font-size:11px;letter-spacing:.04em;vertical-align:middle}
.embedded-broken svg{color:var(--ink-4);stroke-width:2}
.op-edit-notes{margin-top:6px;max-width:760px}
.op-edit-notes .edit-note{
  display:block;font-family:var(--font-mono);
  font-size:10.5px;letter-spacing:.06em;color:var(--ink-4);
}
.op-edit-notes .edit-note + .edit-note{margin-top:3px}
.op-signature{margin-top:26px;padding-top:14px;border-top:1px dashed var(--line);font-family:var(--font-sans);font-size:12.5px;font-style:italic;color:var(--ink-4);line-height:1.5;max-width:760px}

/* ── REPLIES SECTION (Single Post threaded tree) ───────── */
/* The replies index. Same reasoning as the board index: each of these blocks
   is already fenced by a rule or a border, so the space either side of one was
   restating a division the page had drawn. */
.replies-section{margin-top:22px}
.replies-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding-bottom:10px;border-bottom:1px solid var(--line-strong);margin-bottom:4px}
.replies-head h2{font-family:var(--font-serif);font-weight:600;font-size:22px;letter-spacing:-.008em;color:var(--nd-navy);margin:0}
.replies-head h2 .count{font-family:var(--font-mono);font-size:13px;color:var(--ink-3);font-weight:500;letter-spacing:.02em;margin-left:6px}
.replies-controls{margin-left:auto;display:flex;align-items:center;gap:14px}
.collapse-all{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-sans);font-size:12px;font-weight:600;color:var(--ink-2);letter-spacing:.02em;padding:6px 10px;border-radius:4px;border:1px solid var(--line);background:#fff}
.collapse-all:hover{background:var(--bg-muted);color:var(--nd-navy);border-color:var(--line-strong);text-decoration:none}
.collapse-all svg{stroke-width:2;color:var(--ink-3)}

/* One indent step, as a property rather than a literal, so the breakpoints in
   pages.css can retune it by setting one value instead of restating the margin
   at a higher specificity. It inherits, which is what lets the phone give step 1
   its own size and compress every step below it — see pages.css. */
.rt-list{list-style:none;padding:0;margin:0;--rt-step:18px}
.rt-list .rt-list{margin:0 0 0 var(--rt-step);padding-left:0;border-left:1.5px solid var(--thread-rule)}
.rt-list .rt-list .rt-list{border-left-color:var(--line-strong)}
.rt-list .rt-list .rt-list .rt-list{border-left-color:var(--line)}
.rt-list .rt-list .rt-list .rt-list .rt-list{border-left-color:var(--line-soft)}
.rt-list .rt-list .rt-list .rt-list .rt-list .rt-list{border-left-color:var(--line-soft)}
.rt-node{margin:0;position:relative}
/* Padding is the only vertical lever on these rows — .rt-node and .rt-list
   carry no margin, and at desktop widths the row does not wrap, so a reply is
   one 14px line plus whatever sits above and below it. 2px puts the row at
   ~23px against the ~29px it started at, which over a 39-reply thread is well
   over a screen.

   This is the floor. The row is the hover target as well as the line you read,
   and below 2px the highlight stops reading as a band around the subject and
   starts reading as a box clipping it. Past here the only thing left to take
   is .rt-title's own leading, which is a different trade -- 14px at 1.35 has
   about enough room for the descenders in a subject line, and tightening it
   crowds them rather than moving rows closer together. */
.rt-row{display:flex;align-items:baseline;gap:10px;padding:2px 8px 2px 12px;border-radius:4px;position:relative;min-width:0}
.rt-row:hover{background:oklch(0.99 0.005 82)}
.rt-list .rt-list > .rt-node > .rt-row::before{content:"";position:absolute;left:-1px;top:11px;width:9px;height:1.5px;background:currentColor;color:var(--thread-rule);opacity:.85}
.rt-list .rt-list .rt-list > .rt-node > .rt-row::before{color:var(--line-strong)}
.rt-list .rt-list .rt-list .rt-list > .rt-node > .rt-row::before{color:var(--line)}
.rt-list .rt-list .rt-list .rt-list .rt-list > .rt-node > .rt-row::before{color:var(--line-soft)}
.rt-caret{width:14px;height:14px;display:grid;place-items:center;flex-shrink:0;color:var(--ink-3);cursor:pointer;border-radius:3px;transition:transform .15s ease, background .12s ease, color .12s ease;margin-right:-2px}
.rt-caret:hover{background:var(--accent-tint);color:var(--nd-navy)}
.rt-node.is-leaf > .rt-row > .rt-caret{visibility:hidden;cursor:default}
.rt-node.is-collapsed > .rt-row > .rt-caret{transform:rotate(-90deg)}
.rt-node.is-collapsed > .rt-children{display:none}
/* Title + its NT/Link/Img badges, as one flex item — see the comment in
   components/thread_tree.twig for why they cannot simply live inside the
   title. The row's flex sizing lives here; inside it, title and badges flow as
   ordinary inline content so a badge follows the subject's *last* line. It is
   deliberately not a flex container: as flex items the badges would align to
   the title's first baseline and strand themselves at the top right of a
   subject that ran to two lines.

   Subjects wrap here for the same reason they do on the index (see .pr-title):
   the subject is the post's content on this board, so ellipsising it hides the
   post rather than shortening it. .rt-title therefore drops the truncation and
   with it the block box that text-overflow needed. */
.rt-head{flex:1;min-width:0;overflow-wrap:break-word}
.rt-title{color:var(--nd-navy);font-family:var(--font-sans);font-size:14px;font-weight:600;letter-spacing:-.005em;line-height:1.35}
a.rt-title:visited{color:var(--link-visited)}
.rt-title:hover{color:var(--accent-hover);text-decoration:none}
.rt-meta{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-sans);font-size:11.5px;color:var(--ink-3);white-space:nowrap;flex-shrink:0}
.rt-meta .rt-author{color:var(--ink-2);font-weight:600}
.rt-meta time{font-variant-numeric:tabular-nums}
.rt-meta .dot{width:3px;height:3px;border-radius:50%;background:var(--ink-4)}
.rt-badge.is-link{background:var(--accent-tint);color:var(--accent)}
.rt-badge.is-op{background:color-mix(in srgb, var(--nd-gold) 22%, transparent);color:#5e4a0a}
/* The row you are currently viewing. Without this the focused row is
   indistinguishable from its siblings, which matters once the tree is windowed
   and you can arrive mid-thread via "continue this thread". */
.rt-row.is-here{background:var(--gold-tint);border-radius:4px}

/* Ancestor path strip — the posts above the one being viewed. Flat, not
   stair-stepped: matching the tree row's weight would push content down, which
   defeats the purpose. See docs/forum-deep-thread-navigation.md. */
.rt-ancestors{
  display:flex;flex-direction:column;gap:1px;
  margin:0 0 14px;padding:10px 12px 11px;
  background:var(--bg-sunk);border:1px solid var(--line-soft);
  border-radius:var(--r-card);
}
.rt-anc-root{
  display:inline-flex;align-items:center;gap:6px;align-self:flex-start;
  font-family:var(--font-mono);font-size:10px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);
  margin-bottom:5px;
}
.rt-anc-root:hover{color:var(--nd-navy);text-decoration:none}
.rt-anc{
  display:flex;align-items:baseline;gap:10px;min-width:0;
  padding:3px 0;font-family:var(--font-sans);font-size:13px;line-height:1.35;
}
.rt-anc:hover{text-decoration:none}
.rt-anc-title{
  color:var(--ink-2);font-weight:500;flex:1;min-width:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.rt-anc:hover .rt-anc-title{color:var(--nd-navy)}
.rt-anc-by{color:var(--ink-3);font-size:11.5px;white-space:nowrap;flex-shrink:0;font-weight:600}

.rt-continue{margin:3px 0 3px 18px;padding:6px 14px;border-left:1.5px dashed var(--line);display:flex;align-items:center;gap:8px;font-family:var(--font-sans);font-size:12px;font-weight:600;color:var(--nd-navy);letter-spacing:.02em}
.rt-continue:hover{color:var(--accent-hover);text-decoration:none}
.rt-continue svg{transition:transform .15s ease}
.rt-continue:hover svg{transform:translateX(2px)}
.rt-continue .count{font-family:var(--font-mono);font-size:11px;color:var(--ink-3);font-weight:500;letter-spacing:.04em}
.replies-foot{margin-top:12px;padding:12px 0 4px;border-top:1px solid var(--line-soft);display:flex;align-items:center;justify-content:center}
.replies-foot a{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-sans);font-size:13px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--nd-navy);padding:10px 18px;border-radius:6px;border:1px solid var(--line);background:#fff}
.replies-foot a:hover{background:var(--bg-muted);color:var(--accent-hover);text-decoration:none;border-color:var(--line-strong)}
.replies-foot svg{transition:transform .15s ease}
.replies-foot a:hover svg{transform:translateX(2px)}

/* ── RIGHT RAIL (Single Post) ──────────────────────────── */
.rail-card{background:var(--card-raised);border:1px solid var(--line);border-radius:var(--r-card);padding:16px 18px 18px;margin-bottom:18px;box-shadow:var(--shadow-card)}
.rail-title{font-family:var(--font-mono);font-size:10px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-2);margin:0 0 12px}
.topic-info dl{margin:0;display:grid;grid-template-columns:max-content 1fr;gap:7px 14px}
.topic-info dt{font-family:var(--font-mono);font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-4);align-self:baseline}
.topic-info dd{margin:0;font-family:var(--font-sans);font-size:12.5px;color:var(--ink-2);font-weight:500}
.topic-info dd.num{font-variant-numeric:tabular-nums;font-weight:600;color:var(--nd-navy)}
.related-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}
.related-list li{padding-bottom:12px;border-bottom:1px solid var(--line-soft)}
.related-list li:last-child{border-bottom:0;padding-bottom:0}
.related-list a{font-family:var(--font-serif);font-size:14.5px;font-weight:600;color:var(--nd-navy);line-height:1.3;display:block}
.related-list a:hover{color:var(--accent-hover);text-decoration:none}
.related-list .r-meta{display:block;margin-top:4px;font-family:var(--font-sans);font-size:11px;color:var(--ink-3);letter-spacing:.02em}
.related-list .r-meta .author{color:var(--ink-2);font-weight:600}

/* ── VIEW ALL reply cards (flat tree) ──────────────────── */
.va-tree{list-style:none;padding:0;margin:24px 0 0}
.va-tree .va-tree{list-style:none;padding:0;margin:0 0 0 22px;border-left:1.5px solid var(--thread-rule)}
.va-tree .va-tree .va-tree{border-left-color:var(--line-strong)}
.va-tree .va-tree .va-tree .va-tree{border-left-color:var(--line)}
.va-tree .va-tree .va-tree .va-tree .va-tree{border-left-color:var(--line-soft)}
.va-tree .va-tree .va-tree .va-tree .va-tree .va-tree{border-left-color:var(--line-soft)}
.va-node{position:relative;padding:14px 0 0}
.va-tree > .va-node:first-child{padding-top:24px}
.va-tree .va-tree > .va-node > .va-card::before{content:"";position:absolute;left:-1px;top:30px;width:14px;height:1.5px;background:var(--thread-rule)}
.va-tree .va-tree .va-tree > .va-node > .va-card::before{background:var(--line-strong)}
.va-tree .va-tree .va-tree .va-tree > .va-node > .va-card::before{background:var(--line)}
.va-tree .va-tree .va-tree .va-tree .va-tree > .va-node > .va-card::before{background:var(--line-soft)}
.va-card{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--r-card);padding:18px 22px 16px;box-shadow:var(--shadow-sm)}
.va-tree .va-tree .va-node > .va-card{margin-left:18px}
.va-card.is-op-reply{border-color:color-mix(in srgb, var(--nd-gold) 38%, var(--line));background:linear-gradient(180deg, color-mix(in srgb, var(--nd-gold) 4%, #fff), #fff 30%)}
body.no-op-tint .va-card.is-op-reply{border-color:var(--line);background:#fff}
.va-eyebrow{font-family:var(--font-mono);font-size:9.5px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-4);display:inline-flex;align-items:center;gap:8px;margin:0 0 8px}
.va-eyebrow .lvl-num{color:var(--ink-3);font-variant-numeric:tabular-nums}
.va-eyebrow .pip{width:4px;height:4px;border-radius:50%;background:var(--line)}
.va-title{font-family:var(--font-serif);font-weight:600;font-size:18px;line-height:1.3;letter-spacing:-.005em;color:var(--nd-navy);margin:0 0 10px;text-wrap:pretty}
.va-title a{color:inherit}
.va-title a:hover{color:var(--accent-hover);text-decoration:none}
.va-byline{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding-bottom:10px;margin-bottom:12px;border-bottom:1px solid var(--line-soft)}
.va-byline .avatar{width:28px;height:28px;font-size:12px}
.va-byline .who{font-family:var(--font-sans);font-size:13px;font-weight:600;color:var(--nd-navy)}
.va-byline .who a{color:inherit}
.va-byline .posts{font-family:var(--font-sans);font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.va-byline .op-flag{font-family:var(--font-mono);font-size:9px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;background:color-mix(in srgb, var(--nd-gold) 25%, transparent);color:#5e4a0a;padding:2px 6px;border-radius:3px;line-height:1}
.va-byline .dot{width:3px;height:3px;border-radius:50%;background:var(--ink-4)}
.va-byline time{margin-left:auto;font-family:var(--font-mono);font-size:11px;color:var(--ink-3);font-variant-numeric:tabular-nums;letter-spacing:.02em}
.va-body{font-family:var(--font-serif);font-size:15.5px;line-height:1.4;color:var(--text);overflow-wrap:anywhere}
.va-body p{margin:0 0 8px;text-wrap:pretty}
.va-body p:last-child{margin-bottom:0}
.va-body strong{font-weight:600;color:var(--nd-navy)}
.va-body em{font-style:italic}
.va-body a{color:var(--nd-green-ink);font-weight:600}
.va-body img{margin:8px 0;border:1px solid var(--line);border-radius:6px}
.va-body .timestamp-ref{font-family:var(--font-mono);font-size:13px;color:var(--nd-navy);font-weight:600;background:color-mix(in srgb, var(--nd-gold) 14%, transparent);padding:1px 4px;border-radius:3px;letter-spacing:.01em}
.va-body blockquote{margin:8px 0;padding:4px 0 4px 14px;border-left:3px solid var(--nd-gold);font-style:italic;color:var(--ink-2);font-size:14.5px;line-height:1.4}
.va-card.is-nt .va-body{font-family:var(--font-sans);font-size:12.5px;font-style:italic;color:var(--ink-4)}
.va-card .embedded-media{min-height:200px;margin:14px 0 4px}
.va-sig{margin-top:12px;padding-top:10px;border-top:1px dashed var(--line);font-family:var(--font-sans);font-size:11.5px;font-style:italic;color:var(--ink-4);line-height:1.5}
.va-sig .edit-note{display:block;margin-top:3px;font-family:var(--font-mono);font-style:normal;font-size:10px;letter-spacing:.08em;color:var(--ink-4)}
.va-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:12px;padding-top:10px;border-top:1px solid var(--line-soft)}
.va-vote-mini{display:inline-flex;align-items:center;gap:2px}
.va-vote-mini button{width:22px;height:22px;display:grid;place-items:center;border-radius:4px;color:var(--ink-4)}
.va-vote-mini button:hover{color:var(--nd-navy);background:var(--accent-tint)}
.va-vote-mini .v-score{font-family:var(--font-mono);font-size:12px;font-weight:700;color:var(--ink-2);padding:0 6px;letter-spacing:.01em;font-variant-numeric:tabular-nums}
.va-vote-mini .v-score.pos{color:var(--vote-pos)}
.va-vote-mini .v-score.neg{color:var(--vote-neg)}
.va-mini-link{font-family:var(--font-sans);font-size:11.5px;font-weight:600;letter-spacing:.02em;color:var(--ink-2);display:inline-flex;align-items:center;gap:5px;padding:4px 8px;border-radius:4px}
.va-mini-link:hover{color:var(--nd-navy);background:var(--bg-muted);text-decoration:none}
.va-mini-link svg{stroke-width:2;color:var(--ink-3)}
.va-mini-link:hover svg{color:var(--nd-navy)}
.va-actions .perma{margin-left:auto;font-family:var(--font-mono);font-size:10px;color:var(--ink-4);letter-spacing:.04em}
.va-actions .perma:hover{color:var(--ink-2);text-decoration:none}
.va-continue{margin:16px 0 4px 18px;padding:12px 16px;border:1px dashed var(--line);background:var(--bg-sunk);border-radius:6px;display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-family:var(--font-sans);font-size:13px;font-weight:600;color:var(--nd-navy);letter-spacing:.02em}
.va-continue:hover{color:var(--accent-hover);text-decoration:none;background:var(--bg-muted);border-color:var(--line-strong)}
.va-continue svg{transition:transform .15s ease}
.va-continue:hover svg{transform:translateX(2px)}
.va-continue .preview{flex:1;min-width:0;font-weight:500;color:var(--ink-3);font-family:var(--font-serif);font-size:13.5px;font-style:italic;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.va-continue .count{font-family:var(--font-mono);font-size:10.5px;color:var(--ink-3);font-weight:500;letter-spacing:.04em}
.va-end{margin-top:36px;padding:18px 0;text-align:center;font-family:var(--font-mono);font-size:10px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-4);border-top:1px solid var(--line-soft);display:flex;align-items:center;justify-content:center;gap:14px}
.va-end::before,.va-end::after{content:"";width:48px;height:1px;background:var(--line)}
