/* ==========================================================================
   RecipeHub — Warm Table token layer
   ==========================================================================

   The single source of visual truth. Everything below this file is a
   component; nothing above it exists.

   Adapted from the supplied design system (`docs/Design/RecipeHub Design
   System.zip`, tokens/*.css) with three deliberate differences, recorded in
   `docs/42_WORLD_CLASS_DESIGN_IMPLEMENTATION.md`:

     1. Only the Warm Table direction ships. The artifact carries three themes
        in `tokens/directions.css`; two of them are reference material, and a
        theme switcher is not a product feature. Warm Table is `:root`, so the
        night and board blocks are simply absent rather than disabled.

     2. `@font-face` points at this repository's own Heebo binaries, which live
        at `/assets/`, not at the artifact's `../assets/fonts/`. Local, never a
        CDN — a lab machine with no network still has to render the product,
        and this is also CSS3 proof 1 of 5.

     3. The legacy token names the old stylesheet uses (`--bg`, `--accent`,
        `--radius`, …) are kept at the bottom as ALIASES onto the semantic
        layer. That is what lets ~2,300 lines of working CSS keep working while
        each screen migrates, instead of a flag day where everything moves at
        once and nothing can be bisected.

   The rule the artifact states and this file enforces: components read the
   SEMANTIC roles (`--color-accent`), never the ramps (`--rh-clay-500`). A ramp
   is a palette; a role is a decision. */

/* ==========================================================================
   [CSS3 1/5] @font-face — a Hebrew webfont shipped with the project.
   Hosted locally, not from a CDN: requirement 10 warns about lab machines, and
   a demonstration must not depend on the network being up.
   ========================================================================== */
@font-face {
  font-family: 'Heebo';
  src: url('/assets/heebo-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Heebo';
  src: url('/assets/heebo-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* ======================================================================
     COLOUR — ramps first, semantic roles second.
     Warm-neutral throughout. There is no cool grey anywhere in this product:
     a neutral grey next to terracotta reads as dirt rather than as calm.
     ====================================================================== */

  /* clay — the RecipeHub accent. Terracotta, roasted, appetite-warm.
     Descends from the shipped product's own `--accent: #b4562a`. */
  --rh-clay-900: #3d1a0b;
  --rh-clay-800: #6d3116;
  --rh-clay-700: #8e421f;
  --rh-clay-600: #a8431f;
  --rh-clay-500: #b4562a;
  --rh-clay-300: #e0b49c;
  --rh-clay-200: #f0d9cb;
  --rh-clay-100: #fbeee7;
  --rh-clay-50:  #fdf7f3;

  /* saffron — the secondary. Turmeric / egg yolk, used sparingly. */
  --rh-saffron-700: #8a5a06;
  --rh-saffron-500: #c98a2e;
  --rh-saffron-300: #e8c37c;
  --rh-saffron-100: #fdf3e2;

  /* ink — text, from black-coffee to weak-tea. */
  --rh-ink-900: #241d18;
  --rh-ink-800: #2c2622;
  --rh-ink-700: #4a4038;
  /*
   * ink-600 exists because ink-500 DID NOT MEET AA on paper-100, and J-2
   * measured it: `#7a6f66` on `#f3eee7` is 4.24 against a 4.5 requirement, so
   * every `--color-text-muted` label on a sunken surface — the `why` chips on a
   * feed card, the admin tabs, the admin nav groups, "this creator has no food
   * yet" — was a fraction below readable at 12-13px. This is not a design
   * preference: it is the smallest step that clears the threshold (5.29) while
   * still reading as muted, which ink-700 at 8.2 would not.
   */
  --rh-ink-600: #6b6058;
  --rh-ink-500: #7a6f66;
  --rh-ink-400: #8f8379;
  --rh-ink-300: #a99c92;

  /* paper + line — grounds and hairlines. */
  --rh-paper-0:   #ffffff;
  --rh-paper-50:  #faf8f5;
  --rh-paper-100: #f3eee7;
  --rh-line-200:  #e6e0d8;
  --rh-line-300:  #d6cec3;

  /* semantic hues. Each owns one job and is never used decoratively. */
  --rh-olive-700: #235539;
  --rh-olive-600: #2c6e49;
  --rh-olive-100: #e8f3ed;
  --rh-amber-800: #6d4a12;
  --rh-amber-700: #8a4b00;
  --rh-amber-500: #e0a33c;
  --rh-amber-100: #fdf6e9;
  --rh-chili-700: #8f1e18;
  --rh-chili-600: #b3261e;
  --rh-chili-100: #fdecea;

  /* -- semantic roles: surfaces -- */
  --color-bg: var(--rh-paper-50);
  --color-surface: var(--rh-paper-0);
  --color-surface-sunken: var(--rh-paper-100);
  --color-surface-inverse: var(--rh-ink-900);
  --color-surface-accent: var(--rh-clay-100);

  /* -- text -- */
  --color-text: var(--rh-ink-800);
  --color-text-strong: var(--rh-ink-900);
  /* ink-600, not ink-500: see the ramp comment. Measured, not preferred. */
  --color-text-muted: var(--rh-ink-600);
  --color-text-on-accent: #ffffff;
  --color-text-on-media: #ffffff;
  --color-text-inverse: var(--rh-paper-50);

  /* -- lines -- */
  --color-border: var(--rh-line-200);
  --color-border-strong: var(--rh-line-300);
  --color-divider: var(--rh-line-200);

  /* -- accent -- */
  --color-accent: var(--rh-clay-500);
  --color-accent-hover: var(--rh-clay-700);
  --color-accent-press: var(--rh-clay-800);
  --color-accent-soft: var(--rh-clay-100);
  --color-accent-text: var(--rh-clay-700);
  --color-secondary: var(--rh-saffron-500);
  --color-secondary-soft: var(--rh-saffron-100);
  --color-secondary-text: var(--rh-saffron-700);

  /* -- states. Every one has a surface, a border tone and a text tone, so a
        state is never carried by colour alone. -- */
  --color-success: var(--rh-olive-600);
  --color-success-soft: var(--rh-olive-100);
  --color-success-text: var(--rh-olive-700);
  --color-warning: var(--rh-amber-500);
  --color-warning-soft: var(--rh-amber-100);
  --color-warning-text: var(--rh-amber-800);
  --color-danger: var(--rh-chili-600);
  --color-danger-soft: var(--rh-chili-100);
  --color-danger-text: var(--rh-chili-700);
  --color-info: var(--rh-clay-600);
  --color-info-soft: var(--rh-clay-100);

  /* -- focus: one ring for the whole product, never removed -- */
  --color-focus-ring: var(--rh-clay-600);
  --focus-ring: 0 0 0 3px var(--rh-clay-200);

  /* -- media. The scrim is preserved from the shipped feed card and promoted
        from a one-off gradient to a token. -- */
  --scrim-media: linear-gradient(to top, rgba(20,16,13,.88) 0%, rgba(20,16,13,.62) 45%, rgba(20,16,13,0) 100%);
  --scrim-media-top: linear-gradient(to bottom, rgba(20,16,13,.45) 0%, rgba(20,16,13,0) 60%);
  --media-placeholder: linear-gradient(140deg, var(--rh-clay-100), #e7d7c6);
  /* Covers are warm-graded rather than desaturated. `none` in Warm Table; the
     token exists so `.rh-media` has something defined to read. */
  --media-tint: none;

  /* ======================================================================
     TYPE — one family, nine sizes, four line-heights, two weights.

     Body is 17px rather than 16: Heebo's x-height runs small, and 16px Hebrew
     on a phone reads as fine print. Only 400 and 700 exist as local binaries,
     so hierarchy is carried by SIZE and COLOUR, never by a weight this
     repository does not ship.
     ====================================================================== */
  --font-core: 'Heebo', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-numeric: 'Heebo', 'Segoe UI', system-ui, sans-serif;

  --text-2xs: 12px;
  --text-xs:  13px;
  --text-sm:  15px;
  --text-base:17px;
  --text-md:  20px;
  --text-lg:  24px;
  --text-xl:  29px;
  --text-2xl: 35px;
  --text-3xl: 42px;

  --leading-tight: 1.18;
  --leading-snug: 1.3;
  --leading-normal: 1.55;
  --leading-relaxed: 1.75;

  --weight-regular: 400;
  --weight-bold: 700;

  --tracking-tight: -0.01em;
  --tracking-normal: 0;
  --tracking-wide: 0.06em;   /* Latin micro-labels only. Never on Hebrew. */

  --type-display: var(--weight-bold) var(--text-3xl)/var(--leading-tight) var(--font-core);
  --type-title:   var(--weight-bold) var(--text-xl)/var(--leading-tight) var(--font-core);
  --type-heading: var(--weight-bold) var(--text-lg)/var(--leading-snug) var(--font-core);
  --type-subhead: var(--weight-bold) var(--text-md)/var(--leading-snug) var(--font-core);
  --type-body:    var(--weight-regular) var(--text-base)/var(--leading-normal) var(--font-core);
  --type-body-sm: var(--weight-regular) var(--text-sm)/var(--leading-normal) var(--font-core);
  --type-caption: var(--weight-regular) var(--text-xs)/var(--leading-snug) var(--font-core);
  --type-label:   var(--weight-bold) var(--text-sm)/var(--leading-snug) var(--font-core);

  /* ======================================================================
     SPACING — eleven steps on a 4px grid.
     1-4 inside a component, 5-7 between components, 8-10 between regions.
     If a gap needs a value that is not here, the layout is wrong.
     ====================================================================== */
  --space-0: 0;
  --space-px: 1px;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 40px;
  --space-9: 56px;
  --space-10: 72px;

  /* Composed roles — the only place a raw step is reached for twice. */
  --gutter-screen: var(--space-4);
  --gutter-screen-wide: var(--space-7);
  --gap-card: var(--space-4);
  --gap-feed: var(--space-6);
  --gap-section: var(--space-8);
  --pad-card: var(--space-5);

  /* ======================================================================
     RADIUS — six values, each owned by a CLASS OF OBJECT rather than by a
     screen. Choosing radius per component is most of how a product ends up
     with nineteen card treatments.
     ====================================================================== */
  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --radius-pill: 999px;

  --radius-control: var(--radius-pill);
  --radius-input: var(--radius-sm);
  --radius-card: var(--radius-md);
  --radius-media: var(--radius-lg);
  --radius-sheet: var(--radius-xl);
  --radius-avatar: 50%;

  /* ======================================================================
     ELEVATION — tinted with the ink hue, never neutral black: a grey shadow
     on warm paper looks like dirt. Elevation means "this floats", never
     "this is important". If everything is raised, nothing is.
     ====================================================================== */
  --shadow-0: none;
  --shadow-1: 0 1px 2px rgba(44,38,34,.06), 0 4px 16px rgba(44,38,34,.06);
  --shadow-2: 0 2px 4px rgba(44,38,34,.08), 0 12px 28px rgba(44,38,34,.10);
  --shadow-3: 0 8px 16px rgba(44,38,34,.10), 0 28px 60px rgba(44,38,34,.14);
  --shadow-media: 0 2px 6px rgba(44,38,34,.10), 0 18px 40px rgba(44,38,34,.12);
  --shadow-accent: 0 4px 14px rgba(180,86,42,.28);
  --shadow-nav: 0 -1px 12px rgba(44,38,34,.06);

  /* ======================================================================
     MOTION — motion confirms a touch or carries a thing between two places.
     It never decorates and never delays.
     ====================================================================== */
  --speed-fast: 120ms;
  --speed: 160ms;          /* the shipped product's own default. Preserved. */
  --speed-slow: 280ms;
  --ease-out: cubic-bezier(.2,.8,.3,1);
  --ease-in-out: cubic-bezier(.4,0,.2,1);
  --press-scale: 0.97;
  --hover-lift: -2px;

  /* ======================================================================
     LAYOUT — mobile first. 390x844 is the design viewport, 1280 the secondary
     one, and there is exactly ONE breakpoint between them.
     ====================================================================== */
  --bp-wide: 720px;

  --measure-feed: 620px;   /* the vertical feed column */
  --measure-read: 720px;   /* recipe body — Hebrew reads worse past ~72ch */
  --measure-page: 1080px;  /* explore, admin, settings */

  --header-h: 52px;
  --header-h-wide: 60px;
  --tabbar-h: 64px;
  /*
   * The minimum for a control a person AIMS AT. 48 is the design system's
   * target and what most components use; 44 is the floor, and the audit in
   * `docs/42` lists the components that sit between the two and why.
   *
   * A link inside a sentence is deliberately exempt - it takes its height from
   * its line, and padding it would break the paragraph. This comment used to
   * read "nothing interactive is smaller. Ever.", which was not the rule being
   * followed and made the next reader trust a measurement nobody had taken.
   */
  /*
   * TWO FLOORS, AND EACH NOW SAYS WHICH THINGS IT GOVERNS.
   *
   * They sat here as bare numbers and the split between them was history
   * rather than a rule: sixty-nine rules read the first, seventeen the
   * second, and all seventeen were standalone controls that should have been
   * reading the first.
   *
   * The design package settled it on 2026-08-25 - "יומן החלטות - סבב הצפות 1",
   * marked binding - and gave each number a job.
   */

  /* Every standalone control: button, field, tab, rail action, clickable row,
     and the LABEL of a checkbox rather than its box. */
  --tap-min: 48px;

  /* Interactive chips and tags only. The package raised this from 36 to 44 in
     its own `core.css` in the same delivery that set controls at 48: a chip
     sits in a row of siblings and a 48px one breaks the line. */
  --tap-chip: 44px;

  --media-ratio-feed: 4 / 5;
  --media-ratio-feed-wide: 1 / 1;
  --media-ratio-tile: 1 / 1;
  --media-ratio-hero: 4 / 3;

  /* ======================================================================
     LEGACY ALIASES.

     The names the shipped stylesheet already uses, pointed at the semantic
     layer. Nothing new should reference these: they exist so that a screen
     which has not been migrated yet still renders in the new palette, and so
     that the migration can proceed one screen at a time and be bisected.

     Each one is deleted as its last consumer is migrated; the ledger tracks
     which are still alive.
     ====================================================================== */
  --bg: var(--color-bg);
  --surface: var(--color-surface);
  --border: var(--color-border);
  --text: var(--color-text);
  --muted: var(--color-text-muted);
  --accent: var(--color-accent);
  --accent-dark: var(--color-accent-hover);
  --accent-soft: var(--color-accent-soft);
  --danger: var(--color-danger);
  --success: var(--color-success);
  --radius: var(--radius-card);
  /*
   * `--radius-sm` is NOT aliased here.
   *
   * It was, as `--radius-sm: var(--radius-sm)`, which looks like a harmless
   * legacy alias and behaves like a deletion: a custom property cannot read its
   * own previous value, so the declaration resolved to the guaranteed-invalid
   * value and every consumer fell back to the initial one. `--radius-input` is
   * built on it, so EVERY input, select and textarea in the product rendered
   * with square corners instead of 10px - and no visual metric noticed, because
   * a square field is a perfectly plausible design.
   *
   * The name is canonical in the radius block above and the legacy stylesheet
   * used the same name for the same idea, so nothing needs to be aliased: the
   * one declaration serves both.
   */
  --shadow: var(--shadow-1);
}

/* ==========================================================================
   BASE — the smallest possible element layer. Page ground, default type, link
   colour, the focus ring, reduced motion, and the bidi helpers the product
   already depends on. Everything else is a component.
   ========================================================================== */

*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/*
 * The page shell is a column that is at least as tall as the window.
 *
 * Without this the body was exactly as tall as its content, so every short
 * page - sign in, register, an empty Favourites - ended with the footer
 * floating in the middle of the window above 130-165px of bare ground. `main`
 * carried a `min-height: 60vh` that made the gap smaller without removing it,
 * which is the shape of a symptom patch. The column removes the cause:
 * `main` grows, the footer rests at the bottom, and a long page still flows.
 *
 * `dvh` so a phone's collapsing address bar does not leave a strip behind;
 * `vh` first for anything that does not know `dvh`.
 */
body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  color: var(--color-text);
  font: var(--type-body);
  font-family: var(--font-core);
}

/* A link added later must never render browser-blue. */
a { color: var(--color-accent-text); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--color-accent-hover); }
a:visited { color: var(--color-accent-text); }

/* One focus ring for the whole product. Visible, and never removed. */
:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* Mixed Hebrew/English: a number, a price or a handle takes its own direction
   rather than inheriting the paragraph's. Preserved from the product. */
.rh-ltr { direction: ltr; unicode-bidi: isolate; text-align: start; }
.rh-plaintext { unicode-bidi: plaintext; text-align: start; }
.rh-nums { font-variant-numeric: tabular-nums lining-nums; }

/* Nothing may push a phone sideways. Preserved from the product. */
.rh-clamp { min-width: 0; overflow-wrap: anywhere; }

/* Visually hidden, still announced. */
.rh-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

/*
 * THE FEED SURFACE. docs/49 FD-005, docs/53 section "The token layer".
 *
 * A dark media surface is a SPECIALISED surface, not a theme migration - Warm
 * Table stays everywhere else in the product. These exist so no feed component
 * invents a one-off colour, and they are Flayvo values mapped onto the existing
 * scale: nothing here is an Instagram or TikTok brand value.
 */
:root {
  /*
   * WHAT CHANGED, AND WHY IT HAD TO.
   *
   * These were a small dark palette of their own - #14100e, #1d1917, #221d1a -
   * and the immersive Feed painted its whole 100dvh shell with the first of
   * them. That made the application canvas, the navigation, the quiet space and
   * the contextual panels read as one continuous dark theme: a fourth design
   * direction, arrived at by importing the reference product's colour along
   * with its topology.
   *
   * Warm Table is the product's design system. TikTok teaches Flayvo how
   * content is discovered; it does not decide what Flayvo looks like.
   *
   * So darkness is now a MEDIA TREATMENT rather than an application theme, and
   * these values are semantic media roles derived from the existing ramps -
   * `--rh-ink-900` is the same ink Warm Table already uses for
   * `--color-surface-inverse`. No new hue family, no route-only colour.
   */

  /*
   * THE FEED GROUND, AND PRODUCT OVERRULED THE PARAGRAPH ABOVE ON 2026-08-25.
   *
   * The note above records why the immersive Feed stopped painting its shell
   * dark: a whole-shell dark theme read as a fourth design direction, arrived at
   * by importing a reference product's colour along with its topology. That
   * reasoning describes a real risk and is kept rather than deleted.
   *
   * What changed is the AUTHORITY. The design package's handover document -
   * `demo/README.md`, "חבילת העיצוב המלאה (מסירה לקלוד קוד)" - lists the dark
   * feed under MANDATORY, the tier whose rule is "deviation only with a
   * documented TECHNICAL reason", and names the value: "#14100e (לילה מהפלטה),
   * לא שחור". The product's objection was a design judgement rather than a
   * technical constraint, so it does not clear that bar. Product was shown both
   * positions and chose the package.
   *
   * SCOPED TO THE FEED, which is what the package asks and what answers the
   * original objection rather than ignoring it: "הפיד כהה בכל רוחב... שאר
   * המסכים נייר חם." One route is a theatre; the other twenty are paper.
   */
  --fl-feed-ground: #14100e;

  /*
   * THE NIGHT RAMP, VENDORED. `tokens/color.css` in the package.
   *
   * `--fl-feed-ground` above is `--rh-night-900` under a private name, written
   * before the ramp it belongs to was needed. It stays, because forty lines
   * refer to it and renaming a token nothing was wrong with is churn.
   */
  --rh-night-900: #14100e;
  --rh-night-800: #1c1714;
  --rh-night-700: #2a221d;
  --rh-night-600: #3a2f28;

  /* Ember is the night direction's accent and appears NOWHERE else. Clay on
     near-black is mud; this is the ramp the package reaches for instead. */
  --rh-ember-500: #ff5a3d;
  --rh-ember-300: #ff8f78;

  /* LAYER 2 - the media theatre. The only place a dark surface is a surface. */
  --fl-media-ground: var(--color-surface-inverse);   /* behind and around media */
  --fl-media-letterbox: var(--rh-ink-800);           /* the bars a contained photo leaves */

  /* LAYER 3 - the overlay that belongs to the media, not to the application. */
  --fl-media-on: var(--color-text-on-media);
  --fl-media-on-muted: rgb(255 255 255 / 0.80);
  /*
   * The "on" state of a control drawn over a photograph. `--color-accent` is
   * clay-500, a dark ink at 0.26 relative luminance, and measured over a bright
   * dish a liked heart read 2.71:1 against the 3:1 a meaningful graphic needs.
   * `--rh-clay-300` is the same hue further up the SAME ramp - not a new colour.
   */
  --fl-media-on-accent: var(--rh-clay-300);

  /*
   * The older names are kept because 25 rules read them, and they now resolve
   * to the roles above rather than to a private palette. `--fl-feed-bg` is
   * deliberately NOT one of them: nothing may paint an application surface with
   * a media colour, and leaving the name would invite exactly that.
   */
  --fl-feed-on-media: var(--fl-media-on);
  --fl-feed-muted: var(--fl-media-on-muted);
  --fl-feed-surface: var(--color-surface);
  --fl-feed-scrim: rgba(20, 16, 14, 0.55);

  /* C-SOCIAL-3 / C-SOCIAL-4. Added as the components that use them landed,
     which is the rule docs/53 set: a palette declared ahead of its first use is
     how a design system accumulates values nothing renders. */
  --fl-feed-action-bg: var(--color-surface-sunken); /* an icon control on a Flayvo surface */
  --fl-feed-line: var(--color-border);              /* hairlines, Warm Table */
  --fl-feed-sheet: var(--color-surface);            /* the contextual comments panel */

  /*
   * Superseded by `--fl-media-on-accent` above, which is the same idea taken
   * from the clay ramp instead of from a hex nobody else uses. Kept as an alias
   * so the rule that reads it keeps working, and so this file states plainly
   * that #ff9166 was a colour invented outside the system.
   */
  --fl-feed-on-accent: var(--fl-media-on-accent);
}

/*
 * ============================================================================
 * THE NIGHT DIRECTION — A SCOPE, NOT A PAINTED DIV
 * ============================================================================
 *
 * The feed was made dark by painting `.feedshell` and then painting every
 * element inside it that turned out to still be paper. That is a list, and a
 * list is never finished: the design review found the tab bar at 390 (#ffffff,
 * 100% luma, over a 7% ground), the side rail at 1280 (230px of white beside
 * the theatre), the follow pill, the paging arrows and the comment sheet - each
 * of them correct against `--color-surface`, which was still paper.
 *
 * The package does not paint. `demo/screens-discovery.jsx` opens the feed as
 * `<div className="fs-stage" data-direction="night">` and `tokens/directions.css`
 * REDEFINES the semantic layer inside that scope. Every surface that already
 * said `var(--color-surface)` becomes night without being told, including the
 * ones nobody has written yet.
 *
 * So this is vendored whole rather than as the three tokens today's findings
 * needed. A direction adopted in part is a direction that disagrees with itself
 * the first time somebody uses a token from the half that was skipped.
 *
 * ONE CONSEQUENCE WORTH STATING OUT LOUD: `--color-accent` becomes EMBER inside
 * this scope. That is deliberate in the package - clay on near-black is mud -
 * and it means the feed's accent is not the product's accent. It is visible on
 * the tab bar's create mark and the comment sheet's send button. The
 * conformance harness reads the accent from `:root`, which is untouched, so
 * this is a real change that no gate would have reported.
 *
 * WHERE THE SCOPE ENDS is a departure from the demo, and a deliberate one. The
 * demo keeps its rail and mobile top bar OUTSIDE the night stage, as persistent
 * chrome. The design review asked for the opposite in as many words -
 * "הטאבים צריכים לשבת על הכהה" - so `AppLayout` puts the attribute on the
 * fragment that carries the feed AND its navigation.
 */
[data-direction="night"] {
  --color-bg: var(--rh-night-900);
  --color-surface: var(--rh-night-800);
  --color-surface-sunken: #100d0b;
  --color-surface-inverse: var(--rh-paper-50);
  --color-surface-accent: rgba(255, 90, 61, .14);

  --color-text: #f6efe7;
  --color-text-strong: #ffffff;
  --color-text-muted: #a2938a;
  --color-text-on-accent: #1a0d08;
  --color-text-inverse: var(--rh-ink-900);

  --color-border: var(--rh-night-700);
  --color-border-strong: var(--rh-night-600);
  --color-divider: var(--rh-night-700);

  --color-accent: var(--rh-ember-500);
  --color-accent-hover: var(--rh-ember-300);
  --color-accent-press: #e04426;
  --color-accent-soft: rgba(255, 90, 61, .16);
  --color-accent-text: var(--rh-ember-300);
  --color-secondary: #ffc24b;
  --color-secondary-soft: rgba(255, 194, 75, .16);
  --color-secondary-text: #ffd583;

  --color-success: #52b788;
  --color-success-soft: rgba(82, 183, 136, .16);
  --color-success-text: #86d7ae;
  --color-warning: #ffb340;
  --color-warning-soft: rgba(255, 179, 64, .15);
  --color-warning-text: #ffcf85;
  --color-danger: #ff6b5e;
  --color-danger-soft: rgba(255, 107, 94, .15);
  --color-danger-text: #ff9a90;

  --color-focus-ring: #ffc24b;

  /*
   * AND THE TWO MEDIA TOKENS, which the first pass at this block left out.
   *
   * `--media-placeholder` is the ground behind an image that is missing or has
   * not arrived, and under paper it is a pale clay wash - correct there and the
   * brightest thing in a dark theatre. The design review specified the night
   * value by its literal gradient and then said where it already lives: "בחבילה
   * קיים --media-placeholder של כיוון הלילה - להשתמש בו". It does, and this is it.
   */
  --media-placeholder: linear-gradient(140deg, #3a2f28, #14100e);
  --media-tint: saturate(1.06) contrast(1.04) brightness(.98);

  /*
   * AND THE PRIVATE ALIASES, WHICH A SCOPE CANNOT REACH ON ITS OWN.
   *
   * `--fl-feed-sheet: var(--color-surface)` is declared on `:root`, and a custom
   * property is SUBSTITUTED WHERE IT IS DECLARED - so it computed to paper once,
   * at the root, and inherited that frozen value into a scope that had since
   * redefined `--color-surface`. The comment sheet stayed #ffffff over a 7%
   * ground while `.feedrail`, which reads `var(--color-surface)` directly, went
   * night in the same breath.
   *
   * Four of the six `--fl-*` aliases name feed surfaces, which is to say all
   * four live inside the one scope in this product - and every one of them was
   * immune to it. Restated here so the alias survives and re-resolves.
   */
  --fl-feed-surface: var(--color-surface);
  --fl-feed-action-bg: var(--color-surface-sunken);
  --fl-feed-line: var(--color-border);
  --fl-feed-sheet: var(--color-surface);
}
