

/*
 * /posts/:id — unified post detail for all variants (text / video,
 * discussion / announcement / question). All styles live here to keep
 * the page self-contained; promote to @elements/style if any of this
 * shows up on a second page.
 *
 * Primitives used from @elements/style:
 *   .btn / .btn-primary / .btn-sm (button.css).
 */

/* ─── Shell ──────────────────────────────────────────────────────── */

/* Width + horizontal padding inherited from the canonical hero
   shell list in app/shared/styles/global.css (var(--container-marketing)
   forced via !important). The post page used to override these
   to 760px / var(--space-5) but that broke the
   /learn → /feed → /post-detail width consistency. The video
   theater still breaks out to full viewport width; only the
   shell width is capped here. */
.post-shell { /* width forced from global.css canonical rule */ }

/* Top padding is provided by .page-chrome-main (chrome) +
   canonical h1 margin (2rem). No additional .post-body-wrap
   top padding — let the canonical rhythm handle it. */
.post-body-wrap { padding-top: 0; }

/* The .post-back block (legacy "Back to community" link), the
 * .release-banner, and the per-kind .post-status pills are all gone.
 * The unified header anatomy below replaces them: eyebrow above the
 * title, a back-link at the decision point under the meta row, and
 * an action-bar beneath that. See notes/design/feed-and-post-detail.html
 * for the full design rationale. */

/* ─── Encoding error banner ─────────────────────────────────────────
   Shown above the theater when videos.state='error'. Full-bleed like
   the theater so it's impossible to miss. */
.video-error-banner {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  background: #fee2e2;
  color: #991b1b;
  padding: 0.75rem 1.5rem;
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
  justify-content: center;
  text-align: center;
  border-bottom: 1px solid #fca5a5;
}
.video-error-banner-msg {
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  opacity: 0.85;
}

/* ─── Video theater ─────────────────────────────────────────────────
   Breaks out of the article column to full viewport width. Letterbox
   background + centered 16:9 surface capped at 1600px so video stays
   watchable on huge monitors and 85vh so it doesn't push everything
   below the fold on portrait displays. */

.post-theater-wrap {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  /* Match the dark topbar so the chrome flows continuously into the
     theater — feels like one surface, not stacked panels. */
  background: var(--bg-dark);
  display: flex;
  justify-content: center;
  align-items: center;
  margin-bottom: 1.75rem;
}

/* The theater is the locked 16:9 surface inside the viewport-wide
   black wrapper. Three constraints, honored at every viewport size:
     - max-width 1600px so video stays watchable on huge monitors.
     - 16:9 height never exceeds the visible viewport minus the
       sticky topbar. Using `svh` (small viewport height) instead
       of `vh` so iOS Safari's address-bar-eats-vh quirk doesn't
       size the video taller than the actual visible area —
       previously, in landscape on iPhone the bottom of the video
       sat permanently below the visible region, behind the
       address bar / sticky topbar combination.
     - subtract `--topbar-h` (≈4rem covering topbar + breathing
       room) so the video fits BENEATH the sticky topbar in the
       visible area, not clipping behind it.
   `aspect-ratio: 16/9` then computes height from width, so the box
   is always exactly 16:9 — no squash, no stretch, on any viewport. */
.post-theater {
  position: relative;
  width: 100%;
  max-width: min(1600px, calc((100svh - 4rem) * 16 / 9));
  aspect-ratio: 16 / 9;
  background: var(--bg-dark);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Landscape on phones: tighter cap so the byline above + a sliver
   of comments below stay glanceable too. svh already keeps it in
   the visible area; this just leaves room for chrome above the
   video without the user having to scroll up to see it. */
@media (orientation: landscape) and (max-height: 500px) {
  .post-theater {
    max-width: min(1600px, calc((100svh - 6rem) * 16 / 9));
  }
}

.post-theater-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
  display: block;
}

/* Placeholder is the idle state on every visit: dark gradient
   surface + centered "big play" button overlay. Only the play
   button itself is interactive - the surface is decorative. After
   first click the placeholder unmounts and the native <video>
   chrome takes over. For posts without video sources the
   placeholder stays put (clicking the button is a no-op). */
.post-theater-placeholder {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  /* pointer-events:auto — anywhere on the placeholder triggers play.
     The placeholder unmounts on first click, so this never blocks
     the native video controls from receiving clicks afterward. */
}
.post-theater-surface {
  position: absolute;
  inset: 0;
  /* Flat dark to match the topbar + theater shell. The big play
     button is the visual anchor; no surface gradient needed. */
  background: var(--bg-dark);
}

.post-theater-play {
  position: relative;
  z-index: 2;
  /* Hover lives on the button itself; clicks still bubble to the
     parent placeholder so the entire dark surface remains tappable. */
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid rgba(255, 255, 255, 0.85);
  display: flex;
  align-items: center;
  justify-content: center;
  appearance: none;
  padding: 0;
  cursor: pointer;
  transition:
    background  200ms ease,
    border-color 200ms ease;
}
.post-theater-play:hover {
  background: rgba(255, 255, 255, 0.06);
  border-color: #fff;
}
.post-theater-play::before {
  content: "";
  width: 0;
  height: 0;
  border-top: 12px solid transparent;
  border-bottom: 12px solid transparent;
  /* ~24px wide white triangle at 90%; +3px optical centering offset
     so the asymmetric glyph reads centered. */
  border-left: 24px solid rgba(255, 255, 255, 0.9);
  margin-left: 3px;
  transition: border-left-color 200ms ease;
}
.post-theater-play:hover::before {
  border-left-color: #fff;
}

/* Theater overlay duration. Sits in the bottom-right with a soft
   pill so it stays legible on either the placeholder surface or a
   light video frame. */
.post-theater-duration {
  position: absolute;
  bottom: 18px;
  right: 24px;
  z-index: 3;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(0, 0, 0, 0.6);
  padding: 3px 9px;
  border-radius: 3px;
  backdrop-filter: blur(4px);
}

/* ─── Chapters block (collapsible) ────────────────────────────────── */

.chapters-block {
  margin: 0 0 2rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.chapters-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.625rem 0.875rem;
  background: var(--bg-soft);
  border: 0;
  cursor: pointer;
  text-align: left;
  transition: background 100ms var(--ease-out, ease);
}
.chapters-head:hover { background: var(--bg-panel); }
.chapters-block.is-open .chapters-head { border-bottom: 1px solid var(--rule); }

.chapters-head .label {
  font-family: var(--font-sans);
  font-size: 0.65625rem;
  color: var(--ink-dim);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-box-trim: trim-both; text-box-edge: cap alphabetic;
}
/* Caret was rendering at 10px and ink-dim — effectively invisible
   at the top-right of the CHAPTERS header. Bumped to a clearly-
   readable size + ink color so the toggle is visible at a glance. */
.chapters-head .caret {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  color: var(--ink);
  display: inline-block;
  line-height: 1;
  transition: transform 120ms var(--ease-out, ease);
}
.chapters-block.is-open .chapters-head .caret { transform: rotate(180deg); }

.chapters-list {
  padding: 0.25rem 0;
  display: none;
}
.chapters-block.is-open .chapters-list { display: block; }

.chapter-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 0.875rem;
  padding: 0.5rem 0.875rem;
  cursor: pointer;
  transition: background 100ms var(--ease-out, ease);
  text-decoration: none;
  color: inherit;
}
.chapter-row:hover { background: var(--bg-soft); }
.chapter-row .title {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  color: var(--ink);
  line-height: 1.45;
}
.chapter-row .ts {
  font-family: var(--font-sans);
  font-size: 0.78125rem;
  /* Muted by default — the whole row is already clickable, so the
     timestamp doesn't need its own link-style accent. Lights up in
     accent on row hover so it still reads as the seek anchor. */
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  text-align: right;
  min-width: 3rem;
  transition: color var(--duration-fast) var(--ease-out);
}
.chapter-row:hover .ts { color: var(--accent-deep); }
.chapter-row.is-active { background: var(--accent-soft); }
.chapter-row.is-active .ts    { color: var(--accent-deep); font-weight: var(--font-medium); }
.chapter-row.is-active .title { font-weight: var(--font-medium); }

/* ─── Title / eyebrow / byline ────────────────────────────────────── */

.post-title {
  font-family: var(--font-sans);
  font-size: 2.375rem;
  line-height: 1.15;
  letter-spacing: -0.025em;
  font-weight: var(--font-semibold);
  color: var(--ink);
  margin: 0 0 0.875rem;
  /* Hyphenate / break long unbroken strings (URLs, identifiers,
     non-ASCII run-on titles) so they don't bleed past the column
     edge on phone. word-wrap is the legacy alias kept for older
     iOS Safari. */
  overflow-wrap: break-word;
  word-wrap: break-word;
  hyphens: auto;
}

/* ─── Post meta block ───────────────────────────────────────────────
   Identity row (kind · author · ago). The vote+comments cluster + kebab
   live in <ActionRow> below this strip; styling for those is owned by
   the shared template. */
.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--ink-soft);
  margin: 0 0 0.75rem;
  line-height: 1.5;
}
.post-meta > * { white-space: nowrap; }

.post-meta__author      { color: var(--ink-soft); }
.post-meta__author .who { color: var(--ink); text-decoration: none; }
.post-meta__author .who:hover { color: var(--accent); }
.post-meta__time        { color: var(--ink-soft); }
.post-meta__sep         { color: var(--ink-dim); }

/* /read mode body — transcript prose replaces the rendered article.
   Same .post-body chrome so typography matches the article view. */
.post-body-read p {
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--ink);
  margin: 0 0 1.25rem;
}
.post-body-read-lede {
  font-style: italic;
  color: var(--ink-soft);
}
.post-body-read-empty {
  color: var(--ink-dim);
  font-style: italic;
}

/* Type / kind label — colors come from the centralized --kind-*
   tokens in app/shared/styles/global.css (mirrored from KindColor in
   app/lib/enums.ts). Same hue per kind across feed, palette,
   byline, search, post-detail. */
.post-meta__type { font-weight: 400; }
.post-meta__type.eyebrow--show      { color: var(--kind-show);     }
.post-meta__type.eyebrow--ask       { color: var(--kind-ask);      }
.post-meta__type.eyebrow--announce  { color: var(--kind-announce); }
.post-meta__type.eyebrow--discuss   { color: var(--kind-discuss);  }
.post-meta__type.eyebrow--teach     { color: var(--kind-teach);    }
.post-meta__type.eyebrow--course    { color: var(--kind-course);   }
.post-meta__type.eyebrow--guide     { color: var(--kind-guide);    }
.post-meta__type.eyebrow--video     { color: var(--kind-video);    }

/* ActionRow sits directly below the identity row with a small gap.
   The shared template paints its own hover pill; the only thing
   this surface needs is bottom margin before the body / chapters. */
.post-body-wrap > .action-row {
  margin: 0 0 1.75rem;
}

/* Copy-link — display-swap on .is-copied so both spans stay in
   the DOM and reactivity isn't fighting a conditional render. */
.post-copy-link .copy-done { display: none; }
.post-copy-link.is-copied .copy-default { display: none; }
.post-copy-link.is-copied .copy-done    { display: inline; }
.post-copy-link.is-copied                { color: var(--green); }
.post-copy-link.is-copied:hover          { color: var(--green); }

/* ─── Prose body (text posts) ───────────────────────────────────── */

.post-body {
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.7;
  color: var(--ink);
}
.post-body p { margin: 0 0 1.25rem; }
.post-body h2 {
  font-family: var(--font-sans);
  font-size: 1.375rem;
  font-weight: var(--font-semibold);
  letter-spacing: -0.02em;
  margin: 2.25rem 0 0.75rem;
}
.post-body h3 {
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  font-weight: var(--font-semibold);
  margin: 1.75rem 0 0.5rem;
}
.post-body code {
  font-family: var(--font-mono);
  font-size: 0.875rem;
  background: var(--bg-panel);
  padding: 2px 6px;
  border-radius: 3px;
}
.post-body pre {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  /* Softer than the navbar's near-black so the navbar reads as the
     only true black on the page (the brand frame) and code blocks
     visibly recede as content surface. */
  background: #1e1e1e;
  color: var(--term-ink);
  padding: 1rem 1.25rem;
  border-radius: var(--radius-lg);
  overflow-x: auto;
  margin: 1.5rem 0;
  line-height: 1.6;
}
.post-body pre code {
  background: transparent;
  padding: 0;
  font-size: 0.8125rem;
  color: var(--term-ink);
}

/* Copy-code toolbar styles moved to app/lib/copy-code-buttons.css
   so every surface that mounts decorateCodeBlocks (post body,
   comment body, course-lesson body) gets identical styling. */
.post-body blockquote {
  border-left: 3px solid var(--rule);
  padding: 0.25rem 0 0.25rem 1rem;
  color: var(--ink-soft);
  margin: 1.25rem 0;
  font-style: italic;
}

.post-video-caption {
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--ink-soft);
  margin-bottom: 0.5rem;
}
.post-video-caption p { margin: 0 0 0.75rem; }
.post-video-caption p:last-child { margin-bottom: 0; }

/* ─── Answers (question posts) ──────────────────────────────────── */

.post-answers { margin-top: 1.5rem; }

.post-answers-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: 2.5rem 0 1rem;
  padding-bottom: 0.625rem;
  border-bottom: 1px solid var(--rule);
}
.post-answers-head h2 {
  font-family: var(--font-sans);
  font-size: 1.1875rem;
  font-weight: var(--font-semibold);
  letter-spacing: -0.015em;
}
.post-answers-head .count {
  color: var(--ink-dim);
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  font-weight: var(--font-regular);
  margin-left: 0.5rem;
}
.post-answers-head .sort {
  font-family: var(--font-sans);
  font-size: 0.71875rem;
  color: var(--ink-dim);
}

.post-answer {
  padding: 1.25rem 0;
  border-bottom: 1px solid var(--rule-soft);
  display: grid;
  grid-template-columns: 48px 1fr;
  gap: 1rem;
}
.post-answer:last-child { border-bottom: none; }

.post-answer.is-accepted {
  background: var(--green-soft);
  border-radius: var(--radius-md);
  padding: 1.25rem;
  margin: 0 -1.25rem 0.5rem;
  border-bottom: none;
}

.post-answer-vote {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.375rem;
  padding-top: 0.125rem;
}
.post-answer-vote .arrow {
  font-size: 0.875rem;
  color: var(--ink-faint);
  cursor: pointer;
  line-height: 1;
}
.post-answer-vote .arrow:hover    { color: var(--ink); }
.post-answer-vote .arrow.is-cast  { color: var(--accent-deep); }
.post-answer-vote .count {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  font-weight: var(--font-medium);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.post-answer.is-accepted .post-answer-vote .count { color: var(--green); }
.post-answer-vote .accepted-mark {
  font-size: 1.125rem;
  color: var(--green);
  line-height: 1;
  margin-top: 0.25rem;
}

.post-answer-byline {
  font-family: var(--font-sans);
  font-size: 0.71875rem;
  color: var(--ink-dim);
  margin-bottom: 0.5rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.post-answer-byline-who { color: var(--ink-soft); font-weight: var(--font-medium); }
.post-answer-byline-sep { color: var(--ink-faint); }
.post-answer-byline .accepted-tag {
  color: var(--green);
  font-weight: var(--font-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-box-trim: trim-both; text-box-edge: cap alphabetic;
  font-size: 0.65625rem;
}

.post-answer-body {
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--ink);
}
.post-answer-body p { margin: 0 0 0.75rem; }
.post-answer-body p:last-child { margin-bottom: 0; }

.post-answer-actions {
  margin-top: 0.625rem;
  font-family: var(--font-sans);
  font-size: 0.6875rem;
  color: var(--ink-dim);
  display: flex;
  gap: 0.875rem;
}
.post-answer-actions a { cursor: pointer; }
.post-answer-actions a:hover { color: var(--ink); }

/* ─── Thread (comments) ─────────────────────────────────────────────
   Comment rendering itself (.cmt, .replies, .continue-link, vote
   pair, overflow menu, collapsed state) lives in
   app/shared/templates/comment/style.css — this page only owns the section
   wrapper, head, subnav, composer, and empty state. */

/* No tinted strip, no rule — the section break is carried by 4rem
   of whitespace above the heading + the typographic scale shift
   from body text to the larger Comments heading. Quieter than the
   stadium-banner approach and reads as part of the same page
   surface, not a separate region. */
.thread {
  margin-top: 4rem;
  /* Bottom padding so the last comment doesn't sit flush against
     the viewport edge / page footer. Matches the comfortable air
     the top of the thread carries (4rem above the heading). */
  padding-bottom: 6rem;
  /* The topbar is position:sticky (~56px tall + 1px border). Without
     this, scrollIntoView (or `#comments` anchor jumps) parks the
     section heading directly behind the sticky topbar. Reserve the
     topbar height as scroll margin so the heading sits BELOW it. */
  scroll-margin-top: 64px;
}

.thread-subnav {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  color: var(--ink-dim);
  margin-bottom: 1rem;
}
.thread-subnav a { color: var(--ink-soft); cursor: pointer; }
.thread-subnav a:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--ink-faint);
}
.thread-subnav-sep { color: var(--ink-faint); }

/* Inline heading row: "Comments · 12" left, "sorted by top" pushed
   to the right by margin-left:auto on the .sort span. ~1.5rem of
   breathing room below before the composer. */
.thread-head {
  display: flex;
  align-items: baseline;
  margin-bottom: 1.5rem;
}
.thread-head h2 {
  font-family: var(--font-sans);
  font-size: 1.5rem;
  font-weight: var(--font-semibold);
  letter-spacing: -0.015em;
  margin: 0;
}
/* Count: same font family as the h2 but explicitly sized smaller
   so the number reads as secondary metadata, not part of the
   heading itself. The mono digits in the inherited heading size
   were optically larger than the word "Comments". */
.thread-head .count {
  font-size: 1.0625rem;
  color: var(--ink-soft);
  font-weight: var(--font-regular);
  margin-left: 0.375rem;
}

/* Composer panel — three-band anatomy from MarkdownEditor:
   tinted .md-tabs strip / white .md-textarea / tinted .md-footer
   strip. The outer container itself stays transparent so the
   textarea reads as the most prominent surface; chrome bands
   visually frame the input from above and below. Light border +
   md radius keeps the panel polite — composer is a container,
   not a fenced-off region. */
.thread-composer {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0;
  margin-bottom: 1.75rem;
  /* The editor wrap (.md-editor-wrap) provides its own border +
     focus-within ring + radius — composer is just a vertical stack
     for the editor + the kbd hint below. */
}

/* Quiet hint sat below the composer — mirrors the mockup's
   "Markdown supported. ⌘+Enter to post." line. The editor itself
   stays single-purpose; the hint lives outside so it doesn't move
   when the editor focuses. */
.thread-composer-hint {
  font-family: var(--font-sans);
  font-size: 11px;
  color: var(--ink-dim);
  margin-top: 8px;
  padding: 0 4px;
}
.thread-composer-hint kbd {
  background: var(--rule-soft);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 1px 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--ink-soft);
}

/* Min-height — small desktop floor (~80px) so the composer reads
   as compact and grows as the user types. Auto-grow JS pushes
   the textarea height beyond this as content lands. */
.thread-composer .md-editor-wrap       { --md-min-height: 5rem; }
@media (max-width: 640px) {
  .thread-composer .md-editor-wrap     { --md-min-height: 4.5rem; }
}

/* Slot contents on the right side of .md-footer — Clear link +
   Post button live here, paired with </> on the left. */
.thread-composer-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
}
.thread-composer-clear {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  color: var(--ink-soft);
  cursor: pointer;
}
.thread-composer-clear:hover { color: var(--ink); }

.thread-empty {
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  color: var(--ink-dim);
  padding: 1rem 0;
}

/* ─── Accepted-answer pinned block ──────────────────────────────── */

/* Sits at the top of the comments section, before the thread.
   The same comment also renders in its in-tree position with the
   green `is-accepted` highlight; this block is the curated copy. */
.accepted-answer-block {
  margin-bottom: 1.5rem;
  padding: 0.875rem 1rem 1rem;
  background: rgba(63, 107, 58, 0.05);
  border: 1px solid rgba(63, 107, 58, 0.25);
  border-radius: var(--radius-md);
}
.accepted-answer-head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  font-family: var(--font-sans);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-box-trim: trim-both; text-box-edge: cap alphabetic;
  color: #3a9243;
  font-weight: var(--font-semibold);
}
.accepted-answer-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  background: #3a9243;
  color: #fff;
  border-radius: 50%;
  font-size: 0.6875rem;
  font-weight: var(--font-semibold);
  letter-spacing: 0;
}
.accepted-answer-label { flex: 0 0 auto; }
.accepted-answer-jump  {
  margin-left: auto;
  font-weight: var(--font-medium);
  color: #3a9243;
  letter-spacing: 0.04em;
  text-transform: none;
  font-size: 0.71875rem;
  cursor: pointer;
}
.accepted-answer-jump:hover { text-decoration: underline; }
/* Inside the pinned block, neutralize the .is-accepted card-y
   styling on the comment — the block itself already provides
   the green frame, so the inner comment should sit flat. */
.accepted-answer-block .cmt.is-accepted {
  background: transparent;
  border-left: none;
  padding-left: 0;
  margin-left: 0;
}

/* ─── Syntax highlighting (Lezer classHighlighter token classes) ────
   Tokens emitted by @lezer/highlight on the server-rendered code
   blocks. Mapped to the existing terminal palette so code blocks in
   posts use the same colors as the rest of the project's terminal
   surfaces (.code-block, .terminal). When the CodeMirror editor
   lands, this section moves to @elements/style/syntax-highlight.css
   so the editor and the read view use the same source of truth. */

.post-body pre .tok-comment,
.post-body pre .tok-lineComment,
.post-body pre .tok-blockComment   { color: var(--term-dim); font-style: italic; }

.post-body pre .tok-keyword,
.post-body pre .tok-controlKeyword,
.post-body pre .tok-moduleKeyword,
.post-body pre .tok-operatorKeyword,
.post-body pre .tok-modifier,
.post-body pre .tok-self           { color: var(--term-orange); }

.post-body pre .tok-string,
.post-body pre .tok-string2,
.post-body pre .tok-character,
.post-body pre .tok-attributeValue { color: var(--term-green); }

.post-body pre .tok-number,
.post-body pre .tok-integer,
.post-body pre .tok-float,
.post-body pre .tok-bool,
.post-body pre .tok-null,
.post-body pre .tok-atom           { color: var(--term-orange); }

.post-body pre .tok-tagName,
.post-body pre .tok-typeName,
.post-body pre .tok-className,
.post-body pre .tok-namespace      { color: var(--term-amber); }

.post-body pre .tok-attributeName,
.post-body pre .tok-propertyName   { color: var(--term-amber); }

.post-body pre .tok-function,
.post-body pre .tok-macroName,
.post-body pre .tok-labelName      { color: var(--term-amber); }

.post-body pre .tok-meta,
.post-body pre .tok-processingInstruction,
.post-body pre .tok-punctuation,
.post-body pre .tok-bracket,
.post-body pre .tok-paren,
.post-body pre .tok-brace,
.post-body pre .tok-angleBracket,
.post-body pre .tok-squareBracket,
.post-body pre .tok-separator      { color: var(--term-dim); }

.post-body pre .tok-regexp         { color: var(--term-green); }
.post-body pre .tok-escape         { color: var(--term-amber); }
.post-body pre .tok-link,
.post-body pre .tok-url            { color: var(--accent); text-decoration: underline; }

/* Markdown-emitted fence wrapper class. bg + fg come from
   app/shared/styles/syntax-highlight.css (VSCode Dark+ palette). */
.post-body pre.code-fence {
  font-family: var(--font-sans);
  font-size: 0.84375rem;
  line-height: 1.65;
  padding: 1rem 1.25rem;
  border-radius: var(--radius-md);
  overflow-x: auto;
  margin: 1.5rem 0;
}
.post-body pre.code-fence code {
  background: transparent;
  padding: 0;
  border-radius: 0;
  color: inherit;
  font-size: inherit;
}

/* ─── Keyboard shortcut help overlay ───────────────────────────── */

.kbd-help-backdrop {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(10, 10, 14, 0.45);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}

.kbd-help-dialog {
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.25);
  width: min(28rem, 100%);
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  color: var(--ink);
}

.kbd-help-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.875rem 1.125rem;
  border-bottom: 1px solid var(--rule-soft);
}
.kbd-help-title {
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  font-weight: var(--font-semibold);
  letter-spacing: -0.01em;
  color: var(--ink);
}
.kbd-help-close {
  background: transparent;
  border: 0;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 0 0.25rem;
}
.kbd-help-close:hover { color: var(--ink); }

.kbd-help-body {
  padding: 0.625rem 1.125rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}
.kbd-help-section-title {
  font-family: var(--font-sans);
  font-size: 0.6875rem;
  text-transform: uppercase;
  text-box-trim: trim-both; text-box-edge: cap alphabetic;
  letter-spacing: 0.12em;
  color: var(--ink-dim);
  margin-bottom: 0.375rem;
}
.kbd-help-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.1875rem 0;
  color: var(--ink-soft);
}
.kbd-help-row span {
  margin-left: auto;
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: 0.8125rem;
}
.kbd-help-row kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.375rem;
  font-family: var(--font-sans);
  font-size: 0.6875rem;
  color: var(--ink);
  background: var(--bg-soft);
  border: 1px solid var(--rule);
  border-radius: 4px;
  line-height: 1;
}

.thread-composer-error {
  font-size: 0.8125rem;
  color: #b00020;
  background: #fff0f0;
  border: 1px solid #ffd0d0;
  padding: 6px 10px;
  border-radius: 6px;
  margin: 8px 0;
}

.thread-composer-signin {
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  color: var(--ink-soft);
  padding: 1rem 0;
}
.thread-composer-signin a { color: var(--accent-deep); text-decoration: underline; }

/* ─── Mobile ─────────────────────────────────────────────────────── */

@media (max-width: 640px) {
  .post-title { font-size: 1.625rem; }
  .post-body  { font-size: 0.9375rem; }

  .post-answer.is-accepted {
    margin-left: 0;
    margin-right: 0;
  }
  .post-answer {
    grid-template-columns: 40px 1fr;
    gap: 0.75rem;
  }

  /* Identity meta row on mobile — tighter column gap; wrapping
     handled by the parent's flex-wrap. */
  .post-meta {
    column-gap: 0.625rem;
    row-gap: 0.125rem;
  }
}

/* Page-wide horizontal overflow guard — protects against any
   absolutely-positioned popover that briefly overflows during
   open/close animations from triggering a horizontal scroll on
   small viewports. The page never legitimately scrolls
   horizontally; clipping is correct. */
html, body { overflow-x: clip; }

/* Parent link wrapper — sits ABOVE the title (≡ Feed → title →
   meta → article). Small bottom margin pushes the title close
   enough that the link reads as "from feed". */
.post-back {
  margin: 0 0 0.625rem;
}

/* Footer prev / feed / next chrome lives in
   app/shared/templates/nav-icons/style.css under `.nav-footer-row`. The
   posts/show template uses those classes directly. */
