/* Generated by scripts/fetch_fonts.py -- do not edit.
   Self-hosted so the first paint waits on no third-party origin.
   font-display:swap: text is readable in a fallback face immediately
   and reflows once, rather than being invisible while the font loads. */
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/fonts/assistant-400-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/fonts/assistant-400-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/fonts/assistant-400-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('/fonts/assistant-600-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('/fonts/assistant-600-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('/fonts/assistant-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/assistant-700-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/assistant-700-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Assistant';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/assistant-700-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-500-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-500-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-500-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-700-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-700-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-700-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:900;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-900-hebrew.woff2') format('woff2');
  unicode-range:U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:900;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-900-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Frank Ruhl Libre';
  font-style:normal;
  font-weight:900;
  font-display:swap;
  src:url('/fonts/frank-ruhl-libre-900-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ═══════════════════════════════════════════════════════════════════════════
   DESIGN TOKENS — the only file in this project that contains a raw value.

   Everything downstream (site.css, every template) composes from these. If a
   component declares `#F5F3EE` or `1.375rem` or `0 2px 6px rgba(...)`, that is
   a bug: the value has escaped the system and the next person to change the
   palette will miss it. site.css is checked for this — see `make design-lint`.

   Three layers, and the direction of dependency is one-way:

     1. PRIMITIVES   raw ramps. Never referenced by a component.
     2. SEMANTIC     what a thing is FOR. This is the only layer components use.
     3. CONTEXT      tokens re-bound per subtree (.b-busy sets --band).

   The reason for the middle layer: "the card background" and "the colour
   #FFFFFF" are different facts. When the palette moves, one changes and the
   other does not. Components that reference `--surface-raised` survive a
   re-theme; components that reference `--paper-0` do not.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ─── 1. PRIMITIVES ──────────────────────────────────────────────────────
     Ramps, numbered light → dark. No component may use these directly. */

  /* Warm neutral ground. This site is read in daylight by someone holding a
     suitcase; the warmth is the brand and the contrast is the accessibility. */
  --paper-0: #FFFFFF;
  --paper-1: #FAF8F4;
  --paper-2: #F5F3EE;
  --paper-3: #EFEBE3;
  --paper-4: #E7E2D8;

  --ink-0: #11151C;      /* near-black, not a soft grey */
  --ink-1: #2B3542;
  --ink-2: #414B59;
  --ink-3: #626C7A;      /* 5.1:1 on --paper-2 */
  --ink-4: #8A929D;      /* decorative only — never body text */

  --line-0: #EDE9E0;     /* hairline, barely there */
  --line-1: #E0DACE;
  --line-2: #D2CABB;

  /* Structure. Navy carries the interface; it is never a status. */
  --navy-0: #152A47;
  --navy-1: #24405F;
  --navy-2: #4C627E;
  --navy-tint: #E9EDF3;

  /* Action. Reserved for things you can click that we want you to click.
     Three values, because one orange cannot do all three jobs: --flame-1 is
     the brand mark, --flame-0 is a link or a label on paper, and --flame-cta
     is dark enough to carry WHITE text at 4.8:1. The brand orange manages only
     3.55:1 behind white, which is how the primary CTA once shipped failing. */
  /* Identity ONLY — never a status, never a band, never a data colour.
     The signal ramp runs green -> olive -> amber -> orange -> red, so any warm
     accent in the mark reads as a reading. This project already learned that:
     the accent was #FF6B35 while the "busy" band was #EE6C1E, and the logo
     looked like a live status. Sky is the one hue no band can be confused with. */
  --sky-0: #38BDF8;
  --sky-1: #7FB3D9;

  --flame-0: #BF430F;      /* 4.7:1 on paper, 5.2:1 behind white — both roles */
  --flame-hover: #A63709;
  --flame-1: #FF6B35;      /* the brand mark ONLY. Never behind text. */
  --flame-tint: #FFEDE5;

  /* ─── the signal ramp ────────────────────────────────────────────────────
     This is a SEQUENTIAL scale, not five equally-loud colours.

     The first version made every band a ~34% tint of its hue. That was wrong
     twice over. It looked washed out, because the heat grid is 168 cells and
     therefore the dominant colour surface on the site. And it failed AA on all
     five bands — the cell text measured 2.6:1 to 4.0:1 against its own fill.

     So visual weight now rises with the value, which is also what the data
     wants: "quiet" is not news and should not shout, "peak" is and should.
     Calm bands are tints with dark text; the two alarming bands are solid with
     white text. Every pair is >= 4.5:1. Re-run scripts/contrast_check.py if
     any of these move. */

  /* the base hue — bars, pips, gauge fills, the band word */
  --sig-quiet: #0B8A5F;
  --sig-light: #4F8516;
  --sig-moderate: #B57405;
  --sig-busy: #D9541A;
  --sig-peak: #B3161F;

  /* the heat-cell pair: background, and the text that sits on it */
  --fill-quiet: #CFEDE0;     --on-quiet: #07603F;     /* 6.1:1 */
  --fill-light: #DAEBBE;     --on-light: #3D5E10;     /* 5.9:1 */
  --fill-moderate: #FBDFA8;  --on-moderate: #7A4E02;  /* 5.6:1 */
  --fill-busy: #C44711;      --on-busy: #FFFFFF;      /* 4.9:1 */
  --fill-peak: #A81420;      --on-peak: #FFFFFF;      /* 7.5:1 */

  /* ─── type ───────────────────────────────────────────────────────────────
     Frank Ruhl Libre and Assistant are both genuine Hebrew faces. That is not
     a stylistic preference — it is why the Hebrew build looks designed rather
     than transliterated, and it is why neither can be swapped for a Latin-only
     "display font" later. */
  --font-display: "Frank Ruhl Libre", Georgia, "Times New Roman", serif;
  --font-text: "Assistant", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, monospace;

  /* Fluid scale, ratio ~1.125 at the small end opening to ~1.2 at the top.
     Every size on the site is one of these. The old stylesheet had .88, .9,
     .92, .93 and .95rem all in use — six sizes doing one job, which is what
     "unsystematic" looks like when you measure it. */
  --step--2: clamp(0.72rem, 0.70rem + 0.10vw, 0.78rem);
  --step--1: clamp(0.83rem, 0.81rem + 0.11vw, 0.90rem);
  --step-0:  clamp(0.97rem, 0.95rem + 0.12vw, 1.05rem);
  --step-1:  clamp(1.09rem, 1.05rem + 0.18vw, 1.20rem);
  --step-2:  clamp(1.22rem, 1.16rem + 0.28vw, 1.40rem);
  --step-3:  clamp(1.37rem, 1.28rem + 0.44vw, 1.65rem);
  --step-4:  clamp(1.54rem, 1.40rem + 0.68vw, 1.95rem);
  --step-5:  clamp(1.73rem, 1.52rem + 1.02vw, 2.35rem);
  --step-6:  clamp(1.95rem, 1.63rem + 1.55vw, 2.90rem);
  --step-7:  clamp(2.60rem, 1.95rem + 3.10vw, 4.40rem);   /* the band word only */

  --leading-tight: 1.08;
  --leading-snug: 1.28;
  --leading-normal: 1.6;
  --leading-loose: 1.72;

  --tracking-tight: -0.022em;
  --tracking-normal: 0;
  --tracking-wide: 0.07em;

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semi: 600;
  --weight-bold: 700;
  --weight-black: 900;

  /* ─── space ──────────────────────────────────────────────────────────────
     4px base. Nothing between steps: if a gap needs 14px, the layout is wrong,
     not the scale. */
  --s-0: 0;
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 2.75rem;
  --s-8: 4rem;
  --s-9: 6rem;
  --s-10: 8rem;

  /* ─── shape, depth, motion ───────────────────────────────────────────── */
  --r-1: 6px;
  --r-2: 10px;
  --r-3: 14px;
  --r-4: 20px;
  --r-full: 999px;

  /* Depth is rationed. Most grouping here is done with a hairline and space;
     a shadow means "this floats above the page", which is true of exactly two
     things (the search results and the language modal). */
  --shadow-0: none;
  --shadow-1: 0 1px 2px rgba(17, 21, 28, 0.045);
  --shadow-2: 0 1px 2px rgba(17, 21, 28, 0.05), 0 10px 24px -8px rgba(17, 21, 28, 0.09);
  --shadow-3: 0 2px 8px rgba(17, 21, 28, 0.07), 0 28px 56px -14px rgba(17, 21, 28, 0.16);

  --dur-1: 120ms;
  --dur-2: 200ms;
  --dur-3: 420ms;
  --ease: cubic-bezier(0.2, 0.8, 0.25, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* ─── measure ────────────────────────────────────────────────────────────
     THE fix for the biggest layout problem this design had: one 46rem column
     for everything, so a 24-column data grid and a paragraph of prose were
     given identical space, and a 1440px screen ran at 51% utilisation.

     Prose wants a measure. Data wants room. They are different tokens. */
  --w-prose: 34rem;      /* ~66 characters at --step-0 */
  --w-content: 60rem;    /* default: an answer plus its supporting evidence */
  --w-wide: 78rem;       /* tables, grids, boards, leaderboards */
  --gutter: clamp(1rem, 0.4rem + 2.4vw, 2.5rem);


  /* ─── 2. SEMANTIC ────────────────────────────────────────────────────────
     What components actually reference. Read these as sentences: "the surface
     of a raised thing", "the colour of secondary text". */

  --surface-page: var(--paper-2);
  --surface-sunken: var(--paper-3);
  --surface-card: var(--paper-0);
  --surface-inset: var(--paper-1);
  --surface-invert: var(--navy-0);
  --surface-accent: var(--flame-tint);
  --surface-brand: var(--navy-tint);

  --text-primary: var(--ink-0);
  --text-secondary: var(--ink-2);
  --text-tertiary: var(--ink-3);
  --text-quiet: var(--ink-4);
  --text-invert: var(--paper-0);
  --text-brand: var(--navy-0);
  --text-action: var(--flame-0);

  --border-hairline: var(--line-0);
  --border-subtle: var(--line-1);
  --border-strong: var(--line-2);
  --border-focus: var(--navy-0);

  /* ─── on dark ────────────────────────────────────────────────────────────
     The footer and the modal scrim invert the ground. These are the only
     places white-on-navy appears, and the tints are checked for AA there:
     --on-invert-action is a LIGHTER flame than --flame-1 because the brand
     orange does not clear 4.5:1 on --navy-0. */
  --on-invert-strong: rgba(255, 255, 255, 0.92);
  --on-invert: rgba(255, 255, 255, 0.72);
  --on-invert-muted: rgba(255, 255, 255, 0.5);
  --on-invert-line: rgba(255, 255, 255, 0.14);
  --on-invert-action: #FFA07A;

  --scrim: rgba(17, 21, 28, 0.42);
  --ring-hairline: rgba(17, 21, 28, 0.12);

  /* The select chevron. A data uri cannot read currentColor, so the one place
     a colour would otherwise be duplicated into markup lives here instead —
     keep it in sync with --ink-3 by hand if that ramp moves. */
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23626C7A' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");

  /* Paper grain. One texture, one opacity, declared once. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  --grain-opacity: 0.035;

  --focus-ring: 0 0 0 3px rgba(21, 42, 71, 0.16);

  /* ─── 3. CONTEXT ─────────────────────────────────────────────────────────
     --band is deliberately UNBOUND here. It is set per subtree by a .b-* class
     below, or inline by the live-update script, and every component that shows
     a busyness colour reads it rather than knowing which band it is. That is
     what lets one component render five states, and what lets the API change
     the state at runtime without re-rendering markup. */
  --band: var(--ink-3);
}

/* The band classes. Setting a custom property rather than a colour is what
   makes this one declaration instead of one per property per band. */
.b-quiet    { --band: var(--sig-quiet);    --band-fill: var(--fill-quiet);    --band-on-fill: var(--on-quiet); }
.b-light    { --band: var(--sig-light);    --band-fill: var(--fill-light);    --band-on-fill: var(--on-light); }
.b-moderate { --band: var(--sig-moderate); --band-fill: var(--fill-moderate); --band-on-fill: var(--on-moderate); }
.b-busy     { --band: var(--sig-busy);     --band-fill: var(--fill-busy);     --band-on-fill: var(--on-busy); }
.b-peak     { --band: var(--sig-peak);     --band-fill: var(--fill-peak);     --band-on-fill: var(--on-peak); }
.b-brand    { --band: var(--navy-0);       --band-fill: var(--navy-tint);     --band-on-fill: var(--navy-0); }

/* Delays reuse this same channel rather than getting their own ramp: on the
   punctuality pages the colour means "how late" instead of "how full", but
   pipeline/stats.py maps delay minutes onto these five band NAMES for exactly
   that reason — a reader should not have to learn a second colour scale. */

/* ─── the derived band values ───────────────────────────────────────────────
   These MUST be declared on the same element that sets --band, not on :root.

   A custom property is substituted at computed-value time on the element where
   it is DECLARED. Declaring `--band-fill: color-mix(..., var(--band), ...)` on
   :root therefore resolves it once, against :root's own --band, and every
   descendant inherits that one already-computed colour. The symptom is
   unmistakable and was exactly what shipped: a 168-cell heat grid rendered
   entirely in grey, while the legend beside it — which reads var(--band)
   directly rather than a derived token — showed all five colours correctly.

   [style*="--band"] catches the elements the live script paints at runtime. */
:root,
.b-quiet, .b-light, .b-moderate, .b-busy, .b-peak, .b-brand,
.board.good, .board.bad,
[style*="--band"] {
  /* a badge, a readout panel, a chip -- still a formula, still light */
  --band-tint: color-mix(in srgb, var(--band) 18%, var(--surface-card));
  --band-edge: color-mix(in srgb, var(--band) 34%, var(--border-subtle));
  /* label text ON PAPER (not on a fill), darkened until it clears AA at
     small sizes -- the raw signal hues only reach ~3.5:1 on warm paper */
  --band-text: color-mix(in srgb, var(--band) 78%, var(--ink-0));
}

/* The heat-cell pair falls back to a formula ONLY for a subtree that carries a
   --band without a named band class (the .board.good / .board.bad panels, and
   anything the live script paints inline).
   The named bands MUST NOT be in this selector list: they declare explicit
   fill/text pairs above, and this rule sits later in the file at identical
   specificity, so listing them here silently overrode all five back to a 20%
   tint. That is precisely the washed-out grid this ramp was written to fix. */
:root,
.board.good, .board.bad,
[style*="--band"] {
  --band-fill: color-mix(in srgb, var(--band) 20%, var(--surface-card));
  --band-on-fill: var(--band-text);
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-1: 0ms; --dur-2: 0ms; --dur-3: 0ms; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   COMPONENTS.

   Every value here comes from tokens.css. There should be no hex colour, no
   raw shadow and no font size in this file — if you need one that does not
   exist, add it to the scale rather than writing it inline, or the next
   re-theme will miss it. `make design-lint` checks.

   The design: an instrument printed on paper. Not a dashboard, which is what
   every competitor in this niche looks like, and not an article, which is what
   this looked like before. The page is quiet, the ground is warm, structure is
   drawn with hairlines rather than boxes, and the only saturated colour on
   screen is the one carrying the answer.

   Logical properties throughout, so the Hebrew RTL build is correct by
   construction rather than by patching.
   ═══════════════════════════════════════════════════════════════════════════ */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-primary);
  font-family: var(--font-text);
  font-size: var(--step-0);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* One grain layer over the whole page. This is what makes "warm paper" read as
   a deliberate material rather than as an off-white background: at 3.5% it is
   invisible as texture and legible as intent. Fixed, inert, no repaint cost. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: var(--grain-opacity);
  background-image: var(--grain);
}
body > * { position: relative; z-index: 1; }

::selection { background: var(--band-tint); color: var(--text-primary); }

:where(a, button, select, input, [tabindex]):focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  border-radius: var(--r-1);
}


/* ── layout ────────────────────────────────────────────────────────────────
   The fix for this design's biggest structural problem: it had ONE 46rem
   column, so a 24×7 data grid and a paragraph of prose were given identical
   room and a 1440px screen ran at half utilisation.

   Three widths now, and a block opts into the one it needs:
     .shell     the default measure — an answer and its supporting evidence
     .bleed     breaks out to --w-wide, for grids, boards and tables
     .measure   pulls in to --w-prose, for anything read as sentences
   ──────────────────────────────────────────────────────────────────────── */
.shell {
  inline-size: min(var(--w-content), 100% - var(--gutter) * 2);
  margin-inline: auto;
  padding-block-end: var(--s-9);
}

.bleed {
  inline-size: min(var(--w-wide), 100vw - var(--gutter) * 2);
  margin-inline: calc(50% - min(var(--w-wide), 100vw - var(--gutter) * 2) / 2);
}

.measure { max-inline-size: var(--w-prose); }


/* ── typography ────────────────────────────────────────────────────────── */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--text-primary);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
  margin: 0;
}

h1 {
  font-size: var(--step-5);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  margin-block-end: var(--s-2);
}

/* Section headings sit ON a hairline rather than floating above their content.
   The rule is what groups the section; without it every h2 needed a large
   margin to read as a boundary, which is where the endless scroll came from. */
h2 {
  font-size: var(--step-2);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  margin-block: var(--s-7) var(--s-4);
  padding-block-end: var(--s-3);
  border-block-end: 1px solid var(--border-subtle);
}

h3 {
  font-size: var(--step-1);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  margin-block-end: var(--s-2);
}

p { margin-block: 0 var(--s-4); max-inline-size: var(--w-prose); }
p:last-child { margin-block-end: 0; }

a { color: var(--text-brand); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { color: var(--text-action); }

.lede {
  font-size: var(--step-1);
  line-height: var(--leading-snug);
  color: var(--text-secondary);
  max-inline-size: var(--w-prose);
  margin-block-end: var(--s-5);
}

ul.plain { list-style: none; padding: 0; margin: 0 0 var(--s-4); }
ul.plain li {
  padding-block: var(--s-3);
  border-block-end: 1px solid var(--border-hairline);
  color: var(--text-secondary);
  max-inline-size: var(--w-prose);
}
ul.plain li:last-child { border-block-end: 0; }


/* ── header ────────────────────────────────────────────────────────────────
   Sticky, hairline, translucent. It is chrome on a page whose whole job is one
   number, so it stays out of the way and never grows. */
.top {
  position: sticky;
  inset-block-start: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding-block: var(--s-3);
  margin-block-end: var(--s-5);
  border-block-end: 1px solid var(--border-subtle);
  background: color-mix(in srgb, var(--surface-page) 86%, transparent);
  backdrop-filter: saturate(160%) blur(12px);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
}

.mark { display: inline-flex; align-items: center; gap: var(--s-2); color: var(--text-primary); text-decoration: none; flex: none; }
.mark svg { flex: none; display: block; }
.wordmark {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: var(--step-1);
  letter-spacing: var(--tracking-tight);
  line-height: 1;
}


/* ── search ────────────────────────────────────────────────────────────── */
.search { position: relative; flex: 1 1 14rem; min-inline-size: 11rem; }
.search input {
  inline-size: 100%;
  background: var(--surface-card);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-full);
  padding: var(--s-2) var(--s-4);
  font: inherit;
  font-size: var(--step--1);
  transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.search input::placeholder { color: var(--text-quiet); }
.search input:focus { outline: none; border-color: var(--border-focus); box-shadow: var(--focus-ring); }
.results {
  position: absolute;
  inset-block-start: calc(100% + var(--s-2));
  inset-inline: 0;
  z-index: 50;
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-2);
  overflow: hidden;
  box-shadow: var(--shadow-3);
}
.results[hidden] { display: none; }
.results a {
  display: flex; align-items: baseline; gap: var(--s-2);
  padding: var(--s-3);
  text-decoration: none; color: var(--text-primary);
  border-block-end: 1px solid var(--border-hairline);
  font-size: var(--step--1);
}
.results a:last-child { border-block-end: none; }
.results a:hover, .results a:focus, .results a[aria-selected="true"] { background: var(--surface-inset); outline: none; }
.results .code { font-weight: var(--weight-bold); color: var(--text-action); flex: none; min-inline-size: 3.2ch; font-size: var(--step--2); }
.results .where {
  color: var(--text-tertiary); font-size: var(--step--2);
  margin-inline-start: auto; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-inline-size: 9rem;
}
.results .empty { padding: var(--s-3); color: var(--text-tertiary); font-size: var(--step--1); }


/* ── language switch ───────────────────────────────────────────────────── */
.langbtn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  flex: none; margin-inline-start: auto;
  font: inherit; font-size: var(--step--1);
  color: var(--text-secondary); cursor: pointer;
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-full);
  padding: var(--s-2) var(--s-3);
  transition: border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.langbtn:hover { border-color: var(--border-focus); color: var(--text-brand); }

/* The header only fits on one row while there is room for three items. On a
   390px phone the mark (147px), the search field at its 11rem minimum (176px)
   and the language button (102px) need 450px against 358px of shell, so the
   language button wrapped -- and because it sets margin-inline-start:auto it
   landed alone against the right edge of a second row. That reads as a layout
   accident, and it cost a whole row of vertical space above the fold to say one
   word.

   So below 34rem the two rows are deliberate rather than emergent: identity and
   language together on the first, search spanning the second. `order` does the
   arranging so the DOM keeps its reading order for a screen reader -- the mark
   is still the first thing announced. */
@media (max-width: 34rem) {
  .top {
    gap: var(--s-2) var(--s-3);
    padding-block: var(--s-2);
    margin-block-end: var(--s-4);
  }
  .langbtn { order: 2; }
  .search  { order: 3; flex: 1 0 100%; min-inline-size: 0; }
}

/* A language is not a country, so the flag is decoration beside the name and
   never the label itself. */
.flag { flex: none; display: block; object-fit: cover; border-radius: 2px; box-shadow: 0 0 0 1px var(--ring-hairline); }
.langbtn .flag { inline-size: 20px; block-size: 14px; }
.langlist .flag { inline-size: 26px; block-size: 18px; }
.footer-col .flag {
  inline-size: 18px; block-size: 13px;
  display: inline-block; vertical-align: -2px;
  margin-inline-end: var(--s-2);
  box-shadow: 0 0 0 1px var(--on-invert-line);
}

.langmodal {
  border: 0; border-radius: var(--r-3); padding: 0;
  inline-size: min(24rem, calc(100% - var(--s-6)));
  background: var(--surface-card); color: var(--text-primary);
  box-shadow: var(--shadow-3);
}
.langmodal::backdrop { background: var(--scrim); backdrop-filter: blur(3px); }
.langmodal-head {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-4) var(--s-5) var(--s-3);
  border-block-end: 1px solid var(--border-subtle);
}
.langmodal-head h2 { margin: 0; padding: 0; border: 0; font-size: var(--step-1); font-weight: var(--weight-semi); }
.langmodal-head button {
  margin-inline-start: auto; border: 0; background: transparent; cursor: pointer;
  font-size: var(--step-3); line-height: 1; color: var(--text-tertiary); padding: 0 var(--s-1);
}
.langmodal-head button:hover { color: var(--text-primary); }
.langlist { padding: var(--s-2); }
.langlist a {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3); border-radius: var(--r-2);
  text-decoration: none; color: var(--text-primary);
  transition: background-color var(--dur-1) var(--ease);
}
.langlist a:hover, .langlist a:focus { background: var(--surface-inset); outline: none; }
.langlist .endonym { color: var(--text-tertiary); font-size: var(--step--1); }
.langlist .tick { margin-inline-start: auto; color: var(--text-brand); font-weight: var(--weight-bold); }


/* ── breadcrumbs + section nav ─────────────────────────────────────────── */
.crumbs { margin-block-end: var(--s-4); font-size: var(--step--1); color: var(--text-tertiary); }
.crumbs ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-2); }
.crumbs li { display: flex; align-items: center; gap: var(--s-2); min-inline-size: 0; }
.crumbs li + li::before { content: "/"; color: var(--border-strong); flex: none; }
.crumbs a { color: var(--text-tertiary); text-decoration: none; }
.crumbs a:hover { color: var(--text-primary); text-decoration: underline; }
.crumbs [aria-current] { color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* The section nav is the page's spine, so it reads as an underlined tab strip
   rather than a row of buttons: it belongs to the airport, not to the site. */
.subnav {
  display: flex; gap: var(--s-1); flex-wrap: nowrap;
  margin-block: var(--s-5) var(--s-6);
  overflow-x: auto; scrollbar-width: none;
  border-block-end: 1px solid var(--border-subtle);
}
.subnav::-webkit-scrollbar { display: none; }
.subnav a {
  white-space: nowrap; text-decoration: none;
  font-size: var(--step--1); font-weight: var(--weight-medium);
  color: var(--text-tertiary);
  padding: var(--s-2) var(--s-3) var(--s-3);
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.subnav a:hover { color: var(--text-primary); }
.subnav a[aria-current] { color: var(--text-primary); font-weight: var(--weight-semi); border-block-end-color: var(--text-primary); }


/* ── the answer ────────────────────────────────────────────────────────────
   The instrument. Everything else on the page is supporting evidence.

   Horizontal from 44rem up, so the band word, the advice and the number all
   sit above the fold on a laptop. It used to be a ~340px-tall white box
   holding one word. */
.answer {
  display: grid;
  gap: var(--s-4) var(--s-6);
  align-items: center;
  padding: var(--s-5) 0 var(--s-6);
  border-block: 1px solid var(--border-subtle);
  margin-block-end: var(--s-2);
}
@media (min-width: 44rem) {
  .answer {
    grid-template-columns: minmax(min-content, max-content) minmax(0, 1fr);
    column-gap: var(--s-7);
    padding-block: var(--s-6);
  }
}
.answer-body { min-inline-size: 0; }
/* The provenance chips are hidden until the live script has something to say.
   Without this the row still reserved its height, leaving a band of empty
   paper under the gauge on every page where the data was fresh. */
.answer .provenance:not(:has(> :not([hidden]))) { display: none; }

.status { display: flex; align-items: center; gap: var(--s-3); min-inline-size: 0; }
.status .pip {
  inline-size: 0.55em; block-size: 0.55em; border-radius: 50%;
  background: var(--band); flex: none;
  box-shadow: 0 0 0 0.26em color-mix(in srgb, var(--band) 18%, transparent);
}
.status .word {
  font-family: var(--font-display);
  font-size: var(--step-6);
  font-weight: var(--weight-black);
  line-height: 0.92;
  white-space: nowrap;
  letter-spacing: var(--tracking-tight);
  color: var(--band);
}

.answer .advice { font-size: var(--step-2); line-height: var(--leading-snug); color: var(--text-primary); margin: 0; text-wrap: pretty; max-inline-size: none; }
.answer .note { font-size: var(--step--1); color: var(--text-tertiary); margin: var(--s-2) 0 0; }

.gauge { display: flex; align-items: center; gap: var(--s-3); margin-block-start: var(--s-3); flex-wrap: wrap; }
.gauge-track { flex: 0 1 17rem; block-size: 8px; background: var(--surface-sunken); border-radius: var(--r-full); overflow: hidden; }
.gauge-fill {
  block-size: 100%; inline-size: var(--pct, 0%);
  background: var(--band); border-radius: var(--r-full);
  transition: inline-size var(--dur-3) var(--ease-out);
}
.gauge-label { font-size: var(--step--1); color: var(--text-tertiary); font-variant-numeric: tabular-nums; flex: none; }


/* ── city + code ───────────────────────────────────────────────────────── */
.place {
  display: flex; align-items: center; gap: var(--s-2) var(--s-3); flex-wrap: wrap;
  margin: 0 0 var(--s-5);
  color: var(--text-tertiary); font-size: var(--step--1);
}
.place .sep { color: var(--border-strong); }
.place .iata {
  font-weight: var(--weight-bold); font-size: var(--step--2);
  letter-spacing: var(--tracking-wide);
  color: var(--text-brand); background: var(--surface-brand);
  padding: 2px var(--s-2); border-radius: var(--r-1);
}


/* ── cards ─────────────────────────────────────────────────────────────────
   One card component for terminals, airports and weekdays. Hairline plus a
   band edge rather than a shadow: at eight per screen, shadows turn a page
   into rubble. */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 17rem)); gap: var(--s-3); margin-block-end: var(--s-4); }
/* On a phone the capped track leaves a ragged edge; one card per row is both
   tidier and a bigger tap target. */
@media (max-width: 30rem) { .cards { grid-template-columns: 1fr; } }
.tcard {
  display: block; text-decoration: none; color: var(--text-primary);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-inline-start: 3px solid var(--band);
  border-radius: var(--r-2);
  padding: var(--s-4);
  transition: border-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
a.tcard:hover { border-color: var(--band-edge); border-inline-start-color: var(--band); transform: translateY(-1px); }
.tcard .name { font-weight: var(--weight-semi); font-size: var(--step-0); }
.tcard .city { color: var(--text-tertiary); font-size: var(--step--2); margin-block-start: 2px; }
.tcard .row { display: flex; align-items: center; gap: var(--s-2); color: var(--band-text); font-size: var(--step--1); font-weight: var(--weight-medium); margin-block-start: var(--s-2); }
.tcard .pip { inline-size: 8px; block-size: 8px; border-radius: 50%; background: var(--band); flex: none; }
.tcard .bar { block-size: 4px; background: var(--surface-sunken); border-radius: var(--r-full); overflow: hidden; margin-block-start: var(--s-3); }
.tcard .bar span { display: block; block-size: 100%; background: var(--band); inline-size: var(--pct, 0%); border-radius: var(--r-full); }


/* ── segmented controls ────────────────────────────────────────────────── */
.controls { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; margin-block-end: var(--s-4); }
.seg { display: inline-flex; background: var(--surface-sunken); border-radius: var(--r-full); padding: 3px; }
.seg.spacer { margin-inline-start: auto; }
.seg button {
  font: inherit; font-size: var(--step--1); font-weight: var(--weight-medium);
  color: var(--text-tertiary); background: transparent; border: 0; cursor: pointer;
  padding: var(--s-2) var(--s-4); border-radius: var(--r-full);
  transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.seg button:hover { color: var(--text-primary); }
.seg button[aria-pressed="true"] { background: var(--surface-card); color: var(--text-primary); font-weight: var(--weight-semi); box-shadow: var(--shadow-1); }
.seg[hidden] { display: none; }


/* ── hour × day grid ───────────────────────────────────────────────────────
   The densest thing on the site: 24 rows × 7 days, three times over on a
   two-terminal airport. It is a heat table, so the cell IS the datum — colour
   carries the value and the word confirms it. */
.gridwrap { margin-block-end: var(--s-4); }
table.grid {
  inline-size: 100%;
  border-collapse: separate; border-spacing: 3px;
  font-size: var(--step--2);
  table-layout: fixed;
  background: none; border: 0; border-radius: 0; overflow: visible;
}
table.grid th {
  padding: 0 0 var(--s-2);
  font-family: var(--font-text); font-size: var(--step--2); font-weight: var(--weight-semi);
  color: var(--text-tertiary); text-align: center;
  border: 0; text-transform: none; letter-spacing: var(--tracking-normal);
}
table.grid th.hour {
  inline-size: 3.2rem; text-align: end;
  padding-inline-end: var(--s-2); padding-block: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-quiet); font-weight: var(--weight-normal);
}
table.grid th small { display: block; font-weight: var(--weight-normal); color: var(--text-quiet); }
table.grid td { padding: 0; border: 0; }

.cell {
  display: block;
  padding-block: var(--s-2);
  border-radius: var(--r-1);
  text-align: center;
  background: var(--band-fill);
  color: var(--band-on-fill);
  font-weight: var(--weight-semi);
  font-size: var(--step--2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cell.empty { background: var(--surface-sunken); color: var(--text-quiet); font-weight: var(--weight-normal); }
/* Night hours are de-emphasised by desaturating the CELL, not by fading it:
   opacity dropped the tinted bands below AA on their own text. */
tr.rest .cell { filter: saturate(0.72); }
.cell[tabindex] { cursor: pointer; transition: box-shadow var(--dur-1) var(--ease); }
.cell[tabindex]:hover, .cell[tabindex]:focus { box-shadow: 0 0 0 2px var(--surface-card), 0 0 0 3px var(--band); position: relative; z-index: 2; outline: none; }
.cell[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--surface-card), 0 0 0 3px var(--text-primary); }


/* ── bar charts ────────────────────────────────────────────────────────── */
.forecast { margin-block-end: var(--s-4); }
.strip { display: flex; gap: 3px; align-items: flex-end; block-size: 5.5rem; }
.strip i {
  flex: 1 1 0; min-inline-size: 0;
  border-radius: var(--r-1) var(--r-1) 1px 1px;
  background: var(--band); min-block-size: 3px;
  animation: grow var(--dur-3) var(--ease-out) backwards;
}
.strip i.is-now { outline: 2px solid var(--text-primary); outline-offset: 1px; }
@keyframes grow { from { block-size: 3px !important; opacity: 0; } }

.hours { display: flex; gap: 3px; align-items: flex-end; block-size: 8.5rem; margin-block-end: var(--s-2); }
.hours i { flex: 1 1 0; min-inline-size: 0; border-radius: var(--r-1) var(--r-1) 1px 1px; background: var(--band); min-block-size: 3px; position: relative; }
.hours i.peak-hour { outline: 2px solid var(--text-primary); outline-offset: 1px; }
.hours i[tabindex] { cursor: pointer; }
.hours i[tabindex]:hover, .hours i[tabindex]:focus { outline: 2px solid var(--text-primary); outline-offset: 1px; }

.axis, .hourlabels {
  display: flex; justify-content: space-between;
  font-size: var(--step--2); color: var(--text-quiet);
  margin-block-start: var(--s-2);
  font-variant-numeric: tabular-nums;
}


/* ── chart readout ─────────────────────────────────────────────────────── */
.readout { margin-block-start: var(--s-4); padding: var(--s-4); border-radius: var(--r-2); background: var(--band-tint); border: 1px solid var(--band-edge); }
.readout[hidden] { display: none; }
.readout-head { display: flex; align-items: center; gap: var(--s-2); margin-block-end: var(--s-2); }
.readout-head .pip { inline-size: 10px; block-size: 10px; border-radius: 50%; background: var(--band); flex: none; }
.readout-head strong { font-size: var(--step-0); }
.readout-head span[data-ro-band] { color: var(--band-text); font-weight: var(--weight-semi); }
.readout p { margin: 0; font-size: var(--step--1); color: var(--text-secondary); max-inline-size: none; }
.readout-dest { color: var(--text-tertiary) !important; margin-block-start: var(--s-1) !important; }


/* ── legend ────────────────────────────────────────────────────────────── */
.legend { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin-block-start: var(--s-4); font-size: var(--step--2); color: var(--text-tertiary); }
.legend span { display: inline-flex; align-items: center; gap: var(--s-2); }
.legend i { inline-size: 10px; block-size: 10px; border-radius: 3px; background: var(--band); }
.legend-hint { margin-inline-start: auto; color: var(--text-quiet); }


/* ── ranked lists ──────────────────────────────────────────────────────── */
.ranked { display: flex; flex-direction: column; }
.ranked[hidden] { display: none; }
.ranked > * {
  display: flex; align-items: center; gap: var(--s-3);
  padding-block: var(--s-3);
  border-block-end: 1px solid var(--border-hairline);
  text-decoration: none; color: var(--text-primary);
  font-size: var(--step-0);
}
.ranked > *:last-child { border-block-end: 0; }
.ranked a:hover { color: var(--text-action); }
.ranked .rank { flex: none; inline-size: 1.5rem; font-size: var(--step--2); color: var(--text-quiet); font-variant-numeric: tabular-nums; }
.ranked .meta { margin-inline-start: auto; color: var(--text-tertiary); font-size: var(--step--1); font-variant-numeric: tabular-nums; white-space: nowrap; }


/* ── KPI tiles ─────────────────────────────────────────────────────────────
   The one place a big number is the point. Tinted by band, so a bad number
   looks bad without needing a second component. */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--s-3); margin-block-end: var(--s-5); }
.kpi { background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--r-2); padding: var(--s-4); }
.kpi .v {
  font-family: var(--font-display);
  font-size: var(--step-4); font-weight: var(--weight-bold);
  line-height: 1; letter-spacing: var(--tracking-tight);
  color: var(--band); font-variant-numeric: tabular-nums;
}
.kpi .k { font-size: var(--step--2); color: var(--text-tertiary); margin-block-start: var(--s-2); line-height: var(--leading-snug); }


/* ── leaderboards ──────────────────────────────────────────────────────── */
.boards { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: var(--s-4); margin-block-end: var(--s-5); }
.board { background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--r-2); padding: var(--s-4) var(--s-5) var(--s-2); }
.board h3 { font-size: var(--step-0); margin-block-end: var(--s-1); }
.board .sub { font-size: var(--step--2); color: var(--text-tertiary); margin-block-end: var(--s-3); line-height: var(--leading-snug); }
.board ol { list-style: none; margin: 0; padding: 0; }
.board li { display: flex; align-items: center; gap: var(--s-3); padding-block: var(--s-3); border-block-end: 1px solid var(--border-hairline); font-size: var(--step--1); }
.board li:last-child { border-block-end: 0; }
.board .n {
  flex: none; inline-size: 1.4rem; block-size: 1.4rem;
  display: grid; place-items: center; border-radius: var(--r-full);
  background: var(--band-tint); color: var(--band-text);
  font-size: var(--step--2); font-weight: var(--weight-semi);
}
.board .val { margin-inline-start: auto; font-weight: var(--weight-semi); color: var(--band-text); font-variant-numeric: tabular-nums; }
.board.good { --band: var(--sig-quiet); }
.board.bad { --band: var(--sig-peak); }


/* ── the calculator ────────────────────────────────────────────────────── */
.calc {
  max-inline-size: var(--w-prose);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-3);
  padding: var(--s-5);
  margin-block-end: var(--s-5);
}
.field { margin-block-end: var(--s-5); }
.field:last-of-type { margin-block-end: var(--s-4); }
.field label { display: block; font-size: var(--step--1); font-weight: var(--weight-semi); color: var(--text-secondary); margin-block-end: var(--s-2); }
.field select {
  inline-size: 100%;
  font: inherit; font-size: var(--step-0);
  color: var(--text-primary);
  background-color: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-2);
  padding: var(--s-3) var(--s-4);
  padding-inline-end: var(--s-8);
  appearance: none;
  background-image: var(--chevron);
  background-repeat: no-repeat;
  background-position: right var(--s-4) center;
  background-size: 12px;
}
html[dir="rtl"] .field select { background-position: left var(--s-4) center; }
.field select:focus { outline: none; border-color: var(--border-focus); box-shadow: var(--focus-ring); }

.timepair { display: flex; align-items: center; gap: var(--s-2); }
.timepair select { inline-size: auto; flex: 1 1 0; text-align: center; }
.timepair span { color: var(--text-tertiary); font-weight: var(--weight-semi); }

.choices { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.choices button {
  flex: 1 1 8rem;
  font: inherit; font-size: var(--step--1); font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-2);
  padding: var(--s-3);
  cursor: pointer;
  transition: border-color var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease);
}
.choices button:hover { border-color: var(--border-strong); }
.choices button[aria-pressed="true"] { border-color: var(--text-brand); background: var(--surface-brand); color: var(--text-brand); font-weight: var(--weight-semi); }

.cta {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  inline-size: 100%;
  font: inherit; font-size: var(--step-0); font-weight: var(--weight-semi);
  color: var(--text-invert);
  background: var(--surface-invert);
  border: 0; border-radius: var(--r-2);
  padding: var(--s-3) var(--s-5);
  cursor: pointer; text-decoration: none;
  transition: background-color var(--dur-2) var(--ease), transform var(--dur-1) var(--ease);
}
.cta:hover { background: var(--navy-1); color: var(--text-invert); transform: translateY(-1px); }
.cta:active { transform: none; }

.result {
  max-inline-size: var(--w-prose);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-3);
  padding: var(--s-5);
  margin-block-end: var(--s-5);
}
.result[hidden] { display: none; }
.result .k { font-size: var(--step--1); color: var(--text-tertiary); }
.result .time {
  font-family: var(--font-display);
  font-size: var(--step-6); font-weight: var(--weight-bold);
  line-height: 1; letter-spacing: var(--tracking-tight);
  color: var(--text-brand);
  margin-block: var(--s-2);
  font-variant-numeric: tabular-nums;
}
.result .band {
  display: inline-block;
  font-size: var(--step--2); font-weight: var(--weight-semi);
  color: var(--band-text); background: var(--band-tint);
  padding: var(--s-1) var(--s-3); border-radius: var(--r-full);
}
.result dl {
  display: grid; grid-template-columns: 1fr auto;
  gap: var(--s-2) var(--s-4);
  margin: var(--s-4) 0 0;
  padding-block-start: var(--s-4);
  border-block-start: 1px solid var(--border-hairline);
  font-size: var(--step--1);
}
.result dt { color: var(--text-tertiary); }
.result dd { margin: 0; text-align: end; font-weight: var(--weight-medium); }


/* ── notes, cautions, provenance ───────────────────────────────────────── */
.caution, .disclaimer {
  border-radius: var(--r-2);
  padding: var(--s-4);
  font-size: var(--step--1);
  line-height: var(--leading-normal);
  color: var(--text-secondary);
  background: var(--surface-inset);
  border-inline-start: 3px solid var(--border-strong);
  margin-block: var(--s-4);
  max-inline-size: var(--w-prose);
}
.caution strong, .disclaimer strong { color: var(--text-primary); display: block; margin-block-end: var(--s-1); }
.disclaimer { background: var(--surface-brand); border-inline-start-color: var(--navy-0); }

.provenance { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; font-size: var(--step--2); color: var(--text-tertiary); margin-block-start: var(--s-3); }
.chip {
  display: inline-flex; align-items: center;
  font-size: var(--step--2); font-weight: var(--weight-semi);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--text-secondary); background: var(--surface-sunken);
  padding: 2px var(--s-2); border-radius: var(--r-1);
}
.chip.warn { color: var(--flame-0); background: var(--flame-tint); }
.chip[hidden] { display: none; }

.attribution { font-size: var(--step--2); color: var(--text-quiet); }


/* ── FAQ ───────────────────────────────────────────────────────────────── */
.faq { margin-block-start: var(--s-7); }
.faq-item { padding-block: var(--s-4); border-block-end: 1px solid var(--border-hairline); }
.faq-item:last-child { border-block-end: 0; }
.faq h3 { font-size: var(--step-0); margin-block-end: var(--s-2); }
.faq p { color: var(--text-secondary); font-size: var(--step--1); max-inline-size: var(--w-prose); }


/* ── sideways navigation ───────────────────────────────────────────────── */
.sideways { margin-block-start: var(--s-6); }
.sideways .chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.sideways .chips a, nav.pages a {
  text-decoration: none; font-size: var(--step--1);
  color: var(--text-secondary);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-full);
  padding: var(--s-2) var(--s-4);
  transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.sideways .chips a:hover, nav.pages a:hover { border-color: var(--border-focus); color: var(--text-brand); }
nav.pages { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-block-start: var(--s-6); }


/* ── editorial prose ───────────────────────────────────────────────────── */
.prose { max-inline-size: var(--w-prose); margin-block: var(--s-6) var(--s-5); }
.prose h2 { font-size: var(--step-2); }
.prose h3 { font-size: var(--step-1); margin-block-start: var(--s-5); }
.prose p { color: var(--text-secondary); line-height: var(--leading-loose); }
.prose ul, .prose ol { color: var(--text-secondary); padding-inline-start: var(--s-5); line-height: var(--leading-loose); }
.prose strong { color: var(--text-primary); font-weight: var(--weight-semi); }
.prose-updated { font-size: var(--step--2); color: var(--text-quiet); }


/* ── data tables ───────────────────────────────────────────────────────── */
table {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-2);
  overflow: hidden;
}
th {
  text-align: start;
  padding: var(--s-3) var(--s-4);
  font-family: var(--font-text);
  font-size: var(--step--2);
  font-weight: var(--weight-semi);
  color: var(--text-tertiary);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
thead th { border-block-end: 1px solid var(--border-subtle); }
td { padding: var(--s-3) var(--s-4); border-block-end: 1px solid var(--border-hairline); color: var(--text-secondary); font-variant-numeric: tabular-nums; }
tbody th[scope="row"] {
  font-size: inherit; font-weight: var(--weight-medium); color: var(--text-primary);
  text-transform: none; letter-spacing: var(--tracking-normal);
  padding: var(--s-3) var(--s-4);
  border-block-end: 1px solid var(--border-hairline);
  font-variant-numeric: tabular-nums;
}
tr:last-child td, tbody tr:last-child th { border-block-end: none; }
.band-text { color: var(--band-text); font-weight: var(--weight-semi); }


/* ── eSIM ──────────────────────────────────────────────────────────────────
   The commercial block. It is allowed to use the action colour and nothing
   else on the page is, which is the whole reason it gets noticed without
   having to shout. */
.esim {
  margin-block-start: var(--s-7);
  padding: var(--s-5);
  border-radius: var(--r-3);
  background: var(--surface-accent);
  border: 1px solid color-mix(in srgb, var(--flame-1) 24%, transparent);
}
.esim[hidden] { display: none; }
.esim h3 { font-size: var(--step-2); margin-block-end: var(--s-2); }
.esim p { color: var(--text-secondary); font-size: var(--step--1); margin-block-end: var(--s-4); max-inline-size: var(--w-prose); }
.esim .cta { inline-size: auto; background: var(--flame-0); color: var(--text-invert); }
.esim .cta:hover { background: var(--flame-hover); }


/* ── footer ────────────────────────────────────────────────────────────── */
.site-footer { margin-block-start: var(--s-8); background: var(--surface-invert); color: var(--on-invert); font-size: var(--step--1); }
.footer-inner {
  inline-size: min(var(--w-wide), 100% - var(--gutter) * 2);
  margin-inline: auto;
  padding-block: var(--s-7) var(--s-6);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--s-6) var(--s-5);
}
.footer-brand {
  display: flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-display); font-weight: var(--weight-bold);
  font-size: var(--step-1); color: var(--text-invert);
  margin-block-end: var(--s-3);
}
.footer-col h3 {
  margin: 0 0 var(--s-3);
  font-family: var(--font-text);
  font-size: var(--step--2); font-weight: var(--weight-bold);
  color: var(--on-invert-muted);
  text-transform: uppercase; letter-spacing: var(--tracking-wide);
}
html[dir="rtl"] .footer-col h3 { letter-spacing: var(--tracking-normal); }
.footer-col p { color: inherit; margin: 0; max-inline-size: 22rem; }
.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li { margin-block-end: var(--s-2); }
.footer-col a { color: var(--on-invert-strong); text-decoration: none; }
.footer-col a:hover { color: var(--text-invert); text-decoration: underline; }
.footer-col[hidden] { display: none; }

.footer-legal {
  inline-size: min(var(--w-wide), 100% - var(--gutter) * 2);
  margin-inline: auto;
  padding-block: var(--s-4) var(--s-7);
  border-block-start: 1px solid var(--on-invert-line);
  color: var(--on-invert-muted);
  font-size: var(--step--2);
  line-height: var(--leading-normal);
}
.footer-legal p { margin: 0; color: inherit; max-inline-size: var(--w-content); }
.footer-legal a { color: var(--on-invert-strong); }
.footer-links { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5); margin-block-start: var(--s-3) !important; }
.footer-esim { margin-block-start: var(--s-3) !important; }
.footer-esim a { color: var(--on-invert-action); font-weight: var(--weight-semi); }


/* ── utilities ─────────────────────────────────────────────────────────── */
/* Spacing off the scale, for the handful of places a block needs to sit
   further from what precedes it than its component says. Named steps, so the
   rhythm stays the rhythm. */
.mt-5 { margin-block-start: var(--s-5) !important; }
.mt-6 { margin-block-start: var(--s-6) !important; }
.mt-7 { margin-block-start: var(--s-7) !important; }

.sr-only {
  position: absolute; inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

.reveal { animation: rise var(--dur-3) var(--ease-out) backwards; }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

