/*
 * Hearth's visual foundation — tokens, reset, base rules and shared recipes.
 *
 * `docs/design-system.md` is normative for everything in this file. It is not a
 * summary of this stylesheet: the pigments, the ladders and the layer order are
 * decided there, `apps/web/src/design-foundation.test.ts` reads that document
 * and checks these bytes against it, and `packages/kernel/src/design-contrast.ts`
 * recomputes the contrast arithmetic behind the pigments. Change a value here
 * without changing it there and the suite is red — which is the point. Issue
 * #294 builds the foundation the document designed (#259).
 *
 * Served at `/hearth.css` and linked from `index.html` *before* `shell.css`,
 * for the same reason `shell.css` is a served file rather than one the bundle
 * builds at runtime (H5, #221): an inline stylesheet is what forced
 * `style-src 'unsafe-inline'` into the response policy. No framework, no
 * runtime dependency, no remote font, no network asset of any kind.
 *
 * It is opt-in. An app that has not adopted the recipes keeps its own
 * namespaced sheet and inherits the palette; nothing here requires a class
 * rewrite, and nothing here supplies semantics. A recipe styles a control; the
 * app still chooses the element, the visible label, the accessible name and the
 * state attributes. See `docs/accessibility.md`.
 */

/*
 * The cascade order, declared once for the whole product.
 *
 * Every sheet in the shell document lives in one of these layers — this file in
 * the first four, `shell.css` in `hearth.shell`, each app's `client.css` in
 * `hearth.app`. The declaration has to come before the sheets that use the
 * names, and it is here rather than in the document because this file is the
 * first stylesheet the document loads.
 *
 * An *unlayered* sheet would outrank all of it, so leaving one out is not a
 * partial adoption, it is a defeat of the order. `!important` reverses the
 * ranking, which is why the reduced-motion block below sits at the bottom of
 * this list and still wins over an app's animation.
 */
@layer hearth.reset, hearth.tokens, hearth.base, hearth.components, hearth.shell,
  hearth.app;

@layer hearth.tokens {
  /*
   * Every pigment is written exactly once, here, as a palette entry. The three
   * blocks after them map palette entries onto the semantic names and contain
   * no raw values at all.
   *
   * The reason is `data-hearth-theme`. Two palette blocks — one plain, one in a
   * `prefers-color-scheme: dark` query — cannot express "force dark on a
   * light-preference browser", because the dark values would exist only inside
   * a query that browser never matches. Writing the pigments once and mapping
   * them three times is what makes the override real rather than decorative.
   */
  :root {
    --hearth-palette-light-canvas: #f6f3ee;
    --hearth-palette-light-surface: #ffffff;
    --hearth-palette-light-surface-muted: #eeeae3;
    --hearth-palette-light-surface-strong: #e4ded5;
    --hearth-palette-light-text: #24211d;
    --hearth-palette-light-text-muted: #635d54;
    --hearth-palette-light-border: #d7d0c6;
    --hearth-palette-light-border-control: #7f766c;
    --hearth-palette-light-accent: #9a3412;
    --hearth-palette-light-accent-strong: #7c2d12;
    --hearth-palette-light-on-accent: #ffffff;
    --hearth-palette-light-success: #166534;
    --hearth-palette-light-warning: #92400e;
    --hearth-palette-light-danger: #b42318;
    --hearth-palette-light-info: #1d4ed8;
    --hearth-palette-light-focus: #1d4ed8;
    --hearth-palette-light-scrim: rgb(36 33 29 / 0.48);

    --hearth-palette-dark-canvas: #171512;
    --hearth-palette-dark-surface: #211f1b;
    --hearth-palette-dark-surface-muted: #2c2924;
    --hearth-palette-dark-surface-strong: #37332d;
    --hearth-palette-dark-text: #f7f3ed;
    --hearth-palette-dark-text-muted: #c7bfb4;
    --hearth-palette-dark-border: #49443d;
    --hearth-palette-dark-border-control: #8f8679;
    --hearth-palette-dark-accent: #fb923c;
    --hearth-palette-dark-accent-strong: #fdba74;
    --hearth-palette-dark-on-accent: #2a160a;
    --hearth-palette-dark-success: #4ade80;
    --hearth-palette-dark-warning: #fbbf24;
    --hearth-palette-dark-danger: #f87171;
    --hearth-palette-dark-info: #60a5fa;
    --hearth-palette-dark-focus: #93c5fd;
    --hearth-palette-dark-scrim: rgb(0 0 0 / 0.66);
  }

  /*
   * The navigation vocabulary: one value in both themes, so it is declared
   * once and never mapped.
   *
   * "Coal navigation makes the workspace feel anchored" puts a dark region
   * inside the light theme, and no semantic token above can say that —
   * `surface` is `#ffffff` in light mode and an app may not redefine a global
   * token. Three consequences are load-bearing and none of them follows from
   * the values alone: on the rail the accent is `nav-accent`, never `accent`
   * (light `accent` is 2.25:1 on this ground); the focus ring is `nav-focus`,
   * never `focus` (2.45:1, under WCAG 1.4.11's 3:1, which would make the rail
   * the one place keyboard focus is invisible in the default theme); and in
   * dark mode the rail is bounded by `nav-border`, not distinguished by fill,
   * because `nav-surface` on the dark canvas is 1.11:1.
   */
  :root {
    --hearth-color-nav-surface: #211f1b;
    --hearth-color-nav-surface-muted: #2c2924;
    --hearth-color-nav-text: #f7f3ed;
    --hearth-color-nav-text-muted: #c7bfb4;
    --hearth-color-nav-border: #49443d;
    --hearth-color-nav-border-control: #8f8679;
    --hearth-color-nav-accent: #fb923c;
    --hearth-color-nav-on-accent: #2a160a;
    --hearth-color-nav-focus: #93c5fd;
  }

  /* Light is the default mapping. */
  :root {
    --hearth-color-canvas: var(--hearth-palette-light-canvas);
    --hearth-color-surface: var(--hearth-palette-light-surface);
    --hearth-color-surface-muted: var(--hearth-palette-light-surface-muted);
    --hearth-color-surface-strong: var(--hearth-palette-light-surface-strong);
    --hearth-color-text: var(--hearth-palette-light-text);
    --hearth-color-text-muted: var(--hearth-palette-light-text-muted);
    --hearth-color-border: var(--hearth-palette-light-border);
    --hearth-color-border-control: var(--hearth-palette-light-border-control);
    --hearth-color-accent: var(--hearth-palette-light-accent);
    --hearth-color-accent-strong: var(--hearth-palette-light-accent-strong);
    --hearth-color-on-accent: var(--hearth-palette-light-on-accent);
    --hearth-color-success: var(--hearth-palette-light-success);
    --hearth-color-warning: var(--hearth-palette-light-warning);
    --hearth-color-danger: var(--hearth-palette-light-danger);
    --hearth-color-info: var(--hearth-palette-light-info);
    --hearth-color-focus: var(--hearth-palette-light-focus);
    --hearth-color-scrim: var(--hearth-palette-light-scrim);
  }

  /*
   * The browser's preference, unless the document has explicitly asked for
   * light. Following `prefers-color-scheme` by default is what keeps Hearth
   * free of a script-time theme flash: there is no stored preference to read
   * before the first paint, because there is nowhere intentional to store one
   * yet. The override below is for deterministic tests and a future member
   * preference; this slice adds no toggle and no persistence.
   */
  @media (prefers-color-scheme: dark) {
    :root:not([data-hearth-theme="light"]) {
      --hearth-color-canvas: var(--hearth-palette-dark-canvas);
      --hearth-color-surface: var(--hearth-palette-dark-surface);
      --hearth-color-surface-muted: var(--hearth-palette-dark-surface-muted);
      --hearth-color-surface-strong: var(--hearth-palette-dark-surface-strong);
      --hearth-color-text: var(--hearth-palette-dark-text);
      --hearth-color-text-muted: var(--hearth-palette-dark-text-muted);
      --hearth-color-border: var(--hearth-palette-dark-border);
      --hearth-color-border-control: var(--hearth-palette-dark-border-control);
      --hearth-color-accent: var(--hearth-palette-dark-accent);
      --hearth-color-accent-strong: var(--hearth-palette-dark-accent-strong);
      --hearth-color-on-accent: var(--hearth-palette-dark-on-accent);
      --hearth-color-success: var(--hearth-palette-dark-success);
      --hearth-color-warning: var(--hearth-palette-dark-warning);
      --hearth-color-danger: var(--hearth-palette-dark-danger);
      --hearth-color-info: var(--hearth-palette-dark-info);
      --hearth-color-focus: var(--hearth-palette-dark-focus);
      --hearth-color-scrim: var(--hearth-palette-dark-scrim);
    }
  }

  /* The explicit override, which is why the pigments are named at all. */
  :root[data-hearth-theme="dark"] {
    --hearth-color-canvas: var(--hearth-palette-dark-canvas);
    --hearth-color-surface: var(--hearth-palette-dark-surface);
    --hearth-color-surface-muted: var(--hearth-palette-dark-surface-muted);
    --hearth-color-surface-strong: var(--hearth-palette-dark-surface-strong);
    --hearth-color-text: var(--hearth-palette-dark-text);
    --hearth-color-text-muted: var(--hearth-palette-dark-text-muted);
    --hearth-color-border: var(--hearth-palette-dark-border);
    --hearth-color-border-control: var(--hearth-palette-dark-border-control);
    --hearth-color-accent: var(--hearth-palette-dark-accent);
    --hearth-color-accent-strong: var(--hearth-palette-dark-accent-strong);
    --hearth-color-on-accent: var(--hearth-palette-dark-on-accent);
    --hearth-color-success: var(--hearth-palette-dark-success);
    --hearth-color-warning: var(--hearth-palette-dark-warning);
    --hearth-color-danger: var(--hearth-palette-dark-danger);
    --hearth-color-info: var(--hearth-palette-dark-info);
    --hearth-color-focus: var(--hearth-palette-dark-focus);
    --hearth-color-scrim: var(--hearth-palette-dark-scrim);
  }

  :root {
    /*
     * No font is fetched. A future brand font must be open-source, committed
     * or served by Hearth, and justified as its own asset decision.
     */
    --hearth-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
    --hearth-font-mono: ui-monospace, "SFMono-Regular", Consolas, monospace;

    --hearth-font-size-xs: 0.75rem;
    --hearth-font-size-sm: 0.875rem;
    --hearth-font-size-md: 1rem;
    --hearth-font-size-lg: 1.125rem;
    --hearth-font-size-xl: 1.5rem;
    --hearth-font-size-2xl: 2rem;

    --hearth-font-weight-regular: 400;
    --hearth-font-weight-medium: 600;
    --hearth-font-weight-bold: 700;

    --hearth-line-height-tight: 1.25;
    --hearth-line-height-body: 1.5;
    --hearth-line-height-reading: 1.7;

    /* Four CSS pixels, laddered. */
    --hearth-space-1: 0.25rem;
    --hearth-space-2: 0.5rem;
    --hearth-space-3: 0.75rem;
    --hearth-space-4: 1rem;
    --hearth-space-5: 1.5rem;
    --hearth-space-6: 2rem;
    --hearth-space-7: 3rem;

    /*
     * Nested surfaces do not get progressively larger radii: the outer card
     * uses `card`, its panels use `panel`, and controls use `control`.
     */
    --hearth-radius-control: 0.375rem;
    --hearth-radius-panel: 0.625rem;
    --hearth-radius-card: 1rem;
    --hearth-radius-pill: 999px;

    /* Three levels, and no more. Coloured shadows and glass are not part of
       the system; borders do most of the grouping work. */
    --hearth-shadow-0: none;
    --hearth-shadow-1: 0 1px 2px rgb(36 33 29 / 0.08), 0 8px 24px rgb(36 33 29 / 0.06);
    --hearth-shadow-2: 0 16px 40px rgb(36 33 29 / 0.14);

    --hearth-motion-fast: 120ms;
    --hearth-motion-standard: 180ms;
    --hearth-motion-slow: 260ms;
    --hearth-motion-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  }

  /* Dark mode grounds are darker than any shadow, so elevation there is
     carried by a border plus a deeper black rather than by a neutral falloff
     nothing can be seen against. */
  @media (prefers-color-scheme: dark) {
    :root:not([data-hearth-theme="light"]) {
      --hearth-shadow-1: 0 1px 2px rgb(0 0 0 / 0.35), 0 8px 24px rgb(0 0 0 / 0.35);
      --hearth-shadow-2: 0 16px 40px rgb(0 0 0 / 0.45);
    }
  }

  :root[data-hearth-theme="dark"] {
    --hearth-shadow-1: 0 1px 2px rgb(0 0 0 / 0.35), 0 8px 24px rgb(0 0 0 / 0.35);
    --hearth-shadow-2: 0 16px 40px rgb(0 0 0 / 0.45);
  }
}

@layer hearth.reset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  body,
  h1,
  h2,
  h3,
  h4,
  p,
  figure,
  blockquote,
  dl,
  dd {
    margin: 0;
  }

  /* Headings inherit their weight from the recipe that uses them, so a
     document outline is chosen for structure rather than for size. */
  h1,
  h2,
  h3,
  h4 {
    font-size: inherit;
    font-weight: inherit;
  }

  ul[class],
  ol[class] {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* Controls do not inherit type by default, which is how a field ends up
     rendering in the browser's own font inside a product that set one. */
  button,
  input,
  select,
  textarea {
    font: inherit;
    color: inherit;
  }

  img,
  svg,
  video,
  canvas {
    display: block;
    max-width: 100%;
  }

  /* Member text wraps — long titles, filenames, messages and digest prose.
     Truncation may supplement, but never replaces access to the full value. */
  p,
  li,
  dd,
  h1,
  h2,
  h3,
  h4 {
    overflow-wrap: anywhere;
  }
}

@layer hearth.base {
  :root {
    /* Native widgets — scrollbars, form controls, the canvas behind the page —
       follow the theme this document is actually in, including under the
       explicit override. */
    color-scheme: light dark;
  }

  :root[data-hearth-theme="light"] {
    color-scheme: light;
  }

  :root[data-hearth-theme="dark"] {
    color-scheme: dark;
  }

  body {
    background: var(--hearth-color-canvas);
    color: var(--hearth-color-text);
    font-family: var(--hearth-font-sans);
    font-size: var(--hearth-font-size-md);
    line-height: var(--hearth-line-height-body);
  }

  code,
  kbd,
  pre,
  samp {
    font-family: var(--hearth-font-mono);
  }

  a {
    color: var(--hearth-color-accent);
  }

  a:hover {
    color: var(--hearth-color-accent-strong);
  }

  /*
   * The focus treatment, in one place.
   *
   * `:focus-visible` rather than `:focus`, so a pointer press does not draw a
   * ring — but the ring is never removed without a replacement. Two parts: a
   * 2px separation from the control in the ground colour, then a 2px outer
   * ring, so the indicator survives on a fill of any lightness. On the rail
   * the ring is `nav-focus`, which is why `.hearth-ui-rail` re-states it
   * rather than inheriting.
   */
  :focus-visible {
    outline: 2px solid var(--hearth-color-focus);
    outline-offset: 2px;
  }

  /* Only where the platform's own default is already sound. Removing the
     outline outright is what the Docs editor did until #297 replaced it with a
     ring on the canvas around the contenteditable. */
  ::selection {
    background: var(--hearth-color-accent);
    color: var(--hearth-color-on-accent);
  }
}

@layer hearth.components {
  /*
   * The recipes. Each one owns the visual shape of a control and nothing else:
   * no semantics, no placement, no app state. An app adds a shared class
   * alongside its own — `class="hearth-chat-retry hearth-ui-button
   * hearth-ui-button--quiet"` — where the app class owns placement and state
   * and the shared classes own the shape.
   *
   * Interactive targets are at least 2.25rem, and 2.75rem on the narrow
   * layout, which is the one accessibility guarantee a stylesheet can actually
   * make on its own.
   */

  .hearth-ui-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--hearth-space-2);
    min-height: 2.25rem;
    padding: var(--hearth-space-2) var(--hearth-space-4);
    border: 1px solid var(--hearth-color-border-control);
    border-radius: var(--hearth-radius-control);
    background: var(--hearth-color-surface);
    color: var(--hearth-color-text);
    font-size: var(--hearth-font-size-md);
    font-weight: var(--hearth-font-weight-medium);
    line-height: var(--hearth-line-height-tight);
    cursor: pointer;
    transition: background-color var(--hearth-motion-fast) var(--hearth-motion-ease),
      border-color var(--hearth-motion-fast) var(--hearth-motion-ease),
      color var(--hearth-motion-fast) var(--hearth-motion-ease);
  }

  .hearth-ui-button:hover {
    background: var(--hearth-color-surface-muted);
  }

  .hearth-ui-button:active,
  .hearth-ui-button[aria-pressed="true"] {
    background: var(--hearth-color-surface-strong);
  }

  .hearth-ui-button--primary {
    border-color: var(--hearth-color-accent);
    background: var(--hearth-color-accent);
    color: var(--hearth-color-on-accent);
  }

  /*
   * `[aria-pressed="true"]` is named here and not left to the neutral rule
   * above, which is the composition that makes it necessary rather than
   * tidiness. `.hearth-ui-button[aria-pressed="true"]` is a class *and* an
   * attribute; `.hearth-ui-button--primary` is one class. So on a pressed
   * primary button the neutral rule wins the ground and the primary rule keeps
   * the foreground, and the result is `on-accent` on `surface-strong` — 1.34:1
   * in light mode. The inventory requires a pressed button and a primary
   * button, so that pair is reachable, and the document's composition table
   * now states this one and `design-foundation.test.ts` resolves the cascade
   * to check the sheet produces it.
   */
  .hearth-ui-button--primary:hover,
  .hearth-ui-button--primary:active,
  .hearth-ui-button--primary[aria-pressed="true"] {
    border-color: var(--hearth-color-accent-strong);
    background: var(--hearth-color-accent-strong);
    color: var(--hearth-color-on-accent);
  }

  /* The default shape already is the secondary button; the modifier exists so
     an app can say so rather than relying on the absence of one. */
  .hearth-ui-button--secondary {
    background: var(--hearth-color-surface);
  }

  .hearth-ui-button--quiet {
    border-color: transparent;
    background: transparent;
  }

  .hearth-ui-button--danger {
    border-color: var(--hearth-color-danger);
    color: var(--hearth-color-danger);
  }

  .hearth-ui-button--icon {
    min-width: 2.25rem;
    padding: var(--hearth-space-2);
  }

  /*
   * Both, because a refusal is not always `:disabled`. The shell's invite
   * button declines semantically once a link is shown (#156, on #118's
   * reasoning), so `[aria-disabled]` has to read the same as `:disabled` or it
   * looks fully live. `aria-disabled` is still focusable on purpose — that is
   * what lets the control explain itself.
   */
  .hearth-ui-button:disabled,
  .hearth-ui-button[aria-disabled="true"] {
    opacity: 0.6;
    cursor: default;
  }

  /* Busy keeps its readable label: this is a cursor and a dimming, never a
     replacement of the text with a spinner. */
  .hearth-ui-button[aria-busy="true"] {
    cursor: progress;
  }

  .hearth-ui-header {
    display: flex;
    align-items: center;
    gap: var(--hearth-space-3);
    flex-wrap: wrap;
    padding: var(--hearth-space-3) var(--hearth-space-4);
    border-bottom: 1px solid var(--hearth-color-border);
    background: var(--hearth-color-surface);
  }

  .hearth-ui-header__title {
    font-size: var(--hearth-font-size-lg);
    font-weight: var(--hearth-font-weight-medium);
    line-height: var(--hearth-line-height-tight);
  }

  .hearth-ui-header__meta {
    color: var(--hearth-color-text-muted);
    font-size: var(--hearth-font-size-sm);
  }

  .hearth-ui-field {
    display: flex;
    flex-direction: column;
    gap: var(--hearth-space-1);
  }

  .hearth-ui-field__label {
    font-size: var(--hearth-font-size-sm);
    font-weight: var(--hearth-font-weight-medium);
  }

  .hearth-ui-field__hint {
    color: var(--hearth-color-text-muted);
    font-size: var(--hearth-font-size-sm);
  }

  /* An error names the field or action it belongs to; the colour is never the
     only carrier of that. */
  .hearth-ui-field__error {
    color: var(--hearth-color-danger);
    font-size: var(--hearth-font-size-sm);
  }

  .hearth-ui-input {
    min-height: 2.25rem;
    padding: var(--hearth-space-2) var(--hearth-space-3);
    border: 1px solid var(--hearth-color-border-control);
    border-radius: var(--hearth-radius-control);
    background: var(--hearth-color-surface);
    color: var(--hearth-color-text);
  }

  .hearth-ui-input[readonly] {
    background: var(--hearth-color-surface-muted);
  }

  .hearth-ui-panel {
    padding: var(--hearth-space-4);
    border: 1px solid var(--hearth-color-border);
    border-radius: var(--hearth-radius-panel);
    background: var(--hearth-color-surface);
  }

  .hearth-ui-card {
    padding: var(--hearth-space-5);
    border: 1px solid var(--hearth-color-border);
    border-radius: var(--hearth-radius-card);
    background: var(--hearth-color-surface);
    box-shadow: var(--hearth-shadow-1);
  }

  .hearth-ui-toolbar {
    display: flex;
    align-items: center;
    gap: var(--hearth-space-2);
    flex-wrap: wrap;
    padding: var(--hearth-space-2);
    border: 1px solid var(--hearth-color-border);
    border-radius: var(--hearth-radius-control);
    background: var(--hearth-color-surface);
  }

  /*
   * A collection row: conversation, message, document, digest, file, room.
   * Selected, unread, hidden and read-only *state* stays app-owned — this is
   * the shape and the selected ground, not the state machine.
   */
  .hearth-ui-row {
    display: flex;
    align-items: center;
    gap: var(--hearth-space-3);
    width: 100%;
    min-height: 2.25rem;
    padding: var(--hearth-space-2) var(--hearth-space-3);
    border: 1px solid transparent;
    border-radius: var(--hearth-radius-control);
    background: transparent;
    text-align: start;
  }

  .hearth-ui-row:hover {
    background: var(--hearth-color-surface-muted);
  }

  .hearth-ui-row[aria-current="true"],
  .hearth-ui-row[aria-selected="true"] {
    border-color: var(--hearth-color-accent);
    background: var(--hearth-color-surface-muted);
  }

  .hearth-ui-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--hearth-space-1);
    padding: 0 var(--hearth-space-2);
    border: 1px solid var(--hearth-color-border-control);
    border-radius: var(--hearth-radius-pill);
    font-size: var(--hearth-font-size-xs);
    line-height: var(--hearth-line-height-body);
  }

  /*
   * Status marks are a colour *and* a word or a named icon, never a colour
   * alone — selection, presence, gate result, sharing, connection and device
   * state all pass through here, and each of them is information.
   */
  .hearth-ui-status--success {
    color: var(--hearth-color-success);
  }

  .hearth-ui-status--warning {
    color: var(--hearth-color-warning);
  }

  .hearth-ui-status--danger {
    color: var(--hearth-color-danger);
  }

  .hearth-ui-status--info {
    color: var(--hearth-color-info);
  }

  .hearth-ui-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: var(--hearth-radius-pill);
    background: var(--hearth-color-accent);
    color: var(--hearth-color-on-accent);
    font-size: var(--hearth-font-size-sm);
    font-weight: var(--hearth-font-weight-medium);
  }

  .hearth-ui-dialog {
    max-width: 32rem;
    padding: var(--hearth-space-5);
    border: 1px solid var(--hearth-color-border);
    border-radius: var(--hearth-radius-card);
    background: var(--hearth-color-surface);
    color: var(--hearth-color-text);
    box-shadow: var(--hearth-shadow-2);
  }

  .hearth-ui-dialog::backdrop {
    background: var(--hearth-color-scrim);
  }

  /*
   * A visible callout. It is not the live region: the surface's one polite
   * region stays where `docs/accessibility.md` puts it, and a remedy named in
   * its sentence stays beside it. This is the visible half of the same news.
   */
  .hearth-ui-callout {
    padding: var(--hearth-space-3) var(--hearth-space-4);
    border: 1px solid var(--hearth-color-border-control);
    border-inline-start-width: var(--hearth-space-1);
    border-radius: var(--hearth-radius-control);
    background: var(--hearth-color-surface-muted);
  }

  .hearth-ui-callout--warning {
    border-inline-start-color: var(--hearth-color-warning);
  }

  .hearth-ui-callout--danger {
    border-inline-start-color: var(--hearth-color-danger);
  }

  .hearth-ui-callout--info {
    border-inline-start-color: var(--hearth-color-info);
  }

  /* First load, no results, nothing yet, retryable failure. The remedy is a
     control inside it, not a sentence about one. */
  .hearth-ui-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--hearth-space-3);
    padding: var(--hearth-space-6) var(--hearth-space-4);
    color: var(--hearth-color-text-muted);
    text-align: center;
  }

  /*
   * The app rail and its compact horizontal form. Drawn entirely from the
   * navigation tokens: on this ground `accent` and `focus` are 2.25:1 and
   * 2.45:1 in light mode, so a selected item is a `nav-accent` fill with a
   * `nav-on-accent` label and the ring is `nav-focus`.
   */
  .hearth-ui-rail {
    display: flex;
    flex-direction: column;
    gap: var(--hearth-space-1);
    padding: var(--hearth-space-3);
    border-inline-end: 1px solid var(--hearth-color-nav-border);
    background: var(--hearth-color-nav-surface);
    color: var(--hearth-color-nav-text);
  }

  .hearth-ui-rail--bar {
    flex-direction: row;
    align-items: center;
    padding: var(--hearth-space-2) var(--hearth-space-3);
    border-inline-end: 0;
    border-block-end: 1px solid var(--hearth-color-nav-border);
  }

  .hearth-ui-rail__brand {
    color: var(--hearth-color-nav-text);
    font-weight: var(--hearth-font-weight-bold);
  }

  .hearth-ui-rail__item {
    display: flex;
    align-items: center;
    gap: var(--hearth-space-2);
    min-height: 2.25rem;
    padding: var(--hearth-space-2) var(--hearth-space-3);
    border: 1px solid transparent;
    border-radius: var(--hearth-radius-control);
    background: transparent;
    color: var(--hearth-color-nav-text-muted);
  }

  .hearth-ui-rail__item:hover {
    background: var(--hearth-color-nav-surface-muted);
    color: var(--hearth-color-nav-text);
  }

  .hearth-ui-rail__item[aria-current="true"] {
    background: var(--hearth-color-nav-accent);
    color: var(--hearth-color-nav-on-accent);
  }

  .hearth-ui-rail :focus-visible {
    outline-color: var(--hearth-color-nav-focus);
  }

  /*
   * The two structural helpers, and the only two. General margin, grid and
   * colour utilities are excluded: they would move app layout back into markup.
   *
   * `hearth-ui-visually-hidden` is the established clipped-but-exposed idiom —
   * out of flow but *in* the accessibility tree, which is what an empty live
   * region needs so the text written into it later reads as a change rather
   * than as the region appearing.
   */
  .hearth-ui-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .hearth-ui-focus-ring {
    outline: 2px solid var(--hearth-color-focus);
    outline-offset: 2px;
  }

  /*
   * The narrow layout. Below 48rem everything must work in one column, and
   * targets grow: a 2.25rem control is comfortable under a mouse and marginal
   * under a thumb.
   *
   * In this layer, after the defaults, and both halves are load-bearing. A
   * media query carries no specificity and no rank of its own: these rules
   * beat the 2.25rem defaults only by sitting in the same layer and coming
   * later. The same block one layer down in `hearth.base` — where it was, and
   * where it reads as "the responsive section" — is outranked by every
   * `hearth.components` default whatever its source order, so every target
   * silently stayed at 2.25rem on the layout the guarantee exists for.
   */
  @media (max-width: 47.999rem) {
    .hearth-ui-button,
    .hearth-ui-input,
    .hearth-ui-row,
    .hearth-ui-rail__item {
      min-height: 2.75rem;
    }

    .hearth-ui-button--icon {
      min-width: 2.75rem;
    }
  }

  /*
   * Forced colours: keep the platform's own borders and focus outlines, and
   * stop a custom fill being the only indication of a control. `forced-color-
   * adjust: none` is nowhere in this file for the same reason.
   *
   * In this layer for the same reason as the narrow layout above: `border: 1px
   * solid` is a normal declaration, so from `hearth.base` it lost the whole
   * shorthand to each recipe's own `border`, and the one mode where a custom
   * fill is not drawn was the one mode where the boundary was not either.
   */
  @media (forced-colors: active) {
    .hearth-ui-button,
    .hearth-ui-input,
    .hearth-ui-row[aria-current="true"],
    .hearth-ui-row[aria-selected="true"],
    .hearth-ui-badge {
      border: 1px solid;
    }

    :focus-visible {
      outline: 2px solid;
      outline-offset: 2px;
    }
  }
}

@layer hearth.base {
  /*
   * Motion clarifies state; it is never decoration or the only record of a
   * change, so removing it can never remove information.
   *
   * The one block that stays *below* the recipes, and the exception proves the
   * rule the two blocks above had wrong. `!important` in the lowest layer beats
   * `!important` in the highest — important declarations rank the layers in
   * reverse — so this is the only place a foundation rule can override an app's
   * animation without knowing what the app declared. Every declaration here is
   * important for that reason; one that is not ranks normally, which puts it
   * under `hearth.app` and honours the preference only for apps that already
   * did.
   *
   * The universal selector matters as much. These have to reach a transition
   * declared on any element by any sheet, including one this file has never
   * heard of, so `*, *::before, *::after` is the subject rather than a list —
   * `html` alone would leave every app's own animation running.
   *
   * Durations become 0.01ms rather than 0 so that a `transitionend` an app is
   * waiting on still fires; nothing in Hearth may wait for an animation to
   * finish before it works, but that is a rule for the app, not a bet this
   * block should take on the app's behalf. The three duration *tokens* are
   * restated too, so a transition composed from them collapses at the source
   * as well as at the property.
   */
  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }

    :root {
      --hearth-motion-fast: 0.01ms;
      --hearth-motion-standard: 0.01ms;
      --hearth-motion-slow: 0.01ms;
    }
  }
}
