/* ============================================================================
 * site/styles/components.css — component layer
 * Cascade position 3 of 5 (tokens → base → components → sections → responsive).
 *
 * PUBLISH ROOT: `site/` is the only publishable directory in this repository.
 * Nothing here may reference the private research directories, the
 * repository-root legacy page, the older landing seeds, or the raw design
 * deliveries. All paths inside `site/` are relative.
 *
 * ---------------------------------------------------------------------------
 * CASCADE CONTRACT
 * ---------------------------------------------------------------------------
 * The five stylesheets are linked in one fixed order in `index.html`, and that
 * link order IS the cascade order. No `@import`, no dynamic injection, no
 * conditional load. Given equal specificity, later beats earlier:
 *
 *   1. tokens.css      role values only — the sole token carrier under `site/`
 *   2. base.css        document primitives: reset, type, links, focus, skip
 *                      link and layout utilities
 *   3. components.css  reusable component anatomy, variants and states  ← here
 *   4. sections.css    per-section composition and grid placement
 *   5. responsive.css  per-width behavior; loaded last so a breakpoint rule
 *                      wins over the desktop-first rule it steps down from
 *
 * Consequences this layer relies on:
 * - A component rule of equal specificity overrides a `base.css` primitive.
 *   Components therefore never need `!important` to beat a primitive, and
 *   `!important` is not used in this stylesheet.
 * - `sections.css` places components; it does not restyle their internals.
 *   Anatomy, variants and states live here, layout lives there.
 * - `responsive.css` overrides both, so a component must not encode per-width
 *   behavior with its own media query.
 * - Specificity stays flat — single class selectors, at most one state or
 *   attribute qualifier. Nothing here relies on source order *within* the file.
 *
 * ---------------------------------------------------------------------------
 * LAYER RULES
 * ---------------------------------------------------------------------------
 * - Reference token roles through `var()`. Never restate a literal that has a
 *   token role in `tokens.css`.
 * - Every interactive component defines all of: rest, hover, focus-visible,
 *   active/pressed, disabled, and — where it navigates — visited. Hover is
 *   never the only signal and no state is carried by colour alone.
 * - Interactive boundaries use `--border-control` on every surface. The
 *   decorative hairline roles never mark the edge of a control.
 * - Unverified content is omitted from the published document and recorded in
 *   the v2 claim ledger; components do not carry predecessor state switches.
 * - No component may produce page-level horizontal overflow. A fixture that
 *   cannot compress scrolls inside its own panel.
 *
 * ---------------------------------------------------------------------------
 * DERIVED SIZE ALIASES — why they exist
 * ---------------------------------------------------------------------------
 * A handful of component metrics in `design-system/COMPONENTS.md` are stated
 * in pixels that the accepted token set does not carry a role for: the four
 * glyph-chip sizes, the hero cluster chip, and the 44px minimum hit target.
 * Writing those as literals would break the rule that `styles/tokens.css` is
 * the sole carrier of values under `site/`, so each is expressed once here as
 * an alias derived by `calc()` from accepted space roles. These are
 * references and arithmetic over references, never new values.
 *
 * Percentages, `0`, `100%`, `auto`, `none`, `1fr`/`minmax()` track syntax, and
 * the invented figures a fixture renders are structural CSS mechanics or
 * synthetic data, not design values, and have no token role.
 *
 * ---------------------------------------------------------------------------
 * OWNERSHIP
 * ---------------------------------------------------------------------------
 * Task 02 established this layer empty. Task 04 adds the components of
 * `site-header` … `intelligence` — below. Task 05 adds the components of
 * `backlinks` … `closing`. Task 06 adds state and accessibility hardening.
 * ========================================================================= */

:root {
  /* Glyph-chip sizes: 24 / 32 / 40 / 48, the accepted 4px scale steps nearest
   * the 22 / 28 / 40 / 52 anatomy in COMPONENTS.md. Radius is ~30% of size:
   * `--radius-chip` at the two small sizes, `--radius-control` at the two
   * large, exactly as the icon doctrine specifies. */
  --glyph-xs: var(--space-6);
  --glyph-sm: var(--space-7);
  --glyph-md: var(--space-8);
  --glyph-lg: calc(var(--space-10) - var(--space-7));

  /* Minimum hit target below 768px: 40 + 4. */
  --target-min: calc(var(--space-8) + var(--space-1));

  /* Skeleton bar height, inside the 6–12px band COMPONENTS.md allows. */
  --skel-h: var(--space-2);

  /* Compact display step, composed from accepted space roles. */
  --text-display-sm: calc(var(--space-6) + var(--space-1));

  /* Reveal stagger step: 60ms, the interval `MOTION.md` §3 states, as
   * arithmetic over an accepted role rather than a literal duration. */
  --reveal-stagger: calc(var(--duration-fast) / 2);

}

/* ==========================================================================
 * Shared primitives
 * ======================================================================== */

/* --- Button ---------------------------------------------------------------
 * Navigation is an `a[href]`; an in-page action is a `button`. An action whose
 * destination is not configured is never a bare non-interactive element and
 * never an activatable control that silently does nothing: it ships as a real
 * `button` that is genuinely `disabled` and carries `aria-disabled="true"`
 * with its accurate label. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-6);
  border: 0;
  border-radius: var(--radius-control);
  font-family: var(--font-sans);
  font-size: var(--text-body-size);
  font-weight: var(--weight-medium);
  line-height: var(--text-tight-lh);
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--duration-base) var(--ease-standard),
    color var(--duration-base) var(--ease-standard),
    transform var(--duration-base) var(--ease-standard);
}

.btn--sm {
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-caption-size);
}

.btn:active {
  transform: translateY(var(--press-distance));
}

.btn--ink {
  background-color: var(--surface-ink);
  color: var(--text-on-ink);
}

.btn--ink:hover {
  background-color: var(--surface-ink-raised);
  color: var(--text-on-ink);
}

.btn--accent {
  background-color: var(--accent-strong);
  color: var(--text-on-accent);
}

/* The one variant whose fill cannot step. `DESIGN.md` §4.2 allows exactly one
 * accent value under a label — `--accent-strong` — and the system carries no
 * darker accent role, so a hover fill step would have to leave the accent
 * family or drop to `--accent`, which is declared non-text. An elevation step
 * is not available either: this variant's two placements are the recommended
 * tier and the closing band, and `--shadow-none` is the rule inside an ink
 * band. The fill therefore holds and the interaction signal is the shared
 * `.btn:active` press translate, which is a movement rather than a colour.
 * On the shipped launch default all three accent controls render
 * `btn--disabled`, so this rest state is currently unreachable. */
.btn--accent:hover,
.btn--accent:active {
  background-color: var(--accent-strong);
  color: var(--text-on-accent);
}

/* `btn--ink` presses to its own hover fill rather than stepping again, so the
 * press reads as the translate rather than as a third colour. */
.btn--ink:active {
  background-color: var(--surface-ink-raised);
  color: var(--text-on-ink);
}

/* A button-shaped ANCHOR still navigates, so the universal state contract's
 * visited clause reaches it. Only `a.btn` is selected: a `button` has no
 * visited state to have, and the disabled primaries are `button`s. The two on
 * this page are the hero's secondary CTA and its scoring note, both owned
 * same-page anchors on `--surface-card`, where the role measures 7.40:1. */
a.btn:visited {
  color: var(--state-visited-link);
}

a.btn--outline:visited:hover,
a.btn--outline:visited:active {
  color: var(--text-primary);
}

/* A bordered variant presses to `--state-hover-surface`, never to
 * `--state-active-surface`: the border would fall to 2.84:1 there, below the
 * 3:1 non-text requirement, whereas the hover fill holds 3.16:1. */
.btn--outline {
  background-color: var(--surface-card);
  color: var(--text-primary);
  border: var(--border-control);
  box-shadow: var(--shadow-card);
}

.btn--outline:hover,
.btn--outline:active {
  background-color: var(--state-hover-surface);
  color: var(--text-primary);
}

.btn--ghost-ink {
  background-color: var(--state-hover-ink);
  color: var(--text-on-ink);
  border: var(--border-control);
}

.btn--ghost-ink:hover,
.btn--ghost-ink:active {
  background-color: var(--state-active-ink);
  color: var(--text-on-ink);
}

.btn--ghost-ink:focus-visible {
  outline-color: var(--focus-ring-on-ink);
}

/* An unavailable action. Status is carried on five channels, only one of them
 * chromatic, so removing colour never removes the state (Task 06 acceptance
 * criterion 8):
 *
 *   1. the `disabled` attribute and `aria-disabled="true"` in the markup —
 *      programmatic, and what assistive technology actually reports;
 *   2. `cursor: not-allowed` — the pointer answer;
 *   3. a border where the enabled primaries (`btn--ink`, `btn--accent`) have
 *      `border: 0` — a shape difference, not a hue difference;
 *   4. `--shadow-none` where `btn--outline` carries `--shadow-card`;
 *   5. the muted fill and label colour, the chromatic channel.
 *
 * The label takes `--state-disabled-label` (7.64:1 on this fill) rather than
 * `--state-disabled-text` (2.84:1). WCAG 2.2 1.4.3 exempts text in an inactive
 * component, so 2.84:1 was defensible, but this control is the page's only
 * primary conversion action and its label is the only statement of what the
 * page asks for; `tokens.css` records the full reasoning beside the alias.
 *
 * `--state-disabled-border` measures 1.27:1 against this fill and 1.42:1
 * against `--surface-bone`, below the 3:1 of WCAG 2.2 1.4.11. That is taken
 * under 1.4.11's own "except for inactive components" exemption and is left at
 * the value `COMPONENTS.md` §Button specifies, because the boundary of an
 * inactive control is decoration: the four non-chromatic channels above
 * already identify the state, and nothing here has to be operated. The same
 * exemption is NOT taken for the label, which has to be read. */
.btn--disabled {
  background-color: var(--state-disabled-surface);
  color: var(--state-disabled-label);
  border: var(--focus-width) var(--focus-style) var(--state-disabled-border);
  box-shadow: var(--shadow-none);
  cursor: not-allowed;
}

.btn--disabled:hover,
.btn--disabled:active {
  background-color: var(--state-disabled-surface);
  color: var(--state-disabled-label);
  transform: none;
}

/* Any element the fail-closed bootstrap strips, and any control the markup
 * ships unavailable, answers the pointer the same way. `.btn--disabled`
 * carries the visual treatment for controls; this rule is what makes the
 * pointer answer correct on a non-button element too, so a stripped anchor
 * cannot read as a live destination. */
[aria-disabled="true"] {
  cursor: not-allowed;
}

/* A stripped anchor keeps its label — an unavailable action must still say
 * accurately what it would do — but must not keep a link's affordances. The
 * removed `href` already takes the action away and the element out of the tab
 * order; what survives it is the pointer response, because `base.css` gives
 * every `a` an `--accent-strong` hover and press. Left alone, an anchor the
 * guard has just declared unavailable would still light up under the pointer
 * exactly like a live one, which advertises a destination that does not exist.
 *
 * `pointer-events: none` is the only mechanism that suppresses that without
 * naming a replacement colour, and a colour cannot be named here: a stripped
 * anchor may sit on bone, on white or on ink, and one value cannot be legible
 * on all three while an unavailable action still has to be readable. The cost
 * is that `cursor: not-allowed` above no longer reaches an anchor. That is the
 * right side of the trade — a hover response promises a destination, a cursor
 * shape promises nothing — and it costs the shipped page nothing, because
 * every unavailable action on it is a `button`, where the cursor applies and
 * pointer events are untouched. */
a[aria-disabled="true"] {
  text-decoration: none;
  pointer-events: none;
}

/* --- SectionBadge ---------------------------------------------------------
 * One per section. Non-interactive, so it has no states. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-4);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-pill);
  color: var(--text-secondary);
  font-size: var(--text-caption-size);
}

.badge > b {
  color: var(--accent-strong);
  font-weight: var(--weight-regular);
}

.badge--onink {
  background-color: var(--state-hover-ink);
  border: var(--border-on-ink);
  color: var(--text-on-ink-secondary);
}

.badge--onink > b {
  color: var(--accent-on-ink);
}

/* --- HonestyTag -----------------------------------------------------------
 * The `SYNTHETIC` annotation. Always placed before its fixture
 * data in the DOM, so the data is announced as invented before it is read. It
 * never carries content-critical copy. */
.tag {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  background-color: var(--signal-tint);
  border-radius: var(--radius-pill);
  color: var(--signal-text);
  font-family: var(--font-mono-ui);
  font-size: var(--text-tag-size);
  letter-spacing: var(--tracking-label);
  white-space: nowrap;
}

.tag--onink {
  background-color: var(--state-hover-ink);
  color: var(--accent-on-ink);
}

/* --- GlyphChip ------------------------------------------------------------
 * The owned icon primitive: a single mono character on a rounded square.
 * Always decorative — the adjacent text carries the meaning. */
.glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--glyph-md);
  block-size: var(--glyph-md);
  border-radius: var(--radius-control);
  font-family: var(--font-mono-ui);
  font-size: var(--text-body-size);
  line-height: var(--text-tight-lh);
}

.glyph--onink {
  background-color: var(--surface-ink-raised);
  border: var(--border-on-ink);
  color: var(--text-on-ink);
}

.glyph--accent {
  background-color: var(--accent-tint);
  color: var(--accent-strong);
}

.glyph--lg {
  inline-size: var(--glyph-lg);
  block-size: var(--glyph-lg);
  font-size: var(--text-sub-size);
}

/* --- Card -----------------------------------------------------------------
 * Inside an ink band a card uses the raised ink surface and no shadow:
 * elevation on dark is expressed with surface and hairline, never shadow. */
.card {
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-card);
  padding: var(--page-card-pad);
  box-shadow: var(--shadow-card);
  transition: box-shadow var(--duration-base) var(--ease-standard);
}

.card--soft {
  box-shadow: var(--shadow-none);
}

.card--onink {
  background-color: var(--surface-ink-raised);
  border: var(--border-on-ink);
  box-shadow: var(--shadow-none);
  color: var(--text-on-ink);
}

/* `base.css` gives every heading the light-surface text role, so a heading
 * inside an ink card has to take the on-ink role explicitly. Without this the
 * card title falls to roughly 1.3:1 against the raised ink surface. */
.card--onink h3,
.card--onink h4 {
  color: var(--text-on-ink);
}

.card--onink:hover {
  background-color: var(--state-hover-ink);
  box-shadow: var(--shadow-none);
}

/* --- Skeleton -------------------------------------------------------------
 * A non-copy placeholder. Skeletons are the honest alternative to inventing
 * text: they say content lives here without asserting content. */
.skel {
  display: block;
  block-size: var(--skel-h);
  border-radius: var(--radius-pill);
  background-color: var(--line-default);
}

.skel--wide { inline-size: 68%; }
.skel--mid  { inline-size: 46%; }

/* On dark, a skeleton sits on `--surface-ink-raised` rows, so it takes the
 * lighter on-ink step rather than the raised surface itself — otherwise the
 * placeholder is invisible against the row it is standing in for. */
.fixture--onink .skel,
.card--onink .skel {
  background-color: var(--line-on-ink-strong);
}

/* ==========================================================================
 * 1. AnnouncementBar — `site-header`
 * ======================================================================== */

.announce {
  background-color: var(--surface-ink);
  color: var(--text-on-ink-secondary);
}

.announce__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  max-inline-size: calc(var(--container-content) + (var(--page-gutter) * 2));
  margin-inline: auto;
  padding: var(--space-3) var(--page-gutter);
  font-size: var(--text-caption-size);
}

.announce__lead {
  color: var(--text-on-ink);
  font-weight: var(--weight-semibold);
}

.announce__link {
  color: var(--accent-on-ink);
  text-decoration: underline;
}

/* The one link on the page that is underlined at rest, so its hover and press
 * cannot add an underline the way every other text link does. The underline
 * steps AWAY from the text instead — a geometric change, not a hue change —
 * so this link keeps the same guarantee as the rest: neither state is carried
 * by colour alone. */
.announce__link:hover,
.announce__link:active {
  color: var(--text-on-ink);
  text-underline-offset: var(--space-1);
}

.announce__link:focus-visible {
  outline-color: var(--focus-ring-on-ink);
}

/* Visited. `--state-visited-link` is a light-surface role and measures 2.40:1
 * on `--surface-ink`, so this link takes `--state-visited-on-ink` instead —
 * the alias `tokens.css` adds for exactly this placement, 9.39:1 here. The
 * permanent underline means the element is still unmistakably a link in the
 * visited state, so nothing depends on separating the two colours. */
.announce__link:visited {
  color: var(--state-visited-on-ink);
}

.announce__link:visited:hover,
.announce__link:visited:active {
  color: var(--text-on-ink);
}

/* ==========================================================================
 * 2. GlobalNav — `site-header`
 * ======================================================================== */

/* The nav pill itself is not the sticky element — `sections.css` makes the
 * whole `site-header` marker sticky, because a sticky child only sticks while
 * its own parent is still in view. The pill keeps its resting shadow, which is
 * also the correct no-JavaScript outcome for the scroll-shadow behavior.
 *
 * TASK 06 — the sticky-shadow reconciliation, recorded rather than changed.
 * `MOTION.md` §2 describes the pill *gaining* `--shadow-nav` past 8px of
 * scroll; `COMPONENTS.md` §2 lists `--shadow-nav` in the component's resting
 * metrics, all four compositions render it at scroll position 0, and
 * `MOTION.md` §2's own no-JavaScript clause says the nav "simply keeps its
 * resting shadow. Nothing breaks." Shipping the resting shadow satisfies the
 * metrics line, the compositions and the no-JavaScript clause at once, and
 * leaves nothing for the scroll state to add.
 *
 * The alternative — resting at `--shadow-none` and adding the shadow on
 * scroll — would contradict `COMPONENTS.md` §2's metrics and change how the
 * page looks at first paint, which Task 06 is not permitted to do: it corrects
 * behavior, states and semantics, never visual direction. §2 is also outside
 * this task's motion scope item, which enumerates reveal, ticker and media.
 * Nothing moves, resizes or changes height in either reading, so no visitor
 * loses information and no reduced-motion outcome differs. */
.nav {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-6);
  inline-size: 100%;
  max-inline-size: var(--container-content);
  margin-inline: auto;
  margin-block: var(--space-4);
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-nav);
}

.nav__brand {
  margin-inline-end: auto;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
}

.brand__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--glyph-sm);
  block-size: var(--glyph-sm);
  background-color: var(--surface-ink);
  border: var(--border-accent);
  border-radius: var(--radius-control);
  color: var(--accent-on-ink);
  font-family: var(--font-mono-ui);
  font-size: var(--text-caption-size);
}

.brand__word {
  font-family: var(--font-display);
  font-size: var(--text-h4-size);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-heading);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-6);
}

.nav__links a {
  font-size: var(--text-body-size);
  text-decoration: none;
  white-space: nowrap;
}

.nav__links .nav__disabled,
.nav__links .nav__status { white-space: nowrap; }

/* Hover and press both add the underline, so the state is a shape change as
 * well as a colour change. Visited follows the universal state contract's
 * "where it navigates in-page or in-content" clause — these four anchors do —
 * rather than §2's per-component list, which enumerates hover and focus and
 * is not written as an exclusion. 7.40:1 on the white pill. */
.nav__links a:hover,
.nav__links a:active {
  color: var(--accent-strong);
  text-decoration: underline;
}

.nav__links a:visited {
  color: var(--state-visited-link);
}

.nav__links a:visited:hover,
.nav__links a:visited:active {
  color: var(--accent-strong);
}

/* ==========================================================================
 * 3. MobileNav — `site-header`
 *
 * A native `details` disclosure, not an overlay dialog, so it works with
 * JavaScript disabled and `aria-expanded` is supplied by the platform. It is
 * hidden at the desktop composition and revealed by `responsive.css`.
 * ======================================================================== */

.menu {
  display: none;
  position: relative;
}

.menu__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--target-min);
  padding: var(--space-2) var(--space-4);
  background-color: var(--surface-card);
  border: var(--border-control);
  border-radius: var(--radius-control);
  color: var(--text-primary);
  font-size: var(--text-body-size);
  font-weight: var(--weight-medium);
  list-style: none;
  cursor: pointer;
}

/* Suppress the platform disclosure triangle without removing the semantics. */
.menu__toggle::-webkit-details-marker {
  display: none;
}

/* A bordered control, so it presses to `--state-hover-surface` and never to
 * `--state-active-surface`, where `--border-control` would fall to 2.84:1 and
 * the control would lose its 3:1 boundary exactly while being operated. The
 * press translate is what distinguishes active from hover, so the difference
 * is a movement rather than a second colour. */
.menu__toggle:hover,
.menu__toggle:active {
  background-color: var(--state-hover-surface);
}

.menu__toggle:active {
  transform: translateY(var(--press-distance));
}

.menu__glyph {
  font-family: var(--font-mono-ui);
  transition: transform var(--duration-gentle) var(--ease-enter);
}

.menu[open] .menu__glyph {
  transform: rotate(90deg);
}

/* When the disclosure is closed the sheet is removed from layout entirely,
 * not merely hidden: an absolutely-positioned box that still participates can
 * push the page box wider than the viewport. */
.menu:not([open]) .menu__sheet {
  display: none;
}

.menu__sheet {
  position: absolute;
  inset-block-start: calc(100% + var(--space-3));
  inset-inline-end: 0;
  z-index: var(--z-overlay);
  display: grid;
  gap: var(--space-2);
  min-inline-size: var(--container-text);
  max-inline-size: calc(100vw - (var(--page-gutter) * 2));
  padding: var(--space-4);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-panel);
}

.menu__links {
  display: grid;
}

.menu__links a {
  display: flex;
  align-items: center;
  min-block-size: var(--target-min);
  padding-inline: var(--space-3);
  border-radius: var(--radius-control);
  text-decoration: none;
}

/* A borderless list row, so it may take `--state-active-surface` as its press
 * fill; the underline is the non-chromatic half of both states. */
.menu__links a:hover,
.menu__links a:active {
  background-color: var(--state-hover-surface);
  color: var(--accent-strong);
  text-decoration: underline;
}

.menu__links a:active {
  background-color: var(--state-active-surface);
}

/* The sheet carries the same four anchors as the pill, so it carries the same
 * visited treatment. 7.40:1 on `--surface-card`. */
.menu__links a:visited {
  color: var(--state-visited-link);
}

.menu__links a:visited:hover,
.menu__links a:visited:active {
  color: var(--accent-strong);
}

/* Task 04 v2 top fold ---------------------------------------------------- */
.nav__disabled {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-block-size: var(--target-min);
  color: var(--text-muted);
  cursor: default;
}

.nav__status {
  padding: 2px var(--space-1);
  background-color: var(--state-warning-tint);
  border-radius: var(--radius-pill);
  color: var(--state-warning);
  font-family: var(--font-mono-ui);
  font-size: 9px;
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  line-height: 1.4;
  text-transform: uppercase;
}

.menu__links .nav__disabled {
  justify-content: space-between;
  min-block-size: var(--target-min);
  padding-inline: var(--space-3);
}

.hero-orbit {
  position: absolute;
  inset-block: var(--space-5);
  inset-inline: max(var(--page-gutter), calc((100% - var(--container-wide)) / 2));
  z-index: 1;
  inline-size: auto;
  block-size: auto;
  margin: 0;
  pointer-events: none;
}

.hero-orbit::before,
.hero-orbit::after {
  position: absolute;
  border: var(--border-hairline);
  border-radius: 50%;
  content: '';
  opacity: .55;
}

.hero-orbit::before { inset: 17% 6%; transform: rotate(-4deg); }
.hero-orbit::after { inset: 24% 12%; transform: rotate(7deg); opacity: .34; }

.orbit-mark {
  position: absolute;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--space-9);
  height: var(--space-9);
  justify-self: center;
  padding: var(--space-3);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-float);
}

/* Fixed-order CSS fallback. The first 8/6/5 marks form nested, category-mixed
 * desktop/tablet/phone sets; Task 04 may reorder this pool once per page view. */
.orbit-mark:nth-child(n + 9) { display: none; }
.orbit-mark:nth-child(1) { inset-block-start: 8%; inset-inline-start: 50%; transform: translate(-50%, -50%); }
.orbit-mark:nth-child(2) { inset-block-start: 20%; inset-inline-start: 82%; transform: translate(-50%, -50%); }
.orbit-mark:nth-child(3) { inset-block-start: 50%; inset-inline-start: 94%; transform: translate(-50%, -50%); }
.orbit-mark:nth-child(4) { inset-block-start: 80%; inset-inline-start: 82%; transform: translate(-50%, -50%); }
.orbit-mark:nth-child(5) { inset-block-start: 92%; inset-inline-start: 50%; transform: translate(-50%, -50%); }
.orbit-mark:nth-child(6) { inset-block-start: 80%; inset-inline-start: 18%; transform: translate(-50%, -50%); }
.orbit-mark:nth-child(7) { inset-block-start: 50%; inset-inline-start: 6%; transform: translate(-50%, -50%); }
.orbit-mark:nth-child(8) { inset-block-start: 20%; inset-inline-start: 18%; transform: translate(-50%, -50%); }

.platform-mark img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  filter: brightness(0) invert(1);
}
.platform-mark--openai { background-color: var(--platform-openai); }
.platform-mark--gemini { background: linear-gradient(135deg, var(--platform-gemini-blue), var(--platform-gemini-purple), var(--platform-gemini-pink)); }
.platform-mark--perplexity { background-color: var(--platform-perplexity); }
.platform-mark--anthropic { background-color: var(--platform-anthropic); }
.platform-mark--deepseek { background-color: var(--platform-deepseek); }
.platform-mark--qwen { background-color: var(--platform-qwen); }
.platform-mark--reddit { background-color: var(--platform-reddit); }
.platform-mark--tiktok { background-color: var(--platform-tiktok); }
.platform-mark--threads { background-color: var(--platform-threads); }
.platform-mark--snapchat { background-color: var(--platform-snapchat); }
.platform-mark--instagram { background: linear-gradient(135deg, var(--platform-instagram-purple), var(--platform-instagram-pink), var(--platform-instagram-orange)); }
.platform-mark--youtube { background-color: var(--platform-youtube); }
.platform-mark--facebook { background-color: var(--platform-facebook); }
.platform-mark--quora { background-color: var(--platform-quora); }
.platform-mark--linkedin { background-color: var(--platform-linkedin); }
.platform-mark--wikipedia { background-color: var(--platform-wikipedia); }
.platform-mark--snapchat img,
.platform-mark--wikipedia img { filter: none; }

:root.orbit-coordinated .orbit-mark {
  inset: 0 auto auto 0;
  offset-path: none;
  transform: translate3d(var(--orbit-x), var(--orbit-y), 0);
  will-change: transform;
}

.product-stage { position: relative; }
.product-stage__layers { position: absolute; inset: calc(var(--space-5) * -1) var(--space-7) auto; display: grid; gap: calc(var(--space-3) * -1); }
.product-stage__layers span { display: block; height: var(--space-10); background-color: var(--surface-cream-strong); border-radius: var(--radius-panel) var(--radius-panel) 0 0; }
.product-stage__layers span:last-child { margin-inline: var(--space-5); background-color: var(--surface-cream); }
.product-stage__surface { position: relative; display: grid; gap: var(--space-5); padding: var(--space-7); background: var(--surface-card); border: var(--border-hairline); border-radius: var(--radius-panel); box-shadow: var(--shadow-panel); }
.product-stage__heading, .product-tabs { min-inline-size: 0; }
.product-stage__heading { display: flex; justify-content: space-between; gap: var(--space-6); align-items: end; }
.product-stage__heading h2 { font-size: var(--text-h3-size); margin-block: var(--space-2); }
.product-stage__heading p:not(.tag) { color: var(--text-secondary); max-inline-size: var(--container-text); }
.surface-source { color: var(--text-muted); text-align: end; }
.surface-source__label { font-family: var(--font-sans); }
.surface-list { font-family: var(--font-mono-data); font-size: var(--text-mono-label-size); }
.product-tabs__list { display: flex; gap: var(--space-2); border-block-end: var(--border-hairline); }
.product-tabs__list button { appearance: none; border: 0; border-radius: var(--radius-control) var(--radius-control) 0 0; background: var(--surface-cream); color: var(--text-secondary); padding: var(--space-3) var(--space-5); font-weight: var(--weight-semibold); cursor: pointer; }
.product-tabs__list button[aria-selected="true"] { background: var(--surface-ink); color: var(--text-on-ink); }
.product-tabs__panel { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 260px); gap: var(--space-5); padding-block-start: var(--space-3); }
.product-tabs__summary { display: grid; align-content: center; margin: 0; padding: var(--space-5); background: var(--surface-cream); border: var(--border-hairline); border-radius: var(--radius-fixture); color: var(--text-secondary); font-size: var(--text-body-lg-size); line-height: var(--text-prose-lh); }
.marketplace { position: relative; min-inline-size: 0; overflow: hidden; background: var(--surface-ink-panel); color: var(--text-on-ink); border-radius: var(--radius-fixture); }
.marketplace::before { position: absolute; inset: 0; background: url('../assets/interface/hero-marketplace-v2.svg') center / cover no-repeat; content: ''; opacity: .12; pointer-events: none; }
.marketplace > * { position: relative; }
.marketplace__bar, .marketplace__rows > div { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 112px); gap: var(--space-3); align-items: center; }
.marketplace__bar { padding: var(--space-3) var(--space-4); color: var(--text-on-ink-secondary); font-family: var(--font-mono-ui); font-size: var(--text-mono-label-size); border-block-end: var(--border-on-ink); }
.marketplace__rows > div { padding: calc(var(--space-2) / 2) var(--space-4); font-size: var(--text-caption-size); border-block-end: var(--border-on-ink); }
.marketplace__rows b { font-weight: var(--weight-medium); }
.product-tour-poster strong { font-weight: var(--weight-medium); }
.status { padding: calc(var(--space-1) / 2) var(--space-2); border-radius: var(--radius-pill); font-family: var(--font-mono-ui); font-size: var(--text-mono-label-size); white-space: nowrap; }
.product-tour-poster { display: grid; gap: var(--space-3); align-content: center; padding: var(--space-4); background: var(--accent-tint); border-radius: var(--radius-fixture); color: var(--text-primary); font-family: var(--font-mono-ui); font-size: var(--text-mono-label-size); line-height: var(--text-tight-lh); }
.product-tour-poster__score { display: grid; grid-template-columns: auto auto 1fr; gap: var(--space-1); align-items: end; padding: var(--space-3); background: var(--surface-card); border: var(--border-hairline); border-radius: var(--radius-control); }
.product-tour-poster__score span { grid-column: 1 / -1; color: var(--text-secondary); }
.product-tour-poster__score strong { font-family: var(--font-display); font-size: var(--text-h2-size); line-height: 1; }
.product-tour-poster__score small { align-self: end; padding-block-end: var(--space-1); color: var(--text-secondary); }
.product-tour-poster__trend { display: flex; align-items: end; gap: var(--space-2); block-size: var(--space-10); padding: var(--space-2) var(--space-3); background: var(--surface-ink); border-radius: var(--radius-control); }
.product-tour-poster__trend span { flex: 1; min-block-size: var(--space-2); block-size: var(--point); border-radius: var(--radius-pill) var(--radius-pill) var(--radius-chip) var(--radius-chip); background: linear-gradient(180deg, var(--accent-on-ink), var(--accent-strong)); }
.status--blue { color: var(--text-on-ink); background: var(--data-primary); }.status--green { color: var(--state-success); background: var(--state-success-tint); }.status--yellow { color: var(--state-warning); background: var(--state-warning-tint); }.status--purple { color: var(--text-primary); background: var(--accent-tint); }
.platform-rail {
  max-inline-size: 560px;
  margin: var(--space-5) auto 0;
  padding: var(--space-3) 0;
  overflow: hidden;
  background: radial-gradient(circle at center, var(--surface-cream) 0%, transparent 72%);
  border-radius: var(--radius-pill);
  container-type: inline-size;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 20%, #000 80%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 20%, #000 80%, transparent 100%);
}

.platform-rail__track {
  display: flex;
  gap: var(--space-7);
  align-items: center;
  inline-size: max-content;
}

:root.motion-ready .platform-rail__track {
  position: relative;
  display: block;
  inline-size: 100%;
  block-size: var(--space-9);
}

:root.motion-ready .platform-rail__mark {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 100%;
  display: grid;
  opacity: 0;
  animation: platform-rail-drift var(--duration-loop-slow) var(--ease-linear) infinite;
  animation-delay: calc(var(--rail-index, 0) * -3s);
  will-change: transform;
}

@keyframes platform-rail-drift {
  0% { opacity: 0; transform: translate3d(0, -50%, 0) scale(.9); }
  34% { opacity: 0; }
  43% { opacity: .28; }
  48%, 52% { opacity: 1; transform: translate3d(calc(-50cqi - var(--space-6)), -50%, 0) scale(1); }
  57% { opacity: .28; }
  66% { opacity: 0; }
  100% { opacity: 0; transform: translate3d(calc(-100cqi - var(--target-min)), -50%, 0) scale(.9); }
}

.platform-rail__mark {
  flex: 0 0 var(--target-min);
  display: grid;
  place-items: center;
  inline-size: var(--target-min);
  block-size: var(--target-min);
  justify-self: center;
  padding: var(--space-3);
  border: var(--border-hairline);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-card);
}

.platform-rail__mark:nth-child(n + 6) { display: none; }

:root.motion-ready .platform-rail__mark:nth-child(n) { display: grid; }

@media (min-width: 1024px) {
  .marketplace__rows { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .marketplace__rows > div { padding-block: calc(var(--space-1) / 2); font-size: var(--text-mono-label-size); line-height: var(--text-tight-lh); }
}

/* ==========================================================================
 * 4–5. Hero and ProductInterfaceComposition — `hero`
 * ======================================================================== */

.hero__cluster {
  display: inline-flex;
  vertical-align: middle;
  margin-inline-start: var(--space-3);
}

.hero__cluster .glyph {
  margin-inline-start: calc(var(--space-3) * -1);
  border: var(--focus-width) var(--focus-style) var(--surface-bone);
}

.hero__cluster .glyph:first-child {
  margin-inline-start: 0;
}

/* --- the stacked product panel ------------------------------------------- */

/* The stacked composition: two cream surfaces peek above a white panel, each
 * inset horizontally and pulled up under the next, so the stack reads as depth
 * rather than as three separate bands. The white panel carries the surface,
 * radius and shadow; `.panel` itself is only the stacking context. */
.panel {
  position: relative;
}

/* Two cream surface tabs peeking above the white panel, inset horizontally so
 * the stack reads as depth. They are presentational at v1: there is no tab
 * interaction, so they are labels rather than a `tablist`. */
.panel__tabs {
  display: grid;
}

.panel__tab {
  padding: var(--space-3) var(--space-6) var(--space-8);
  margin-block-end: calc(var(--space-8) * -1);
  background-color: var(--surface-cream-strong);
  border-start-start-radius: var(--radius-panel);
  border-start-end-radius: var(--radius-panel);
  color: var(--text-secondary);
  font-size: var(--text-caption-size);
}

.panel__tab:first-child {
  margin-inline: var(--space-10);
}

.panel__tab:last-child {
  margin-inline: var(--space-9);
  background-color: var(--surface-cream);
}

.panel__body {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
  gap: var(--space-7);
  padding: var(--space-8) var(--space-7);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-panel);
}

.panel__heading {
  margin-block-end: var(--space-4);
}

.panel__text {
  color: var(--text-secondary);
  font-size: var(--text-body-lg-size);
  line-height: var(--text-prose-lh);
}

/* ==========================================================================
 * Fixture surfaces — console, cream inset, chart
 *
 * Rule 4 of the fixture language: a fixture may crop or scroll INSIDE its own
 * panel and may never create page-level horizontal overflow.
 * ======================================================================== */

/* `minmax(0, 1fr)` rather than the implicit `auto` track: an `auto` track
 * refuses to shrink below its content's min-content width, which is exactly
 * how a fixture that scrolls inside its own panel would instead widen the
 * page. Every ancestor of a scrolling fixture repeats this. */
.fixture {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3);
  min-inline-size: 0;
}

.fixture__cap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
}

.fixture__eq {
  color: var(--text-muted);
  font-size: var(--text-caption-size);
}

.fixture--onink .fixture__eq {
  color: var(--text-on-ink-muted);
}

.console {
  background-color: var(--surface-ink-panel);
  border-radius: var(--radius-fixture);
  color: var(--text-on-ink);
}

.console__scroll {
  min-inline-size: 0;
  overflow-x: auto;
  border-radius: var(--radius-fixture);
}

/* TASK 06 — a scroll container is a tab stop.
 *
 * An element with `overflow-x: auto` that actually overflows is focusable in
 * every engine that gives keyboard access to a scrolled region, so it takes a
 * ring like any other tab stop. Two corrections are needed and neither is
 * cosmetic:
 *
 *   · the colour. Inheriting `--focus-ring` here measured 1.03:1 against
 *     `--surface-ink-panel` — a focus indicator that is present, correct and
 *     completely invisible, which is the worst of the three. `MOTION.md`'s
 *     focus rule and `DESIGN.md` §7 both put `--focus-ring-on-ink` on ink;
 *     it measures 17.40:1 here.
 *   · the offset. The scroller fills its panel edge to edge, so a ring drawn
 *     at a positive offset lands on whatever surface the panel sits on — a
 *     white card in `hero`, an ink stage in `backlinks` — and stops being
 *     measurable against one known surface. Insetting it keeps the ring on
 *     the panel it belongs to at both placements.
 *
 * The scrolled content is synthetic fixture data in both cases, so
 * `RESPONSIVE.md` guardrail 11 holds: nothing a visitor must read to
 * understand the page lives only behind a horizontal scroll. */
.console__scroll:focus-visible {
  outline-color: var(--focus-ring-on-ink);
  outline-offset: calc(var(--focus-offset) * -1);
}

.console__scroll .console__inner {
  min-inline-size: var(--container-text);
}

.console__inner {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-6);
}

.console__label {
  color: var(--text-on-ink-muted);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-label-size);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

.console__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block-start: var(--space-3);
  border-block-start: var(--border-on-ink);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
}

.console__num {
  color: var(--data-on-ink);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

.score {
  display: grid;
  gap: var(--space-1);
}

.score__label {
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
}

.score__value {
  font-family: var(--font-display);
  font-size: var(--text-h2-size-tablet);
  font-weight: var(--weight-bold);
  line-height: var(--text-tight-lh);
  letter-spacing: var(--tracking-display);
}

.score__scale {
  color: var(--text-on-ink-muted);
  font-size: var(--text-sub-size);
}

.score__meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.score__window,
.score__pos {
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
}

/* A delta always carries an explicit sign, so no information is encoded by
 * colour alone. */
.delta {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  background-color: var(--state-hover-ink);
  border-radius: var(--radius-pill);
  color: var(--state-success-on-ink);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

.spark {
  inline-size: 100%;
  block-size: auto;
  overflow: visible;
}

.spark__line {
  fill: none;
  stroke: var(--accent);
  stroke-width: var(--focus-width);
  stroke-linecap: round;
  stroke-linejoin: round;
}

.spark__dot {
  fill: var(--data-on-ink);
}

.chart {
  inline-size: 100%;
  block-size: auto;
}

/* The tracked-prompt rows are a real table: they are tabular data, and a
 * header row is what makes each figure readable in isolation. */
.rows {
  inline-size: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
  text-align: start;
}

.rows th,
.rows td {
  padding: var(--space-3);
  border-block-start: var(--border-on-ink);
  font-weight: var(--weight-regular);
  text-align: start;
}

.rows thead th {
  border-block-start: 0;
  color: var(--text-on-ink-muted);
  font-size: var(--text-mono-label-size);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

.rows tbody th {
  color: var(--text-on-ink);
}

.rows td {
  color: var(--data-on-ink);
  text-align: end;
}

/* Cream inset fixture on a white card. */
.inset {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5);
  background-color: var(--surface-cream);
  border-radius: var(--radius-fixture);
}

.bubble-ink {
  padding: var(--space-3) var(--space-4);
  background-color: var(--surface-ink-panel);
  border-radius: var(--radius-chip);
  color: var(--text-on-ink-secondary);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

.tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-2);
}

.tile {
  display: grid;
  gap: var(--space-1);
  padding: var(--space-3);
  background-color: var(--surface-ink-panel);
  border-radius: var(--radius-chip);
  text-align: center;
}

.tile__value {
  color: var(--data-on-ink);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

/* Guardrail 8: `--text-tag-size` is reserved for the SYNTHETIC
 * tag and nothing else drops below `--text-caption-size`. This label is what
 * makes its tile's value readable, so it sits at the caption floor. */
.tile__label {
  color: var(--text-on-ink-muted);
  font-size: var(--text-caption-size);
}

.collage {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  justify-content: center;
}

.collage__card {
  display: grid;
  align-content: center;
  gap: var(--space-1);
  inline-size: 30%;
  min-block-size: var(--space-10);
  padding: var(--space-2);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-chip);
  box-shadow: var(--shadow-card);
  text-align: center;
}

.collage__card strong { color: var(--text-primary); font-family: var(--font-display); font-size: var(--text-h3-size); line-height: 1; }
.collage__card small { color: var(--text-secondary); font-size: var(--text-mono-label-size); line-height: var(--text-tight-lh); }

/* Bar cluster. CSS, never a bitmap; every series carries its label AND its
 * value as text, so the chart is fully readable without being seen. */
.bars {
  display: grid;
  gap: var(--space-2);
}

.bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-1) var(--space-3);
}

.bar__fill {
  grid-column: 1 / -1;
  display: block;
  inline-size: var(--bar);
  block-size: var(--skel-h);
  border-radius: var(--radius-pill);
}

.bar__fill--a { background-color: var(--data-series-a); }
.bar__fill--b { background-color: var(--data-series-b); }
.bar__fill--c { background-color: var(--data-series-c); }
.bar__fill--d { background-color: var(--data-series-d); }

.bar__label {
  color: var(--text-secondary);
  font-size: var(--text-caption-size);
}

.bar__value {
  color: var(--text-primary);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

/* Citation ledger. Generic source descriptors only — a real publisher or
 * domain name is prohibited here. The cited row is marked by an accent border
 * AND by its own "Cited" text, never by colour alone. */
.ledger {
  display: grid;
  gap: var(--space-2);
}

.ledger__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-1) var(--space-3);
  padding: var(--space-3);
  background-color: var(--surface-ink-raised);
  border: var(--border-on-ink);
  border-radius: var(--radius-chip);
}

.ledger__row--cited {
  border: var(--border-accent);
}

.ledger__name {
  color: var(--text-on-ink);
  font-size: var(--text-caption-size);
}

/* The source category and the cited / not-cited state are the whole point of
 * this fixture, so neither may sit below the caption floor (guardrail 8). */
.ledger__kind {
  grid-column: 1;
  color: var(--text-on-ink-muted);
  font-size: var(--text-caption-size);
}

.ledger__state {
  grid-row: 1 / span 2;
  grid-column: 2;
  align-self: center;
  color: var(--text-on-ink-secondary);
  font-family: var(--font-mono-ui);
  font-size: var(--text-caption-size);
}

.ledger__row--cited .ledger__state {
  color: var(--accent-on-ink);
}

/* ==========================================================================
 * 6. ProductPillarRail — `pillars`
 * ======================================================================== */

.pillar {
  display: grid;
  align-content: start;
  gap: var(--space-3);
}

.pillar:hover {
  box-shadow: var(--shadow-panel);
}

.pillar__body {
  color: var(--text-secondary);
}

/* The link is the only focusable element in the card — no nested interactive
 * targets. */
.pillar__link {
  margin-block-start: var(--space-3);
  color: var(--text-primary);
  font-weight: var(--weight-medium);
  text-decoration: none;
}

.pillar__link:hover,
.pillar__link:active {
  color: var(--accent-strong);
  text-decoration: underline;
}

/* Visited is the one state that cannot take a non-chromatic companion: every
 * engine restricts `:visited` to colour, background-colour, border-colour and
 * outline-colour for history-leak reasons, and silently drops anything else.
 * That is a user-agent constraint rather than a design choice, and it costs no
 * information here — visited is a convenience, never a status. What the link
 * is and where it goes is carried by its permanent label and `→` in every
 * state, so nothing is lost by a visitor who cannot separate the two colours.
 * Both clear AA as text: 6.98:1 on `--surface-bone`, 7.40:1 on
 * `--surface-card`. */
.pillar__link:visited {
  color: var(--state-visited-link);
}

.pillar__link:visited:hover,
.pillar__link:visited:active {
  color: var(--accent-strong);
}

/* ==========================================================================
 * 7–8. PlatformStrip and TrustModule — `platforms`
 * ======================================================================== */

.strip {
  display: grid;
  gap: var(--space-5);
}

.strip__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-6);
}

/* `--text-muted` on bone is the system's lowest light-surface pair (4.95:1) and
 * DESIGN.md restricts it to ≥13px labels and meta. This label is a permitted
 * 12px uppercase row label, so it takes `--text-secondary` instead. */
.strip__label {
  color: var(--text-secondary);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-label-size);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

/* Chip rows wrap freely and never become horizontal scrollers. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-pill);
  font-size: var(--text-body-size);
  white-space: nowrap;
}

.chip__glyph {
  color: var(--accent-strong);
  font-family: var(--font-mono-ui);
  font-weight: var(--weight-regular);
}

/* The caption-only launch state. Withheld is honest, not apologetic: it uses
 * no lower-contrast or de-emphasised treatment. */
.trust {
  margin-block-start: var(--space-9);
  padding-block-start: var(--space-7);
  border-block-start: var(--border-hairline);
  text-align: center;
}

.trust__caption {
  margin-inline: auto;
  max-inline-size: var(--container-text);
  color: var(--text-secondary);
  font-size: var(--text-caption-size);
}

/* ==========================================================================
 * 9. ProblemNarrative — `problem`
 * ======================================================================== */

.bubbles {
  display: grid;
  gap: var(--space-5);
  align-content: center;
}

.bubble {
  display: flex;
  min-inline-size: 0;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-6);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-card);
}

.bubble__glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  inline-size: var(--glyph-sm);
  block-size: var(--glyph-sm);
  background-color: var(--accent-tint);
  border-radius: var(--radius-pill);
  color: var(--accent-strong);
  font-family: var(--font-mono-ui);
}

/* A synthetic prompt, not document structure — so it is a `p`, never a
 * heading. */
.bubble__q {
  font-family: var(--font-display);
  font-size: var(--text-h3-size);
  font-weight: var(--weight-bold);
  line-height: var(--text-h3-lh);
  letter-spacing: var(--tracking-heading);
  overflow-wrap: anywhere;
}

html[lang="en"] .bubble__q {
  overflow-wrap: break-word;
}

@media (max-width: 340px) {
  html[lang="en"] .bubble {
    gap: var(--space-1);
    padding-inline: var(--space-2);
  }
}

/* ==========================================================================
 * 10. EngagementWorkflow — `engagement`
 * ======================================================================== */

/* The band shell: an inset ink surface with a radial glow, framed by bone
 * paper on every side. Everything inside it is `--shadow-none`. */
.band {
  margin-inline: var(--page-band-inset);
  border-radius: var(--radius-band);
  background-color: var(--surface-ink);
  background-image: radial-gradient(
    circle at 50% 0%,
    var(--surface-ink-glow-from),
    var(--surface-ink-glow-to) 70%
  );
  color: var(--text-on-ink);
}

.band__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: var(--space-7);
  max-inline-size: var(--container-wide);
  margin-inline: auto;
  padding: var(--space-11) var(--space-8) var(--space-10);
}

.band__title,
.band__stand {
  text-align: center;
}

.band__title {
  color: var(--text-on-ink);
}

.band__stand {
  max-inline-size: var(--container-text);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-sub-size);
  line-height: var(--text-sub-lh);
}

.band :focus-visible {
  outline-color: var(--focus-ring-on-ink);
}

/* --- FunnelDiagram --------------------------------------------------------
 * Node labels are real DOM text, so the relationship is readable rather than
 * locked inside a graphic; the connector artwork is decorative and the caption
 * states the same relationship in prose. The diagram is never load-bearing. */
.funnel {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: var(--space-4);
  inline-size: 100%;
}

.funnel__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
}

.node {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background-color: var(--surface-ink-raised);
  border: var(--border-on-ink);
  border-radius: var(--radius-control);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
  white-space: nowrap;
}

.node__glyph {
  color: var(--accent-on-ink);
  font-family: var(--font-mono-ui);
  font-weight: var(--weight-regular);
}

.node [data-mark-role="platform-reference"] {
  display: inline-grid;
  place-items: center;
  inline-size: var(--space-5);
  block-size: var(--space-5);
  flex: none;
}

.node [data-mark-role="platform-reference"] img {
  inline-size: 100%;
  block-size: 100%;
}

.node [data-mark-role="platform-reference"] {
  inline-size: var(--space-6);
  block-size: var(--space-6);
  padding: var(--space-1);
  border-radius: var(--radius-chip);
}
.node [data-platform]:not([data-platform="wikipedia"]) img { filter: brightness(0) invert(1); }
.node [data-platform="google-gemini"] { background: linear-gradient(135deg, var(--platform-gemini-blue), var(--platform-gemini-purple), var(--platform-gemini-pink)); }
.node [data-platform="perplexity"] { background-color: var(--platform-perplexity); }
.node [data-platform="reddit"] { background-color: var(--platform-reddit); }
.node [data-platform="quora"] { background-color: var(--platform-quora); }
.node [data-platform="facebook"] { background-color: var(--platform-facebook); }
.node [data-platform="instagram"] { background: linear-gradient(135deg, var(--platform-instagram-purple), var(--platform-instagram-pink), var(--platform-instagram-orange)); }
.node [data-platform="wikipedia"] { background-color: var(--platform-wikipedia); }
.node [data-platform="youtube"] { background-color: var(--platform-youtube); }

.funnel__paths {
  max-block-size: calc(var(--space-12) * 2);
  object-fit: contain;
  opacity: .9;
}

/* A high-density lower story uses the same semantic cards, with a visibly
 * different surface treatment for each product mode. */
.intel .quad,
.listen .quad { gap: var(--space-4); }

.intel .fcard,
.listen .fcard {
  min-block-size: 0;
  padding: var(--space-4);
  box-shadow: var(--shadow-card);
}

.intel .fcard:nth-child(2n) { background-color: var(--surface-cream); }
.listen .fcard:nth-child(2n) { background-color: var(--surface-cream); }

/* V4 authority uses the content order visibility → prompts → citations →
 * reporting and gives those four bound fixtures an intentional dark/lilac/
 * mint/white reading order.  These are exact approved-composition surfaces,
 * not locale variants: both dictionaries keep the same hierarchy. */
.intel [data-specimen-id="visibility-trend"],
.intel [data-specimen-id="visibility-trend"] .console,
.intel [data-specimen-id="visibility-trend"] .console__inner {
  background-color: var(--surface-ink);
  color: var(--text-on-ink);
}

.intel [data-specimen-id="visibility-trend"] * {
  color: var(--text-on-ink);
}

.intel [data-specimen-id="visibility-trend"] .tag { color: var(--text-primary); }

.intel [data-specimen-id="prompt-cluster"],
.intel [data-specimen-id="prompt-cluster"] .inset {
  background-color: #f0edff;
  color: var(--text-primary);
}

.intel [data-specimen-id="citation-ledger"],
.intel [data-specimen-id="citation-ledger"] .console,
.intel [data-specimen-id="citation-ledger"] .console__inner {
  background-color: #eef7f0;
  color: var(--text-primary);
}

.intel [data-specimen-id="citation-ledger"] *,
.intel [data-specimen-id="report-summary"] * {
  color: var(--text-primary);
}

.intel [data-specimen-id="citation-ledger"] .ledger__name { color: var(--text-on-ink); }
.intel [data-specimen-id="citation-ledger"] .ledger__kind { color: var(--text-on-ink-muted); }
.intel [data-specimen-id="citation-ledger"] .ledger__state { color: var(--text-on-ink-secondary); }
.intel [data-specimen-id="citation-ledger"] .ledger__row--cited .ledger__state { color: var(--accent-on-ink); }

.intel [data-specimen-id="report-summary"],
.intel [data-specimen-id="report-summary"] .inset {
  background-color: var(--surface-card);
  color: var(--text-primary);
}

/* The approved narrow composition keeps citation evidence as readable rows;
 * its decorative chart is omitted before it can create a second data surface. */
@media (max-width: 767px) {
  .intel [data-specimen-id="citation-ledger"] .chart {
    display: none;
  }
}

.intel .fixture__cap .tag,
.listen .fixture__cap .tag,
.market .fixture__cap .tag { max-inline-size: var(--space-12); }

.market__flow,
.alerts__signal { inline-size: 100%; object-fit: cover; border-radius: var(--radius-fixture); }

.market__panel {
  min-block-size: 0;
  background-color: var(--surface-cream);
  border-radius: var(--radius-band);
}

.market__stage { background-color: var(--surface-ink); border-radius: var(--radius-panel); padding: var(--space-5); }

.rails .tag { text-transform: none; }

/* Product-story density is intentional: fixtures retain their complete first
 * state while using compact, readable rows rather than predecessor whitespace. */
.band__inner { gap: var(--space-5); padding: var(--space-8) var(--space-7); }
.wf { gap: var(--space-4); }
.wf__card { gap: var(--space-2); padding: var(--space-4); }
.wf__body { font-size: var(--text-caption-size); }
.rails { gap: var(--space-2); }

.intel .fcard,
.listen .fcard { gap: var(--rhythm-card-head-to-fixture); }

.intel .fcard__head,
.listen .fcard__head { gap: var(--rhythm-card-head-to-fixture); }

.intel .fcard__head p,
.listen .fcard__head p { font-size: var(--text-caption-size); line-height: var(--text-tight-lh); }

.intel .console__inner,
.listen .console__inner { gap: var(--space-2); padding: var(--space-3); }

.intel .inset,
.listen .inset { gap: var(--space-2); padding: var(--space-3); }

.intel .ledger,
.listen .alerts { gap: var(--space-1); }

.intel .ledger__row,
.listen .thread,
.listen .alert { padding: var(--space-2); }

.market .sechead,
.intel .sechead,
.listen .sechead { margin-block-end: var(--space-5); }

/* The full sample descriptions remain available to assistive technology, while
 * the visible tag and the rendered interface carry the compact visual state. */
.intel .fixture__eq,
.market .fixture__eq,
.listen .fixture__eq,
.engagement .fixture__eq {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.funnel__paths {
  inline-size: 100%;
  max-inline-size: var(--container-content);
  block-size: var(--space-10);
  object-fit: contain;
}

.intel .chart {
  block-size: var(--space-10);
  object-fit: contain;
}

.intel .ledger__row {
  gap: 0 var(--space-2);
  padding: var(--space-1) var(--space-2);
}

.funnel__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-5);
  background-color: var(--surface-bone);
  border: var(--border-accent);
  border-radius: var(--radius-pill);
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}

.funnel__mark {
  color: var(--accent-strong);
  font-family: var(--font-mono-ui);
}

.funnel__cap {
  max-inline-size: var(--container-text);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
  text-align: center;
}

/* --- WorkflowCard ×3 ------------------------------------------------------ */

.wf {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: start;
  gap: var(--space-6);
  inline-size: 100%;
  min-inline-size: 0;
}

.wf__card {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: var(--space-3);
}

.wf__body {
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
  line-height: var(--text-tight-lh);
}

.fixture--onink .console,
.fixture--onink .inset {
  background-color: var(--surface-ink-panel);
}

.queue {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  background-color: var(--surface-ink-panel);
  border-radius: var(--radius-fixture);
}

.queue__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  background-color: var(--surface-ink-raised);
  border-radius: var(--radius-chip);
}

.queue__row .skel {
  flex: 1 1 auto;
}

.queue__row--sel {
  border: var(--border-accent);
}

.queue__rel {
  color: var(--data-on-ink);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

/* A presentational affordance inside a fixture: it is part of the picture, not
 * an input, so it is never a real control. */
.pill-chip {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  background-color: var(--state-hover-ink);
  border: var(--border-on-ink);
  border-radius: var(--radius-pill);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
  white-space: nowrap;
}

.pill-chip--accent {
  background-color: var(--accent-strong);
  border-color: var(--accent-strong);
  color: var(--text-on-accent);
}

.composer {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4);
  background-color: var(--surface-cream);
  border-radius: var(--radius-fixture);
}

.composer__body {
  padding: var(--space-3);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-chip);
  color: var(--text-secondary);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

.composer__sources {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-caption-size);
}

.composer__sources li {
  padding: var(--space-1) var(--space-3);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-pill);
}

.composer__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.composer__avatars {
  display: inline-flex;
}

.composer__avatars i {
  display: block;
  inline-size: var(--space-6);
  block-size: var(--space-6);
  margin-inline-start: calc(var(--space-2) * -1);
  border: var(--focus-width) var(--focus-style) var(--surface-cream);
  border-radius: var(--radius-pill);
  background-color: var(--line-default);
}

.composer__avatars i:first-child {
  margin-inline-start: 0;
}

.published {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4);
  background-color: var(--surface-ink-panel);
  border-radius: var(--radius-fixture);
}

.published__state {
  color: var(--state-success-on-ink);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

.published__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* --- OpportunityRail ×2 -------------------------------------------------
 * The two visual rows move continuously when motion is allowed. Hover and
 * focus pause them without adding a playback button to the section. */
.rails {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
  inline-size: 100%;
}

.rail {
  inline-size: 100%;
  min-inline-size: 0;
}

.rail__clip {
  min-inline-size: 0;
  overflow: hidden;
}

.rail__track {
  display: flex;
  inline-size: 100%;
}

:root.motion-ready .rail__track {
  inline-size: max-content;
}

.rail__set {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding-inline-end: var(--space-3);
}

:root.motion-ready .rail__set {
  flex: 0 0 auto;
  flex-wrap: nowrap;
  will-change: transform;
  animation-name: opportunity-rail-marquee;
  animation-timing-function: var(--ease-linear);
  animation-iteration-count: infinite;
}

:root.motion-ready .rail__track--fwd .rail__set {
  animation-duration: var(--duration-loop-base);
}

:root.motion-ready .rail__track--rev .rail__set {
  animation-duration: var(--duration-loop-slow);
  animation-direction: reverse;
}

:root.motion-ready .rail__clip:hover .rail__set,
:root.motion-ready .rail__clip:focus .rail__set {
  animation-play-state: paused;
}

@keyframes opportunity-rail-marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-100%); }
}

.rail__set--dup {
  display: none;
}

:root.motion-ready .rail__set--dup {
  display: flex;
}

.rail__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background-color: var(--state-hover-ink);
  border-radius: var(--radius-control);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
  white-space: nowrap;
}

.rail__chip b {
  color: var(--accent-on-ink);
  font-family: var(--font-mono-ui);
  font-weight: var(--weight-regular);
}

.badge-num {
  padding: var(--space-1) var(--space-2);
  background-color: var(--state-hover-ink);
  border-radius: var(--radius-pill);
  color: var(--state-success-on-ink);
  font-family: var(--font-mono-ui);
  font-size: var(--text-caption-size);
}

/* ==========================================================================
 * 11. IntelligenceFeatureGrid — `intelligence`
 * ======================================================================== */

.sechead {
  display: grid;
  justify-items: center;
  gap: var(--space-4);
  margin-block-end: var(--space-9);
  text-align: center;
}

.sechead__stand {
  max-inline-size: var(--container-text);
  color: var(--text-secondary);
  font-size: var(--text-sub-size);
  line-height: var(--text-sub-lh);
}

.sechead h2 {
  max-inline-size: var(--container-content);
}

.quad {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: var(--space-6);
}

/* The head always precedes the fixture in the DOM, and nothing reverses that
 * visually: the system permits exactly two visual reorders in total and both
 * are elsewhere. */
.fcard {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: var(--space-5);
}

.fcard:hover {
  box-shadow: var(--shadow-panel);
}

.fcard__head {
  display: grid;
  gap: var(--space-2);
}

.fcard__head p {
  color: var(--text-secondary);
}

/* ==========================================================================
 * Shared disclosure chevron
 *
 * Every FAQ disclosure is native `details`/`summary`. The platform
 * therefore owns `aria-expanded`, keyboard operation and the open/closed
 * state, and all three work with JavaScript disabled. The chevron is a
 * decorative text glyph: the state is already carried by the platform and by
 * the visible answer body, never by this rotation alone.
 * ======================================================================== */

.chev {
  flex: none;
  color: var(--text-muted);
  font-family: var(--font-mono-ui);
  font-size: var(--text-caption-size);
  transition: transform var(--duration-gentle) var(--ease-enter);
}

details[open] > summary .chev {
  transform: rotate(180deg);
}

/* The platform disclosure triangle is suppressed on every styled `summary`
 * without removing the semantics that supply `aria-expanded`. */
.faq__q {
  list-style: none;
}

.faq__q::-webkit-details-marker {
  display: none;
}

/* ==========================================================================
 * 12. BacklinksMarketplaceShowcase — `backlinks`
 *
 * The cream mega-panel. Both fixtures are permanently `synthetic`: every
 * host is invented under the IANA-reserved `.example` TLD, every authority,
 * traffic and price figure is invented, and prices are denominated in a
 * fictional `credits` unit so no row can read as a purchasable offer. No
 * publisher count appears anywhere.
 * ======================================================================== */

.market__panel {
  display: grid;
  grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
  gap: var(--space-6);
  padding: var(--space-6);
  background-color: var(--surface-cream);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-panel);
}

.market__copy {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: var(--space-4);
  min-inline-size: 0;
}

.market__lead {
  display: grid;
  gap: var(--space-3);
  inline-size: 100%;
}

.market__flow {
  inline-size: 100%;
  max-inline-size: var(--container-text);
  block-size: auto;
  margin-block-start: var(--space-2);
}

.market .console__inner { padding: var(--space-2); }

.market__block {
  display: grid;
  gap: var(--space-2);
}

.market__block p {
  color: var(--text-secondary);
}

/* The ink stage inside the cream panel. Radius decreases with nesting depth —
 * panel 28 → card 22 → fixture 16 → chip 8 — so a child never has a larger
 * radius than its parent. */
.market__stage {
  display: grid;
  align-content: start;
  gap: var(--space-3);
  min-inline-size: 0;
  padding: var(--space-4);
  border-radius: var(--radius-card);
  background-color: var(--surface-ink-panel);
  background-image: radial-gradient(
    circle at 50% 0%,
    var(--surface-ink-glow-from),
    var(--surface-ink-glow-to) 72%
  );
  color: var(--text-on-ink);
}

.market__stage :focus-visible {
  outline-color: var(--focus-ring-on-ink);
}

/* --- the synthetic assistant answer --------------------------------------- */

.answer {
  display: grid;
  gap: var(--space-4);
  min-inline-size: 0;
  padding: var(--space-5);
  background-color: var(--surface-ink-raised);
  border: var(--border-on-ink);
  border-radius: var(--radius-fixture);
}

.answer__stem {
  color: var(--text-on-ink);
}

/* `base.css` strips the marker from every classed list with `ol[class]`, but
 * this one is a real ordered recommendation list and the numbers are part of
 * what the fixture shows. The selector is qualified to match that specificity
 * and wins on source order, because `components.css` loads after `base.css`. */
ol.answer__rows {
  display: grid;
  gap: var(--space-3);
  padding-inline-start: var(--space-7);
  list-style: decimal;
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
}

.answer__rows li::marker {
  color: var(--text-on-ink-muted);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
}

/* The hosts are not links and are never styled as links: they are invented
 * `.example` strings inside a fixture, and an underline would suggest a
 * destination that does not and cannot exist. */
.answer__host {
  color: var(--accent-on-ink);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
  font-weight: var(--weight-regular);
}

.answer__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.answer__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.answer__chips li {
  padding: var(--space-1) var(--space-3);
  background-color: var(--state-hover-ink);
  border: var(--border-on-ink);
  border-radius: var(--radius-pill);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
  white-space: nowrap;
}

/* Presentational, `aria-hidden`, and deliberately not a control: it is part of
 * the picture. If a real input is ever added it needs a label, a name and a
 * focus ring. */
.answer__send {
  color: var(--accent-on-ink);
  font-family: var(--font-mono-ui);
}

/* --- the publisher catalog ------------------------------------------------ */

.catalog {
  inline-size: 100%;
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
  text-align: start;
}

.catalog th,
.catalog td {
  padding: var(--space-3);
  border-block-start: var(--border-on-ink);
  font-weight: var(--weight-regular);
  text-align: start;
  white-space: nowrap;
}

.catalog thead th {
  border-block-start: 0;
  color: var(--text-on-ink-muted);
  font-size: var(--text-mono-label-size);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

.catalog tbody th {
  color: var(--text-on-ink);
}

.catalog td {
  color: var(--data-on-ink);
}

/* The catalog's sixth column. Inert presentation, never a control: there is no
 * marketplace behind this page, so an activatable cell would be an action that
 * silently does nothing. It has no hover state, no pointer cursor and no
 * focus behavior, because it is not interactive at all. */
.cell-chip {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  background-color: var(--state-hover-ink);
  border: var(--border-on-ink);
  border-radius: var(--radius-chip);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
}

/* ==========================================================================
 * 13. ListeningAlertShowcase — `listening`
 *
 * The same centred head and 2×2 quad shell as `intelligence`, so the two
 * sections share one component vocabulary rather than growing a second. Every
 * thread, meta line, volume and alert body is `synthetic`; no real handle,
 * author, community, forum or platform name appears anywhere.
 * ======================================================================== */

/* Presentational tab and toggle rows. Part of the picture, not a `tablist`:
 * `aria-hidden` in the markup, and nothing here is focusable. */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.tabs__tab {
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  color: var(--text-on-ink-secondary);
  font-size: var(--text-caption-size);
  white-space: nowrap;
}

.tabs__tab--sel {
  background-color: var(--state-hover-ink);
  border: var(--border-on-ink);
  color: var(--text-on-ink);
}

/* Inside the cream inset the toggle row sits on light paper. */
.inset .tabs__tab {
  color: var(--text-secondary);
}

.inset .tabs__tab--sel {
  background-color: var(--surface-card);
  border: var(--border-hairline);
  color: var(--text-primary);
}

.threads {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}

.thread {
  display: grid;
  align-content: start;
  gap: var(--space-2);
  min-inline-size: 0;
  padding: var(--space-3);
  background-color: var(--surface-ink-raised);
  border: var(--border-on-ink);
  border-radius: var(--radius-chip);
}

/* Inside a cream inset the thread card keeps the ink surface, so the fixture
 * still reads as a console row on light paper. */
.thread--ink {
  background-color: var(--surface-ink-panel);
}

.thread__topic {
  color: var(--text-on-ink);
  font-size: var(--text-caption-size);
}

.thread__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  justify-content: space-between;
  color: var(--text-on-ink-muted);
  font-family: var(--font-mono-ui);
  font-size: var(--text-caption-size);
}

.replies {
  display: grid;
  gap: var(--space-2);
  padding-inline-start: var(--space-5);
}

/* --- single search -------------------------------------------------------- */

/* A drawn search pill, not an input: no label, no name, no focus ring, because
 * it is not a control. */
.search {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-inline-size: 0;
  padding: var(--space-3) var(--space-5);
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-pill);
}

.search__glyph {
  flex: none;
  color: var(--accent-strong);
  font-family: var(--font-mono-ui);
}

/* `min-inline-size: 0` is what lets the flex item shrink past the min-content
 * width of its own unbreakable query string. Without it the nowrap text sets a
 * floor that the pill inherits, and a 320px viewport gets a page-wide
 * scrollbar from one fixture — guardrail 3's failure mode, in flex form. */
.search__q {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  color: var(--text-secondary);
  font-family: var(--font-mono-ui);
  font-size: var(--text-mono-data-size);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* On a cream inset the chip needs the light-surface pair. */
.search__scope .pill-chip {
  background-color: var(--surface-card);
  border: var(--border-hairline);
  color: var(--text-secondary);
}

/* --- alerts --------------------------------------------------------------- */

.alerts__signal {
  inline-size: 100%;
  block-size: auto;
}

.alerts {
  display: grid;
  gap: var(--space-2);
}

.alert {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  background-color: var(--surface-ink-raised);
  border: var(--border-on-ink);
  border-radius: var(--radius-chip);
}

/* Decorative reply affordance, `aria-hidden`: a shape, not a control. */
.alerts__bar {
  display: block;
  block-size: var(--space-5);
  border-radius: var(--radius-pill);
  background-color: var(--accent-strong);
}

.alerts__summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
.alerts__summary span { display: grid; gap: var(--space-1); padding: var(--space-3); background: var(--surface-ink-raised); border: var(--border-on-ink); border-radius: var(--radius-chip); color: var(--text-on-ink-secondary); font-size: var(--text-mono-label-size); }
.alerts__summary b { color: var(--accent-on-ink); font-family: var(--font-display); font-size: var(--text-h3-size); line-height: 1; }

/* ==========================================================================
 * Synthetic proof bento — six compact, explicitly labelled design specimens.
 * ======================================================================== */
.proof__head { margin-block-end: var(--rhythm-section-head-to-content); }
.proof-bento { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; gap: var(--space-3); margin-block-start: 0; overflow: hidden; }
.proof-card { position: relative; z-index: 1; display: grid; align-content: start; gap: var(--space-2); padding: var(--space-4); border-radius: var(--radius-card); color: var(--text-primary); }
.proof-card > strong { font-family: var(--font-display); font-size: var(--text-h2-size); line-height: var(--text-h2-lh); letter-spacing: var(--tracking-display); }
.proof-card--coral { background: var(--accent-tint); } .proof-card--lilac { background: var(--accent-tint); } .proof-card--mint { background: var(--state-success-tint); } .proof-card--sun { background: var(--state-warning-tint); } .proof-card--blue { background: var(--data-primary); color: var(--text-on-ink); } .proof-card--cream { background: var(--surface-cream); }
.synthetic-marker { display: inline-flex; align-items: center; justify-content: center; inline-size: fit-content; max-inline-size: var(--space-11); min-block-size: var(--space-6); padding-inline: var(--space-2); border: var(--border-hairline); border-radius: var(--radius-pill); background: var(--surface-card); color: var(--text-secondary); font-family: var(--font-mono-ui); font-size: var(--text-mono-label-size); font-weight: var(--weight-medium); line-height: var(--text-h3-lh); letter-spacing: var(--tracking-label); text-transform: uppercase; white-space: nowrap; }
.proof-card__label, .proof-card__role { color: var(--text-secondary); font-family: var(--font-mono-ui); font-size: var(--text-mono-label-size); line-height: var(--text-h3-lh); letter-spacing: var(--tracking-label); text-transform: uppercase; }
.proof-card__quote { font-family: var(--font-display); font-size: var(--text-h3-size); font-weight: var(--weight-bold); line-height: var(--text-h3-lh); }
.fictional-mark { display: inline-flex; align-items: center; justify-content: center; inline-size: var(--space-7); block-size: var(--space-7); border-radius: var(--radius-control); background: var(--surface-card); color: var(--accent-strong); font-family: var(--font-display); font-size: var(--text-h3-size); }
.fictional-mark--grid { color: var(--data-primary); }.fictional-wordmark { font-family: var(--font-mono-data); font-size: var(--text-caption-size); font-weight: var(--weight-medium); letter-spacing: var(--tracking-label); }
.proof-bento__texture { position: absolute; inset-inline-end: 0; inset-block-end: 0; z-index: 0; inline-size: calc(var(--space-12) * 2); opacity: .28; pointer-events: none; }
.proof__disclosure { max-inline-size: var(--container-text); margin: var(--space-4) auto 0; color: var(--text-muted); font-size: var(--text-caption-size); text-align: center; }

.engagement .pill-chip--accent,
#closing .btn--accent {
  background-color: var(--accent-on-ink);
  border-color: var(--accent-on-ink);
  color: var(--text-on-accent);
}

#closing .btn--accent:hover,
#closing .btn--accent:active { background-color: var(--accent-on-ink); color: var(--text-on-accent); }

/* ==========================================================================
 * 18. FAQList — `faq`
 *
 * Native `details`/`summary`, so the platform supplies `aria-expanded` and the
 * whole list works with JavaScript disabled. The question lives in the
 * `summary`, never in a heading, so six questions do not inject six headings
 * into the document outline. Multiple items may be open at once and nothing
 * auto-closes an item the visitor opened.
 * ======================================================================== */

.faq__head {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: var(--space-4);
}

.faq__support {
  max-inline-size: var(--container-text);
  color: var(--text-secondary);
}

.faq__list {
  display: grid;
  gap: var(--space-3);
}

.faq__item {
  background-color: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-fixture);
}

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-block-size: var(--target-min);
  padding: var(--space-5) var(--space-6);
  font-weight: var(--weight-medium);
}

/* Hover and press both underline the question, so neither is carried by colour
 * alone, and the press adds the same translate every control on the page uses
 * — a movement rather than a third colour. No fill is introduced: the item
 * shell owns the radius and carries no `overflow: hidden` (clipping it would
 * clip the summary's own focus ring, which sits at `--focus-offset` outside
 * the row), so a row fill would paint square corners over a rounded card.
 * `--accent-strong` measures 5.81:1 on `--surface-card`. The open/closed state
 * itself is the platform's `aria-expanded`, never this colour. */
.faq__q:hover,
.faq__q:active {
  color: var(--accent-strong);
  text-decoration: underline;
}

.faq__q:active {
  transform: translateY(var(--press-distance));
}

.faq__a {
  padding: 0 var(--space-6) var(--space-5);
  color: var(--text-secondary);
  line-height: var(--text-prose-lh);
}

/* ==========================================================================
 * Decorated closing brand band and compact footer. Platform marks only identify public
 * surfaces; they are not proof, endorsements, or interactive controls.
 * ======================================================================== */
.closing-band { margin-inline: var(--page-band-inset); overflow: hidden; background: radial-gradient(ellipse at 50% 0, var(--surface-ink-glow-from), var(--surface-ink) 62%); }
.closing__inner { position: relative; display: grid; justify-items: center; gap: var(--space-4); padding-block: var(--space-10); }
.badge--onink { background: var(--state-hover-ink); border-color: var(--line-on-ink-strong); color: var(--text-on-ink-secondary); }
.closing__title { max-inline-size: calc(var(--container-text) + var(--space-9)); color: var(--text-on-ink); font-size: var(--text-h1-size); }
.closing__title span { color: var(--accent-on-ink); }.closing__title em { color: var(--data-on-ink); font-style: normal; }
.closing-platforms { position: relative; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--space-5); align-items: center; inline-size: min(100%, calc(var(--container-text) + var(--space-12))); min-block-size: var(--space-10); margin-block-start: var(--space-4); }
.closing-platforms__lines { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; pointer-events: none; }
.closing-mark { position: relative; z-index: 1; display: grid; place-items: center; inline-size: var(--space-9); block-size: var(--space-9); justify-self: center; padding: var(--space-4); background: var(--surface-card); border: var(--border-on-ink); border-radius: var(--radius-card); box-shadow: var(--shadow-card); }
.closing-mark img { inline-size: 100%; block-size: 100%; object-fit: contain; }.closing-mark:not(.closing-mark--wikipedia) img { filter: brightness(0) invert(1); }.closing-mark--gemini { background: linear-gradient(135deg, var(--platform-gemini-blue), var(--platform-gemini-purple), var(--platform-gemini-pink)); }.closing-mark--perplexity { background: var(--platform-perplexity); }.closing-mark--reddit { background: var(--platform-reddit); }.closing-mark--quora { background: var(--platform-quora); }.closing-mark--wikipedia { background: var(--platform-wikipedia); }.closing-mark--youtube { background: var(--platform-youtube); }
.footer { inline-size: min(var(--container-content), calc(100% - (var(--page-gutter) * 2))); margin: var(--space-7) auto 0; background: var(--surface-ink); color: var(--text-on-ink-secondary); border-radius: var(--radius-panel); }
.footer__grid { display: grid; grid-template-columns: minmax(0, 1.5fr) repeat(4, minmax(0, 1fr)); gap: var(--space-3); padding: var(--space-5) var(--space-6); }.footer__brand, .footer__group { display: grid; align-content: start; gap: var(--space-2); }.footer .brand { color: var(--text-on-ink); }.footer__tagline { max-inline-size: var(--container-text); }.footer__heading { color: var(--text-on-ink); font-size: var(--text-caption-size); letter-spacing: var(--tracking-label); text-transform: uppercase; }.footer__links { display: grid; gap: var(--space-1); }.footer__links a { color: var(--text-on-ink-secondary); text-decoration: none; }.footer__links a:hover, .footer__links a:focus-visible { color: var(--accent-on-ink); text-decoration: underline; }.footer__disabled, .footer__status { color: var(--text-on-ink-muted); cursor: not-allowed; }.footer__legal { display: flex; flex-wrap: wrap; gap: var(--space-3); padding: var(--space-2) var(--space-6); border-block-start: var(--border-on-ink); color: var(--text-on-ink-muted); font-size: var(--text-caption-size); }.footer__affiliation { margin-inline-start: auto; max-inline-size: var(--container-text); }
.footer__locale .locale-current,
.footer__locale .locale-link { display: inline-flex; align-items: center; justify-content: center; min-inline-size: var(--target-min); min-block-size: var(--target-min); }

/* ==========================================================================
 * 21. Disclosure entrance — `MOTION.md` §5 and §6 (Task 06)
 *
 * §5 gives the FAQ answer panel a fade and a `--reveal-distance` slide over
 * `--duration-gentle` `--ease-enter`; §6 gives the mobile navigation sheet the
 * same. Both are gated on `motion-ready`, so the panel is present and readable
 * the instant the platform opens it whether or not a script is running, and
 * neither animation uses a fill mode, so an interrupted or unsupported
 * animation lands on the element's own resting state and no panel can be left
 * invisible.
 *
 * THE EXIT IS DELIBERATELY NOT ANIMATED, and the reason is §5's own words
 * rather than a platform limitation alone. A native `details` removes its
 * panel from layout the instant it closes, so the only way to animate a close
 * is to intercept the `summary` activation, hold `open` true for the duration
 * of the animation, and set it false when the animation finishes. That
 * directly contradicts the sentence §5 uses to justify its own interruption
 * clause — "because the element is a native `details`, the open/closed state
 * is correct at all times regardless of the animation" — because for the
 * length of the exit the state would be open while the visitor has asked for
 * closed. It would also make the disclosure's close path depend on JavaScript,
 * which is the one thing `COMPONENTS.md` §3 and §18 chose `details` to avoid,
 * and it would spend motion-JavaScript budget that perf limit 6 does not have.
 *
 * So the close snaps, and the snap is the platform being correct rather than
 * an animation failing. `--ease-exit` has no element to apply to here. The
 * half of §5 that CAN honour interruption does ship: the `.chev` rotation is a
 * transition on an element that persists across the state change, so
 * re-activating mid-rotation reverses from wherever it is.
 * ======================================================================== */

@keyframes disclosure-in {
  from {
    opacity: 0;
    transform: translateY(calc(var(--reveal-distance) * -1));
  }
}


:root.motion-ready details[open] > .faq__a,
:root.motion-ready details[open] > .menu__sheet {
  animation: disclosure-in var(--duration-gentle) var(--ease-enter);
}

/* ==========================================================================
 * 22. ScrollReveal — `MOTION.md` §3 (Task 06)
 *
 * The last entry in the motion catalogue. Four properties of the contract
 * decide the whole shape of it, and the fourth decides where this comment
 * lives.
 *
 * 1. "The hidden pre-reveal state is applied by a script-set class, never by
 *    the stylesheet alone. If the script does not run, nothing is ever
 *    hidden." So the hidden state is doubly gated — on `:root.motion-ready`,
 *    which only `scripts/landing.js` can set, and on
 *    `@media (prefers-reduced-motion: no-preference)`, which the contract
 *    names explicitly so reduced-motion and no-JavaScript visitors reach the
 *    same correct result by the same mechanism. Content on this page can never
 *    depend on JavaScript to become visible.
 * 2. "No animation on an element larger than the viewport" (performance limit
 *    3). Every revealed element is a compact head block — a `sechead`, a
 *    `faq__head`, a band title or standfirst — never a section, a grid or a
 *    fixture. Those are shorter than a 640px viewport at every width from 320
 *    to 1600, and the verification harness asserts it — `tools/verify-landing.mjs`
 *    check MOT-1, named so the sentence cannot drift back into describing a
 *    measurement nothing performs.
 * 3. "Entrance animations on the `h1` or the navigation" are prohibited.
 *    `hero` and `site-header` carry no reveal at all, and no `.btn` or
 *    `.proof-card` is ever a target. The marked blocks in `backlinks` and
 *    `closing` are their compact heading blocks.
 *    Eight sections are marked against a budget of ten, and at most three
 *    children stagger inside any one of them.
 * 4. "Total JavaScript for all motion ≤ 4KB uncompressed" (performance limit
 *    6). This site has no build step, so shipped bytes are measured bytes and
 *    prose in `landing.js` is charged against the cap. The reveal's reasoning
 *    therefore lives HERE, in the layer that owns the gate, the hidden state
 *    and the stagger, and `landing.js` keeps only the invariants a reader of
 *    the code needs plus a pointer to this block. Nothing is undocumented;
 *    the documentation is in the layer that is not on the meter. The meter is
 *    `tools/verify-landing.mjs` check MOT-3, which sums the four
 *    MOTION-BUDGET-delimited regions of the SERVED `landing.js` — the three
 *    behaviour bodies plus the region holding the motion entry points, so a
 *    call cannot be moved out of scope to buy budget — and so moving prose here
 *    is a real saving against a real measurement, not a convention.
 *
 * WHAT `bindReveal()` DOES, since its byte budget will not carry the sentence.
 * The hidden pre-reveal state is CSS, behind the two gates in item 1. The
 * script only ever TAKES the state off, and when it cannot observe — no
 * `motion-ready`, or no `IntersectionObserver` — it takes it off every marked
 * element synchronously and returns, so no path leaves content hidden. When it
 * can observe there are three contracted ways in, and any one of them is
 * enough: crossing the 12% threshold; already sitting past the viewport centre,
 * which is the interruption case for a visitor who arrives mid-page; and
 * intersecting at all while taller than the viewport, which is the case a
 * threshold alone can never satisfy. Each target is unobserved once revealed.
 *
 * The stagger step is `--reveal-stagger`, 60ms, expressed as arithmetic over
 * the accepted `--duration-fast` role rather than as a literal duration, and
 * applied by sibling depth rather than by an inline style, so the markup
 * carries no duration and no rule restates one. Three children maximum puts
 * the largest delay at 120ms, inside the contract's 180ms cap.
 * ======================================================================== */

@media (prefers-reduced-motion: no-preference) {
  :root.motion-ready [data-reveal] {
    transition:
      opacity var(--duration-reveal) var(--ease-enter),
      transform var(--duration-reveal) var(--ease-enter);
  }

  :root.motion-ready [data-reveal]:not(.reveal--in) {
    opacity: 0;
    transform: translateY(var(--reveal-distance));
  }

  /* Second staggered child. The general sibling combinator counts only marked
   * elements, so an unmarked sibling between two targets does not shift the
   * step. */
  :root.motion-ready [data-reveal] ~ [data-reveal] {
    transition-delay: var(--reveal-stagger);
  }

  /* Third and last; no section marks a fourth. */
  :root.motion-ready [data-reveal] ~ [data-reveal] ~ [data-reveal] {
    transition-delay: calc(var(--reveal-stagger) * 2);
  }
}

/* ==========================================================================
 * Reduced motion — the system-wide pass (Task 06)
 *
 * `MOTION.md` rule 2: every non-instant animation has a reduced-motion
 * outcome, and that outcome is a stable final state — not a faster animation,
 * not a hidden element.
 *
 * This block is written to be correct even if `motion-ready` is present, which
 * is the documented risk for this task: the class is set by a media-query
 * listener in `scripts/landing.js` and removed again when the preference
 * changes, but a stale class, a listener that never fires, or an engine
 * without `matchMedia` must not be able to leave a loop running or a block
 * hidden. Every selector below therefore repeats the `:root.motion-ready`
 * qualifier where the rule it overrides carries one, so it matches at equal
 * specificity and wins on source order — this file is the last one to define
 * any of them, and `responsive.css` defines none.
 *
 * The result is that reduced motion is enforced twice by CSS alone: once by
 * the absence of the gate class, and once here regardless of it. Neither path
 * hides content.
 *
 * This is a preference query, not a width query, so it does not belong in
 * `responsive.css`.
 * ======================================================================== */

@media (prefers-reduced-motion: reduce) {
  .rail__track,
  :root.motion-ready .rail__track {
    inline-size: 100%;
  }

  .platform-rail__track,
  :root.motion-ready .platform-rail__track,
  .rail__set,
  :root.motion-ready .rail__set {
    animation: none;
    transform: none;
    will-change: auto;
  }

  .rail__clip {
    overflow-x: auto;
    overflow-y: hidden;
  }

  .rail__set,
  :root.motion-ready .rail__set {
    flex-wrap: nowrap;
  }

  .rail__set--dup,
  :root.motion-ready .rail__set--dup {
    display: none;
  }

  /* Bounded control-state transitions apply instantly. Nothing is hidden and
   * no state is lost — each one only ever moved between two static states. */
  a,
  .btn,
  .card,
  .chev,
  .menu__glyph {
    transition: none;
  }


  /* The press translate is movement, so it goes too; the fill change that
   * accompanies it in every variant remains, so the press is still visible. */
  .btn:active,
  .menu__toggle:active,
  .faq__q:active {
    transform: none;
  }
  /* Scroll reveal — no reveal at all, final state from first paint. The
   * pre-reveal rules live inside a `no-preference` query so they cannot match
   * here in the first place; this is the second, independent guarantee, and
   * the one that holds if a stale `motion-ready` survives a preference change
   * mid-session. */
  :root.motion-ready [data-reveal],
  :root.motion-ready [data-reveal]:not(.reveal--in) {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }

  /* Disclosure entrances are instant. */
  :root.motion-ready details[open] > .faq__a,
  :root.motion-ready details[open] > .menu__sheet {
    animation-name: none;
    animation-duration: 0s;
  }
}
