/* ============================================================================
   DETAIL — the vocabulary the detail pages share

   Seven DS components are used identically by every object-detail page in this
   app. They were first styled in event.css (`s/events` — full detail
   23260:442253, invitation 39296:180830, live 17615:295021) and then restated
   in video.css (`s/videos` — body `Body / Videos / Detail` 23304:478311),
   which flagged the duplication rather than reaching across pages mid-change.
   This file is that promotion: one copy, under a neutral `.detail-*` prefix.

     `p/card/content`                              the card shell
     `Row / Section Title`                         .detail-card__title
     `Community / All / Detail / Sections Items`   .detail-group-heading
     `Row / Default`                     §22.1     .detail-row
     `e/button v2 ✅ - Context`                    .detail-icon-btn
     `Community / All / Detail / Avatar`           .detail-person
     `Post / Body / Show More`                     .detail-desc

   ── The frames on both pages are pre-tokenisation. Every colour in them is a
   LOCAL Figma style, not a variable — `get_variable_defs` on 23304:478311
   returns local styles only — so none was copied. Both pages resolved them
   through DESIGN.md against the same table, which is why the two agree:

   | Figma local style              | resolves to | Token used                    |
   |--------------------------------|-------------|-------------------------------|
   | General/White                  | #ffffff     | `surface/raised`              |
   | General/BG Light               | #f6f6f6     | `soft/neutral/default`        |
   | Text & Icons/Headlines         | #262626     | `content/headline`            |
   | Text & Icons/Primary           | #595959     | `content/primary`             |
   | Text & Icons/Marginal          | #8c8c8c     | `content/secondary`           |
   | Action/BigHeart/Primary        | #4211a0     | `content/brand` (never a hex) |
   | Elements/Border Button Default | #d9d9d9     | `border/default`              |
   | Elements/Borders & Dividers    | #e8e8e8     | `border/default`              |
   | Elements/Other/Likes           | #f5222d     | `content/danger`              |

   ── DELIBERATE DIVERGENCES carried by the blocks below. Each is a defect
   named in apps/fe-client/CLAUDE.md, COMPONENTS.md or DESIGN.md.

   D3  No focus and no pressed state exists on any component in either set of
       frames. Both are implemented, per DESIGN.md §7 and the CLAUDE.md known
       gaps — the `pressed` state tokens are correct and were unconsumed.
   D6  `Post / Body / Show More` fades the description into the frame's
       General/White. The token here is `surface/raised`, so the fade still
       works in Dark, where a white smear would sit on a #2f2f2f card.

   ── Page-local divergences stay in event.css / video.css, scoped under the
   page root (`.event`, `.vdetail`). Two exist, and both are real differences
   between the two instances rather than leftovers: the collapsed height of the
   description (`--detail-desc-collapsed-size`, read below) and the weight of a
   person's name.

   TODO(tokens): every bare px length in this file is a SIZE or a BREAKPOINT.
   DESIGN.md §12.4 records both as not built. No colour, radius, spacing,
   border-width or font-size literal appears anywhere in this file.
   ========================================================================== */

/* ============================================================================
   Card + `Row / Section Title` — the shell every detail card shares.
   `p/card/content`: one raised card at the card radius.
   ========================================================================== */

.detail-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  padding: var(--space-md);
  background: var(--color-surface-raised);
  border-radius: var(--shape-radius-card);
}

.detail-card[hidden] {
  display: none;
}

.detail-card__title {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.detail-card__title-label {
  display: flex;
  margin: 0;
  flex: 1 1 auto;
  min-inline-size: 0;
  align-items: center;
  gap: var(--space-2xs);
}

.detail-card__title-label .icon {
  /* TODO(tokens): size not built. 16px is the DS's section-title icon slot. */
  inline-size: 16px;
  block-size: 16px;
  color: var(--color-content-headline);
}

/* ============================================================================
   `Community / All / Detail / Sections Items` group heading — Heading/XS
   Medium, upper-cased.

   The frame binds this label to Text & Icons/Headlines at 12px; at that size
   and weight it is a label above content, not a heading, so it takes
   `content/secondary`. §7.3 F8 binds the same label off RAW #8c8c8c
   elsewhere — this is the token, not the raw value.
   ========================================================================== */

.detail-group-heading {
  margin: 0;
  color: var(--color-content-secondary);
  font-family: var(--font-family-display);
  font-size: var(--font-heading-xs-size);
  line-height: var(--font-heading-xs-line-height);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--font-letter-spacing-default);
  text-transform: uppercase;
}

/* ============================================================================
   `Row / Default` — §22.1. Icon or avatar at 20/32, title, secondary line.
   ========================================================================== */

.detail-row {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding-block: var(--space-xs);
}

/* The leading glyph is always a direct child; a row body may contain its own
   icons, which must keep their own ink. */
.detail-row > .icon {
  flex: none;
  color: var(--color-content-headline);
}

.detail-row__body {
  display: flex;
  flex: 1 1 auto;
  min-inline-size: 0;
  flex-direction: column;
}

.detail-row__title {
  margin: 0;
  color: var(--color-content-headline);
  font-weight: var(--font-weight-medium);
}

/* The row's second line — a date, a count, whatever the row is qualified by.
   `content/secondary` so it reads as a qualifier of the title above it rather
   than a second title. */
.detail-row__meta {
  margin: 0;
  color: var(--color-content-secondary);
}

.detail-row__sub {
  margin: 0;
  color: var(--color-content-primary);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
}

/* ASSETS.md §3 — the `_fill` weight IS the on state, so a row switched on
   (`Featured`) is not signalled by colour alone. */
.detail-row--on > .icon {
  --icon-src: var(--icon-src-fill);
  color: var(--color-content-brand);
}

/* ============================================================================
   `e/button v2 ✅ - Context` — icon-only, no chrome until hover. The DS gives
   it a 4px inset and a `shape/radius/button` corner.

   The video header's like button puts a count beside the glyph inside the same
   component, so the type properties are declared here rather than left to the
   UA's button font.
   ========================================================================== */

.detail-icon-btn {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: var(--space-3xs);
  padding: var(--space-2xs);
  border: var(--border-width-thin) solid transparent;
  border-radius: var(--shape-radius-button);
  background: none;
  color: var(--color-content-primary);
  font-family: var(--font-family-text);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  transition: background-color 100ms ease, color 100ms ease; /* TODO(tokens): motion not built */
}

.detail-icon-btn:hover {
  background: var(--color-soft-neutral-hover);
  color: var(--color-content-headline);
}

/* D3 — pressed exists in the token layer and nothing consumes it. */
.detail-icon-btn:active {
  background: var(--color-soft-neutral-pressed);
}

/* ASSETS.md §3 — the _fill weight IS the selected state, so a toggled button
   (bookmarked, liked) is never signalled by colour alone. */
.detail-icon-btn[aria-pressed="true"] .icon {
  --icon-src: var(--icon-src-fill);
}

/* `--toggle` adds brand ink on top of the weight swap, for the bookmark-style
   toggles whose whole button is the state. It is a modifier rather than the
   default because the like button carries a neutral count inside the same
   button and paints only its glyph — see `.vdetail-like` in video.css. */
.detail-icon-btn--toggle[aria-pressed="true"] {
  color: var(--color-content-brand);
}

/* ============================================================================
   `Community / All / Detail / Avatar` — avatar, name, and an optional action.
   Four per row in both frames. Both frames clip the fourth name mid-word
   inside a 424 sidebar; that is not copied — the names wrap.
   ========================================================================== */

.detail-person {
  display: flex;
  flex: 1 1 0;
  min-inline-size: 0;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3xs);
  text-align: center;
}

.detail-person__avatar {
  position: relative;
}

/* `Avatar v2 / Badge` — the small status mark on the avatar's corner.
   §16.1 binds the badge ring to the surface it sits on. */
.detail-person__badge {
  position: absolute;
  inset-block-end: 0;
  inset-inline-end: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* TODO(tokens): size not built. 12 is the documented Avatar v2 / Badge slot
     at the 40 step. */
  inline-size: 12px;
  block-size: 12px;
  border-radius: var(--radius-full);
  border: var(--border-width-thin) solid var(--color-surface-raised);
  background: var(--color-solid-success-default);
  color: var(--color-on-solid-success);
}

.detail-person__badge .icon {
  inline-size: 100%;
  block-size: 100%;
}

.detail-person__name {
  margin: 0;
  color: var(--color-content-headline);
  /* Two lines, then wrap — the frames' names wrap to two. */
  overflow-wrap: anywhere;
}

.detail-person__note {
  margin: 0;
  color: var(--color-content-secondary);
}

/* `Community / All / Detail / Sponsors` prints a share of the sponsorship
   under the mark, in the same tile. */
.detail-person__percent {
  margin: 0;
  color: var(--color-content-secondary);
  font-size: var(--font-body-xs-size);
  line-height: var(--font-body-xs-line-height);
  font-weight: var(--font-weight-medium);
}

/* ============================================================================
   `Community / All / Detail / Description` + `Post / Body / Show More`
   The copy is clipped to a page-set height and a gradient fades it into the
   card, with a Show more control sitting in the fade.

   Each page sets its own collapsed height, because the two descriptions are
   different lengths in the comps and the control has to have something to
   hide. The value is read from `--detail-desc-collapsed-size`, set on
   `.detail-desc` in event.css / video.css.
   TODO(tokens): size not built — DESIGN.md §12.4.
   ========================================================================== */

.detail-desc {
  position: relative;
}

.detail-desc[data-expanded="false"] .detail-desc__prose {
  max-block-size: var(--detail-desc-collapsed-size);
  overflow: clip;
}

.detail-desc__more {
  display: flex;
  justify-content: center;
}

/* `display` on a class outranks the UA's `[hidden] { display: none }`, so the
   control needs this to actually disappear when the copy already fits — the
   same trap button.css documents for `.btn[hidden]`. */
.detail-desc__more[hidden] {
  display: none;
}

/* D6 — the frames' gradient runs from transparent to General/White; the token
   here is `surface/raised`, so the fade also works in Dark, where the card is
   #2f2f2f and a white fade would be a grey smear. */
.detail-desc[data-expanded="false"] .detail-desc__more {
  position: absolute;
  inset-inline: var(--space-md);
  inset-block-end: var(--space-md);
  align-items: end;
  padding-block-start: var(--space-2xl);
  background: linear-gradient(
    to bottom,
    transparent 0%,
    color-mix(in srgb, var(--color-surface-raised) 80%, transparent) 40%,
    var(--color-surface-raised) 64%
  );
}

/* ============================================================================
   Comments — COMPONENTS.md §32

   SHARED. The event detail page and the video detail page mount the same
   component, so it lives here rather than twice: `s/events` 23260:442253 and
   `s/videos` 22038:403118 (the `Detail Redesign` master, where the section is
   visible — the instance on the detail screen has it switched off).

   Source: the FE Client product file, section 47675:178825 — NOT the DS file.
   Recipe: `COMPONENTS.md` §32. The whole family is bound to the legacy
   `✅ …` library there (§32 F1), so every declaration below resolves through
   the §32.1 legacy → semantic map rather than off the design.

   Findings handled, not reproduced:
     F2  `✅ Action/BigHeart/Primary` = RAW #4211a0 on the send fill and every
         link. `solid/brand/default` / `content/brand` here.
     F3  `Reactions` has no Selected axis — a liked comment looks unliked.
         `.comment__likes[aria-pressed="true"]` swaps to the `_fill` weight
         AND to `content/danger`: two channels, per DESIGN.md §9.2.
     F4  Level 3 is drawn at 50% opacity in Figma with nothing to explain it.
         Not shipped.
     F5  `soft/neutral/default` on `surface/raised` collides in Dark — see the
         note on `.comment__content`.
     F7  The unlabelled `solid/warning/default` `Suggestions` dot on a resting
         composer. Not shipped.
     F9  Focus is specified for the author name and avatar only, and neither is
         interactive in any drawn instance. Implemented on both (they are
         profile links, per the `Username states` / `Avatar states` frames) and
         on every control the section left out.
   ========================================================================== */

.detail-comments {
  gap: var(--space-none);
  padding: var(--space-none);
}

.detail-comments__title {
  padding: var(--space-md) var(--space-md) var(--space-none);
}

.detail-comments__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-none);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* `Comment / Item / Load Comments` (§32.6) — section level, above the first
   thread. Distinct from `Load Replies`, which lives inside a rail. */
.detail-comments__load {
  align-self: start;
  margin: var(--space-xs) var(--space-md);
}

/* --- `Comments` type=Empty (§32.2) --------------------------------------- */
.detail-comments__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-2xl) var(--space-md);
  text-align: center;
}

.detail-comments__empty-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  /* TODO(tokens): size not built — DESIGN.md §12.4. The frame's circle is 80
     around a 40 glyph. */
  inline-size: 80px;
  block-size: 80px;
  margin-block-end: var(--space-xs);
  border-radius: var(--shape-radius-avatar);
  background: var(--color-soft-neutral-default);
  color: var(--color-content-secondary);
}

.detail-comments__empty-mark .icon {
  inline-size: 40px;
  block-size: 40px;
}

.detail-comments__empty-title {
  margin: 0;
  color: var(--color-content-headline);
  font-size: var(--font-heading-sm-size);
  line-height: var(--font-heading-sm-line-height);
  font-weight: var(--font-weight-bold);
}

.detail-comments__empty-text {
  margin: 0;
  color: var(--color-content-secondary);
}

/* --- `Comments / Item` (§32.3) -------------------------------------------
   `Columns`: one rail per ancestor level, then the body. Depth is expressed by
   PREPENDING a rail that carries the ancestor's line — never by an indent
   value — so a reply's own rail is always the last one.

   FE.C threads go TWO levels deep. `Level=3` and `3 + More` exist in the
   Figma section but are not used on this app's surfaces, so the 24-wide
   `Comment / Avatars / Level 2` rail, its 12 elbow step and the standalone
   `Connector=Line` are not built. Adding a third level means adding those
   three rules back, not changing these. */
.comment {
  display: flex;
  align-items: stretch;
  gap: var(--space-xs);
  padding-inline: var(--space-md);
}

/* `Comment / Item / Avatars / Level 1` — 40 wide, carries a 40 avatar.
   `Comment / Avatars / Level 2` — 24 wide, carries a 24 avatar. Both are the
   same object with a different width, so one class with a modifier. */
.comment__rail {
  display: flex;
  position: relative;
  flex: none;
  /* TODO(tokens): size not built — matches the 40 avatar step. */
  inline-size: 40px;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2xs);
}

/* `Connector Wrapper` — the thread line. A rotated `Divider` in the frame; a
   1px block here, which is the same hairline and needs no asset. */
.comment__connector {
  flex: 1 1 auto;
  min-block-size: 0;
  inline-size: var(--border-width-thin);
  background: var(--color-border-default);
}

/* `Connector=Solo` — the leaf case. Avatar, no line below it. */
.comment__rail--solo > .comment__connector {
  visibility: hidden;
}

/* `Connector=Empty` — a spacer that reserves the column and draws nothing.
   Used where an ancestor's thread has already ended above this row. */
.comment__rail--empty > .comment__connector {
  visibility: hidden;
}

/* `Comment / Item / Connector / Corner` (§32.3) — the elbow that turns an
   ancestor's line into the child's avatar. 20×20 at level 1, 12×12 at level
   2+, top-aligned to the row and right-aligned in its rail. Two borders and a
   radius, not an SVG. */
.comment__rail--corner > .comment__connector {
  position: absolute;
  inset-block-start: 0;
  inset-inline-end: 0;
  /* TODO(tokens): size not built — the frame's 20 elbow. */
  inline-size: 20px;
  block-size: 20px;
  flex: none;
  background: none;
  border-inline-start: var(--border-width-thin) solid var(--color-border-default);
  border-block-end: var(--border-width-thin) solid var(--color-border-default);
  border-end-start-radius: var(--shape-radius-card);
}

/* `Connector=Line + Corner` — the ancestor's line continues past the elbow, so
   the rail draws both. The line is the pseudo-element; the elbow is the
   connector element positioned over it. */
.comment__rail--line-corner::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inline-size: var(--border-width-thin);
  background: var(--color-border-default);
}

.comment__body {
  display: flex;
  flex: 1 1 auto;
  min-inline-size: 0;
  flex-direction: column;
  gap: var(--space-2xs);
  padding-block-end: var(--space-md);
}

/* --- `Comment / Item / Body` type=Default (§32.4) ------------------------ */
.comment__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding-block: var(--space-md);
  background: var(--color-soft-neutral-default);
  border-radius: var(--shape-radius-card);
  /* ⚠️ §32 F5 — TOKEN COLLISION. `soft/neutral/default` and `surface/raised`
     resolve to DIFFERENT values in Light (#f6f6f6 on #ffffff) and to the SAME
     value in Dark — both are Neutral/950 — so the bubble that separates a
     comment from the card disappears entirely in Dark mode. Verified in the
     browser: both compute to rgb(47, 47, 47).

     Forking the fill Light/Dark is not available (root CLAUDE.md
     non-negotiable 5), so a hairline carries the edge where the fill cannot.
     This is the pattern modal.css, toast.css and dropdown.css already use for
     the same class of problem ("shadow does not read in Dark"), and
     light-dark() keeps it as ONE declaration rather than a forked rule.

     TODO(tokens): the DS needs a soft-neutral step that is guaranteed to
     differ from `surface/raised` in both modes. Reported for DESIGN.md §4. */
  border: var(--border-width-thin) solid
    light-dark(transparent, var(--color-border-default));
}

.comment__header {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding-inline: var(--space-md);
}

.comment__author {
  margin: 0;
  flex: 1 1 auto;
  min-inline-size: 0;
}

/* `Username states` 27475:487004 (§32.8) — the author name is a profile link.
   Hover: `content/brand` + underline. Focus: `border/focus` outline. This and
   the avatar below are the only interaction states the section specifies. */
.comment__author-link {
  color: inherit;
  text-decoration: none;
  border-radius: var(--shape-radius-button);
}

.comment__author-link:hover {
  color: var(--color-content-brand);
  text-decoration: underline;
}

.comment__author-link:focus-visible {
  outline: var(--shape-focus-width) solid var(--color-border-focus);
  outline-offset: var(--shape-focus-offset);
}

/* `Avatar states` 27475:486992 (§32.8) — hover 80% opacity, focus a
   `border/focus` outline with an offset. */
.comment__avatar-link {
  display: inline-flex;
  border-radius: var(--shape-radius-avatar);
}

.comment__avatar-link:hover {
  opacity: 0.8;
}

.comment__avatar-link:focus-visible {
  outline: var(--shape-focus-width) solid var(--color-border-focus);
  outline-offset: var(--shape-focus-offset);
}

.comment__actions {
  display: flex;
  flex: none;
  align-items: start;
  gap: var(--space-xs);
}

.comment__text {
  margin: 0;
  padding-inline: var(--space-md);
  color: var(--color-content-primary);
  overflow-wrap: anywhere;
}

/* An @-mention inside a comment body. The frame renders these in the brand
   colour with no background — `content/brand`, which is exactly its
   documented use ("brand text with no background behind it"). */
.comment__mention {
  color: var(--color-content-brand);
  font-weight: var(--font-weight-medium);
}

.comment__link {
  color: var(--color-content-brand);
}

.comment__translate {
  align-self: start;
  margin-inline: var(--space-md);
}

/* `Comment / Item / Reactions` (§32.5) — `align-items: flex-start` and
   `gap: 16` in the frame, on a 22-tall row: the row is the height of its own
   text line, because `Like` and `Reply` are Inline-size buttons rather than
   control slots. Centring them would only differ once something in the row
   was taller than the rest, and the frame says top. */
.comment__reactions {
  display: flex;
  align-items: flex-start;
  gap: var(--space-md);
}

.comment__time {
  margin: 0;
  color: var(--color-content-secondary);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
}

/* `Like` and `Reply` are `Button / Link / Secondary` at the **Inline** size
   (§1.1) — no fill, no border, `content/primary` → `content/brand` on hover.
   NOT Tertiary, which would draw a `border/default` outline around each one
   and turn a quiet row of subordinate actions into two competing controls.

   §32 F3 — the set has no Selected axis, so a liked comment is identical to an
   unliked one. Two channels added: the `_fill` weight and `content/danger`.
   The count stays on `content/primary` inside the same button, so only the
   glyph carries colour — the pattern `.vdetail-like` in video.css uses. */
.comment__likes[aria-pressed="true"] .icon {
  --icon-src: var(--icon-src-fill);
  color: var(--color-content-danger);
}

/* --- `Comment / Item / Load Replies` (§32.6) -----------------------------
   NOT a section-level link. It sits inside a 40-wide rail carrying
   `Connector=Corner`, so the elbow points at the replies it will reveal —
   which is the only cue that says which thread it belongs to. */
.comment-load-replies {
  display: flex;
  align-items: stretch;
  gap: var(--space-xs);
  padding-inline: var(--space-md);
}

.comment-load-replies__btn {
  align-self: start;
  margin-block: var(--space-xs) var(--space-lg);
}

/* --- `Comments / Input` (§32.7) ------------------------------------------
   Seven states, and they are a progressive-disclosure sequence, not seven
   independent looks. `data-state` on the wrapper drives it:
     collapsed  → State=Default   (avatar + one 40-tall field, 72 tall)
     open       → State=Opened / Focus / Filled (label, toolbar, attach, send)
   Error and the attachment rows are additive within `open`. */
.detail-comments__input {
  display: flex;
  align-items: end;
  gap: var(--space-xs);
  padding: var(--space-md);
  background: var(--color-surface-raised);
}

.detail-comments__input-body {
  display: flex;
  flex: 1 1 auto;
  min-inline-size: 0;
  flex-direction: column;
  gap: var(--space-xs);
}

/* `State=Default` — the collapsed field. A button, not an input: clicking it
   is what opens the composer, and a button is what announces that. */
.detail-comments__collapsed {
  display: flex;
  align-items: center;
  /* TODO(tokens): size not built. 40 is the documented input height. */
  block-size: 40px;
  inline-size: 100%;
  padding: var(--space-xs);
  background: var(--color-soft-neutral-default);
  /* Same collision as `.comment__content` above — in Dark the field's fill
     equals the card's, so a control with no border would have no edge at all
     until it is focused. */
  border: var(--border-width-thin) solid
    light-dark(transparent, var(--color-border-default));
  border-radius: var(--shape-radius-input);
  /* ⚠️ DESIGN.md §9.2 A2: `content/placeholder` measures 1.69–1.84:1 in Light
     and fails 4.5:1, despite its own description claiming otherwise. It is
     still the only token scoped to a placeholder, and the field carries an
     accessible name of its own, so it stands — flagged, not substituted. */
  color: var(--color-content-placeholder);
  font-family: var(--font-family-text);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  text-align: start;
  cursor: text;
}

.detail-comments__collapsed:hover {
  background: var(--color-soft-neutral-hover);
}

.detail-comments__collapsed:focus-visible {
  outline: var(--shape-focus-width) solid var(--color-border-focus);
  outline-offset: var(--shape-focus-offset);
}

/* `Input / RTE` — label, shell, caption. §2.1 is the focus reference
   implementation CLAUDE.md names, and this follows it. */
.detail-comments__rte {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
}

.detail-comments__rte-label {
  color: var(--color-content-secondary);
  font-size: var(--font-label-sm-size);
  line-height: var(--font-label-sm-line-height);
}

.detail-comments__rte-shell {
  display: flex;
  flex-direction: column;
  background: var(--color-surface-raised);
  border: var(--border-width-thin) solid var(--color-border-default);
  border-radius: var(--shape-radius-input);
}

.detail-comments__rte-shell:focus-within {
  border-color: var(--color-border-focus);
}

/* `Input / RTE / Toolbar` — 14 controls, wraps. */
.detail-comments__toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  padding: var(--space-xs);
}

.detail-comments__tool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3xs);
  padding: var(--space-3xs);
  border: var(--border-width-thin) solid transparent;
  border-radius: var(--shape-radius-button);
  background: none;
  color: var(--color-content-primary);
  font-family: var(--font-family-text);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
}

.detail-comments__tool:hover {
  background: var(--color-soft-neutral-hover);
}

/* §31.3 — the pressed tokens exist and nothing consumes them. */
.detail-comments__tool:active {
  background: var(--color-soft-neutral-pressed);
}

.detail-comments__tool:focus-visible {
  outline: var(--shape-focus-width) solid var(--color-border-focus);
  outline-offset: var(--shape-focus-offset);
}

.detail-comments__toolbar-sep {
  flex: none;
  align-self: stretch;
  inline-size: var(--border-width-thin);
  margin-inline: var(--space-2xs);
  background: var(--color-border-default);
}

/* `Input / Default / Base` — 40 tall, and it grows as the comment does. */
.detail-comments__field {
  display: block;
  inline-size: 100%;
  /* TODO(tokens): size not built. 40 is the documented input height. */
  min-block-size: 40px;
  padding: var(--space-xs);
  border: none;
  border-end-start-radius: var(--shape-radius-input);
  border-end-end-radius: var(--shape-radius-input);
  background: none;
  color: var(--color-content-primary);
  font-family: var(--font-family-text);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  resize: vertical;
}

.detail-comments__field::placeholder {
  /* DESIGN.md §9.2 A2 — see the note on `.detail-comments__collapsed`. */
  color: var(--color-content-placeholder);
}

/* The shell carries the focus ring, so the control inside does not draw a
   second one — §2.1's own arrangement. */
.detail-comments__field:focus-visible {
  outline: none;
}

/* `State=Error` — `border/danger/default` on the shell, and an
   `Input / Caption` in `content/danger` below it. Bold `Error:` prefix, per
   the frame. */
.detail-comments__input[data-invalid="true"] .detail-comments__rte-shell {
  border-color: var(--color-border-danger-default);
}

.detail-comments__caption {
  display: flex;
  gap: var(--space-3xs);
  color: var(--color-content-danger);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
}

.detail-comments__caption strong {
  font-weight: var(--font-weight-bold);
}

/* `Button Wrapper` — attach above send, bottom-aligned with the field. */
.detail-comments__send-wrap {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
}

/* §32 F2 — the frame freezes RAW #4211a0 on this fill. `solid/brand/default`
   with `on-solid/brand` ink, which is the same colour under BigHeart and the
   right one under every other brand. */
.detail-comments__send {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-sm);
  border: var(--border-width-thin) solid transparent;
  border-radius: var(--shape-radius-button);
  background: var(--color-solid-brand-default);
  color: var(--color-on-solid-brand);
}

.detail-comments__send:hover {
  background: var(--color-solid-brand-hover);
}

.detail-comments__send:active {
  background: var(--color-solid-brand-pressed);
}

.detail-comments__send:focus-visible {
  outline: var(--shape-focus-width) solid var(--color-border-focus);
  outline-offset: var(--shape-focus-offset);
}

/* `State=1 attachment` / `State=Multiple attachment` — the rows sit ABOVE the
   RTE. With more than one, the group gains a collapsible header carrying the
   count and a `Clear all` link. */
.detail-comments__attachments {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
}

.detail-comments__attachments-head {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-none);
  border: none;
  background: none;
  color: var(--color-content-primary);
  font-family: var(--font-family-text);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  text-align: start;
}

.detail-comments__attachments-head:focus-visible {
  outline: var(--shape-focus-width) solid var(--color-border-focus);
  outline-offset: var(--shape-focus-offset);
}

.detail-comments__attachments-count {
  flex: 1 1 auto;
  min-inline-size: 0;
}

.detail-comments__attachments-head[aria-expanded="false"] .icon--caret-down {
  rotate: -90deg;
}

.detail-comments__attachments-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.detail-comments__attachment {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  /* TODO(tokens): size not built. 40 is the documented row height. */
  block-size: 40px;
  padding-inline: var(--space-md);
  background: var(--color-soft-neutral-default);
  border: var(--border-width-thin) solid var(--color-border-default);
  border-radius: var(--shape-radius-input);
}

/* §32 F6 — the file-type marks are multi-colour brand assets (PDF red, PPT
   gold) with no semantic equivalent, so they are `<img>`, not masked glyphs.
   Same call event.css D4 makes. ASSETS.md §6 rule 1 still holds: the file is
   referenced, never inlined.
   TODO(tokens): file-type ink is a real gap in the token layer. */
.detail-comments__attachment-mark {
  flex: none;
  /* TODO(tokens): size not built. */
  inline-size: 16px;
  block-size: 16px;
}

.detail-comments__attachment-name {
  flex: 1 1 auto;
  min-inline-size: 0;
  color: var(--color-content-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* `display` on a class outranks the UA's `[hidden] { display: none }`, so
   every flex box in this section that toggles needs its own guard — the trap
   button.css documents for `.btn[hidden]` and collection.css for
   `.collection__empty-state[hidden]`. Load-bearing here: the composer's seven
   states, the empty state and the populated list all live in the DOM at once
   and are switched with `hidden`. */
.detail-comments__empty[hidden],
.detail-comments__list[hidden],
.detail-comments__rte[hidden],
.detail-comments__attachments[hidden],
.detail-comments__attachments-head[hidden],
.detail-comments__attachments-list[hidden],
.detail-comments__collapsed[hidden],
.detail-comments__caption[hidden],
.detail-comments__send-wrap[hidden] {
  display: none;
}
