/* ══════════════════════════════════════════════════════════════════════════
   GlueArrow rail — LAYER 1
   ══════════════════════════════════════════════════════════════════════════

   Structure, rhythm and order. Identical on every storefront, in every repo.
   A merchant cannot change anything in this file, and no customer can see it.

   WHY IT IS PLAIN CSS AND NOT A REACT PACKAGE.
   Four stacks consume this: Vite (Korra), Next (glueArrow_web), Jinja
   (glueArrow_cloud) and static storefront HTML. Only two of them can import a
   React component. All four can link a stylesheet, so the rail is the layer
   that has to be framework-free. React primitives sit on top of it and are
   optional.

   WHAT DOES NOT BELONG HERE.
   Any colour a storefront may own. Those are the eight custom properties in
   skin.css, and nothing else in any GlueArrow codebase may name a colour.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Type ────────────────────────────────────────────────────────────────
     TAKEN FROM glueArrow_web, WHICH ALREADY SOLVED THIS PROPERLY.
     `src/lib/network-type.ts` is the source. The first version of this file
     shipped six FIXED px steps, which is the exact bug web had already fixed
     and documented: sizes that look right on desktop are far too big on a
     phone — an article H1 floored at 32px and body at 19px, against the
     BBC-mobile target of about 22px and 16px. A fixed scale would have put
     that bug back into every repo that adopted this kit.

     So every step is clamp(MIN, FLUID, MAX):
       MIN   what it is on a small phone. This is the number that matters.
       FLUID how it grows with the viewport.
       MAX   the desktop ceiling.

     AND THE STEPS ARE NAMED BY ROLE, NOT BY SIZE. You pick `dek` or `meta`,
     not `lg`. Size names go stale the moment the scale is retuned, and they
     tell the next person nothing about when to use one.

     A console reads at --ga-text-body-sm; an article reads at --ga-text-body.
     One scale serves both. */
  --ga-text-h1:      clamp(23px, 4.6vw, 44px);
  --ga-text-h2:      clamp(21px, 3.4vw, 34px);
  --ga-text-h3:      clamp(18px, 2.4vw, 24px);
  --ga-text-h4:      clamp(16px, 1.9vw, 20px);
  --ga-text-dek:     clamp(17px, 1.9vw, 21px);
  --ga-text-quote:   clamp(19px, 2.6vw, 26px);
  --ga-text-body:    clamp(16px, 1.4vw, 17px);
  --ga-text-body-sm: clamp(14px, 1.3vw, 15px);
  --ga-text-meta:    clamp(12px, 1.1vw, 13px);
  --ga-text-label:   clamp(11px, 1.1vw, 12px);

  /* Line height belongs to the role, not to the element. Web's pairing:
     tight for big headlines, snug for card titles, body for running text. */
  --ga-leading-tight: 1.1;
  --ga-leading-snug:  1.25;
  --ga-leading-dek:   1.5;
  --ga-leading:       1.6;

  /* Vertical rhythm scales with the viewport for the same reason type does. */
  --ga-para-gap:  clamp(16px, 2.4vw, 22px);
  --ga-block-gap: clamp(20px, 3vw, 28px);

  --ga-tracking-tight: -0.02em;
  --ga-tracking:        0;

  /* Four weights. Anything between them is a rounding decision a browser
     makes for you, differently on each platform. */
  --ga-weight-normal: 400;
  --ga-weight-medium: 500;
  --ga-weight-semi:   600;
  --ga-weight-bold:   700;

  /* ── Space ───────────────────────────────────────────────────────────── */
  --ga-space-1:  4px;
  --ga-space-2:  8px;
  --ga-space-3: 12px;
  --ga-space-4: 16px;
  --ga-space-5: 24px;
  --ga-space-6: 32px;
  --ga-space-7: 48px;
  --ga-space-8: 64px;

  /* ── Shape ───────────────────────────────────────────────────────────────
     Scaled by the skin's --ga-radius-scale, so a storefront can read squarer
     or rounder without inventing its own radii. 0.5 is square-ish, 1.5 soft. */
  --ga-radius-sm:   calc(8px  * var(--ga-radius-scale, 1));
  --ga-radius:      calc(12px * var(--ga-radius-scale, 1));
  --ga-radius-lg:   calc(16px * var(--ga-radius-scale, 1));
  --ga-radius-pill: 999px;

  /* ── Elevation. Three, and they mean three different distances. ───────── */
  --ga-shadow-sm: 0 1px 4px rgba(0, 0, 0, .04);
  --ga-shadow:    0 2px 12px rgba(0, 0, 0, .06);
  --ga-shadow-lg: 0 12px 40px rgba(0, 0, 0, .1);
  /* Cast UPWARD, for a sheet that rises from the bottom edge. --ga-shadow-lg
     points down and reads as a panel hanging off the top of the screen, which
     is the opposite of what a bottom sheet is. */
  --ga-shadow-sheet: 0 -14px 34px rgba(0, 0, 0, .18);

  /* ── Status. THREE MEANINGS, AND THEY ARE NOT BRAND COLOURS. ─────────────
     These live in the rail, not the skin, because a storefront does not get to
     choose what "failed" looks like. Red is red on every GlueArrow surface, or
     a person who moves between two of them has to relearn the alphabet.

     Each has a wash for the pill it sits in. They are flat rather than derived
     from the accent, because the whole point is that they do not move with the
     brand.

     Contrast against #ffffff, measured, for the ink values:
       good  #146c43   5.1:1
       warn  #8a5a00   4.8:1
       bad   #b02a1e   5.1:1
     All clear the 4.5:1 that small text needs. The wash values are backgrounds
     only and never carry text of their own. */
  --ga-good:      #146c43;
  --ga-good-wash: #e6f4ec;
  --ga-warn:      #8a5a00;
  --ga-warn-wash: #fdf1dc;
  --ga-bad:       #b02a1e;
  --ga-bad-wash:  #fdeceb;
  /* Text that sits ON a status colour, for the one control that fills itself
     with one: a danger button. White measures 5.1:1 on --ga-bad. It is a token
     rather than a literal because a pattern may not name a colour, and that
     rule is what keeps every pattern re-skinnable. */
  --ga-bad-ink:   #ffffff;

  /* ── Pattern knobs ───────────────────────────────────────────────────────
     Defaults a CALLER may override on one element, not part of the skin. A
     storefront does not set these; a page does, when one grid of cards wants
     a different shape from another. They are declared here because the guard
     in test/rail.test.js refuses a pattern that reads a token nothing defines
     — including one with a fallback, which is right: a fallback hides a typo
     until someone looks at the screen. */
  --ga-card-ratio:       4 / 3;
  --ga-card-min:         240px;
  --ga-card-thumb:       96px;
  --ga-card-thumb-phone: 80px;
  --ga-stat-min:         150px;

  /* ── Controls ────────────────────────────────────────────────────────────
     --ga-touch-min is the floor for anything a finger presses. It is 44px
     because that is the smallest reliably hittable target, not because it
     looks right. Never set a button shorter than this on a phone. */
  --ga-control-h:   38px;
  --ga-touch-min:   44px;
  --ga-nav-h:       60px;
  /* A wordmark's height is a property of the ARTWORK, not of the bar. Some
     read at 22px; rentnzoom's leading R is squeezed below 34. A storefront
     shipping its own wordmark sets this and nothing else. */
  --ga-wordmark-h:  22px;
  /* The status-bar inset, for a bar that has to sit under a notch. 0 here
     because a layout that measures the header with its own variable would be
     out by the inset otherwise: the bar grows, its page padding does not. A
     storefront that owns both sets this to env(safe-area-inset-top, 0px). */
  --ga-safe-top:    0px;
  /* Chrome that shows the page through itself. A translucent --ga-surface is
     only half of it; the blur is this. none by default, because a
     backdrop-filter creates a compositing layer even when it does nothing. */
  --ga-head-filter: none;
  /* The page column the bar's contents line up with, when a storefront has one.
     100% means full-bleed, which is what an app console wants. */
  --ga-head-max:    100%;
  --ga-nav-h-phone: 52px;
  /* The tab strip that some verticals pin under the header on a phone. */
  --ga-subnav-h:    44px;
  --ga-side-w:      240px;
  --ga-side-w-narrow: 80px;
  --ga-page-max:    1240px;

  /* ── Motion ────────────────────────────────────────────────────────────── */
  --ga-fast: .12s;
  --ga-base: .2s;
  --ga-ease: cubic-bezier(.2, 0, 0, 1);

  /* ── Order ───────────────────────────────────────────────────────────────
     Mirrors Korra's lib/zLayers.js exactly. Keep the two in step; the guard
     in test/rail.test.js pins these numbers.

     The numbers start high on purpose. Leaflet paints its own panes and
     controls between 400 and 1000 and we do not own that stylesheet, so
     anything that must appear over a map has to clear 1000. A tidy 0-1000
     scale would quietly put every floating surface back under the map. That
     bug has been shipped twice.

     A surface outranks whatever it explains or interrupts. A scrim sits
     exactly one below the thing it dims. */
  --ga-z-base:        0;
  --ga-z-raised:      10;
  --ga-z-sticky:      50;
  /* Leaflet owns 400-1000. Nothing of ours belongs in there. */
  --ga-z-map-control: 1100;
  /* A tab strip pinned under the header on a phone. Above the map furniture,
     below the header it hangs from. rentnzoom's .rz-top-tabs already sits
     here; zLayers.js never named the band, so this is the kit naming it. */
  --ga-z-subnav:      1150;
  /* The player's floating tiers (PATTERNS.md §15). The bottom bar itself
     rides --ga-z-subnav - it IS the phone tab strip. The orb floats over
     content, the TV picture-in-picture over the orb, and both stay under the
     header and every scrim. zLayers.js gains playerOrb/playerPip in the same
     change that adopts the pattern in Korra, or the two drift and the z-band
     guard is a lie. */
  --ga-z-player-orb:  1160;
  --ga-z-player-pip:  1170;
  --ga-z-app-bar:     1200;
  --ga-z-drawer-scrim: 1299;
  --ga-z-drawer:      1300;
  --ga-z-dropdown:    1400;
  --ga-z-modal-scrim: 1499;
  --ga-z-modal:       1500;
  --ga-z-sheet-over:  1600;
  --ga-z-toast:       1700;
  --ga-z-critical:    1800;

  /* ── The player's rhythm (PATTERNS.md §15) ──────────────────────────────
     Sizes and timing every surface's player shares. Colours are NOT here -
     the media wash derives from the skin's accent inside the pattern. */
  --ga-player-nav-h: 75px;      /* the bar, both layers                      */
  --ga-player-dock: 64px;       /* the centre dock button                    */
  --ga-player-orb: 56px;        /* the floating artwork disc                 */
  --ga-player-fade: 500ms;      /* the nav ⇄ media crossfade                 */
  --ga-player-scrub: 3px;       /* the honest hairline (estimate)            */
  --ga-player-scrub-seek: 6px;  /* a real timeline grows a touch target      */
  --ga-player-scrub-drag: 10px; /* and grows again under the finger          */
}

/* ── Base ──────────────────────────────────────────────────────────────────
   Deliberately small. The rail sets rhythm, not appearance. */

.ga-root {
  font-family: var(--ga-font);
  font-size: var(--ga-text-body-sm);
  line-height: var(--ga-leading);
  color: var(--ga-ink);
  background: var(--ga-ground);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

/* Numbers in a column line up or they cannot be compared. Money, counts,
   dates and serials all take this. */
.ga-num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* ── Focus ─────────────────────────────────────────────────────────────────
   The one place the accent is not optional. A keyboard user has no hover and
   no pointer, so this ring is their entire sense of place. Never remove it,
   and never replace it with an outline colour that fails contrast. */
.ga-root :focus-visible {
  outline: 2px solid var(--ga-accent);
  outline-offset: 2px;
  border-radius: var(--ga-radius-sm);
}

/* ── Reduced motion ───────────────────────────────────────────────────────
   A person who asked their operating system to stop animations meant it. */
@media (prefers-reduced-motion: reduce) {
  .ga-root *,
  .ga-root *::before,
  .ga-root *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── Phone ─────────────────────────────────────────────────────────────────
   One breakpoint for the chrome, at 860px. Patterns may add their own, but
   the header collapse and the sidebar drawer both happen here so they cannot
   disagree with each other.

   860 IS NOT A ROUND NUMBER, WHICH IS WHY IT IS THE RIGHT ONE. This kit shipped
   with 900, which I chose. Korra arrived at 860 by fixing a real screen:
   rental.css hides its sidebar at 1024px, so collapsing the tabs anywhere above
   860 left "a dead nav gap on tablets/small laptops" — the comment forbidding it
   is still in that file. At 900 the kit would have re-opened a 40px band with no
   visible nav on the flagship storefront. The number taken from the application
   wins over the number taken from a round figure. */
@media (max-width: 860px) {
  :root { --ga-nav-h: var(--ga-nav-h-phone); }
}
