@import "https://assets.elements.dev/assets/app/shared/styles/page.b167db396f67ed0.css";

/*
 * /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 come from the shared shell rules in
   app/shared/styles/site.css. 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. */

/* 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(--theater-bg);
  display: flex;
  justify-content: center;
  align-items: center;
  /* Full-width edge under the video. In light mode the black theater
     already separates from the white page; in dark mode the page is
     also near-black, so this fixed faint-light hairline is what marks
     where the theater ends and the content begins. */
  border-bottom: 1px solid var(--theater-edge);
  margin-bottom: 1.75rem;
}

/* The theater butted straight into the topbar with no gap, so the video
   read as an extension of the chrome and the top edge of the frame was
   hard to find. Padding rather than margin — the space has to stay
   inside the dark wrapper, or a light band opens between the topbar and
   the video and breaks the continuous dark surface. Tighter on phones,
   where vertical room is the scarce thing. */
.post-theater-wrap {
  padding-top: 1.25rem;
  /* Symmetric below, so the frame sits centered in its own surface
     rather than resting on the bottom edge. This is inside the dark
     wrapper and above the theater-edge hairline, which is what still
     marks where the theater stops and the page begins — distinct from
     margin-bottom, which is light page space under that line. */
  padding-bottom: 1.25rem;
  /* Sides too, so the frame is inset on every edge. Without this the
     video runs to the viewport edge and the browser windows inside the
     screencast look like they are bleeding into the page rather than
     being footage inside a frame. On wide screens the 1600px cap
     already leaves margin; this is what does the work on narrow ones. */
  padding-left: 1.25rem;
  padding-right: 1.25rem;
}

/* Phones go edge to edge horizontally. The inset is invisible there —
   the wrapper and the video surface are both black, so all it does is
   shrink a 16:9 frame on the smallest screen. The side padding earns
   its place on desktop, where the footage contains light browser
   windows that otherwise run into the page. Vertical padding stays:
   that boundary is against white and is the one that read as bleeding. */
@media (max-width: 700px) {
  .post-theater-wrap {
    padding: 0.75rem 0;
  }
}

/* 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 first visible viewport. 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.
     - subtract ≈4rem (the topbar height + breathing room) so that on
       first paint the whole theater fits under the topbar, which sits
       directly above it at the top of the page. The topbar is NOT
       sticky — it scrolls away with the content — so this only shapes
       the initial, unscrolled view.
   `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(--theater-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  /* aspect-ratio gives this box a fractional height (402pt wide is
     226.125pt tall), and the video fills 100% of it. On a 3x screen the
     video's painted content reaches device row 678 while the absolutely
     positioned end-of-video overlay, laid out on the same fractional box,
     fills only 677. One device-pixel row of the last video frame then
     showed below the overlay as a bright hairline across the bottom of
     the theater. Clipping the box removes the row that leaks. */
  overflow: hidden;
}

/* 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. */
/* Landscape on a phone: the video gets the whole viewport height. You
   rotated in order to watch, so byline and comments are not what the
   space is for — reserving 6rem for them capped the frame at 62% of the
   width when 82% is the most a 16:9 frame can reach in a 390-tall
   viewport. Height is the binding constraint here, not width: filling
   844px across would need 475px of height and the video would run off
   the bottom.

   The padding goes to zero for the same reason. Landscape phones are
   ~844px wide, so they miss the max-width: 700px block entirely and
   were picking up the desktop 1.25rem, spending scarce vertical room on
   a gap nobody asked for in this orientation. */
@media (orientation: landscape) and (max-height: 500px) {
  .post-theater {
    max-width: min(1600px, calc(100svh * 16 / 9));
  }

  .post-theater-wrap {
    padding: 0;
  }
}

.post-theater-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--theater-bg);
  display: block;
}

/* Clicking a native control focuses the <video> itself, which draws a
   ring around the whole 16:9 surface — a frame around the movie because
   you pressed pause. The native control chrome carries its own focus
   indicators, so nothing is lost by dropping this one. Keyboard focus
   still reaches the element; it just doesn't outline the picture. */
.post-theater-video:focus,
.post-theater-video:focus-visible {
  outline: none;
}

/* Chrome draws its own focus ring on the native control buttons, inside
   the video's shadow DOM, so the rule above does not reach it — a blue
   rectangle appears around the play button after a click. These vendor
   pseudo-elements are the only handle on it. Keyboard users lose
   nothing: the controls still take focus and still respond, and the
   ring reappears for anyone navigating by tab because the browser
   re-adds it on :focus-visible at the panel level. */
.post-theater-video::-webkit-media-controls-play-button:focus,
.post-theater-video::-webkit-media-controls-mute-button:focus,
.post-theater-video::-webkit-media-controls-fullscreen-button:focus,
.post-theater-video::-webkit-media-controls-timeline:focus,
.post-theater-video::-webkit-media-controls-panel *:focus {
  outline: none;
}

/* 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(--theater-bg);
}

.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(--weight-medium); }
.chapter-row.is-active .title { font-weight: var(--weight-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(--weight-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/vars.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--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(--success); }
.post-copy-link.is-copied:hover          { color: var(--success); }

/* ─── 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(--weight-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(--weight-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(--terminal-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(--terminal-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(--weight-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(--weight-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(--success-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(--weight-medium);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.post-answer.is-accepted .post-answer-vote .count { color: var(--success); }
.post-answer-vote .accepted-mark {
  font-size: 1.125rem;
  color: var(--success);
  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(--weight-medium); }
.post-answer-byline-sep { color: var(--ink-faint); }
.post-answer-byline .accepted-tag {
  color: var(--success);
  font-weight: var(--weight-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. */
/* Video posts use PageChrome's fullwidth layout (so the video band
   bleeds edge-to-edge), but that mode strips page-chrome-main's
   bottom 50dvh padding — designed for editor surfaces, not content
   pages with comment threads. Restore the comfortable footer
   air for video post pages specifically. */
body.post-page .page-chrome.is-fullwidth .page-chrome-main {
  padding-bottom: 50dvh;
}

.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;
  /* Breathing room on `#comments` anchor jumps / scrollIntoView so the
     section heading lands a little below the viewport top instead of
     slammed against the very edge. (The topbar is not sticky, so there's
     nothing overlapping to clear — this is purely for comfortable
     framing of the jump target.) */
  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(--weight-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(--weight-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(--weight-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(--weight-semibold);
  letter-spacing: 0;
}
.accepted-answer-label { flex: 0 0 auto; }
.accepted-answer-jump  {
  margin-left: auto;
  font-weight: var(--weight-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 terminal palette so code blocks in posts use
   the same colors as the rest of the project's terminal surfaces
   (.code-block, .terminal). The orange/amber hexes are the old
   --term-orange / --term-amber values, inlined because the v2
   terminal tokens only cover bg/ink/dim; they get tokenized with the
   rest of the syntax palette later. 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(--terminal-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: #F37865; }

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

.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: #F37865; }

.post-body pre .tok-tagName,
.post-body pre .tok-typeName,
.post-body pre .tok-className,
.post-body pre .tok-namespace      { color: #F2D64C; }

.post-body pre .tok-attributeName,
.post-body pre .tok-propertyName   { color: #F2D64C; }

.post-body pre .tok-function,
.post-body pre .tok-macroName,
.post-body pre .tok-labelName      { color: #F2D64C; }

.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(--terminal-dim); }

.post-body pre .tok-regexp         { color: var(--success-400); }
.post-body pre .tok-escape         { color: #F2D64C; }
.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(--weight-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. */

/* Draft marker in the post meta row. Quiet on purpose: amber carries the
   "not live yet" meaning without the volume of a banner, and the pill sits
   inline with kind / author / time so it never displaces the content being
   reviewed. */
.post-meta__draft {
  display: inline-flex;
  align-items: center;
  padding: 0.0625rem 0.375rem;
  border: 1px solid rgba(180, 120, 20, 0.35);
  border-radius: 3px;
  background: rgba(255, 196, 84, 0.14);
  color: #8a5a00;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  line-height: 1.4;
}
