/* ============================================================
   tokens.css — the ONLY file allowed to define a variable.
   No selectors other than :root and @font-face. No component rules.
   Load first, on every page, exactly once.
   Font: JetBrains Mono (SIL OFL 1.1, free commercially,
   NOT installed on any OS — self-host it).
   ============================================================ */

/* Self-hosted rather than a Google Fonts <link>: the portal already depends
   on two CDNs (maplibre, three) and a jury demo must survive a dead network.
   Three weights only — 400/500/600 are the ones the type scale below uses. */
@font-face {
  font-family: "JetBrains Mono";
  src: url("../assets/fonts/JetBrainsMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../assets/fonts/JetBrainsMono-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../assets/fonts/JetBrainsMono-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* ============================================================
     TYPE — TWO SCALES. Know which one you are editing.
     ============================================================ */

  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo,
               Consolas, "Cascadia Mono", monospace;

  /* ------------------------------------------------------------
     SCALE 1 — THE UI SCALE.  Read by BOTH pages.
     WARNING: EDITING ANYTHING BELOW CHANGES THE PORTAL PANEL TOO.

     Calibrated for a 320px control column read at arm's length,
     where 10px is a unit suffix or a status line — a glance, not
     a sentence. base.css turns these into the .t-* roles, and the
     Simulation panel and Analytic Mode are built from them.

     If you are trying to make the HOME PAGE bigger, you are in
     the wrong block. Scroll down to scale 2.
     ------------------------------------------------------------ */
  --fs-display: 24px;  --fw-display: 500;  --ls-display: 0.04em;
  /* Between display and title, and it exists because the gap between them
     is 9px with nothing in it.

     Read by ONE rule: the three figure tiles in Analytic Mode's ANALYSIS
     card (styles/analytic.css's `.metric-fig .metric-value`). Those cannot
     use --fs-display -- at --w-panel a tile is about 86px wide and a
     24px "1.64 kWh/m2" is roughly 145px, so it clipped -- but at
     --fs-title they are the same size as a section heading while being
     the number the whole card exists to show.

     18px is the CEILING: the largest value whose longest realistic reading
     still wraps into two lines that each FIT ("-1.64" is about 54px and
     "kWh/m2" about 65px against the 86px a tile has), and past it the unit
     breaks onto a third line.

     16 is what ships, one step under that ceiling. At 18 the three tiles
     read as crowded -- the tile's constraint is WIDTH, and 18 was chosen
     against a different problem (the figure competing with the section
     headings at --fs-title's 15). The rule that reads this also applies
     letter-spacing: -0.01em, which is the only other lever there is;
     JetBrains Mono ships no condensed face, so `font-stretch` does
     nothing at all here. */
  --fs-figure:  16px;
  --fs-title:   15px;  --fw-title:   500;  --ls-title:   0.06em;
  --fs-step:    13px;  --fw-step:    600;  --ls-step:    0.03em;
  --fs-label:   12px;  --fw-label:   400;  --ls-label:   0;
  --fs-hint:    10px;  --fw-hint:    400;  --ls-hint:    0;

  /* The two uppercase label tiers are shared by both scales — an
     eyebrow is an eyebrow at any size, and both pages want these
     exact values. They are listed here rather than duplicated. */
  --fs-eyebrow: 10px;  --fw-eyebrow: 500;  --ls-eyebrow: 0.18em;
  --fs-micro:    9px;  --fw-micro:   500;  --ls-micro:   0.14em;

  /* ------------------------------------------------------------
     SCALE 2 — THE HOME PAGE SCALE.  Read ONLY by styles/home.css.
     SAFE TO EDIT. Nothing in the portal reads any of these.

     A landing page is READ, at a full-window measure, often from
     further away than a control column. It needs bigger absolute
     sizes and — more importantly — BIGGER GAPS BETWEEN STEPS.
     Clarity on a reading page comes from few tiers far apart, not
     many tiers close together: six sizes spanning 54→12 here,
     versus five spanning 24→10 above.

     RULE: THE RULE THAT KEEPS THE TWO SCALES SEPARATE: home.css may
     read scale 2 and the shared eyebrow/micro tiers, and must NOT
     reach into scale 1 for body text. portal.css / analytic.css /
     controls.css may NOT read scale 2 at all. A control column
     that wants 12px hints wants --fs-hint changed, not this.
     Wanting a home-page size that does not exist here means
     adding a --fs-page-* token, never borrowing from scale 1.
     ------------------------------------------------------------ */

  /* h1, once per page, nowhere else. clamp() rather than a fixed
     size because this is the one element whose job depends on
     window width: it must dominate a 2560px window and still fit
     a phone. The lower bound replaces what used to be a separate
     `font-size: 30px` inside the 900px breakpoint — one knob now,
     not two that have to be kept agreeing. */
  --fs-page-hero: clamp(30px, 3.2vw, 54px);

  --fs-page-head:  26px;   /* section <h2> — "How it works" etc.   */
  --fs-page-title: 18px;   /* step card <h3>                        */
  --fs-page-lead:  15px;   /* hero lede; progress card name         */
  --fs-page-body:  13px;   /* step body copy; the two hero buttons  */
  --fs-page-hint:  12px;   /* caption, progress note, caveat, foot  */

  /* Reading-page leading. Looser than --lh-body below, which is
     already generous for a panel but tight for prose at a 50-60
     character measure. */
  --lh-page-body: 1.75;

  --lh-tight: 1.3;
  --lh-body:  1.75;

  /* Letter-spacing for CLICKABLE labels. The --ls-* above belong to the type
     roles in base.css (.t-title, .t-step …); buttons read this token
     instead of carrying their own literal, so a single knob covers .btn,
     .seg, .mode-switch and the viewer's camera buttons. Nudge this and
     every button in both modes moves together. */
  --ls-button: 0.04em;

  /* ------------------------------------------------------------
     TOP BAR TYPE — its own knobs, read only by styles/topbar.css.
     Safe to edit; nothing else reads them. WARNING: But they apply to
     BOTH pages, because there is one top bar and it must look the
     same on the home page and in portal mode.

     Why not --fs-hint / a literal: the bar is the only chrome a
     reader meets before they know what the product is, so it reads
     larger and clearer than the panel scale's 10px uppercase, which
     read as a caption rather than as navigation.

     WARNING: TRACKING COMES DOWN AS SIZE GOES UP. 0.14em was doing the
     work of making 10px legible; at 12px the same value just pulls
     the words apart. If you raise the size again, lower this.

     WARNING: These widen the bar. The nav is `overflow: hidden`, so if
     brand + nav ever exceed the bar the LAST item is cut with no
     warning — check the two breakpoints at the bottom of
     topbar.css after changing anything here. At the current values,
     nav needs ~556px and brand ~244px, so the bar needs ~852px before
     the nav is hidden entirely. */
  --fs-topbar-brand: 16px;
  --fs-topbar-nav:   12px;
  --ls-topbar-nav:   0.09em;

  /* ---- tone ladder (no alpha) ---- */
  --bg-ground:   #0a0b0c;  /* viewport / page ground   */
  --bg-panel:    #101213;  /* panel, header, status bar */
  --bg-inset:    #181b1c;  /* input, select, hover      */
  --line:        #2b2f30;  /* default 1px rule   */
  --line-strong: #3d4245;  /* control border, track */
  --text-3:      #7a8083;  /* hint, unit, group label */
  --text-2:      #c3c7c9;  /* field label               */
  --text-1:      #e6e4e1;  /* value, step title         */
  /* floating panels sit over the viewport, so they are translucent.
     Two levels: a tall control column is more opaque than a small
     readout, because text over a moving map needs the extra ground. */
  --overlay-bg:      rgba(16, 18, 19, 0.88); /* control columns   */
  --overlay-bg-thin: rgba(16, 18, 19, 0.80); /* legend, readouts  */
  --overlay-blur:    blur(10px);             /* backdrop-filter   */

  /* ---- interface state: exactly three meanings ---- */
  --accent:         #ff8a3d;  /* LIVE — actionable, active, selected */
  --accent-hi:      #ffab77;  /* accent hover / link hover           */
  --accent-fill:    rgba(255, 138, 61, 0.08);  /* primary button bed  */
  --accent-fill-hi: rgba(255, 138, 61, 0.16);  /* its hover           */
  --accent-soft:    rgba(255, 138, 61, 0.10);  /* pressed seg / tool  */
  --accent-line:    rgba(255, 138, 61, 0.55);  /* site box hairline   */
  --done:        #4dc98a;  /* COMPLETE — nothing else, ever       */
  --done-fill:   rgba(77, 201, 138, 0.10);
  /* NOT YET REACHED = the neutral greys above. There is no red. */

  --text-off: #4f5456;     /* disabled text   */
  --line-off: #2b2f30;     /* disabled border */
  /* locked-but-coming: a destination, not a dead control. One notch
     brighter than disabled, still clearly not live. */
  --text-locked: #7c8285;
  --line-locked: #3a3f42;
  /* a control that is ALWAYS available (the way back to portal) needs to
     read as clickable without taking the accent, which belongs to the one
     live thing. A brighter-than-line-strong border does that job. */
  --line-bright: #6b7073;

  /* ---- data palette: values only, never interface state ----
     No caller in this repo yet — the map/heatmap shading reads its own
     palette (HEATMAP_PALETTES in predict.js). Kept for spec completeness
     and for future chart work in Analytic Mode's ANALYSIS panel. */
  --data-0: #1d1b2e;
  --data-1: #3f6280;
  --data-2: #8a7a6a;
  --data-3: #e8a24c;
  --data-4: #f6e0a8;
  --ramp-flux: linear-gradient(to right, #1d1b2e, #3f6280, #8a7a6a, #e8a24c, #f6e0a8);
  --ramp-svf:  linear-gradient(to right, #14212b, #2e5d78, #7fb3c9, #d9e4ea);
  /* signed figures: coloured ONLY when the number carries direction.
     LITERAL TEMPERATURE — cooler and warmer, nothing else. */
  --delta-cooler: #5f8397;
  --delta-warmer: #e8a24c;

  /* RULE: DIRECTION OF MERIT IS NOT THE SAME THING AS TEMPERATURE.
     Analytic Mode's delta line says whether an edit made the site BETTER, and
     "better" is not "cooler": a wall that sends LESS radiation into the
     street is an improvement, and it can be warmer while doing it. Reusing
     --delta-cooler/--delta-warmer for this would render "better" in a blue
     that reads as "colder", which is a wrong signal for a criterion whose
     direction of merit is not temperature.

     WARNING: --worse IS THE SAME HEX AS --delta-warmer TODAY, AND THE TWO NAMES ARE
     DELIBERATE. They will move for different reasons: one tracks the data
     ramp's warm end, the other tracks whatever reads as a regression. Two
     identical values are not an invitation to collapse them into one.

     RULE: --better MUST NOT BE --done (#4dc98a). That green means COMPLETE and
     nothing else (see the interface-state block above), and the reference
     system keeps interface state and data strictly apart. A data figure
     wearing the interface's green would sit next to a finished step in exactly
     the same colour. This one is desaturated to sit in the data family. */
  --better: #6fb894;
  --worse:  #e8a24c;

  /* material swatches — neutral greys. Material identity is not a
     thermal value, so it must never borrow the data ramp. */
  --mat-1: #c3c7c9;
  --mat-2: #8b8f92;
  --mat-3: #5f6467;
  --mat-4: #3a3f42;

  /* ---- spacing: 4px base, five steps only ---- */
  --sp-1:  4px;   /* label -> its own control  */
  --sp-2:  6px;   /* inside one control        */
  --sp-3: 10px;   /* chip and icon gaps        */
  --sp-4: 16px;   /* between controls; padding; overlay inset */
  --sp-5: 24px;   /* between steps             */

  /* ---- portal step rail ----
     The 2px bar down the left of the Simulation panel's step list. It is
     the ONLY thing that says which step you are on, so its three numbers
     are tokens rather than literals buried in portal.css: the break in
     particular is derived from .fpanel-body's gap over there, and a
     number that has to agree with another number must have one home. */
  --rail-w:      2px;   /* segment weight - 1px read as a hairline, not as progress */
  --rail-gutter: 16px;  /* rail + the air between it and the step's content */
  --rail-break:   8px;  /* ground between two segments - see portal.css STEPS */

  /* ---- geometry ---- */
  --h-control: 32px;
  --h-touch:   44px;
  --h-mode:    36px;   /* mode switch — one line, inset from panel edge */
  --h-topbar:  48px;
  --h-status:  26px;
  --w-panel:  320px;   /* left column, both modes */

  /* THE ANALYTIC RIGHT COLUMN, which is wider than the left one.
     It carries two ECharts plots and a four-figure readout row, and the
     radar inside it is bounded by its axis labels rather than by its own
     height -- so 40px of width is 40px of diamond, while the same 40px on
     the left would only stretch a column of checkboxes.
     WARNING: three things in analytic.css are positioned FROM this width --
     the viewport insets, the icon rail and the legend dock all sit left of
     the column and read it in a calc(). Widening --w-panel instead would
     move all three AND the left column, which is not what this is for. */
  --w-panel-analysis: 360px;
  /* The floating legend in Analytic Mode. Narrower than a panel on
     purpose: it holds two colour ramps and four numbers, and it now sits
     ON the scene rather than in a card, so every pixel of it is scene it
     covers. Widen it only if a ramp's end labels start colliding. */
  --w-legend: 150px;
  --w-value:   56px;   /* right-aligned numeric column */
  --w-unit:    18px;
  --w-toolbtn: 34px;
  --radius:     0px;   /* 2 everywhere, or 0 everywhere — never mixed */
  --border:     1px;   /* never 2px */
  --inset-overlay:   6px;  /* every viewport overlay, all four corners */
  /* --inset-right-col (74px) removed with the rail move: it existed on
     .col-right to leave room for the analytic tool rail, which sat to
     the column's RIGHT at its own corner. The follow-up
     swapped sides — the rail now sits to .col-right's LEFT instead
     (styles/analytic.css's `#viewer-root > .vt-root` override) — so
     nothing sits to .col-right's right any more and its own `right`
     is back to plain --inset-overlay, same as every other corner.
     Grepped — zero remaining callers of this token. */
  /* The home page is full bleed — content stretches with the window and ONE
     fixed distance is deducted from each side. This is that distance, and it
     is the page's only inset: the top bar, all five sections and the footer
     share it, so the wordmark, every heading, every card and the footer's
     first word sit on one left edge. The left margin exists to hold the
     section rail (which centres itself inside it — see home.css); the right
     one is deliberately empty so the two balance. Read only by
     styles/home.css. */
  --inset-page: 132px;

  /* RULE: the home page's width knob — the one you are most likely to want to
     tune by hand. How wide the content is allowed to get, BEFORE the
     --inset-page margins are added on top.

       larger  → content stretches further on a wide monitor, lines get
                 longer, the portal frame gets taller (it is 16:9 of this)
       smaller → more empty margin either side, shorter lines, smaller frame

     Effective band = --content-max, and total occupied width =
     --content-max + 2 × --inset-page. At 1440 that is 1440 + 264 = 1704px,
     so any window narrower than 1704 is unaffected and behaves exactly as
     it did before this token existed — full bleed, 132px a side. Only wider
     windows see the cap, which is the point.

     WHY A CAP AT ALL. With no cap, at a wide 2560px viewport the band grows
     enough to make the portal frame taller than the screen (it is 16:9 of
     this content width), step body copy runs well past a comfortable
     45-75 characters per line, and leaves a large dead-space gap beside
     the h1, which is capped separately. The design was drawn at ~1440 and
     degrades upward, not downward.

     Read by styles/home.css only. Nothing in the portal reads it. */
  --content-max: 1440px;

  
  /* ---- home page: progress grid (section 4 of styles/home.css) ----
     Read ONLY by styles/home.css.

     --home-part-gap    the space between the four progress cells. It used
                        to be a 1px gap over a --line background, i.e. a
                        hairline separator; it is now real space, so each
                        cell carries its own top rule. 0 does NOT restore
                        the old hairline — the background trick is gone.
     --home-part-rule   how far the live cell's accent underline is pulled
                        in from each side. It matches the cell's own side
                        padding by default, so the rule sits under the text
                        block rather than under the full cell. */
  --home-part-gap:  5px;
  --home-part-rule: var(--sp-4);

  /* Locked-but-coming, HOME PAGE ONLY — one notch brighter than the portal's
     --text-locked / --text-off. The portal greys are calibrated against
     translucent overlay panels sitting on a moving map; the home page puts
     the same states on a flat opaque --bg-panel, where the same values read
     as switched off rather than as not-yet-built. Brightening the shared
     tokens instead would repaint every disabled control in the portal. */
  --text-page-locked: #9aa0a3;   /* portal equivalent: --text-locked #7c8285 */
  --text-page-off:    #6e7477;   /* portal equivalent: --text-off    #4f5456 */


  /* scrollbars are part of the tone ladder, not the OS — an
     unstyled bar is brighter than the accent and wins the eye */
  --scrollbar-w:     8px;
  --scrollbar-thumb: var(--line-strong);
  --scrollbar-hover: var(--text-3);

  /* ---- range input track and thumb ----
     Read by styles/controls.css's input[type="range"] rules. Kept as named
     knobs rather than literals because a slider is drawn from five separate
     vendor pseudo-elements, and the same five numbers have to reach all of
     them. */
  --slider-track-height: 2px;
  --slider-track-color: var(--line-strong);
  --slider-thumb-size: 10px;
  --slider-thumb-color: var(--text-1);
  --slider-thumb-border: 0;

  /* ---- tool rail (js/ui/view-tools.js, js/viewer/tools.js) ----
     The rail's own box is --w-toolbtn above; these three are what every
     popover in the rail reads from controls.css. */
  --vt-z-index: 5;              /* above the map canvas, below any future modal */
  --vt-icon-glyph-size: 18px;   /* the SVG glyph inside each button */
  /* THE popover width. One number for every popover in the rail — basemap,
     camera modes, measure, bookmark — because they stack in the same place
     and a column of boxes that each guess their own width reads as sloppy.
     Sized by the widest content (the basemap group: a slider plus four
     checkbox rows); everything else is narrower than it needs to be, and
     that is the price of "all the same". There is deliberately NO
     per-popover override — a second width is the only way the popovers
     could disagree. */
  --vt-popover-width: 220px;

  /* The one type tier the panel still names rather than reads directly:
     controls.css's .wf-status. Same value as --fs-hint; kept separate
     because "how big is a status line" is a thing someone may want to tune
     on its own. */
  --wf-status-font-size: var(--fs-hint);

  /* ---- exploded-view guide colours ----
     Read from JS via getComputedStyle(document.documentElement) in
     workflow/exploded-view.js — this is a live JS contract, not decoration.
     MUST stay on :root (not scoped to body or any selector): moving them
     would silently break the guides (they'd just keep the old colour, no
     error). Names must not change; workflow/exploded-view.js reads them
     by these exact strings. */
  --xv-frame-color: var(--line-strong);   /* the copied site square at each level */
  --xv-frame-thickness: 0.5;              /* m */
  --xv-frame-opacity: 0.5;
  --xv-leader-color: var(--line-strong);  /* corner-to-corner bars chaining the levels */
  --xv-leader-thickness: 0.5;             /* m */
  --xv-leader-opacity: 0.5;
}
