/* =========================================================================
   Self-hosted fonts — latin subset only (GDPR: no external font requests).
   Variable fonts: Fraunces wght 300–700 + opsz; Public Sans wght 400–600.
   ========================================================================= */

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("/static/vendor/fonts/fraunces-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: 'Public Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/vendor/fonts/public-sans-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;
}

/* JetBrains Mono (variable, latin subset) — powers the "brutal" design mode
   only. Self-hosted; no external font request, matching the fonts above. */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/static/vendor/fonts/jetbrains-mono-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;
}

/* Space Grotesk (variable, latin subset) + Space Mono — power the "studio"
   brand mode only. Self-hosted; no external font request, matching the fonts
   above. Space Grotesk carries display + body (a calm editorial grotesk);
   Space Mono carries code surfaces. Both SIL OFL. */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("/static/vendor/fonts/space-grotesk-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: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/vendor/fonts/space-mono-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;
}

/* =========================================================================
   Teaser — a warm-paper editorial "almanac of the world economy".
   Fraunces (optical serif) for voice + headline figures; Public Sans for UI.
   Emerald accent seeded at runtime from branding; clay-red for losses.
   ========================================================================= */

:root {
  --accent: #1a7f5f;              /* overwritten from branding at load */
  --accent-deep: #12503b;
  --paper: #f6f2e8;
  --paper-2: #efe9db;
  --surface: #fffdf7;
  --ink: #1c1b17;
  --ink-soft: #5f5a4e;           /* secondary text — 6.14:1 on #f6f2e8 (was near-identical to --ink-faint; now a real emphasis step) */
  --ink-faint: #6e6a5e;          /* tertiary text — 4.84:1 on #f6f2e8 (passes 4.5:1 WCAG AA) */
  --line: #e4ddcc;
  --line-strong: #d6cdb7;
  /* Data valence. --gain is the FILL for "better" (charts, map ramp, chips'
     tint); --pos is "better" as running TEXT — the deep accent, because the
     mid green sits at only 4.43:1 as normal-size text (a11y review
     2026-07-15). --neg darkened from #b23a2e: the old green/red pair
     simulated to two same-lightness olives for deutan/protan viewers
     (sim luminance ratio 1.01); #8a251c carries the difference in lightness
     (2.6:1 protan) and reads 7.95:1 as text. Green stays "better",
     red stays "worse" — the mandate — now also for colourblind readers. */
  --gain: var(--accent);
  --pos: var(--accent-deep);
  --neg: #8a251c;
  /* Neutral diverging scale (consumer prices, imports) — a DIRECTION, not a
     good/bad valence, so it must stay off the green/red pair (a price drop must
     never read as a "household gain"). Emitted by metricSign()/mapColor() for
     `neutral` metrics since the 2026-07-15 design review (the tokens existed
     before but nothing emitted them — rising prices wore winner green). Kept
     inside the warm palette: a rise is the theme amber, a fall is a muted warm
     indigo — cool enough to separate from "rise" but low-saturation so it sits
     on the paper canvas. */
  --up: #b9722a;
  --down: #5a6284;
  /* Running/queued admin status colour (rail dot + pill) — same amber in both
     brand modes, so it isn't re-declared under [data-brand-mode="brutal"]
     the way --pos/--neg/--up/--down are. */
  --warn: #c98a2e;
  --warn-text: #8a5a10;
  --shadow-soft: 0 1px 2px color-mix(in srgb, var(--ink) 4%, transparent), 0 8px 30px color-mix(in srgb, var(--ink) 6%, transparent);
  --shadow-lift: 0 2px 6px color-mix(in srgb, var(--ink) 6%, transparent), 0 18px 50px color-mix(in srgb, var(--ink) 10%, transparent);
  --radius: 14px;
  --maxw: 1180px;
  /* Semantic font tokens (renamed from --serif/--sans, which lied in the
     non-editorial designs — brutal's "serif" was a mono): display face,
     body face, code face. Each design layer re-declares them. */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "Public Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", Menlo, monospace;
  /* Select chevron as a token: data-URIs can't reference var(--ink), so each
     design layer re-declares this with its own ink hex. */
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%231c1b17' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* =========================================================================
   [data-brand-mode="brutal"] — the neo-brutalist design for the KITE brand
   (formerly the "technical"/"kite" mode; renamed to "brutal" — the design is
   named, the KITE Model Suite copy/assets stay). Both "brutal" and "studio"
   are designs for the KITE brand; only "editorial" is Ricardo.

   A TOKEN-LEVEL swap only: the editorial layout/structure is untouched. It
   trades the warm-paper serif almanac for kite-model.org's monochrome
   technical look — JetBrains Mono throughout, near-black ink on off-white,
   a chartreuse accent used for data FILLS (bars, choropleth) and hairline
   highlights, and orange for losses. Colours are the real tokens lifted from
   the site's stylesheet (--bg #fafaf7, --ink #0a0a0a, --accent #E8FF3A,
   --accent-2 #FF5C2B, --muted #6b6b6b, --hairline #d9d9d3).

   app.js also sets --accent/--paper/--ink inline from /api/config.branding;
   the values here match, and this layer additionally derives the supporting
   tokens the inline set doesn't carry.
   ========================================================================= */
[data-brand-mode="brutal"] {
  --accent: #e8ff3a;             /* chartreuse — data fills + highlights */
  --accent-deep: #0a0a0a;        /* accent-as-text falls back to ink (mono) */
  --paper: #fafaf7;
  --paper-2: #f0f0ea;
  --surface: #ffffff;
  --ink: #0a0a0a;
  --ink-soft: #3a3a37;
  --ink-faint: #6b6b6b;          /* the site's --muted */
  --line: #d9d9d3;               /* the site's --hairline */
  --line-strong: #b9b9b1;
  /* Positive FIGURES get a voice: a dark chartreuse-family green (5.76:1 on
     --paper) instead of the former mute ink — losses shouted orange while wins
     whispered (design-review 2026-07-15). Data FILLS keep the raw chartreuse
     via --gain (inherited: var(--accent)); its weak fill contrast is carried
     by 1px ink outlines (--bar-outline) + solid map strokes, NOT by darkening
     the fill — a darker olive would collapse the design's excellent
     colourblind separation (deutan ΔE 52.7 → ~5). */
  --pos: #3f6f00;
  /* Darkened from the site's raw --accent-2 #ff5c2b: the literal brand orange
     is only 2.95:1 on --paper / 3.08:1 on --surface as TEXT (used directly on
     .hero-stat.neg, .cstat.neg, .sector-table td.num.neg, etc. — normal-size
     body copy needing 4.5:1), so a same-hue, lower-lightness shade is used for
     text while the vendored data-fill hex is untouched. 4.86:1 / 5.08:1. */
  --neg: #d13000;
  /* Neutral diverging scale kept in the KITE mono/warm-neutral world — a muted
     amber rise and a warm graphite fall, so it stays off the chartreuse/orange
     good-bad pair while still reading as on-brand (no stray indigo). Darkened
     from #b98a2a (same fix as --neg above: 2.98:1 / 3.12:1 as text → fails
     AA) to a same-hue shade that clears 4.5:1: 5.46:1 / 5.71:1. */
  --up: #82611d;
  --down: #565049;
  /* Solid, hard-offset "brutal" shadow (kite-model.org --shadow: 4px 4px 0 0
     --ink). Full-opacity ink, no blur — the signature neo-brutalist drop. */
  --shadow-soft: 3px 3px 0 0 var(--ink);
  --shadow-lift: 5px 5px 0 0 var(--ink);
  --radius: 0px;                  /* kite-model.org --radius: 0px (square edges) */
  --font-display: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --font-body: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%230a0a0a' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  /* Chartreuse fills are ~1.07:1 on white — the outline carries the boundary. */
  --bar-outline: var(--ink);
}
/* Chartreuse focus rings are invisible (1.07:1) — the brutal ring is ink. */
[data-brand-mode="brutal"] .preset-card:focus-visible,
[data-brand-mode="brutal"] .blank:focus-visible,
[data-brand-mode="brutal"] .btn:focus-visible,
[data-brand-mode="brutal"] .metric-tab:focus-visible,
[data-brand-mode="brutal"] .select:focus-visible { outline-color: var(--ink); }
/* Map fills need a boundary for the same reason (chartreuse vs white). */
[data-brand-mode="brutal"] .map-country.has-data { stroke: var(--ink); stroke-width: .4; }
/* Square the components the original reskin whitelist missed. */
[data-brand-mode="brutal"] .metric-switch,
[data-brand-mode="brutal"] .metric-tab,
[data-brand-mode="brutal"] .blank,
[data-brand-mode="brutal"] .map-tip,
[data-brand-mode="brutal"] .preset-chip,
[data-brand-mode="brutal"] .map-row-chip,
[data-brand-mode="brutal"] .trade-tag { border-radius: 0; }
/* Mono type wants slightly tighter leading + no old-style serif features. */
[data-brand-mode="brutal"] body { font-feature-settings: normal; font-size: 16px; }
/* Accent-as-TEXT spots would vanish in chartreuse — pin them to ink, and give
   the eyebrow a chartreuse highlight chip (a signature KITE move). */
[data-brand-mode="brutal"] .crow-lead em,
[data-brand-mode="brutal"] .fail-mark,
[data-brand-mode="brutal"] .btn-ghost .plus { color: var(--ink); }
[data-brand-mode="brutal"] .hero-eyebrow {
  color: var(--ink); background: var(--accent);
  display: inline-block; padding: .18em .5em; letter-spacing: .16em;
}
/* KITE mark — the real kite-model.org logo (see .hero-visual in index.html). */
[data-brand-mode="brutal"] .hero-kite,
[data-brand-mode="studio"] .hero-kite { display: block; }
/* Headings drop the serif's negative tracking; mono reads cleaner slightly open. */
[data-brand-mode="brutal"] .hero-title,
[data-brand-mode="brutal"] .section-heading,
[data-brand-mode="brutal"] .panel-heading { letter-spacing: -.005em; }

/* =========================================================================
   Faithfulness pass — kite-model.org neo-brutalism (assets/css/{tokens,
   components}.css). Tokens ADOPTED from the real site, verbatim:

     --bg      #fafaf7   → --paper          (off-white canvas)
     --ink     #0a0a0a   → --ink            (near-black)
     --paper   #ffffff   → --surface        (card white)
     --muted   #6b6b6b   → --ink-faint
     --hairline#d9d9d3   → --line
     --accent  #E8FF3A   → --accent         (chartreuse data fills + chips)
     --accent-2#FF5C2B   → --neg            (hot orange, negatives)
     --bw 3px / --bw-sm 2px                  → card + button borders
     --radius  0px                           → square edges everywhere
     --shadow  Npx Npx 0 0 --ink             → solid hard-offset drop shadow
     btn: mono, UPPERCASE, letter-spacing .1em, translate(-2,-2) on hover,
          translate(2,2)+no-shadow on active, .solid = ink bg / paper text
     kicker/label: mono UPPERCASE, letter-spacing .12–.18em, --muted
     brutal-table: header UPPERCASE .14em; row :hover → --accent fill

   We keep OUR app layout — only the token palette, typography feel, and
   component chrome (borders / shadows / edges) are made faithful.
   ========================================================================= */

/* Cards, panels, shells → 2px ink border, square, hard shadow. */
[data-brand-mode="brutal"] .preset-card,
[data-brand-mode="brutal"] .crow,
[data-brand-mode="brutal"] .chart-panel,
[data-brand-mode="brutal"] .sector-panel,
[data-brand-mode="brutal"] .trade-panel,
[data-brand-mode="brutal"] .country-panel,
[data-brand-mode="brutal"] .map-panel,
[data-brand-mode="brutal"] .provenance-panel,
[data-brand-mode="brutal"] .rail-card,
[data-brand-mode="brutal"] .cstat,
[data-brand-mode="brutal"] .gate-card,
[data-brand-mode="brutal"] .admin-panel,
[data-brand-mode="brutal"] .fail-card,
[data-brand-mode="brutal"] .compare-picker,
[data-brand-mode="brutal"] .map-overlay-panel {
  border: 2px solid var(--ink);
  border-radius: 0;
}

/* Buttons — the site's signature brutalist control. */
[data-brand-mode="brutal"] .btn {
  border: 3px solid var(--ink);
  border-radius: 0;
  font-family: var(--font-body);      /* --sans is already JetBrains Mono in brutal mode; --mono is not a defined token */
  text-transform: uppercase;
  letter-spacing: .1em;
  font-weight: 700;
  box-shadow: var(--shadow-soft);
  transition: transform 120ms ease, box-shadow 120ms ease, background 120ms ease;
}
[data-brand-mode="brutal"] .btn-solid { background: var(--ink); color: var(--surface); }
[data-brand-mode="brutal"] .btn-ghost { background: var(--surface); color: var(--ink); }
[data-brand-mode="brutal"] .btn:not(:disabled):hover {
  transform: translate(-2px, -2px); box-shadow: var(--shadow-lift);
  background: var(--ink); color: var(--surface);
}
[data-brand-mode="brutal"] .btn-solid:not(:disabled):hover { background: var(--accent); color: var(--ink); }
[data-brand-mode="brutal"] .btn:not(:disabled):active { transform: translate(2px, 2px); box-shadow: 0 0 0 0 var(--ink); }

/* Inputs / selects → square, 2px ink. */
[data-brand-mode="brutal"] .gate-input,
[data-brand-mode="brutal"] .select,
[data-brand-mode="brutal"] .set-input,
[data-brand-mode="brutal"] .select-mini,
[data-brand-mode="brutal"] .rename-input,
[data-brand-mode="brutal"] .token-input {
  border: 2px solid var(--ink);
  border-radius: 0;
}

/* Kickers / labels → mono uppercase, KITE tracking. */
[data-brand-mode="brutal"] .section-heading,
[data-brand-mode="brutal"] .gate-eyebrow,
[data-brand-mode="brutal"] .cstat-label,
[data-brand-mode="brutal"] .panel-sub { letter-spacing: .14em; }
[data-brand-mode="brutal"] .hero-eyebrow,
[data-brand-mode="brutal"] .gate-eyebrow { letter-spacing: .18em; }
[data-brand-mode="brutal"] .gate-eyebrow { color: var(--ink); }

/* Tables → brutal header + accent row hover (both landing + admin). */
[data-brand-mode="brutal"] .sector-table th,
[data-brand-mode="brutal"] .dtable th { letter-spacing: .14em; }
[data-brand-mode="brutal"] .sector-table tbody tr:hover td,
[data-brand-mode="brutal"] .dtable-click tbody tr.clickable:hover { background: var(--accent); }

/* Chips → square hard edge. */
[data-brand-mode="brutal"] .preset-chip,
[data-brand-mode="brutal"] .agg-chip { border-radius: 0; }

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

/* ---- slim maintenance banner (both brand modes) ---- */
.maintenance-banner {
  position: relative; z-index: 3;
  margin: 0; padding: .55rem 1.25rem;
  font-family: var(--font-body); font-size: .84rem; font-weight: 600;
  letter-spacing: .01em; text-align: center;
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 22%, var(--surface));
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, var(--line));
}
[data-brand-mode="brutal"] .maintenance-banner {
  background: var(--accent); color: var(--ink);
  border-bottom: 2px solid var(--ink); text-transform: uppercase;
  letter-spacing: .08em;
}

/* ---- consent banner (opt-out privacy model, both brand modes) ----
   A bottom bar, not a modal — it never blocks the page underneath. */
.consent-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .6rem 1.25rem;
  padding: .9rem 1.25rem;
  background: var(--surface);
  border-top: 1px solid var(--line-strong);
  box-shadow: var(--shadow-lift);
}
.consent-text {
  margin: 0; flex: 1 1 320px; font-family: var(--font-body);
  font-size: .86rem; line-height: 1.5; color: var(--ink);
}
.consent-text a { color: var(--accent-deep); text-decoration: underline; text-underline-offset: 2px; }
.consent-actions { display: flex; gap: .6rem; flex: 0 0 auto; }
[data-brand-mode="brutal"] .consent-banner {
  border-top: 2px solid var(--ink);
}
[data-brand-mode="brutal"] .consent-text a { color: var(--ink); text-decoration-color: var(--accent); }
@media (max-width: 560px) {
  .consent-banner { padding: .8rem 1rem; }
  .consent-actions { width: 100%; }
  .consent-actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* The `hidden` attribute must win over any element that sets its own display
   (e.g. flex sections like .admin-gate / .agg-chips). */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--paper);
  font-size: 17px;
  line-height: 1.55;
  font-feature-settings: "ss01", "cv05";
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* ---- atmosphere: grain + faint cartographic meridians ---- */
.paper-grain {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  opacity: .5; mix-blend-mode: multiply;
  background-image: 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.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.35'/%3E%3C/svg%3E");
}
.meridian-field {
  position: fixed; inset: -10% -10% auto -10%; height: 120vh; z-index: 0; pointer-events: none;
  opacity: .5;
  background:
    radial-gradient(120% 90% at 82% -8%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 55%),
    repeating-linear-gradient(76deg, transparent 0 78px, color-mix(in srgb, var(--accent) 5%, transparent) 78px 79px);
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent 70%);
          mask-image: linear-gradient(to bottom, #000, transparent 70%);
}

/* ---- screens (view swap) ---- */
.screen { position: relative; z-index: 1; display: none; }
.screen.is-active { display: block; animation: rise .5s cubic-bezier(.2,.7,.2,1) both; }
.screen-center.is-active { min-height: 82vh; display: flex; align-items: center; justify-content: center; }

@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ============================= HERO ============================= */
.hero {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(3rem, 8vw, 6.5rem) clamp(1.25rem, 5vw, 3rem) clamp(2rem, 5vw, 3.5rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: clamp(1.5rem, 5vw, 4rem);
}
/* Copy leads at the page's left edge (same padding as every section below), so
   the headline aligns with the rest of the page — no left mark pushing it in. */
.hero-copy { grid-column: 1; max-width: 34ch; }
/* Brand visual sits to the RIGHT of the copy, vertically centred against it. */
.hero-visual { grid-column: 2; justify-self: end; align-self: center; }
/* KITE logo — shown in the brutal & studio designs (brand-mode rule); large, right-hand. */
.hero-kite { display: none; width: auto; height: clamp(160px, 26vw, 340px); }
.hero-eyebrow {
  margin: 0 0 1.1rem;
  font-size: .74rem; letter-spacing: .22em; text-transform: uppercase;
  font-weight: 600;
  /* --accent (#1a7f5f on the default --paper #f6f2e8) is only 4.43:1 here —
     under the 4.5:1 AA minimum for this weight/size. --accent-deep passes
     comfortably (8.4:1) and is the same hue, just darker. */
  color: var(--accent-deep);
}
.hero-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 340;
  font-optical-sizing: auto;
  font-size: clamp(2.5rem, 6vw, 4.6rem);
  line-height: 1.02;
  letter-spacing: -.015em;
  font-variation-settings: "SOFT" 30;
}
.hero-lede {
  margin: 1.4rem 0 0;
  font-size: clamp(1.05rem, 2vw, 1.32rem);
  color: var(--ink-soft);
  max-width: 34ch;
}
/* Editorial portrait — just the image, right of the headline: no mat, shadow, or
   tilt. Slightly larger than before so it reads as the brand, not a thumbnail. */
.hero-portrait { margin: 0; }
.hero-portrait img {
  display: block;
  width: clamp(150px, 23vw, 320px); height: auto; aspect-ratio: 260 / 335;
  object-fit: cover; border-radius: 6px;
}

/* ---- section rule ---- */
.section-rule { max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.25rem, 5vw, 3rem); }
.section-heading {
  font-family: var(--font-display); font-weight: 380; font-size: clamp(1.5rem, 3vw, 2.05rem);
  margin: 0; letter-spacing: -.01em;
}
.section-sub { margin: .35rem 0 1.6rem; color: var(--ink-soft); font-size: 1rem; }

.presets, .composer { padding: clamp(1.6rem, 4vw, 2.6rem) 0; }
.presets { border-top: 1px solid var(--line); }

/* ============================= PRESET CARDS ============================= */
.preset-grid {
  max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.25rem, 5vw, 3rem);
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: clamp(.9rem, 2vw, 1.4rem);
}
.preset-card {
  position: relative; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.5rem 1.5rem 1.35rem;
  display: flex; flex-direction: column; gap: .7rem; min-height: 200px;
  box-shadow: var(--shadow-soft);
  transition: transform .35s cubic-bezier(.2,.7,.2,1), box-shadow .35s, border-color .35s;
  font: inherit; color: inherit;
}
.preset-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lift); border-color: var(--line-strong); }
.preset-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.preset-card::before {
  content: ""; position: absolute; left: 0; top: 1.5rem; bottom: 1.35rem; width: 3px;
  border-radius: 3px; background: var(--accent); opacity: .0; transition: opacity .35s;
}
.preset-card:hover::before { opacity: .9; }
.preset-index {
  font-family: var(--font-display); font-size: .82rem; color: var(--ink-faint);
  font-variant-numeric: tabular-nums; letter-spacing: .04em;
}
.preset-title {
  font-family: var(--font-display); font-weight: 420; font-size: 1.4rem; line-height: 1.15;
  margin: 0; letter-spacing: -.01em;
}
.preset-story { margin: 0; color: var(--ink-soft); font-size: .97rem; flex: 1; }
.preset-chip {
  align-self: flex-start; margin-top: .2rem;
  display: inline-flex; align-items: baseline; gap: .45rem;
  font-family: var(--font-display); font-variant-numeric: tabular-nums;
  font-size: 1.15rem; font-weight: 460;
  padding: .3rem .7rem; border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  color: var(--ink);
}
.preset-chip .chip-note { font-family: var(--font-body); font-size: .72rem; letter-spacing: .03em; color: var(--ink-soft); font-weight: 500; }
.preset-chip.pos { color: var(--pos); background: color-mix(in srgb, var(--pos) 11%, transparent); }
.preset-chip.neg { color: var(--neg); background: color-mix(in srgb, var(--neg) 10%, transparent); }
/* ≈0 must look like neither side — without this rule the base chip's accent
   tint leaked through and "≈0 %" wore brand colour (design-review 2026-07-15). */
.preset-chip.zero { color: var(--ink-soft); background: color-mix(in srgb, var(--ink) 6%, transparent); }
.preset-chip.skeleton {
  color: transparent; width: 9rem; height: 1.9rem; background: var(--paper-2);
  animation: shimmer 1.4s ease-in-out infinite;
}
@keyframes shimmer { 0%,100% { opacity: .55; } 50% { opacity: 1; } }
/* Cards stay clickable while their headline chip warms up (startPreset() hits
   the same cached/in-flight run and resolves as soon as it's ready) — no
   pointer-events:none here. Silently swallowing the click for the duration of
   a real solve (which can take real wall-clock seconds) read as "broken", not
   "loading", with only a small shimmering chip as any cue. */

/* ============================= COMPOSER ============================= */
.composer { border-top: 1px solid var(--line); }
.composer-form { max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.25rem, 5vw, 3rem); }
.rows { display: flex; flex-direction: column; gap: 1rem; }

.crow {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.3rem 1.4rem; box-shadow: var(--shadow-soft);
  animation: rise .35s cubic-bezier(.2,.7,.2,1) both;
}
.crow-sentence {
  font-family: var(--font-display); font-size: clamp(1.15rem, 2.4vw, 1.5rem); line-height: 1.9;
  letter-spacing: -.005em; color: var(--ink);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .18em .1em;
}
.crow-lead { color: var(--ink-soft); }
.crow-lead em { font-style: italic; color: var(--accent); }

/* inline "fill-in-the-blank" controls */
.blank {
  position: relative; font-family: var(--font-body); font-size: .82em; font-weight: 600;
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 7%, var(--surface));
  border: 1px solid var(--line-strong);
  border-bottom: 2px solid var(--accent);
  border-radius: 8px; padding: .12em .55em; margin: 0 .05em;
  appearance: none; -webkit-appearance: none;
  cursor: pointer; transition: background .2s, border-color .2s;
  vertical-align: baseline;
}
.blank:hover { background: color-mix(in srgb, var(--accent) 13%, var(--surface)); }
.blank:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
select.blank {
  padding-right: 1.6em;
  background-image: var(--chevron);
  background-repeat: no-repeat; background-position: right .55em center;
}
input.blank-num {
  width: 3.4em; text-align: center; font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
}
input.blank-num::-webkit-outer-spin-button,
input.blank-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
select.sel-verb { max-width: 100%; }
.blank.invalid { border-bottom-color: var(--neg); background: color-mix(in srgb, var(--neg) 8%, var(--surface)); }

.crow-foot { display: flex; align-items: center; gap: 1rem; margin-top: .9rem; min-height: 1.3rem; }
.crow-error { color: var(--neg); font-size: .85rem; font-family: var(--font-body); flex: 1; }
.crow-remove {
  font: inherit; font-family: var(--font-body); font-size: .82rem; color: var(--ink-faint);
  background: none; border: none; cursor: pointer; padding: .2rem .4rem; border-radius: 6px;
  transition: color .2s, background .2s;
}
.crow-remove:hover { color: var(--neg); background: color-mix(in srgb, var(--neg) 8%, transparent); }

.composer-actions { display: flex; flex-wrap: wrap; gap: .8rem; align-items: center; margin-top: 1.4rem; }

/* buttons */
.btn {
  font-family: var(--font-body); font-weight: 600; font-size: .98rem; letter-spacing: .005em;
  border-radius: 10px; padding: .78em 1.4em; cursor: pointer; border: 1px solid transparent;
  display: inline-flex; align-items: center; gap: .5em;
  transition: transform .2s cubic-bezier(.2,.7,.2,1), box-shadow .25s, background .25s, opacity .25s, border-color .25s;
}
.btn:active { transform: translateY(1px); }
.btn-solid { background: var(--ink); color: var(--paper); box-shadow: var(--shadow-soft); }
.btn-solid:hover { background: color-mix(in srgb, var(--accent) 30%, var(--ink)); box-shadow: var(--shadow-lift); }
.btn-solid:disabled { opacity: .38; cursor: not-allowed; box-shadow: none; }
.btn-solid:disabled:hover { background: var(--ink); }
.btn-solid .arrow { transition: transform .25s; }
.btn-solid:not(:disabled):hover .arrow { transform: translateX(3px); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.btn-ghost:hover { border-color: var(--ink); background: color-mix(in srgb, var(--ink) 4%, transparent); }
.btn-ghost .plus { color: var(--accent); font-size: 1.2em; line-height: 0; }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.composer-errors {
  list-style: none; margin: 1.2rem 0 0; padding: 1rem 1.2rem; max-width: var(--maxw);
  background: color-mix(in srgb, var(--neg) 7%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--neg) 30%, var(--line));
  border-radius: var(--radius); color: var(--neg); font-size: .95rem;
}
.composer-errors li { margin: .2rem 0; }
.composer-errors li::before { content: "•"; margin-right: .5em; opacity: .6; }

/* ============================= RUNNING ============================= */
.run-stage { text-align: center; padding: 2rem; max-width: 30rem; }

/* Kite-in-the-wind scene (the KITE designs: brutal & studio) — built by
   kite_animation.js. Colour comes from `color` (--ink) and the accent sail's
   var(--accent) via each design's own tokens. */
.kite-sky {
  position: relative;
  width: 100%;
  height: 210px;
  margin: 0 auto 1.6rem;
  color: var(--ink);
  overflow: hidden;
}
.kite-sky .kite-anchor {
  position: absolute; right: 12%; bottom: 8px;
  width: 26px; height: 39px; z-index: 4; pointer-events: none;
}
.kite-sky .kite-string {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 2; pointer-events: none;
}
.kite-sky .kite-body {
  position: absolute; top: 0; left: 0; z-index: 3;
  will-change: transform, top, left; pointer-events: none;
}
.orbit { position: relative; width: 128px; height: 128px; margin: 0 auto 2.2rem; }
.orbit-ring {
  position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-top-color: var(--accent); border-right-color: transparent;
  animation: spin 2.6s linear infinite;
}
.orbit-ring.r2 { inset: 16px; animation-duration: 1.9s; animation-direction: reverse; opacity: .8; }
.orbit-ring.r3 { inset: 32px; animation-duration: 1.4s; opacity: .55; }
.orbit-core {
  position: absolute; inset: 52px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 15%, transparent);
  animation: pulse 1.8s ease-in-out infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pulse { 0%,100% { transform: scale(.85); opacity: .8; } 50% { transform: scale(1.05); opacity: 1; } }
.run-phase {
  font-family: var(--font-display); font-size: clamp(1.4rem, 3.5vw, 1.9rem); font-weight: 380;
  margin: 0; letter-spacing: -.01em; transition: opacity .4s;
}
.run-phase.fade { opacity: 0; }
.run-sub { color: var(--ink-soft); margin: .6rem 0 0; min-height: 1.2em; font-size: .95rem; }
.run-bar {
  margin: 1.8rem auto 0; width: 220px; max-width: 70vw; height: 4px; border-radius: 999px;
  background: var(--line); overflow: hidden; position: relative;
}
.run-bar-fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: 40%; border-radius: 999px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  animation: sweep 1.6s cubic-bezier(.5,0,.5,1) infinite;
}
.run-bar-fill.determinate { animation: none; left: 0; background: var(--accent);
  transition: width .6s cubic-bezier(.2,.7,.2,1); }
@keyframes sweep { 0% { left: -40%; } 100% { left: 100%; } }

/* ============================= FAILED ============================= */
.fail-card {
  text-align: center; max-width: 30rem; padding: 2.5rem 2rem; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-soft);
}
.fail-mark {
  font-size: 2rem; width: 3.4rem; height: 3.4rem; line-height: 3.4rem; margin: 0 auto 1.2rem;
  border-radius: 50%; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.fail-message { font-family: var(--font-display); font-size: 1.3rem; font-weight: 380; margin: 0 0 1.6rem; line-height: 1.4; }
.fail-actions { display: flex; justify-content: center; }

/* ============================= RESULTS ============================= */
.results-inner { max-width: var(--maxw); margin: 0 auto; padding: clamp(1.5rem, 5vw, 3rem) clamp(1.25rem, 5vw, 3rem) 1rem; }
.back-btn { margin-bottom: 2rem; }
.back-btn .arrow-back { transition: transform .25s; }
.back-btn:hover .arrow-back { transform: translateX(-3px); }

.headline-block { margin-bottom: clamp(2rem, 5vw, 3.4rem); max-width: 62ch; }
/* Scenario recap now leads as a small kicker above the hero numbers. */
.headline-story {
  margin: 0 0 1.1rem; color: var(--ink-soft); font-size: 1.02rem; line-height: 1.5;
  max-width: 46ch;
}

/* Hero: biggest single loser + winner side by side — the human stakes first. */
.headline-hero {
  display: flex; flex-wrap: wrap; gap: clamp(1.4rem, 5vw, 3.4rem);
  align-items: flex-start; margin: 0 0 1.2rem;
}
.hero-stat { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.hero-stat-label {
  font-size: .74rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-soft); font-weight: 700;
}
.hero-stat-country {
  font-family: var(--font-display); font-size: clamp(1.15rem, 3.4vw, 1.7rem);
  font-weight: 400; letter-spacing: -.01em; line-height: 1.1;
}
.hero-stat-val {
  font-family: var(--font-display); font-weight: 340; font-variant-numeric: tabular-nums;
  font-size: clamp(2.7rem, 9vw, 5rem); line-height: .95; letter-spacing: -.03em;
}
.hero-stat.pos .hero-stat-val { color: var(--pos); }
.hero-stat.neg .hero-stat-val { color: var(--neg); }
.hero-stat.zero .hero-stat-val { color: var(--ink-faint); }
/* Mono digits run ~30% wider than the serif, so the editorial value size makes
   the two figures overflow the 62ch block and wrap onto separate rows. Rein the
   mono value in (and tighten the gap) so loss + gain stay side by side. */
[data-brand-mode="brutal"] .headline-hero { gap: clamp(1.2rem, 4vw, 2.6rem); }
[data-brand-mode="brutal"] .hero-stat-val {
  font-size: clamp(1.9rem, 5.6vw, 3.3rem); letter-spacing: -.01em;
}

/* Global welfare — secondary, always defined inline so the number is never bare. */
.headline-welfare {
  margin: 0; color: var(--ink-soft); font-size: 1rem; line-height: 1.5;
  padding-top: 1rem; border-top: 1px solid var(--line); max-width: 52ch;
}
.headline-welfare .hw-label { font-weight: 600; color: var(--ink); }
.headline-welfare .hw-val { font-family: var(--font-display); font-variant-numeric: tabular-nums; font-weight: 600; }
.headline-welfare .hw-val.pos { color: var(--pos); }
.headline-welfare .hw-val.neg { color: var(--neg); }
.headline-welfare .hw-val.zero { color: var(--ink-faint); }
.headline-welfare .hw-gloss { color: var(--ink-faint); }

/* ---- results top bar: back button + export/share actions ---- */
.results-topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: .8rem 1.2rem; flex-wrap: wrap; margin-bottom: clamp(1.2rem, 3vw, 1.8rem);
}
.results-actions { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; }
.btn-mini-action { font-size: .82rem; padding: .5em .9em; text-decoration: none; }
.copy-note { font-size: .82rem; color: var(--accent-deep); font-weight: 600; }

.results-grid { display: grid; grid-template-columns: 1.35fr 1fr; gap: clamp(1.2rem, 3vw, 2.2rem); align-items: start; }
.chart-panel, .sector-panel, .trade-panel, .country-panel {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(1.3rem, 3vw, 1.9rem); box-shadow: var(--shadow-soft);
  /* grid/flex items default to min-width:auto (min-content); the Chart.js canvas
     carries a 300px intrinsic width that would otherwise push the track wider than
     the viewport on narrow screens. Let these panels shrink and the canvas follows. */
  min-width: 0;
}
.chart-holder, .mini-chart-holder { min-width: 0; }
#welfare-chart, #sector-mini-chart { max-width: 100%; }
.country-panel { margin-top: clamp(1.2rem, 3vw, 2.2rem); }
.panel-heading { font-family: var(--font-display); font-weight: 400; font-size: 1.35rem; margin: 0; letter-spacing: -.01em; }
.panel-sub { margin: .35rem 0 1.2rem; color: var(--ink-soft); font-size: .92rem; }
.chart-holder { position: relative; width: 100%; height: clamp(260px, 42vw, 420px); }
.chart-hint { margin: -.7rem 0 1rem; font-size: .8rem; color: var(--ink-faint); font-style: italic; }
.chart-note { margin: .7rem 0 0; font-size: .8rem; color: var(--ink-faint); }
.sector-empty { margin: .4rem 0 1rem; font-size: .9rem; color: var(--ink-soft); }

/* ---- metric switcher (segmented control above the country chart) ----
   Single horizontally-scrollable row: never wraps to multiple rows and never
   pushes the page sideways (min-width:0 + inner overflow-x). Tabs are ≥44px
   tall for comfortable touch targets. */
.metric-switch {
  display: flex; flex-wrap: nowrap; gap: .25rem; margin: 0 0 1.15rem;
  padding: .28rem; background: var(--paper-2); border: 1px solid var(--line);
  border-radius: 12px; min-width: 0; max-width: 100%;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.metric-switch::-webkit-scrollbar { display: none; }
.metric-tab {
  font: inherit; font-family: var(--font-body); font-weight: 600; font-size: .84rem;
  color: var(--ink-soft); background: transparent; border: 0; cursor: pointer;
  padding: .5em 1em; border-radius: 9px; letter-spacing: .005em;
  min-height: 44px; flex: 0 0 auto; white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .18s, color .18s, box-shadow .18s;
}
.metric-tab:hover { color: var(--ink); }
.metric-tab.is-active {
  color: var(--ink); background: var(--surface);
  box-shadow: 0 1px 2px rgba(28, 27, 23, .08), 0 1px 0 rgba(28, 27, 23, .03);
}
.metric-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Plain-English gloss under the switcher; neutral metrics read as a caveat. */
.metric-gloss {
  margin: -.4rem 0 1.1rem; font-size: .88rem; line-height: 1.45; color: var(--ink-soft);
  max-width: 60ch;
}
.metric-gloss.is-neutral {
  padding-left: .7rem; border-left: 3px solid var(--down); color: var(--ink);
}

/* ===================== WORLD MAP (results choropleth) ===================== */
.map-panel {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(1.3rem, 3vw, 1.9rem); box-shadow: var(--shadow-soft);
  margin-bottom: clamp(1.2rem, 3vw, 2.2rem);
}
.map-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: .9rem 1.4rem; flex-wrap: wrap; margin-bottom: 1.1rem;
}
.map-titles { min-width: 0; }
.map-sub { margin-bottom: 0; }
.map-head .metric-switch { margin: 0; }   /* the switch lives inline with the title */

.map-stage {
  position: relative; width: 100%; overflow: hidden; border-radius: 10px;
  background:
    radial-gradient(130% 140% at 50% -10%, color-mix(in srgb, var(--accent) 6%, transparent), transparent 62%),
    var(--paper);
  border: 1px solid var(--line);
}
.map-svg { display: block; width: 100%; height: auto; }
.map-country {
  fill: color-mix(in srgb, var(--line) 60%, var(--paper-2));   /* absent / no estimate */
  stroke: color-mix(in srgb, var(--ink) 16%, transparent);
  stroke-width: .4; stroke-linejoin: round;
  transition: fill .4s ease, stroke-width .12s ease, stroke .12s ease;
}
.map-country.has-data { cursor: pointer; }
.map-country.hover { stroke: var(--ink); stroke-width: 1; }

.map-tip {
  position: absolute; z-index: 6; left: 0; top: 0;
  transform: translate(-50%, calc(-100% - 10px));
  pointer-events: none; background: var(--ink); color: var(--surface);
  padding: .42rem .62rem; border-radius: 9px; box-shadow: var(--shadow-lift);
  display: flex; flex-direction: column; gap: .1rem; white-space: nowrap; max-width: 70vw;
}
.map-tip-name { font-size: .8rem; font-weight: 600; }
.map-tip-val { font-family: var(--font-display); font-variant-numeric: tabular-nums; font-size: 1.02rem; letter-spacing: -.01em; }
.map-tip-val.pos { color: color-mix(in srgb, var(--gain) 45%, #fff); }
.map-tip-val.neg { color: color-mix(in srgb, var(--neg) 42%, #fff); }
.map-tip-val.up { color: color-mix(in srgb, var(--up) 50%, #fff); }
.map-tip-val.down { color: color-mix(in srgb, var(--down) 55%, #fff); }

.map-legend-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem 1.4rem; flex-wrap: wrap; margin-top: 1.1rem;
}
.map-legend { display: flex; flex-direction: column; gap: .34rem; flex: 1 1 15rem; min-width: min(14rem, 100%); }
.legend-track { position: relative; height: 10px; }
.legend-bar { display: block; height: 100%; width: 100%; border-radius: 999px; border: 1px solid var(--line-strong); }
/* Valence words under the legend numbers ("worse off / better off", or
   "fell / rose" for neutral metrics) — first-time readers decode from words,
   not hue (design-review 2026-07-15). */
.legend-ends span { display: inline-flex; flex-direction: column; }
.legend-ends span:last-child { align-items: flex-end; }
.legend-word { font-size: .68rem; color: var(--ink-faint); letter-spacing: .02em; }
/* Expanded-map (lightbox) second channel for losses: colour must not be the
   sole carrier on the one surface without printed numbers (WCAG 1.4.1). */
#map-overlay-stage .map-country.is-loss {
  stroke: var(--ink); stroke-width: .55; stroke-dasharray: 3 2.2;
  vector-effect: non-scaling-stroke;
}
.legend-tick { position: absolute; top: -3px; width: 1.5px; height: 16px; background: var(--ink); border-radius: 1px; }
.legend-tick::after {
  content: "0"; position: absolute; top: -13px; left: 50%; transform: translateX(-50%);
  font-size: .6rem; font-weight: 700; color: var(--ink-faint);
}
.legend-ends { display: flex; justify-content: space-between; font-size: .72rem; font-weight: 600; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.map-row-chip {
  display: inline-flex; align-items: baseline; gap: .5rem; flex: none;
  padding: .4rem .8rem; border-radius: 999px; background: var(--paper); border: 1px solid var(--line-strong);
}
.map-row-chip .row-chip-label { font-size: .78rem; font-weight: 600; color: var(--ink-soft); }
.map-row-chip .row-chip-val { font-family: var(--font-display); font-variant-numeric: tabular-nums; font-size: 1.02rem; }
.map-row-chip.pos .row-chip-val { color: var(--pos); }
.map-row-chip.neg .row-chip-val { color: var(--neg); }
.map-row-chip.up .row-chip-val { color: var(--up); }
.map-row-chip.down .row-chip-val { color: var(--down); }
.map-row-chip.zero .row-chip-val { color: var(--ink-faint); }

/* Expand affordance — floats over the top-right corner of the fixed inline
   map; opens the pan/zoom lightbox (.map-overlay below). Sizing/hover/focus
   all come from the shared .btn/.btn-ghost/.btn-mini-action primitives —
   this rule only positions it over the map. */
.map-expand-btn {
  position: absolute; top: .6rem; right: .6rem; z-index: 5;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.map-expand-icon { flex: none; }

/* ===================== MAP LIGHTBOX (expand overlay) =====================
   A near-fullscreen dialog: edge-to-edge on phones, a centered card with a
   scrim behind it from ~720px up. Hosts the SAME <svg class="map-svg">
   moved in from #map-stage (see openMapOverlay/closeMapOverlay in app.js) —
   pan/zoom is a transform on its inner <g>, hand-rolled (no vendored
   d3-zoom; see MAP_ZOOM_* in app.js). */
.map-overlay {
  position: fixed; inset: 0; z-index: 70;
  background: color-mix(in srgb, var(--ink) 55%, transparent);
  display: flex; align-items: stretch; justify-content: center;
}
.map-overlay[hidden] { display: none; }
.map-overlay-panel {
  background: var(--surface); width: 100%; height: 100%;
  display: flex; flex-direction: column; min-height: 0;
}
@media (min-width: 46rem) {
  .map-overlay { padding: 2.4vh 2.6vw; }
  .map-overlay-panel {
    max-width: 1100px; margin: 0 auto; border-radius: var(--radius);
    border: 1px solid var(--line); box-shadow: var(--shadow-lift); overflow: hidden;
  }
}
.map-overlay-head {
  display: flex; align-items: center; justify-content: space-between; gap: .7rem;
  padding: .8rem .9rem; border-bottom: 1px solid var(--line); flex: none;
}
.map-overlay-title {
  font-family: var(--font-display); font-weight: 400; font-size: 1.1rem; margin: 0;
  letter-spacing: -.01em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.map-overlay-actions { display: flex; align-items: center; gap: .4rem; flex: none; }
.map-zoom-btn { padding: .5em .7em; min-width: 44px; justify-content: center; font-weight: 700; }
.map-overlay-close { padding: .5em .8em; min-width: 44px; justify-content: center; font-size: 1.15rem; line-height: 1; margin-left: .25rem; }
.map-overlay-stage {
  position: relative; flex: 1 1 auto; min-height: 0; overflow: hidden;
  background:
    radial-gradient(130% 140% at 50% -10%, color-mix(in srgb, var(--accent) 6%, transparent), transparent 62%),
    var(--paper);
  display: flex; align-items: center; justify-content: center;
  touch-action: none;      /* we do our own pan/pinch — don't fight the browser's */
  cursor: grab;
}
.map-overlay-stage:active { cursor: grabbing; }
.map-overlay-stage .map-svg { display: block; width: auto; height: auto; }
.map-overlay-hint {
  flex: none; margin: 0; padding: .5rem 1rem calc(.5rem + env(safe-area-inset-bottom));
  font-size: .72rem; color: var(--ink-faint); text-align: center; border-top: 1px solid var(--line);
}
.map-tip-overlay { z-index: 6; }
body.map-overlay-open { overflow: hidden; }

/* ---- biggest trade shifts ---- */
.trade-list { list-style: none; margin: 0; padding: 0; }
.trade-row {
  position: relative;
  display: flex; align-items: baseline; justify-content: space-between; gap: .8rem;
  padding: .62rem 0 .78rem; border-bottom: 1px solid var(--line);
}
.trade-row:last-child { border-bottom: none; }
/* Subtle bar along the row foot, sized by DOLLAR change — a sense of scale so
   the ranking (by material size, not raw %) reads at a glance. */
.trade-bar {
  position: absolute; left: 0; bottom: 3px; height: 3px; border-radius: 2px;
  background: color-mix(in srgb, var(--gain) 50%, transparent);
  transition: width .5s ease;
}
.trade-bar.neg { background: color-mix(in srgb, var(--neg) 50%, transparent); }
.trade-bar.zero { background: var(--line-strong); }
.trade-tag {
  font-size: .6rem; letter-spacing: .1em; text-transform: uppercase; font-weight: 700;
  color: var(--ink-faint); border: 1px solid var(--line-strong); border-radius: 999px;
  padding: .12em .5em; align-self: center; flex: none; white-space: nowrap;
}
.trade-pair { display: flex; align-items: baseline; gap: .45em; min-width: 0; font-size: .96rem; }
.trade-from, .trade-to { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trade-arrow { color: var(--ink-faint); font-weight: 600; flex: none; }
.trade-val {
  font-family: var(--font-display); font-variant-numeric: tabular-nums; font-size: 1.12rem;
  flex: none; letter-spacing: -.01em;
}
.trade-val.pos { color: var(--pos); }
.trade-val.neg { color: var(--neg); }
.trade-val.zero { color: var(--ink-faint); }

/* ---- country drill-down ---- */
.sector-titles { min-width: 0; }
.sector-titles .panel-sub { margin-bottom: 0; }
.cstat-row { display: flex; flex-wrap: wrap; gap: .55rem; margin: 1.2rem 0 1.4rem; }
.cstat {
  display: flex; flex-direction: column; gap: .12rem; padding: .5rem .8rem;
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px; min-width: 5.4rem;
}
.cstat-label { font-size: .68rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint); font-weight: 600; }
.cstat-value { font-family: var(--font-display); font-variant-numeric: tabular-nums; font-size: 1.22rem; letter-spacing: -.01em; color: var(--ink-soft); }
.cstat.pos .cstat-value { color: var(--pos); }
.cstat.neg .cstat-value { color: var(--neg); }
.cstat.up .cstat-value { color: var(--up); }
.cstat.down .cstat-value { color: var(--down); }
.country-body { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.2rem, 3vw, 2rem); align-items: start; }
.mini-heading { margin: 0 0 .6rem; font-size: .74rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); font-weight: 600; }
.mini-chart-holder { position: relative; width: 100%; height: 260px; }

.sector-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.picker { display: inline-flex; align-items: center; gap: .5em; min-width: 0; max-width: 100%; }
.picker .select { min-width: 0; }
.picker-label { font-size: .82rem; color: var(--ink-soft); font-weight: 500; }
.select {
  font: inherit; font-family: var(--font-body); font-weight: 600; font-size: .92rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line-strong); border-radius: 8px;
  padding: .35em 1.8em .35em .7em; appearance: none; -webkit-appearance: none; cursor: pointer;
  background-image: var(--chevron);
  background-repeat: no-repeat; background-position: right .6em center;
}
.select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.sector-table { width: 100%; border-collapse: collapse; margin-top: .4rem; }
.sector-table th, .sector-table td { text-align: left; padding: .7rem .2rem; border-bottom: 1px solid var(--line); }
.sector-table th { font-size: .74rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); font-weight: 600; }
.sector-table td { font-size: 1rem; }
.sector-table .num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-display); font-size: 1.1rem; }
.sector-table td.num.pos { color: var(--pos); }
.sector-table td.num.neg { color: var(--neg); }
.sector-table tbody tr:last-child td { border-bottom: none; }

/* ---- provenance: "About these numbers" ---- */
.provenance-panel {
  margin-top: clamp(1.4rem, 4vw, 2.2rem);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(1.2rem, 3vw, 1.7rem); box-shadow: var(--shadow-soft);
}
.provenance-panel .panel-heading { margin-bottom: .9rem; }
.prov-list { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: .4rem 1.1rem; }
.prov-item { display: contents; }
.prov-list dt {
  font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 700; padding-top: .12rem;
}
.prov-list dd { margin: 0; color: var(--ink); font-size: .96rem; line-height: 1.45; }
.prov-note {
  margin: 1rem 0 0; color: var(--ink-soft); font-size: .9rem; line-height: 1.5;
  max-width: 68ch;
}
/* KITE house style for text links (see kite-model.org): ink-colored text with a
   solid bottom border — never a distinct link hue. --accent-deep resolves to ink
   (#0a0a0a) in technical mode, matching the site exactly, and to the deep-green
   editorial accent otherwise. The bright chartreuse --accent is reserved for
   button fills, never text. */
.prov-methods-link {
  color: var(--accent-deep); font-weight: 700;
  text-decoration: none;
  border-bottom: 2px solid currentColor; padding-bottom: 1px;
}
.prov-methods-link:hover, .prov-methods-link:focus-visible { border-bottom-width: 3px; }
/* ============================= FOOTER ============================= */
.site-footer {
  position: relative; z-index: 1; max-width: var(--maxw); margin: clamp(3rem, 8vw, 6rem) auto 0;
  padding: 2rem clamp(1.25rem, 5vw, 3rem) 3rem; border-top: 1px solid var(--line);
}
.site-footer p { margin: 0; color: var(--ink-faint); font-size: .88rem; font-family: var(--font-display); font-style: italic; }
.footer-privacy { font-size: .8rem !important; font-style: normal !important; margin-top: .5rem !important; }
/* Required CC BY 4.0 attribution for the bundled DB-IP Lite geolocation data —
   kept small and unobtrusive but always present on the public page. */
.footer-geo-attr { font-size: .74rem !important; font-style: normal !important; margin-top: .35rem !important; }
.footer-geo-attr a { color: inherit; }

/* ---- cross-device continuity: reveal / restore ---- */
.device-continuity { display: flex; flex-wrap: wrap; gap: .55rem; margin-top: 1rem; }
.token-panel { position: relative; margin-top: .8rem; max-width: 32rem; }
.token-close {
  position: absolute; top: .2rem; right: .2rem; width: 40px; height: 40px;
  border: none; background: transparent; color: var(--ink-soft);
  font-size: 1.4rem; line-height: 1; cursor: pointer; border-radius: 8px;
}
.token-close:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 8%, transparent); }
.token-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.token-hint { margin: 0 0 .5rem; color: var(--ink-soft); font-size: .85rem; }
.token-row { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.token-input {
  font: inherit; font-family: var(--font-body); font-size: .92rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line-strong); border-radius: 8px;
  padding: .5em .7em; flex: 1 1 auto; min-width: 0; max-width: 100%;
}
.token-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.token-input:read-only { color: var(--ink-soft); }
.token-msg { font-size: .82rem; color: var(--neg); margin: .5rem 0 0; }

/* ===================== SCENARIO RAILS (mine / examples) ===================== */
.strip { border-top: 1px solid var(--line); padding: clamp(1.6rem, 4vw, 2.6rem) 0; }
.rail {
  display: flex; gap: clamp(.8rem, 2vw, 1.2rem);
  max-width: var(--maxw); margin: 0 auto;
  padding: .3rem clamp(1.25rem, 5vw, 3rem) 1rem;
  /* Match scroll-padding to the inline padding: without it, snap-align:start
     auto-scrolls the first card flush to x=0 on load, eating the left inset
     (the right padding shows, the left doesn't). */
  scroll-padding-inline: clamp(1.25rem, 5vw, 3rem);
  overflow-x: auto; scroll-snap-type: x proximity;
  scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent;
  -webkit-overflow-scrolling: touch;
}
.rail::-webkit-scrollbar { height: 8px; }
.rail::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 999px; }
.rail::-webkit-scrollbar-track { background: transparent; }

.rail-card {
  scroll-snap-align: start; flex: 0 0 auto;
  width: clamp(15rem, 24vw, 17.5rem); min-height: 6.4rem;
  text-align: left; cursor: pointer; font: inherit; color: inherit;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.05rem 1.15rem 1.1rem;
  display: grid; grid-template-columns: 1fr auto; grid-auto-rows: min-content;
  align-content: space-between; gap: .5rem .6rem;
  box-shadow: var(--shadow-soft);
  transition: transform .3s cubic-bezier(.2,.7,.2,1), box-shadow .3s, border-color .3s;
}
.rail-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); border-color: var(--line-strong); }
.rail-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.rail-status {
  grid-column: 1; justify-self: start; align-self: center;
  width: .58rem; height: .58rem; border-radius: 50%;
  background: var(--ink-faint); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink-faint) 16%, transparent);
}
.rail-status.dot-succeeded { background: var(--pos); box-shadow: 0 0 0 3px color-mix(in srgb, var(--pos) 18%, transparent); }
.rail-status.dot-failed { background: var(--neg); box-shadow: 0 0 0 3px color-mix(in srgb, var(--neg) 16%, transparent); }
.rail-status.dot-running,
.rail-status.dot-queued { background: var(--warn); box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 20%, transparent); animation: pulse-dot 1.5s ease-in-out infinite; }
@keyframes pulse-dot { 0%,100% { opacity: .55; } 50% { opacity: 1; } }
.rail-state {
  grid-column: 2; justify-self: end; align-self: center;
  font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
  font-weight: 600; color: var(--ink-faint);
}
.rail-title {
  grid-column: 1 / -1; font-family: var(--font-display); font-weight: 400;
  font-size: 1.06rem; line-height: 1.25; letter-spacing: -.005em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.rail-figure {
  grid-column: 1 / -1; justify-self: start; align-self: end;
  font-family: var(--font-display); font-variant-numeric: tabular-nums;
  font-size: 1.5rem; font-weight: 440; letter-spacing: -.02em; line-height: 1;
}
.rail-figure.pos { color: var(--pos); }
.rail-figure.neg { color: var(--neg); }

/* ---- hideable rail cards ("Your scenarios") ---- */
/* .rail-card (above) carries scroll-snap-align + flex: 0 0 auto for its use
   in the unwrapped "Examples" rail. Hideable cards wrap it in .rail-item, so
   .rail-item must be the one to carry those — it's the rail's direct child
   (scroll-snap targets its direct children only), and flex: 0 0 auto stops
   it shrinking the way a bare flex item would. */
.rail-item {
  position: relative; display: inline-flex; flex: 0 0 auto; scroll-snap-align: start;
  /* The wrapper carries the card's fixed width — width:100% on the inner card
     against an auto-sized wrapper would balloon cards to their content width. */
  width: clamp(15rem, 24vw, 17.5rem);
}
.rail-item .rail-card { width: 100%; }
/* Keep the status word clear of the absolutely-positioned × */
.rail-item .rail-state { margin-right: 1.5rem; }
.rail-x {
  position: absolute; top: .3rem; right: .3rem;
  width: 1.6rem; height: 1.6rem; line-height: 1;
  border: none; border-radius: 50%;
  background: transparent; color: var(--ink-soft);
  font-size: 1rem; cursor: pointer;
}
.rail-x:hover { color: var(--neg); background: color-mix(in srgb, var(--neg) 10%, transparent); }
.rail-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ===================== GROUP AGGREGATE CHIPS (results headline) ===================== */
.agg-chips { display: flex; flex-wrap: wrap; gap: .55rem; margin: 1.3rem 0 .2rem; }
.agg-chip {
  display: inline-flex; align-items: baseline; gap: .5rem;
  padding: .4rem .8rem; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-soft);
}
.agg-chip .agg-name {
  font-size: .82rem; font-weight: 600; letter-spacing: .01em; color: var(--ink-soft);
}
.agg-chip .agg-value {
  font-family: var(--font-display); font-variant-numeric: tabular-nums;
  font-size: 1.02rem; font-weight: 460; color: var(--ink);
}
.agg-chip.pos .agg-value { color: var(--pos); }
.agg-chip.neg .agg-value { color: var(--neg); }
.agg-chip.up .agg-value { color: var(--up); }
.agg-chip.down .agg-value { color: var(--down); }
.agg-chip.hl {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, var(--surface));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent), var(--shadow-soft);
}
.agg-chip.hl .agg-name { color: var(--accent-deep); }

/* ============================= ADMIN ============================= */
/* Reserved hook for admin-only body overrides (mirrors .methods-body's
   per-page pattern below) — admin currently uses the shared editorial theme
   as-is, so there is nothing to override yet. */
.admin-body { }
.admin-gate {
  min-height: 82vh; display: flex; align-items: center; justify-content: center; padding: 2rem;
}
.gate-card {
  width: min(26rem, 100%); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-lift); padding: 2.2rem 2rem;
}
.gate-eyebrow { margin: 0 0 .5rem; font-size: .72rem; letter-spacing: .22em; text-transform: uppercase; font-weight: 600; color: var(--accent); }
.gate-title { font-family: var(--font-display); font-weight: 360; font-size: 1.8rem; margin: 0 0 1.4rem; letter-spacing: -.01em; }
.gate-form { display: flex; flex-direction: column; gap: .8rem; }
.gate-input {
  font: inherit; font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line-strong); border-radius: 10px;
  padding: .7em .9em; width: 100%;
}
.gate-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.gate-msg { min-height: 1.2em; margin: .2rem 0 0; color: var(--neg); font-size: .88rem; }

.admin-shell { max-width: 1240px; margin: 0 auto; padding: clamp(1.5rem, 4vw, 2.6rem) clamp(1.25rem, 5vw, 2.4rem) 3rem; }
.admin-top { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.6rem; }
.admin-top h1 { font-family: var(--font-display); font-weight: 360; font-size: clamp(1.7rem, 4vw, 2.4rem); margin: 0; letter-spacing: -.015em; }
.admin-top .admin-tools { display: flex; gap: .6rem; align-items: center; }
.admin-tick { font-size: .8rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.btn-mini {
  font-family: var(--font-body); font-weight: 600; font-size: .82rem; cursor: pointer;
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
  border-radius: 8px; padding: .45em .9em; transition: border-color .2s, background .2s;
}
.btn-mini:hover { border-color: var(--ink); }
.btn-mini:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: .9rem; margin-bottom: 1.6rem; }
.stat-cell { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 1rem 1.1rem; box-shadow: var(--shadow-soft); }
.stat-cell .k { font-size: .68rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); font-weight: 600; }
.stat-cell .v { font-family: var(--font-display); font-variant-numeric: tabular-nums; font-size: 2rem; font-weight: 380; margin-top: .2rem; line-height: 1; }

.admin-panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-soft); padding: 1.2rem 1.3rem 1.4rem; margin-bottom: 1.4rem; }
.admin-panel h2 { font-family: var(--font-display); font-weight: 400; font-size: 1.2rem; margin: 0 0 .9rem; letter-spacing: -.005em; }
.admin-empty { color: var(--ink-faint); font-style: italic; font-family: var(--font-display); font-size: .95rem; margin: .3rem 0; }

/* Wide admin tables scroll inside their own box — never the page. */
.table-scroll {
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
/* Keep the natural column widths inside the scroller so it actually scrolls
   (rather than crushing columns to fit and wrapping the page). */
.table-scroll > .dtable { min-width: max-content; }
.dtable { width: 100%; border-collapse: collapse; font-size: .86rem; }
.dtable th, .dtable td { text-align: left; padding: .5rem .55rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
.dtable th { font-size: .66rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint); font-weight: 600; white-space: nowrap; }
.dtable td.num, .dtable th.num { text-align: right; font-variant-numeric: tabular-nums; }
.dtable tbody tr:last-child td { border-bottom: none; }
.dtable .mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .78rem; color: var(--ink-soft); }
.dtable .fig { font-family: var(--font-display); font-variant-numeric: tabular-nums; }
.dtable .fig.pos { color: var(--pos); } .dtable .fig.neg { color: var(--neg); }
.pill { display: inline-block; padding: .12em .55em; border-radius: 999px; font-size: .72rem; font-weight: 600; letter-spacing: .02em; }
.pill.s-succeeded { background: color-mix(in srgb, var(--pos) 14%, transparent); color: var(--accent-deep); }
.pill.s-running, .pill.s-queued { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn-text); }
.pill.s-failed { background: color-mix(in srgb, var(--neg) 13%, transparent); color: var(--neg); }

/* visibility toggle switch */
.toggle { position: relative; display: inline-flex; align-items: center; cursor: pointer; }
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle .track { width: 2.4rem; height: 1.3rem; border-radius: 999px; background: var(--line-strong); transition: background .2s; position: relative; }
.toggle .track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 1.1rem; height: 1.1rem; border-radius: 50%; background: var(--surface); box-shadow: 0 1px 2px rgba(28,27,23,.3); transition: transform .2s; }
.toggle input:checked + .track { background: var(--accent); }
.toggle input:checked + .track::after { transform: translateX(1.1rem); }
.toggle input:focus-visible + .track { outline: 2px solid var(--accent); outline-offset: 2px; }
.toggle.busy { opacity: .5; pointer-events: none; }

/* ---- admin hint + clickable rows ---- */
.admin-hint { color: var(--ink-faint); font-size: .84rem; margin: -.4rem 0 .9rem; }
.dtable-click tbody tr.clickable { cursor: pointer; }
.dtable-click tbody tr.clickable:hover { background: color-mix(in srgb, var(--accent) 6%, transparent); }
.row-actions { text-align: right; white-space: nowrap; }
.linklike {
  background: none; border: none; padding: 0; margin: 0; cursor: pointer;
  color: var(--accent-deep); font: inherit; text-decoration: underline;
  text-underline-offset: 2px; text-decoration-thickness: 1px;
}
.linklike:hover { color: var(--accent); }

/* ---- danger + spinner mini buttons ---- */
.btn-danger-mini {
  font: 600 .78rem/1 var(--font-body); padding: .38rem .7rem; border-radius: 8px;
  background: color-mix(in srgb, var(--neg) 10%, transparent);
  color: var(--neg); border: 1px solid color-mix(in srgb, var(--neg) 35%, transparent);
  cursor: pointer; transition: background .15s, border-color .15s;
}
.btn-danger-mini:hover { background: color-mix(in srgb, var(--neg) 18%, transparent); border-color: var(--neg); }
.btn-danger-mini:focus-visible { outline: 2px solid var(--neg); outline-offset: 2px; }
.spin {
  display: inline-block; width: .8em; height: .8em; margin-left: .5em;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  vertical-align: -1px; animation: spin .6s linear infinite;
}
/* @keyframes spin is shared with .orbit-ring above (line ~556) — same keyframes,
   byte-identical, deliberately not redefined here. */
.is-busy { opacity: .8; }

/* ---- System card grid ---- */
.sys-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: .8rem .9rem; }
.geo-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1rem, 2.5vw, 1.6rem); align-items: start; }
.geo-subhead { font-family: var(--font-display); font-weight: 400; font-size: .92rem; margin: 0 0 .5rem; color: var(--ink-soft); }
.sys-cell { display: flex; flex-direction: column; gap: .18rem; }
.sys-cell .k { font-size: .64rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); font-weight: 600; }
.sys-cell .v { font-variant-numeric: tabular-nums; font-size: 1rem; }
.sys-cell .v.mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .84rem; color: var(--ink-soft); word-break: break-all; }

/* ---- Detail drawer ---- */
.drawer-scrim { position: fixed; inset: 0; background: rgba(28,27,23,.34); z-index: 40; animation: fade .2s ease; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.drawer {
  position: fixed; top: 0; right: 0; height: 100%; width: min(560px, 94vw);
  background: var(--surface); border-left: 1px solid var(--line); box-shadow: var(--shadow-lift);
  z-index: 41; display: flex; flex-direction: column; animation: slidein .24s cubic-bezier(.22,.61,.36,1);
}
@keyframes slidein { from { transform: translateX(100%); } to { transform: translateX(0); } }
.drawer-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: 1.2rem 1.3rem 1rem; border-bottom: 1px solid var(--line); }
.drawer-title { font-family: var(--font-display); font-weight: 400; font-size: 1.3rem; margin: 0; letter-spacing: -.01em; line-height: 1.25; }
.drawer-body { overflow-y: auto; padding: 1.1rem 1.3rem 2.2rem; }
.drawer-h3 { font-family: var(--font-display); font-weight: 400; font-size: 1.02rem; margin: 1.5rem 0 .6rem; }
.fact-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .7rem .9rem; }
.fact { display: flex; flex-direction: column; gap: .1rem; }
.fact-k { font-size: .64rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); font-weight: 600; }
.fact-v { font-variant-numeric: tabular-nums; font-size: .95rem; }
.code-block {
  background: var(--paper-2); border: 1px solid var(--line); border-radius: 10px;
  padding: .7rem .85rem; font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: .78rem; line-height: 1.5; overflow-x: auto; white-space: pre; margin: 0;
}
.log-tail { max-height: 16rem; overflow-y: auto; white-space: pre-wrap; word-break: break-word; }
.drawer-err { font-size: .86rem; margin: .3rem 0 .5rem; }
.drawer-actions { display: flex; flex-direction: column; gap: .8rem; }
.action-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.rename-input {
  flex: 1 1 12rem; padding: .45rem .6rem; border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--surface); font: inherit; font-size: .88rem; color: var(--ink);
}
.rename-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.toggle-box { display: inline-flex; align-items: center; gap: .4rem; margin-left: auto; }
.toggle-caption { font-size: .8rem; color: var(--ink-soft); }
.btn-solid.btn-mini { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn-solid.btn-mini:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
body.drawer-open { overflow: hidden; }

/* ---- Toasts ----
   Single shared implementation: both the public front-end (showToast() in
   app.js — "Hidden — the scenario stays available…" + Undo) and the admin
   dashboard (toast() in admin.js) append a `.toast` into the same `#toasts`
   flex-column host. There used to be a SECOND, unscoped `.toast{...}` rule
   above (a fixed-position single-instance version, transform-driven,
   `.is-visible` toggle) that collided with this one at equal specificity —
   whichever rule came later in the file won as the base `opacity:0` state,
   and since the two implementations used different toggle classes neither
   toast's "shown" rule ever matched reliably. Merged into one rule that
   accepts either toggle class. */
.toasts { position: fixed; bottom: 1.4rem; left: 50%; transform: translateX(-50%); z-index: 50; display: flex; flex-direction: column; gap: .5rem; align-items: center; pointer-events: none; }
.toast {
  display: flex; align-items: center; gap: .8rem;
  background: var(--ink); color: var(--surface); padding: .6rem 1rem; border-radius: 10px;
  font-family: var(--font-body); font-size: .86rem; box-shadow: var(--shadow-lift);
  opacity: 0; transform: translateY(8px);
  transition: opacity .28s, transform .28s; max-width: 90vw;
  pointer-events: auto;   /* the host ignores pointer events; each toast (and its Undo button) must not */
}
.toast.show, .toast.is-visible { opacity: 1; transform: translateY(0); }
.toast-action {
  border: none; background: transparent; color: inherit;
  font: inherit; font-weight: 700; text-decoration: underline; cursor: pointer;
  min-height: 44px;
}
.toast-error { background: var(--neg); }

/* ---- overflow guards: nothing may push the page sideways ---- */
/* Long option labels ("São Tomé and Príncipe", "United Arab Emirates") must
   never make a <select> wider than its container — clamp every inline blank. */
.blank, select.blank, .select { max-width: 100%; }
.crow-sentence { min-width: 0; }
/* The sector table is an intentional horizontal scroller on narrow screens:
   it scrolls WITHIN its wrap, never the page. */
.sector-table-wrap { min-width: 0; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.sector-table { min-width: 18rem; }

/* ============================= RESPONSIVE ============================= */
@media (max-width: 860px) {
  .results-grid { grid-template-columns: 1fr; }
  .country-body { grid-template-columns: 1fr; }
  .geo-grid { grid-template-columns: 1fr; }
}
@media (max-width: 620px) {
  body { font-size: 16px; }
  /* Single column: brand visual on top, copy below — both flush left. */
  .hero { grid-template-columns: 1fr; row-gap: 1.5rem; padding-top: 3rem; }
  .hero-copy { grid-column: 1; grid-row: 2; }
  .hero-visual { grid-column: 1; grid-row: 1; justify-self: start; }
  .hero-kite { height: clamp(120px, 34vw, 180px); }
  .crow-sentence { font-size: 1.14rem; line-height: 1.95; }
  .composer-actions { flex-direction: column-reverse; align-items: stretch; }
  .composer-actions .btn { justify-content: center; }
  /* stack the map title over the switch; the switch wraps within its width
     (min-width:0 defeats the flex auto-minimum so it can never widen the page) */
  .map-head { flex-direction: column; align-items: stretch; }
  .map-head .metric-switch { min-width: 0; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
  .orbit-ring, .orbit-core, .run-bar-fill { animation: none !important; }
}

/* =========================================================================
   WP8 admin — settings, sessions, bulk toolbar, maintenance, session drawer.
   Admin keeps the editorial theme (not brand-switched); reuses .dtable etc.
   ========================================================================= */
.settings-form { display: flex; flex-direction: column; gap: .7rem; max-width: 640px; }
.set-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 1rem; }
.set-label { font-size: .9rem; color: var(--ink-soft); font-weight: 500; }
.set-input { font: inherit; font-size: .9rem; padding: .4rem .55rem; border: 1px solid var(--line-strong);
  border-radius: 8px; background: var(--surface); color: var(--ink); }
.set-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-color: var(--accent); }
.set-num { width: 7rem; text-align: right; font-variant-numeric: tabular-nums; }
.set-input[type=text] { min-width: min(20rem, 60vw); }
.set-check { width: 18px; height: 18px; accent-color: var(--accent); justify-self: end; }
.set-radios { display: inline-flex; flex-wrap: wrap; gap: .4rem .9rem; max-width: 100%; }
.set-radio { display: inline-flex; align-items: center; gap: .3rem; font-size: .88rem; }
.set-radio input { accent-color: var(--accent); }
.set-actions { display: flex; align-items: center; gap: .9rem; margin-top: .4rem; }
.set-note { font-size: .82rem; color: var(--ink-faint); }
.set-note.ok { color: var(--accent-deep); }
.set-note.err { color: var(--neg); }
.set-hint { margin: -.3rem 0 0; }

.scenarios-toolbar { display: flex; flex-wrap: wrap; justify-content: space-between;
  align-items: center; gap: .8rem; margin-bottom: .7rem; }
.filters { display: flex; flex-wrap: wrap; gap: .8rem; align-items: center; }
.filt { display: inline-flex; align-items: center; gap: .35rem; font-size: .8rem; color: var(--ink-faint); }
.filt-check { gap: .3rem; }
.select-mini { font: inherit; font-size: .82rem; padding: .25rem .4rem; border: 1px solid var(--line-strong);
  border-radius: 7px; background: var(--surface); color: var(--ink); }
.bulk-actions { display: flex; align-items: center; gap: .5rem; padding: .3rem .5rem;
  background: color-mix(in srgb, var(--accent) 8%, var(--surface)); border: 1px solid var(--line); border-radius: 9px; }
.bulk-count { font-size: .8rem; color: var(--ink-soft); font-weight: 600; }
.sel-col { width: 2.2rem; text-align: center; }
.sel-col input { accent-color: var(--accent); }

.maint-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .8rem; }
.maint-result { font-size: .82rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }

.session-scn-list { display: flex; flex-direction: column; gap: .4rem; }
.session-scn { display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  width: 100%; text-align: left; font: inherit; font-size: .9rem; padding: .5rem .7rem;
  border: 1px solid var(--line); border-radius: 9px; background: var(--surface); color: var(--ink); cursor: pointer; }
.session-scn:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
.session-scn-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.session-scn-fig { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.session-scn-fig.pos { color: var(--pos); } .session-scn-fig.neg { color: var(--neg); } .session-scn-fig.zero { color: var(--ink-faint); }
.row-actions .btn-mini, .row-actions .btn-danger-mini { margin-left: .35rem; }

.device-list { display: flex; flex-direction: column; gap: .6rem; }
.device-card { border: 1px solid var(--line); border-radius: 9px; padding: .6rem .7rem; background: var(--surface); }
.device-card-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: .5rem; }
.device-visits { font-size: .78rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.device-facts { grid-template-columns: repeat(2, 1fr); gap: .4rem .8rem; margin: 0; }
.device-facts .fact-v, .device-facts .fact-k { font-size: .82rem; }

@media (max-width: 560px) {
  .set-row { grid-template-columns: 1fr; align-items: start; gap: .3rem; }
  .set-check, .set-num { justify-self: start; }
}

/* =========================================================================
   METHODS — the standalone methodology "model card" page (/methods).
   Long-form article layout on the same warm-paper canvas; reuses the shared
   tokens (--serif/--sans/--ink/--paper/--accent/--maxw/--radius/--shadow)
   and the .panel-heading / .hero-eyebrow / .btn-ghost primitives from above.
   ========================================================================= */
.methods-body { background: var(--paper); }
.methods-page { position: relative; z-index: 1; }
.methods-inner {
  max-width: 74ch; margin: 0 auto;
  padding: clamp(2rem, 6vw, 4rem) clamp(1.25rem, 5vw, 2rem) clamp(4rem, 10vw, 6rem);
}

.methods-back {
  display: inline-block; margin-bottom: 2rem; color: var(--ink-soft);
  font-size: .9rem; text-decoration: none;
}
.methods-back:hover, .methods-back:focus-visible { color: var(--accent); text-decoration: underline; }

.methods-header { margin-bottom: clamp(2rem, 5vw, 3rem); }
.methods-title {
  font-family: var(--font-display); font-weight: 400; font-size: clamp(1.7rem, 4vw, 2.4rem);
  line-height: 1.15; margin: .4rem 0 .8rem; letter-spacing: -.01em;
}
.methods-lede { color: var(--ink-soft); font-size: 1.05rem; line-height: 1.6; max-width: 58ch; margin: 0; }

.methods-section {
  margin: 0 0 clamp(2rem, 5vw, 3rem); padding-top: clamp(2rem, 5vw, 3rem);
  border-top: 1px solid var(--line);
}
.methods-section:first-of-type { border-top: none; padding-top: 0; }
.methods-section .panel-heading { margin: 0 0 .9rem; font-size: 1.25rem; }
.methods-section p { margin: 0 0 1rem; line-height: 1.65; }
.methods-section p:last-child { margin-bottom: 0; }
.methods-section ul { margin: 0 0 1rem; padding-left: 1.3rem; line-height: 1.6; }
.methods-section ul:last-child { margin-bottom: 0; }
.methods-section li { margin-bottom: .5rem; }
.methods-section li:last-child { margin-bottom: 0; }
.methods-note { color: var(--ink-faint); font-size: .86rem; }

.methods-sector-list {
  list-style: none; margin: 0 0 1rem; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: .4rem .8rem;
}
.methods-sector-list li {
  margin: 0; padding: .5rem .8rem; background: var(--surface); border: 1px solid var(--line);
  border-radius: 9px; font-size: .92rem;
}

.methods-elasticity-table { width: 100%; border-collapse: collapse; margin-bottom: .8rem; }
.methods-elasticity-table th, .methods-elasticity-table td {
  text-align: left; padding: .5rem .6rem; border-bottom: 1px solid var(--line); font-size: .92rem;
}
.methods-elasticity-table th { color: var(--ink-faint); font-weight: 600; text-transform: uppercase; font-size: .72rem; letter-spacing: .08em; }
.methods-elasticity-table td.num, .methods-elasticity-table th.num { text-align: right; font-variant-numeric: tabular-nums; }

.methods-cite { margin-bottom: 2rem; }
.methods-cite:last-of-type { margin-bottom: .8rem; }
.methods-cite-label { font-size: .92rem; color: var(--ink-soft); margin: 0 0 .5rem; }
.methods-cite-text {
  margin: 0 0 .8rem; padding: .8rem 1rem; border-left: 3px solid var(--accent);
  background: var(--surface); font-size: .95rem; line-height: 1.55; font-style: normal;
}
.methods-placeholder-tag {
  display: inline-block; margin-left: .4rem; padding: .1rem .5rem; border-radius: 999px;
  background: color-mix(in srgb, var(--neg) 14%, var(--surface)); color: var(--neg);
  font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  vertical-align: middle;
}
.methods-bibtex-row { display: flex; flex-direction: column; align-items: flex-start; gap: .6rem; }
.methods-bibtex {
  width: 100%; margin: 0; padding: .9rem 1rem; background: var(--ink); color: var(--surface);
  border-radius: 9px; font-family: var(--font-body); font-size: .78rem; line-height: 1.5;
  overflow-x: auto; white-space: pre;
}

@media (max-width: 620px) {
  .methods-sector-list { grid-template-columns: 1fr 1fr; }
}

/* =========================================================================
   Scenario comparison (A vs B) — F1. The "Compare with…" picker panel on
   the results screen, and the standalone #screen-compare it opens into
   (deep-linkable at #/c/<keyA>/<keyB>). Deliberately reuses existing
   component classes wherever the shape matches (.rail/.rail-card for
   picker items, .sector-table for the delta table, .headline-welfare for
   the three-row headline, .chart-note for inline notices) rather than
   introducing a parallel visual language.
   ========================================================================= */

/* Screen-reader-only text — used for the delta table's accessible <caption>,
   the equivalent of the single view's canvas aria-label. */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.compare-picker {
  position: relative;
  max-width: 44rem;
  margin: 0 0 1.6rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-soft);
  padding: 1.1rem 1.3rem 1.3rem;
}
.compare-picker-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: .8rem; }
.compare-picker-title { font-family: var(--font-display); font-weight: 400; font-size: 1.15rem; margin: 0; letter-spacing: -.005em; }
.compare-key-form { margin-bottom: .3rem; }
.compare-key-label { display: block; font-size: .82rem; color: var(--ink-soft); margin-bottom: .4rem; }
.compare-picker-error { color: var(--neg); font-size: .85rem; margin: .7rem 0 0; }
.compare-picker-group { margin-top: 1rem; }
.compare-picker-sub {
  font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 600; margin: 0 0 .55rem;
}
/* Picker rails sit inside a padded panel, not a full-bleed page section —
   undo .rail's page-level max-width/gutter so cards align with the panel. */
.compare-pick-rail.rail { max-width: none; margin: 0; padding: 0 0 .3rem; }
.compare-pick-rail .rail-item, .compare-pick-rail .compare-pick-card {
  width: clamp(10.5rem, 40vw, 13.5rem);
}
.compare-pick-card { min-height: 4.6rem; padding: .8rem .9rem; }
.compare-pick-card.loading { opacity: .55; pointer-events: none; }

/* ---- #screen-compare ---- */
.compare-hw { margin-bottom: .2rem; }
.compare-hw + .compare-hw { border-top: none; padding-top: .3rem; }
/* .hw-label/.hw-val already set their own font-weight (600) inline from the
   single-view rule above, so bolding .compare-hw-diff itself is a no-op —
   target the spans directly to actually make the difference row stand out. */
.compare-hw-diff .hw-label, .compare-hw-diff .hw-val { font-weight: 700; }

.compare-table-wrap { margin-top: .2rem; }
.table-scroll > .compare-table { min-width: max-content; }
.compare-table { width: 100%; }
.compare-table td.num.up, .compare-table th.num.up { color: var(--up); }
.compare-table td.num.down { color: var(--down); }

/* =========================================================================
   [data-brand-mode="studio"] — a second design for the KITE brand: a warm-
   calm, editorial developer-tools look inspired by cursor.com. Adapted per
   brief: a COOL off-white canvas (not beige), an off-black ink (not pure
   black), a SOFTENED coral voltage in place of Cursor's vivid orange, and a
   pastel data palette. Space Grotesk carries display + body (weight ~500,
   magazine voice — never heavy), Space Mono the code surfaces.

   Like "brutal", this is a TOKEN-LEVEL swap — the editorial layout/structure
   is untouched, so it inherits the calm base component chrome (hairline
   borders, soft shadows, rounded cards) rather than the brutalist overrides.
   app.js also sets --accent/--paper/--ink inline from /api/config.branding;
   the values here match and derive the supporting tokens.
   ========================================================================= */
[data-brand-mode="studio"] {
  /* Softened coral — the single focal voltage (CTAs, links, accent chips,
     positive data fills). A muted terracotta, not Cursor's vivid #f54e00. */
  --accent: #d96a4a;
  --accent-deep: #b8502f;        /* readable coral for accent-as-text + active */
  --paper: #f6f7f8;              /* cool off-white canvas — deliberately NOT beige */
  --paper-2: #eef0f2;            /* soft canvas / chart neutral midpoint */
  --surface: #ffffff;           /* white cards float on the off-white canvas */
  --ink: #232427;               /* off-black, not pure #000 — a cool graphite */
  --ink-soft: #55575c;
  --ink-faint: #6c6e73;         /* 4.7:1 on #f6f7f8 — passes WCAG AA */
  --line: #e7e8ea;              /* hairline — depth here is hairline-only */
  --line-strong: #d2d4d7;
  /* Data valence — REPLACED after the 2026-07-15 design review: the original
     coral-positive/raspberry-negative pair was one red family (ΔE 29 even for
     typical vision; a deuteranopic reader confidently read the welfare map as
     "everyone lost"). "Better" is now a studio-temperament sage green — cool,
     desaturated, sits naturally on the off-white canvas — and "worse" a deep
     wine. Coral stays what the layer always claimed it was: brand chrome
     (CTA, wordmark, links), scarce. Fill #389878 = 3.3:1 on canvas; text
     #1f7a63 = 4.87:1; wine #9f3049 = 6.54:1; CVD lum separation 1.68/2.84. */
  --gain: #389878;
  --pos: #1f7a63;
  --neg: #9f3049;
  /* Neutral diverging scale — soft gold rise, soft periwinkle fall — off the
     coral/raspberry good-bad pair (Cursor's pastel timeline family). */
  --up: #c08a3e;
  --down: #6d7aa8;
  /* Hairline-only depth: no brutalist drop, no heavy editorial shadow — a
     barely-there lift so white cards separate on the off-white canvas. */
  --shadow-soft: 0 1px 2px rgba(35, 36, 39, .04);
  --shadow-lift: 0 6px 24px rgba(35, 36, 39, .06);
  --radius: 12px;                /* Cursor's clean, modern card radius */
  --font-display: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  --font-body: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "Space Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23232427' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
}
/* Space Grotesk display wants a whisper of negative tracking and a medium (not
   heavy) weight — the calm, magazine-editorial voice. */
[data-brand-mode="studio"] .hero-title,
[data-brand-mode="studio"] .section-heading,
[data-brand-mode="studio"] .panel-heading { letter-spacing: -0.02em; font-weight: 500; }
/* Code surfaces switch to Space Mono. */
[data-brand-mode="studio"] code,
[data-brand-mode="studio"] pre,
[data-brand-mode="studio"] .mono { font-family: var(--font-mono); }
/* The wordmark eyebrow carries the single coral voltage — Cursor keeps the
   accent scarce, reserved for CTA + brand. */
[data-brand-mode="studio"] .hero-eyebrow { color: var(--accent-deep); letter-spacing: .16em; }
/* Compact, softly-rounded, hairline-framed controls (developer dialect). */
[data-brand-mode="studio"] .gate-input,
[data-brand-mode="studio"] .select,
[data-brand-mode="studio"] .set-input,
[data-brand-mode="studio"] .select-mini,
[data-brand-mode="studio"] .rename-input,
[data-brand-mode="studio"] .token-input { border-radius: 8px; }
