

/*
 * Comment thread styles — recursive, N-level nesting with a depth
 * cap and a "continue this thread →" affordance past the cap.
 * Matches notes/design/2026-04-23-comments-final.htm.
 */

/* ─── Comment — tap to collapse ─────────────────────────────────── */

.cmt {
  /* Tight intra-comment spacing so each comment reads as a unit.
     Vertical hierarchy: byline → 6px → body → 6px → actions.
     The padding here gives breathing room between sibling comments
     without inflating each one. */
  padding: 0.5rem 0;
  /* When scrollIntoView lands a comment at the top of the
     viewport (View in thread → from accepted answer pin, hash-
     anchored deep links), reserve room for the sticky topbar so
     the comment's byline isn't covered. ~5rem covers a typical
     topbar with breathing room. */
  scroll-margin-top: 5rem;
}
/* Collapsed strip is the only state where the whole row is
   clickable (only the meta line is visible — nothing else to
   target). Expanded comments use the explicit `[−]` toggle so
   body links + code blocks stay independently clickable. */
.cmt.is-collapsed { cursor: pointer; }

/* Meta row — also acts as the collapse / expand toggle. Tap anywhere
   on this row (handle, time, ago, blank space) flips the comment's
   collapsed state. The .cmt onclick handler filters out clicks on
   real interactive children (.cmt-body, .cmt-actions, links,
   buttons) so those still do their own thing. */
.cmt-meta {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  color: var(--ink-dim);
  margin-bottom: 0.375rem;       /* 6px byline → body */
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  cursor: pointer;
  /* Slightly bigger tap target on touch devices — extends the
     hit-zone above and below the text without changing the visible
     row height. */
  padding: 4px 0;
  margin-top: -4px;
}
.cmt-meta .handle {
  color: var(--ink);
  font-weight: var(--font-medium);
}
.cmt-meta .handle:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--ink-faint);
}
.cmt-meta .sep { color: var(--ink-faint); }
.cmt-meta .expand-hint { color: var(--ink-soft); }
.cmt-meta .expand-hint:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--ink-faint);
}

/* Body — server-rendered markdown HTML.
   Matches the post body's prose treatment but tighter (smaller type,
   less vertical rhythm) since comments live in dense threads. */
.cmt-body {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink);
}
.cmt-body > *:first-child { margin-top: 0; }
.cmt-body > *:last-child  { margin-bottom: 0; }

.cmt-body p { margin: 0 0 0.5rem; }
.cmt-body strong { font-weight: var(--font-semibold); }
.cmt-body em     { font-style: italic; }

.cmt-body a {
  color: var(--accent-deep);
  border-bottom: 1px dotted var(--accent-dot);
  padding-bottom: 1px;
}
.cmt-body a:hover { border-bottom-color: var(--accent-deep); }

.cmt-body ul,
.cmt-body ol {
  margin: 0 0 0.5rem 1.25rem;
  padding: 0;
}
.cmt-body li { margin-bottom: 0.125rem; }
.cmt-body li:last-child { margin-bottom: 0; }

.cmt-body blockquote {
  margin: 0.25rem 0 0.625rem;
  padding: 0.0625rem 0 0.0625rem 0.75rem;
  border-left: 2px solid var(--rule);
  color: var(--ink-soft);
}

.cmt-body code {
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  background: var(--bg-panel);
  padding: 1px 5px;
  border-radius: 3px;
}

/* Fenced code block — Lezer headless emits .tok-* spans inside
   <pre class='code-fence'><code>. Match the post body treatment but
   slightly smaller. Token coloring lives in the @import at the top
   of this file (app/shared/styles/syntax-highlight.css). */

/* Match the article's dark terminal-palette fence — same surface
   for code regardless of whether it lives in a post body or a
   comment. Slightly tighter padding + smaller type than the article
   because comments are denser. Token coloring (.tok-*) is shared
   via app/shared/styles/syntax-highlight.css and uses --term-* hues that
   read on this dark ground. */
.cmt-body pre.code-fence {
  margin: 0.5rem 0;
  padding: 0.625rem 0.875rem;
  /* bg + fg come from app/shared/styles/syntax-highlight.css (VSCode Dark+). */
  border-radius: var(--radius-sm);
  overflow-x: auto;
  font-family: var(--font-sans);
  font-size: 0.78125rem;
  line-height: 1.55;
}
.cmt-body pre.code-fence code {
  background: transparent;
  padding: 0;
  border-radius: 0;
  color: inherit;
  font-size: inherit;
}

/* ─── Actions row ───────────────────────────────────────────────── */

.cmt-actions {
  margin-top: 0.375rem;          /* 6px body → actions */
  display: flex;
  align-items: center;
  gap: 0.875rem;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  color: var(--ink-dim);
}

.votepair {
  display: inline-flex;
  align-items: center;
  /* Symmetric gap so the count sits visually between the two
     triangles. vote-up has its own 4px gap between ▲ and the digit;
     this 4px between vote-up and ▽ mirrors that on the other side,
     centering the digit between the two arrow glyphs. */
  gap: 4px;
}

/* `.vote-up` wraps arrow + count as one tap target. Color-only
   hover (no bg pill), matching the post-detail <ActionRow> pattern. */
.votepair .vote-up {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--ink-soft);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--duration-fast) var(--ease-out);
}
.votepair .vote-up:hover,
.votepair .vote-up:hover .arrow,
.votepair .vote-up:hover .count {
  color: var(--accent-deep);
}

.votepair .arrow {
  /* Two-state visual: outline triangle (△) when not voted, filled
     (▲) when voted. */
  color: var(--accent-deep);
  cursor: pointer;
  font-size: 0.6875rem;
  line-height: 1;
  user-select: none;
  background: transparent;
  -webkit-tap-highlight-color: transparent;
  outline: none;
}
/* Standalone downvote arrow (outside .vote-up). Color-only hover. */
.votepair > .arrow {
  color: var(--ink-soft);
  transition: color var(--duration-fast) var(--ease-out);
}
.votepair > .arrow:hover,
.votepair > .arrow:active,
.votepair > .arrow:focus {
  color: var(--accent-deep);
}
.votepair > .arrow:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}
.votepair .count {
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  font-weight: var(--font-medium);
  min-width: 0.75rem;
  text-align: center;
  /* Optical centering with Unicode triangle arrows. The △/▽ glyphs
     are drawn at 0.6875rem with line-height:1 while the count
     inherits the surrounding comment-actions text size — flexbox
     `align-items: center` then centers based on the larger line
     box, which leaves the digit sitting visually low between the
     two apex points. Lock font-size + line-height to match the
     arrows so all three children share one line box. */
  font-size: 0.6875rem;
  line-height: 1;
}
.votepair .count.is-positive { color: var(--ink); }
.votepair .count.is-negative { color: var(--ink-soft); }

.cmt-actions a {
  cursor: pointer;
  color: var(--ink-dim);
}
.cmt-actions a:hover { color: var(--ink); }

/* ─── Overflow menu ─────────────────────────────────────────────── */

/* Wrapper provides positioning context for the absolutely-placed
   menu when it falls back to absolute (mountMenu uses fixed when
   mounted, but the initial layout is still relative to this). */
.cmt-more-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}
/* Bare kebab — matches the post-meta kebab. Inline meta-line
   affordance, no boxed chrome at rest; faint wash on hover so the
   click target reads without crowding the row. */
.cmt-more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-family: var(--font-sans);
  line-height: 1;
  height: auto;
  min-height: 0;
  color: var(--ink-soft);
  background: transparent;
  border: 0;
  cursor: pointer;
  flex-shrink: 0;
  transition: color var(--duration-fast) var(--ease-out);
}
.cmt-more:hover,
.cmt-more.is-open {
  color: var(--accent-deep);
  background: transparent;
  border-color: transparent;
}
.cmt-more:active {
  background: transparent;
  border-color: transparent;
  transform: none;
}
.cmt-more:focus,
.cmt-more:focus-visible {
  outline: none;
  box-shadow: none;
}
.cmt-more svg { display: block; }

.cmt-more-menu {
  position: absolute;
  top: calc(100% + 0.25rem);
  left: 0;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius-md);
  padding: 0.25rem 0;
  box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.08);
  min-width: 10.625rem;
  z-index: 10;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  cursor: default;
}
.cmt-more-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.4375rem 0.875rem;
  color: var(--ink-soft);
  background: transparent;
  border: 0;
  font: inherit;
  cursor: pointer;
}
.cmt-more-menu button:hover { background: var(--bg-soft); color: var(--ink); }
.cmt-more-menu .sep-row {
  border-top: 1px solid var(--rule-soft);
  margin: 0.25rem 0;
}

/* ─── Nesting ───────────────────────────────────────────────────── */

.replies {
  margin-left: 1.125rem;             /* 18px */
  padding-left: 0.75rem;             /* 12px */
  border-left: 1px solid var(--rule);
  margin-top: 0.25rem;
}

/* When a direct child is the keyboard-focused comment, RECOLOR the
   indent guide instead of drawing a second accent bar inside the
   focused .cmt. Two parallel lines (gray guide + accent inset) read
   as a UI bug; one accent-colored guide reads as a single highlight.
   The .cmt.is-focused rule below also strips its own bar when nested,
   so the recolored guide is the sole indicator. Top-level focused
   comments still draw their own bar (no guide to recolor up there). */
.replies:has(> .cmt.is-focused) {
  border-left-color: var(--accent);
}

/* ─── Continue link (at depth cap) ──────────────────────────────── */

.continue-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
  padding: 0.375rem 0.75rem 0.375rem 0.625rem;
  background: var(--bg-panel);
  color: var(--ink-soft);
  border-radius: var(--radius-xs);
  font-family: var(--font-sans);
  font-size: 0.71875rem;
  cursor: pointer;
  border: 1px solid var(--rule);
  transition: border-color var(--duration-fast) var(--ease-out),
              color         var(--duration-fast) var(--ease-out);
}
.continue-link:hover { border-color: var(--ink); color: var(--ink); }
.continue-link::before { content: "↳"; color: var(--ink-faint); }
.continue-link .arrow { color: var(--ink-faint); }

/* ─── Collapsed state ───────────────────────────────────────────── */

/* Animated collapse via CSS grid 1fr ↔ 0fr trick. The .cmt-collapse
   wrapper is a 1-row grid; we transition grid-template-rows between
   `1fr` (open) and `0fr` (collapsed). The inner div needs
   overflow:hidden + min-height:0 so its content is clipped during
   the transition rather than escaping. */
.cmt-collapse {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 120ms ease-out;
}
.cmt.is-collapsed > .cmt-collapse {
  grid-template-rows: 0fr;
}
.cmt-collapse-inner {
  min-height: 0;
  overflow: hidden;
}
.cmt.is-collapsed > .cmt-meta { margin-bottom: 0; }

/* Keyboard-focused comment highlight. Driven imperatively by
   posts/show's onPostKeydown — j/k navigation toggles .is-focused
   on a single .cmt at a time. Just a colored left bar (no bg
   tint) so the focus indicator doesn't compete with the inline
   reply/edit composer when one is open. The bar is drawn via
   inset box-shadow so the comment's box position is unchanged;
   padding-left + matching negative margin-left reserves room
   for the bar without shifting the content column. */
.cmt.is-focused {
  box-shadow: inset 1px 0 0 var(--accent);
  padding-left: 0.625rem;
  margin-left: -0.625rem;
}

/* When the focused .cmt is nested under a .replies, suppress its own
   inset accent bar — its parent .replies' guide line is already
   recolored to accent (rule above). Without this we'd render BOTH
   the recolored guide AND the cmt's own bar, giving us back the
   original double-line. */
.replies > .cmt.is-focused {
  box-shadow: none;
  padding-left: 0;
  margin-left: 0;
}


/* One-shot highlight on freshly inserted comments. Used in concert
   with smooth scrollIntoView so the user actually sees their post
   land — pre-animation, the comment just popped into the tree
   with no visual cue and felt unsatisfying. The blue tint matches
   the site accent and fades out over 1.5s. */
.cmt.is-new {
  animation: cmt-flash 1.5s ease-out;
}
@keyframes cmt-flash {
  0%   { background: rgba(74, 123, 196, 0.16); }
  50%  { background: rgba(74, 123, 196, 0.10); }
  100% { background: transparent; }
}

/* ─── Accepted answer — left bar only, in-tree ──────────────────── */

/* The pinned block at the top of the thread (post-show template)
   carries the full "Accepted answer" chrome with green check,
   header, and link. The in-tree copy shouldn't double-shout —
   it just gets a thin green bar on the left so it's still
   recognizable as the accepted answer in context. The pinned
   block's CSS in app/pages/posts/show/style.css strips this bar
   from the inner copy so the chrome reads cleanly. */
.cmt.is-accepted {
  border-left: 3px solid #3f6b3a;
  padding-left: 0.625rem;
  margin-left: -0.625rem;
}

/* ─── Top-level comments — faint rule + generous gap ────────────── */

/* Adjacent root comments get a thin rule that sits IN the gap
   between them rather than inside either comment's box. Drawn via
   ::before so the .cmt's own padding stays tight — important for
   the .is-focused state, where any padding-top on the comment
   itself shows up as dead space inside the highlighted area
   (especially when the comment is collapsed). The first root
   suppresses the rule so the section header above sits flush. */
.cmt.is-top-level {
  position: relative;
  /* Cut from 2.5rem → 0.75rem. Comments are conversational, not
     architectural — they should sit close enough that the thread
     reads as discussion, not a stack of plaques. */
  margin-top: 0.75rem;
}
.cmt.is-top-level::before {
  content: "";
  position: absolute;
  /* Divider centered in the inter-comment gap. */
  top: -0.375rem;
  left: 0;
  right: 0;
  border-top: 1px solid rgba(23, 23, 26, 0.05);
}
.cmt.is-top-level:first-child {
  margin-top: 0;
}
.cmt.is-top-level:first-child::before {
  display: none;
}

/* ─── Drilled-subthread root ────────────────────────────────────── */

.cmt.is-root {
  background: var(--bg-soft);
  border-radius: var(--radius-md);
  padding: 0.75rem 0.875rem;
  margin-bottom: 0.375rem;
}

/* Inline reply composer. ALWAYS mounted in the DOM (the inner
   MarkdownEditor with it) so a Reply tap can synchronously focus
   the editor before the open-state flips — that's the iOS rule
   for popping the soft keyboard.
   Closed state: max-height 0 + opacity 0 + pointer-events none.
   The element stays focusable (no display:none, no
   visibility:hidden — both block iOS focus). When .is-open, the
   max-height grows enough to hold the editor + bar, opacity
   restores, pointer-events come back. */
/* .cmt-reply and .cmt-edit are always-mounted but visibility-toggled
   via .is-open. Closed state: max-height 0 + opacity 0 + pointer-
   events none. The element stays focusable (no display:none, no
   visibility:hidden — both block iOS gesture-time focus). On open
   the parent's tap handler synchronously calls mount.ta.focus()
   inside the gesture, which lets the iOS soft keyboard pop. */
.cmt-reply,
.cmt-edit {
  margin: 0;
  max-height: 0;
  opacity: 0;
  pointer-events: none;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  transition: max-height 140ms ease-out, opacity 100ms ease-out, margin 140ms ease-out;
}

.cmt-reply.is-open,
.cmt-edit.is-open {
  margin: 0.5rem 0 0.75rem;
  max-height: 32rem;
  opacity: 1;
  pointer-events: auto;
}

/* Inline reply / edit composers — the MarkdownEditor wrap now
   carries its own border + bg + focus-within ring (mockup-aligned
   single-bordered-field), so we no longer paint a wash here. The
   `.cmt-reply` / `.cmt-edit` containers are just open/close
   transition boxes around the editor. */

/* Inline reply/edit editor min-height — small, since the surface
   is nested inside a thread. Set via --md-min-height on the wrap
   so the textarea AND preview both size the same; toggling Edit ↔
   Preview doesn't make the panel jump. Mobile gets a tighter
   floor. */
.cmt-reply .md-editor-wrap,
.cmt-edit  .md-editor-wrap {
  --md-min-height: 5rem;
}
@media (max-width: 640px) {
  .cmt-reply .md-editor-wrap,
  .cmt-edit  .md-editor-wrap {
    --md-min-height: 4rem;
  }
}

/* Slot contents on the right side of .md-footer in inline reply
   and edit composers — Cancel link + Reply/Save button. */
.cmt-reply-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
}
.cmt-reply-actions a {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  color: var(--ink-soft);
  cursor: pointer;
}
.cmt-reply-actions a:hover { color: var(--ink); }

.cmt-reply-error {
  font-size: 0.8125rem;
  color: #b00020;
  background: #fff0f0;
  border: 1px solid #ffd0d0;
  padding: 0.375rem 0.625rem;
  border-radius: 4px;
}

.cmt-actions .arrow { cursor: pointer; }

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

@media (max-width: 640px) {
  .replies {
    margin-left: 0.625rem;
    padding-left: 0.5rem;
  }
}
