/* Inframation -- public site
   Tokens, scales and components from docs/31-design-system.md and the brand system in
   docs/31-brand-identity.md (owner, 2026-10-23; Inframation stands alone since 2026-10-30). Every colour, type,
   space, radius and motion value below is a custom property (D-19); components reference tokens only.
   Fonts: Geist and Geist Mono, self-hosted from web/static/fonts (D-21). */

/* Self-hosted web fonts (D-21: no third-party font CDN). Geist and Geist Mono, SIL OFL 1.1 with no
   Reserved Font Name: the variable (wght 100-900) files of the npm `geist` 1.7.2 release, subset to the
   latin and latin-ext ranges Google Fonts uses (the latin file also keeps the arrows, approximately
   equal and less- and greater-or-equal signs the site prints). Origins, the subset command and
   the licence: web/static/fonts/README.md. One variable file holds every weight, so base.html preloads
   the one latin Geist file; latin-ext and Geist Mono (identifiers only) load when a page prints one of
   their characters. The latin face is `font-display: optional`, as the IBM Plex faces it replaces were:
   Chrome holds first render briefly for a preloaded optional font, so Geist is normally used from the
   first paint, and when it is late the page keeps "Geist Fallback" for the view instead of swapping.
   A swap at a wrap point is the reflow no metric override can rule out at every width: laid out in the
   fallback, six pages (map, a list, a record, Companies, Infrastructure, About) match Geist to the pixel
   in 9 of their 18 views at 1440, 768 and 390, and the rest differ where a line wraps (up to 72px of page
   height); the Plex fallbacks matched 7 of 18. Measured CLS from fonts: 0, on time and with every font
   held back 2.5 s. The other three faces swap: they are not on the first paint, and their fallbacks are
   metric-matched (Geist Mono and Courier New share a 600-unit advance). */
@font-face {
  font-family: "Geist"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("/static/fonts/geist-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Geist"; font-style: normal; font-weight: 100 900; font-display: optional;
  src: url("/static/fonts/geist-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+2190-2194, U+2212, U+2215, U+2248, U+2264-2265, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Geist Mono"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("/static/fonts/geist-mono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Geist Mono"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("/static/fonts/geist-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+2190-2194, U+2212, U+2215, U+2248, U+2264-2265, U+FEFF, U+FFFD;
}

/* Metric-matched fallbacks (frontend audit F8). Until a web font arrives the page is set in a local
   face scaled to the web font's average advance width and vertical metrics, so a swap does not reflow
   text. By the capsize method the Plex fallbacks used: size-adjust is the ratio of the two faces'
   average advances, weighted by the character frequencies of the site's own text (54,610 characters of
   ten pages: map, lists, a record, About, Methodology, the site finder, Prices); then Geist's own
   ascent (1005), descent (295) and line gap (0, per 1000) divided by it. The 100-499 face is Geist at
   wght 400 against Arial; the 500-900 face Geist at 600, the weight most bold text takes, against
   Arial Bold. Geist Mono and Courier New share a 600-unit advance. Liberation Sans and Mono have
   Arial's and Courier New's metrics, so the same numbers hold where they stand in. */
@font-face {
  font-family: "Geist Fallback"; font-weight: 100 499;
  src: local("Arial"), local("ArialMT"), local("Liberation Sans"), local("LiberationSans");
  size-adjust: 103.55%; ascent-override: 97.05%; descent-override: 28.49%; line-gap-override: 0%;
}
@font-face {
  font-family: "Geist Fallback"; font-weight: 500 900;
  src: local("Arial Bold"), local("Arial-BoldMT"), local("Liberation Sans Bold"), local("LiberationSans-Bold");
  size-adjust: 101.39%; ascent-override: 99.12%; descent-override: 29.09%; line-gap-override: 0%;
}
@font-face {
  font-family: "Geist Mono Fallback";
  src: local("Courier New"), local("CourierNewPSMT"), local("Liberation Mono"), local("LiberationMono");
  size-adjust: 99.98%; ascent-override: 100.52%; descent-override: 29.5%; line-gap-override: 0%;
}

/* ---------- 1. Tokens ---------- */
/* The brand system of docs/31-brand-identity.md §4 (owner, 2026-10-23: "Go with B"): Compass navy as the
   ink, a blue-grey ledger ground, no colour on the chrome, one evergreen on the data, and Compass orange
   only as the dot over the i. Ratios are WCAG 2.x against the page ground (--bg) and panels
   (--surface); web/test_map_a11y.py and web/test_type_and_buttons.py recompute them. */
:root {
  /* 1.1 core brand colours (docs/31 §1.1). The copper names are aliases of the accent for one release
     (docs/31-brand-identity.md T-1): admin.css still reads --color-copper. */
  --color-ink: #0b1023;           /* Compass navy: 16.66:1 on --bg, 18.87:1 on --surface */
  --color-paper: #eef1f5;         /* the ledger ground */
  --color-muted: #4a5063;         /* 7.08:1 on --bg, 8.02:1 on --surface */
  --color-accent: #1d7356;        /* the one data hue (evergreen): 5.09:1 / 5.77:1 */
  --color-accent-deep: #16624a;   /* the accent as small text: 6.44:1 / 7.29:1 */
  --color-accent-tint: #5fcf9f;   /* the accent on navy or dark fields: 9.81:1 on navy */
  --color-copper: var(--color-accent);
  --color-copper-deep: var(--color-accent-deep);
  --color-copper-tint: var(--color-accent-tint);
  /* Compass orange: the dot over the i (the wordmark's, and the mark's in favicon.svg), never text or
     data (a mark, not text: 2.81:1 on white). The one token; og_card.py `BRAND_DOT` writes the same value
     into the drawn files (favicon.svg, wordmark.svg, the icons and the share card). */
  --brand-dot: #e68023;
  /* The wordmark's letters (docs/31-brand-identity.md §5.1): navy; on dark, the mark's light #eef1f5. */
  --wordmark-ink: var(--color-ink);

  /* semantic roles (light) */
  --bg: var(--color-paper);
  --surface: #ffffff;
  --raised: #f5f7fa;              /* a filled field on a surface */
  --active: #e8ebf1;              /* a selected row, a pressed secondary */
  --skel-band: #f5f7fa;           /* the light passing over a loading bar (`.skel`): lighter than --active */
  --text: var(--color-ink);
  --text-muted: var(--color-muted);
  --link: var(--color-ink);       /* achromatic chrome: links are ink, underlined (C-7) */
  --link-visited: var(--color-muted);
  --border: #dde1e8;              /* panel and card edges: 1.16:1 on --bg, 1.31:1 on --surface */
  --rule: #eceff3;                /* row rules in tables */
  --control: #7d8496;             /* input and outlined-control borders: 3.74:1 on --surface (SC 1.4.11) */
  --focus-ring: var(--color-accent); /* 5.09:1 on --bg, 5.77:1 on --surface */
  --primary: var(--color-ink);    /* the one filled button */
  --primary-ink: #ffffff;         /* 18.87:1 on --primary */
  --secondary: #e8ebf1;           /* the grey secondary button */
  --secondary-ink: var(--color-ink); /* 15.80:1 on --secondary */
  --accent: var(--color-accent);
  --accent-deep: var(--color-accent-deep);
  --accent-tint: var(--color-accent-tint);
  --accent-ink: #ffffff;          /* text on an accent fill: 5.77:1 */
  --negative: #c4242a;            /* a change in the bad direction, with its sign: 5.10:1 / 5.78:1 */
  --dot: var(--color-accent);     /* a project marker in process: 5.62:1 on --map-land */
  --select: var(--color-ink);     /* the 2px selected-tab line */

  /* 1.2 status families -- text + chip fill (docs/31 §1.2; docs/31-brand-identity.md §4). Progress,
     the in-process states, is the main data element, so it takes the accent; committed is navy. Text on
     fill: neutral 8.59, progress 4.96, committed 14.55, success 9.79, danger 6.19 (all over 4.5). */
  --family-neutral-text: #3d4254;
  --family-neutral-fill: #eceef3;
  --family-progress-text: #1d7356;
  --family-progress-fill: #e0f2e9;
  --family-committed-text: #0b1023;
  --family-committed-fill: #dde2ee;
  --family-success-text: #0e3f2c;
  --family-success-fill: #d6efe1;
  --family-danger-text: #a3211b;
  --family-danger-fill: #fbe4e1;

  /* map basemap (docs/04 D-13): cool and quiet, so the projects are the only saturated layer; never a
     status-family colour, so the backdrop never reads as a lifecycle state (docs/30 §7 "Basemap").
     `--ctx` is existing infrastructure's grey (5.37:1 on --bg), for context drawn at 24% opacity. */
  --map-land: #fbfcfd;
  --map-water: #dfe5ee;
  --map-border: #c3cad6;
  --map-flavor: light;
  --ctx: #5b6275;
  /* Loads are the logo dot's Compass orange (--brand-dot; owner, 2026-10-31: "inframation/compass orange is
     better"), fixed in light (owner, 2026-11-03: "never change"), its edge the fill itself. Stage is the fill,
     never the colour (map.js STAGE_FILL). */
  --mark-load: var(--brand-dot);
  --mark-load-edge: var(--mark-load);
  /* The fuel families (owner, 2026-11-03; docs/31-brand-identity.md §4): every map draws every power mark in
     its family (`dots.family`, web/page.py `map_family`), loads in --mark-load. A plant's fill fades by its use,
     its rim stays the full family colour; retired is 12% of it toward the land. */
  --fam-combustion: #214682;
  --fam-clean-firm: #177ba8;
  --fam-wind-solar: #42b59a;
  --fam-storage: #849be3;
  --fam-bioenergy: #3c740d;
  --fam-unspecified: #8c8478;
  /* One fuel palette, derived from the families (owner, 2026-11-03: "all the assets will follow the same color
     system throughout the app ... Like on the generation summary"): a chart with finer fuels gives each its own
     lightness step in its family's hue (CSS color-mix in OKLab toward white or black), so gas, coal and oil read
     as one family in three shades of the combustion blue. Every fuel chart, legend, capacity bar and stack reads
     these (`.chart-seg--gen-<key>`); there is no second palette. Validated as stacked neighbours with the dataviz
     validator, light on #ffffff and dark on #17181b: the generation stack (gas, coal, nuclear, hydro, wind,
     solar, other) worst adjacent CVD dE 17.0 light, 17.8 dark, normal 18.6 and 19.2; the fuel-burned stack (gas,
     coal, oil, nuclear, bio, other) CVD 12.8 and 12.4, normal 15.1 and 17.7. Some shades sit under 3:1 on their
     surface (WCAG AA is not a gate, owner 2026-11-01); every chart names its fuels in its legend. */
  --fuel-gas: var(--fam-combustion);
  --fuel-coal: color-mix(in oklab, var(--fam-combustion) 55%, #ffffff);
  --fuel-oil: color-mix(in oklab, var(--fam-combustion) 30%, #ffffff);
  --fuel-nuclear: color-mix(in oklab, var(--fam-clean-firm) 62%, #000000);
  --fuel-hydro: var(--fam-clean-firm);
  --fuel-geothermal: color-mix(in oklab, var(--fam-clean-firm) 55%, #ffffff);
  --fuel-wind: var(--fam-wind-solar);
  --fuel-solar: color-mix(in oklab, var(--fam-wind-solar) 60%, #000000);
  --fuel-storage: var(--fam-storage);
  --fuel-bio: var(--fam-bioenergy);
  --fuel-load: var(--mark-load);
  --fuel-other: var(--fam-unspecified);

  /* existing-plants context layer (docs/00-PLAN.md 2026-09-14/15 owner decision; map task item
     2) -- desaturated versions of hues a reader already associates with each technology from
     other built-infrastructure maps (Open Grid Works, Open Infrastructure Map), deliberately
     dimmer than the status-family palette above so the layer reads as subordinate context, never
     mistaken for a proposal's lifecycle state. Contrast checked against `--bg` (WCAG relative-
     luminance formula, docs/31 §1.1's own method) because the legend renders these as text, not
     only as marker fills: every one clears 4.5:1 on the ledger ground (4.57-6.61:1, 5.04-7.29:1 on
     --map-land). On the map they draw faint, at 24% opacity (32% on dark; docs/31-brand-identity.md
     M-2), so the projects lead; a marker fill is not text, so D-20's ratio applies to the legend. */
  --plant-solar: #846818;
  --plant-wind: #3f6a8a;
  --plant-gas: #5f6469;
  --plant-nuclear: #6a4f80;
  --plant-hydro: #2f6f68;
  --plant-storage: #3f6f4a;
  --plant-coal: #6a5a48;
  /* Added 2026-09-15 with the plant-type filter (owner: biomass/waste must be distinct). Same
     method: oil 6.61:1, biomass 4.96:1, geothermal 5.94:1, other 4.57:1 against --bg. */
  --plant-oil: #6b4f3a;
  --plant-biomass: #55702a;
  --plant-geothermal: #8a4a3a;
  --plant-other: #6d6d6d;

  /* Midstream asset layers (docs/00-PLAN.md 2026-09-19 owner decision, option (a); docs/31 §1.6):
     one hue per asset type, drawn beside the plant palette and, like it, dimmer than the status
     families so an existing asset never reads as a proposal state. Type is never carried by
     colour alone (D-5): pipelines are lines, processing plants diamonds, storage rings, LNG
     terminals triangles, ethanol hexagons, RNG pentagons -- see map.js `ASSET_TYPE_SHAPE`.
     Contrast on --bg (WCAG relative-luminance formula, docs/31 §1.1's method), legend text usage:
     pipeline 6.28:1, processing 5.78:1, storage 5.86:1, LNG 5.35:1, ethanol 4.73:1, RNG 4.57:1. RNG's
     green sits near the accent; its pentagon tells it apart. Interstate vs intrastate pipelines share
     the hue and differ by dash (solid vs dashed), plus the label. */
  --asset-gas-pipeline: #6e4b7a;
  --asset-gas-processing: #8a4a5a;
  --asset-gas-storage: #4f5a8a;
  --asset-lng-terminal: #2f6a7a;
  --asset-ethanol: #7a6a2a;
  --asset-rng: #2f7a5a;
  /* Transmission lines (grid lane G2, 2026-09-28): amber, 4.80:1 on --bg, chosen far from the
     pipeline purple because the two line layers overlap everywhere at national zoom. Drawn dash-dot, so the
     stroke pattern -- not this hue -- is what tells a power line from a pipeline (D-5). */
  --asset-transmission: #8a6300;
  /* Retired and retiring plants (lane R1, 2026-10-06): hollow rings, so a retired site never reads as
     an operating plant's filled square. Magenta and burnt orange, far from every plant-family hue;
     the ring's centre mark (cross or dot) carries the status, the hue is secondary (D-5). */
  --asset-retired: #7a2e5c;
  --asset-retiring: #a3480a;

  /* ADR 0008 region features (placement grade "region") -- one hue, not a status-family colour
     (same reasoning as the plant palette above): a highlighted county/state/country must never
     read as a lifecycle state. 5.80:1 against --bg (WCAG relative-luminance formula,
     docs/31 §1.1's method), used for the outline/label text only -- the fill itself is drawn at
     the data-driven 0.15-0.7 opacity computed in map.js, not this ratio (a fill is not text). */
  --region-fill: #4a6070;
  --region-line: #4a6070;

  /* Site finder (web/site_finder.py): lines and substations by voltage class, an ordinal ramp of the
     transmission amber, light to dark as voltage rises (one hue, OKLCH L monotone, every step at
     least 0.06 apart, the lightest 2.51:1 on --map-land); the map also widens a line with its class,
     so the class never rests on shade alone. "Voltage not stated" is grey and dashed. The candidate
     band and the open band are teal, a hue no line takes. */
  --sf-kv-69: #c99a2e;
  --sf-kv-115: #a87a10;
  --sf-kv-230: #8a6300;
  --sf-kv-345: #6b4a00;
  --sf-kv-500: #4a3200;
  --sf-kv-unknown: #7d858c;
  --sf-band: #1d7f8f;
  --sf-selected: #0b5563;

  /* 1.3 typography: one family (docs/31-brand-identity.md §4). Geist sets everything; Geist Mono sets
     identifiers only (queue IDs, docket numbers, keys). --font-display stays a name of its own so a
     later display face is a one-line change. */
  --font-display: "Geist", "Geist Fallback", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-body: "Geist", "Geist Fallback", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: "Geist Mono", "Geist Mono Fallback", "SFMono-Regular", Consolas, Menlo, monospace;
  --text-1: 0.8rem;    /* 12.8px */
  --text-2: 1rem;      /* 16px base */
  --text-3: 1.2rem;    /* 19.2px */
  --text-4: 1.4375rem; /* 23px */
  --text-5: 1.725rem;  /* 27.6px */
  --text-6: 1.75rem;   /* 28px: an app title stays at 32px or less (C-1) */
  --text-7: 2.4875rem; /* 39.8px */
  --text-label: 0.8125rem; /* 13px: sentence-case labels in the text face (C-2) */

  /* 1.4 spacing, 4px base */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-7: 2rem;
  --space-8: 2.5rem;
  --space-9: 3rem;
  --space-10: 4rem;

  /* 1.5 radius, shadow, motion. Cards 8px, controls 6px. No shadow at rest: --shadow-1 is kept as a
     name and draws nothing; what truly floats (a menu, a list of suggestions, the drawer) takes
     --shadow-float. */
  --radius-1: 2px;
  --radius-2: 6px;
  --radius-3: 8px;
  --shadow-1: none;
  --shadow-float: 0 8px 24px rgba(11, 16, 35, 0.14);
  --motion-fast: 150ms;
  --motion-base: 200ms;
  --motion-slow: 300ms;
  --motion-map: 600ms;
}

/* Dark theme: a true-neutral dark, not navy (taste skill; docs/31-brand-identity.md T-2), with the same
   roles. System preference drives it; `data-theme` forces either. Ratios: text 17.28:1 on --bg and
   16.00:1 on --surface, muted 9.32:1 and 8.63:1, the accent 9.96:1 and 9.22:1. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --color-ink: #f2f3f6;
    --color-paper: #0e0f11;
    --color-muted: #b0b5bf;
    --color-accent: #5fcf9f;
    --color-accent-deep: #5fcf9f;
    --color-accent-tint: #5fcf9f;
    --wordmark-ink: #eef1f5;
    --bg: var(--color-paper);
    --surface: #17181b;
    --raised: #1f2024;
    --active: #26282d;
    --skel-band: #33363c;
    --text: var(--color-ink);
    --text-muted: var(--color-muted);
    --link: var(--color-ink);
    --link-visited: var(--color-muted);
    --border: #2a2c31;
    --rule: #1d1e22;
    --control: #7b808b;
    --focus-ring: var(--color-accent);
    --primary: var(--color-ink);
    --primary-ink: #0e0f11;
    --secondary: #26282d;
    --secondary-ink: var(--color-ink);
    --accent-ink: #0e0f11;
    --negative: #f0857a;
    --shadow-float: 0 8px 24px rgba(0, 0, 0, 0.5);

    --family-neutral-text: #c2c7d0;
    --family-neutral-fill: #24262b;
    --family-progress-text: #6fd8a8;
    --family-progress-fill: #15302a;
    --family-committed-text: #cdd5ea;
    --family-committed-fill: #232a3d;
    --family-success-text: #a8e8c8;
    --family-success-fill: #1a352b;
    --family-danger-text: #f3a39a;
    --family-danger-fill: #3a201e;

    --map-land: #1a1c20;
    --map-water: #0b0c0e;
    --map-border: #32353c;
    --map-flavor: dark;
    --ctx: #8b909b;
    --mark-load: #f08f33;
    --mark-load-edge: var(--mark-load);
    --fam-combustion: #769fe3;
    --fam-clean-firm: #138db1;
    --fam-wind-solar: #42b59a;
    --fam-storage: #4460a2;
    --fam-bioenergy: #2f751d;
    --fam-unspecified: #8c8478;
    --fuel-gas: var(--fam-combustion);
    --fuel-coal: color-mix(in oklab, var(--fam-combustion) 60%, #000000);
    --fuel-oil: color-mix(in oklab, var(--fam-combustion) 55%, #ffffff);
    --fuel-nuclear: var(--fam-clean-firm);
    --fuel-hydro: color-mix(in oklab, var(--fam-clean-firm) 60%, #000000);
    --fuel-geothermal: color-mix(in oklab, var(--fam-clean-firm) 55%, #ffffff);
    --fuel-wind: var(--fam-wind-solar);
    --fuel-solar: color-mix(in oklab, var(--fam-wind-solar) 58%, #000000);
    --fuel-storage: var(--fam-storage);
    --fuel-bio: var(--fam-bioenergy);
    --fuel-load: var(--mark-load);
    --fuel-other: var(--fam-unspecified);

    --plant-solar: #c9b877;
    --plant-wind: #9ab6d1;
    --plant-gas: #aab0b6;
    --plant-nuclear: #b49bc7;
    --plant-hydro: #7cb8b0;
    --plant-storage: #86b98f;
    --plant-coal: #ac9c88;
    --plant-oil: #c9a98a;
    --plant-biomass: #a9c77a;
    --plant-geothermal: #d29a86;
    --plant-other: #b5b5b5;

  /* Midstream asset layers, dark tints: 9.05 / 8.96 / 9.29 / 10.20 / 10.48 / 10.79 : 1 on --bg. */
  --asset-gas-pipeline: #c9a6d6;
  --asset-gas-processing: #d9a3b0;
  --asset-gas-storage: #a9b3dc;
  --asset-lng-terminal: #8ec6d3;
  --asset-ethanol: #cfc07a;
  --asset-rng: #8fd0b0;
  --asset-transmission: #e8c15f; /* 11.16:1 on --bg */
  --asset-retired: #e7a3c9;
  --asset-retiring: #f2a66b;

    --region-fill: #9ab6d1;
    --region-line: #9ab6d1;
    /* Site finder, dark: the ramp flips, dark to light as voltage rises (the darkest step 3.52:1 on
       --map-land). */
    --sf-kv-69: #8f6c1c;
    --sf-kv-115: #b38a2a;
    --sf-kv-230: #d4a940;
    --sf-kv-345: #e8c15f;
    --sf-kv-500: #f7e0a0;
    --sf-kv-unknown: #8d9aa6;
    --sf-band: #4fc1d1;
    --sf-selected: #8fe3ee;
  }
}
:root[data-theme="dark"] {
  --color-ink: #f2f3f6;
  --color-paper: #0e0f11;
  --color-muted: #b0b5bf;
  --color-accent: #5fcf9f;
  --color-accent-deep: #5fcf9f;
  --color-accent-tint: #5fcf9f;
  --wordmark-ink: #eef1f5;
  --bg: var(--color-paper);
  --surface: #17181b;
  --raised: #1f2024;
  --active: #26282d;
  --skel-band: #33363c;
  --text: var(--color-ink);
  --text-muted: var(--color-muted);
  --link: var(--color-ink);
  --link-visited: var(--color-muted);
  --border: #2a2c31;
  --rule: #1d1e22;
  --control: #7b808b;
  --focus-ring: var(--color-accent);
  --primary: var(--color-ink);
  --primary-ink: #0e0f11;
  --secondary: #26282d;
  --secondary-ink: var(--color-ink);
  --accent-ink: #0e0f11;
  --negative: #f0857a;
  --shadow-float: 0 8px 24px rgba(0, 0, 0, 0.5);
  --family-neutral-text: #c2c7d0;
  --family-neutral-fill: #24262b;
  --family-progress-text: #6fd8a8;
  --family-progress-fill: #15302a;
  --family-committed-text: #cdd5ea;
  --family-committed-fill: #232a3d;
  --family-success-text: #a8e8c8;
  --family-success-fill: #1a352b;
  --family-danger-text: #f3a39a;
  --family-danger-fill: #3a201e;
  --map-land: #1a1c20;
  --map-water: #0b0c0e;
  --map-border: #32353c;
  --map-flavor: dark;
  --ctx: #8b909b;
  --mark-load: #f08f33;
  --mark-load-edge: var(--mark-load);
  --fam-combustion: #769fe3;
  --fam-clean-firm: #138db1;
  --fam-wind-solar: #42b59a;
  --fam-storage: #4460a2;
  --fam-bioenergy: #2f751d;
  --fam-unspecified: #8c8478;
  --fuel-gas: var(--fam-combustion);
  --fuel-coal: color-mix(in oklab, var(--fam-combustion) 60%, #000000);
  --fuel-oil: color-mix(in oklab, var(--fam-combustion) 55%, #ffffff);
  --fuel-nuclear: var(--fam-clean-firm);
  --fuel-hydro: color-mix(in oklab, var(--fam-clean-firm) 60%, #000000);
  --fuel-geothermal: color-mix(in oklab, var(--fam-clean-firm) 55%, #ffffff);
  --fuel-wind: var(--fam-wind-solar);
  --fuel-solar: color-mix(in oklab, var(--fam-wind-solar) 58%, #000000);
  --fuel-storage: var(--fam-storage);
  --fuel-bio: var(--fam-bioenergy);
  --fuel-load: var(--mark-load);
  --fuel-other: var(--fam-unspecified);

  --plant-solar: #c9b877;
  --plant-wind: #9ab6d1;
  --plant-gas: #aab0b6;
  --plant-nuclear: #b49bc7;
  --plant-hydro: #7cb8b0;
  --plant-storage: #86b98f;
  --plant-coal: #ac9c88;
  --plant-oil: #c9a98a;
  --plant-biomass: #a9c77a;
  --plant-geothermal: #d29a86;
  --plant-other: #b5b5b5;

  /* Midstream asset layers, dark tints: 9.05 / 8.96 / 9.29 / 10.20 / 10.48 / 10.79 : 1 on --bg. */
  --asset-gas-pipeline: #c9a6d6;
  --asset-gas-processing: #d9a3b0;
  --asset-gas-storage: #a9b3dc;
  --asset-lng-terminal: #8ec6d3;
  --asset-ethanol: #cfc07a;
  --asset-rng: #8fd0b0;
  --asset-transmission: #e8c15f; /* 11.16:1 on --bg */
  --asset-retired: #e7a3c9;
  --asset-retiring: #f2a66b;

  --region-fill: #9ab6d1;
  --region-line: #9ab6d1;
  --sf-kv-69: #8f6c1c;
  --sf-kv-115: #b38a2a;
  --sf-kv-230: #d4a940;
  --sf-kv-345: #e8c15f;
  --sf-kv-500: #f7e0a0;
  --sf-kv-unknown: #8d9aa6;
  --sf-band: #4fc1d1;
  --sf-selected: #8fe3ee;
}

/* ---------- 2. Reset ---------- */
* { box-sizing: border-box; }
html { color-scheme: light dark; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--text-2);
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
}
.tnum { font-variant-numeric: tabular-nums; }
img { max-width: 100%; }
/* C-7: links are ink with a thin underline set off the baseline; on hover the underline takes the one
   hue. The chrome stays achromatic: no link is coloured. */
a { color: var(--link); text-decoration-thickness: 0.07em; text-underline-offset: 0.18em; }
a:hover { text-decoration-color: var(--accent); }
a:visited { color: var(--link-visited); }
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-2);
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
/* The `hidden` attribute must win over any class that sets `display` (`.filter-field`,
   `.legend`, ...): the UA's `[hidden] { display: none }` loses to a single-class rule, so without
   this the plant-type select and plants legend showed with the layer off (owner, 2026-09-15). */
[hidden] { display: none !important; }
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--surface); color: var(--text); padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border); border-radius: var(--radius-2);
}
.skip-link:focus { left: var(--space-4); top: var(--space-4); }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* ---------- 3. Layout ---------- */
/* The header (top bar, section bar, phone Menu) and the footer's link row are in the "Navigation v2
   shell" section further down. The wordmark's own rule stays here, for the admin header too
   (`admin/base.html`, the name and its "admin" tag); the top bar sets its own size. */
.wordmark {
  font-family: var(--font-display); font-size: var(--text-5); font-weight: 700; letter-spacing: -0.03em;
  color: var(--wordmark-ink); text-decoration: none; display: flex; align-items: baseline; gap: var(--space-2);
}
.wordmark:visited { color: var(--wordmark-ink); }
/* The lockup (docs/31-brand-identity.md §5.1, B-2): the outlined wordmark alone since 2026-10-30 (Inframation
   stands alone; the endorsement line was removed). `.wordmark__endorse` below is kept unused until the brand doc
   is brought into line. The wordmark is web/static/img/wordmark.svg's paths inline ("infra" Geist 700, "mation"
   Geist 400, the dot centred on the bold stem), so the font never moves it: its letters take the link's colour
   (--wordmark-ink), its dot --brand-dot, and its box (sized in em from the link's font size) ends at the
   baseline. */
.wordmark__svg { display: block; flex: none; }
.wordmark__dot { fill: var(--brand-dot); }
.wordmark__endorse {
  margin-inline-start: 14px; font-size: 0.58em; font-weight: 500; letter-spacing: 0; white-space: nowrap;
  color: var(--text-muted);
}
/* The endorsement is never drawn in the top bar: the one-line navigation (2026-10-31) leaves it no room at
   any width, and the lockup has stood alone since 2026-10-30. */
.top-bar .wordmark__endorse { display: none; }
main { max-width: 1440px; margin: 0 auto; padding: 0 var(--space-5) var(--space-9); }
.site-footer {
  border-top: 1px solid var(--border); padding: var(--space-6) var(--space-5);
  color: var(--text-muted); font-size: var(--text-1);
}
/* B-4: the footer opens with the endorsement, in ink (docs/31-brand-identity.md §5.1). */
.site-footer__endorse { margin: 0 0 var(--space-3); color: var(--text); }

@media (max-width: 719px) {
  /* The My list chip goes with the other chips when the phone sheet is open (lane private-map). */
  .map-landing:not([data-sheet="closed"]) .map-chip--mine { display: none; }
  main { padding: 0 var(--space-4) var(--space-8); }
}

h1, h2, h3 { font-family: var(--font-display); font-optical-sizing: auto; font-weight: 600; line-height: 1.25; margin: 0 0 var(--space-4); }
h1 { font-size: var(--text-6); }
h2 { font-size: var(--text-5); display: flex; align-items: baseline; gap: var(--space-2); }
h3 { font-size: var(--text-4); }
/* C-3: the text face with tabular figures, not mono (the numbering itself goes with the record lane's C-5). */
.section-num {
  font-family: var(--font-body); font-variant-numeric: tabular-nums; font-size: var(--text-2); font-weight: 400;
  color: var(--text-muted);
}
.page-header { padding: var(--space-5) 0 var(--space-4); border-bottom: 1px solid var(--border); margin-bottom: var(--space-5); }
.page-header p { color: var(--text-muted); max-width: 68ch; }

/* ---------- 4. Delayed notice, attribution, provenance (D-3, D-27, D-28) ----------
   The delayed notice is a quiet document stamp, not an alert banner: no fill colour, a single
   ink rule on the left, a sentence-case label in the text face (C-2). The dev-preview notice stays
   visibly distinct (dashed rule, its own label) because it only ever appears in a non-production build. */
.stamp-label {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
  color: var(--text); margin-inline-end: var(--space-2);
}
.delayed-notice {
  background: transparent; color: var(--text-muted);
  border: none; border-inline-start: 3px solid var(--text);
  padding: var(--space-2) var(--space-4); margin: var(--space-4) 0;
  font-size: var(--text-1);
}
.delayed-notice a { color: var(--link); font-weight: 600; }

.preview-banner {
  background: transparent; color: var(--family-committed-text);
  border: 1px dashed var(--family-committed-text); border-radius: var(--radius-2);
  padding: var(--space-2) var(--space-4); margin: 0 0 var(--space-4); font-size: var(--text-1);
}
.preview-banner .stamp-label { color: var(--family-committed-text); }

.view-notice {
  font-size: var(--text-1); color: var(--text-muted);
  padding: var(--space-2) 0 var(--space-4);
}

.attribution-line { font-size: var(--text-1); color: var(--text-muted); }
/* A status read from a compiled file (MISO and SPP rows from Berkeley Lab's queue file): a short outlined tag
   in the slip note's idiom, then the file's label as the owner's 2026-10-30 condition words it, quiet; the
   explanation behind the (i) (docs/13 §1.7; 2026-11-01). */
.as-of-line { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--space-2); margin: var(--space-1) 0; font-size: var(--text-1); color: var(--text); }
.as-of-tag {
  display: inline-flex; align-items: center; padding: 0 var(--space-2);
  border: 1px solid currentColor; border-radius: var(--radius-1); font-weight: 500; white-space: nowrap;
}
.as-of-label { color: var(--text-muted); }
.as-of-line .map-info { width: 1.75rem; height: 1.75rem; }
.as-of-mark { margin-left: 2px; color: var(--text-muted); }

/* A block's sources (`_macros.html::credits`, 2026-11-01): one quiet line of short names, each a link, and
   the (i); only wording a licence requires sits under it. The popover is the map's (`.map-pop`). */
.credits { margin: var(--space-4) 0 0; font-size: var(--text-1); color: var(--text-muted); }
.credits__line { display: flex; flex-wrap: wrap; align-items: center; column-gap: 0.3em; margin: 0; line-height: 1.5; }
.credits__k { color: var(--text-muted); margin-inline-end: var(--space-1); }
.credits__line a { color: var(--text); text-decoration-color: var(--border); text-underline-offset: 2px; }
.credits__line a:hover { text-decoration-color: currentColor; }
.credits__line .map-info { width: 1.75rem; height: 1.75rem; margin-block: -0.25rem; }
.credits__must { margin: 2px 0 0; max-width: 80ch; }
.map-pop.credits-pop { width: min(28rem, calc(100vw - 2rem)); }
.map-pop .credits-pop__list { list-style: none; margin: 0 0 var(--space-3); padding: 0; }
.map-pop .credits-pop__list li { margin: 0; padding: var(--space-2) 0; border-top: 1px solid var(--border); }
.credits-pop__list li:first-child { border-top: 0; padding-top: 0; }
.credits-pop__list li > a { font-weight: 500; }
.credits-pop__meta, .credits-pop__credit { display: block; color: var(--text-muted); }
.credits-pop__more { margin: 0; color: var(--text-muted); }

/* Provenance bar idiom: hairline rules top and bottom, no card chrome -- a filed citation strip,
   not a floating panel (D-2, D-27, docs/30 §7/§9). Class name stays "provenance-panel"
   (web/test_e2e.py selects it); this is the styling that turns it into the bar. */
.provenance-panel {
  border-block: 1px solid var(--border); padding: var(--space-4) 0; margin: var(--space-6) 0;
}
.provenance-panel h2 { font-size: var(--text-4); margin-bottom: var(--space-3); }
.provenance-panel__list { list-style: none; margin: 0; padding: 0; }
.provenance-panel__row {
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: var(--space-3);
  padding: var(--space-2) 0; border-bottom: 1px solid var(--border);
}
.provenance-panel__row:last-child { border-bottom: none; }
.provenance-panel__details { flex: 1 1 auto; min-width: 0; }
.provenance-panel__details summary {
  display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: baseline; cursor: pointer;
  list-style: none;
}
.provenance-panel__details summary::-webkit-details-marker { display: none; }
/* The disclosure mark rides on the name, not on the summary: as its own flex item it was left alone
   on a line above a long name at 400px (audit 2026-10-07 UX-11). */
.provenance-panel__name::before { content: "+ "; color: var(--text-muted); font-family: var(--font-body); font-variant-numeric: tabular-nums; font-weight: 400; }
.provenance-panel__details[open] .provenance-panel__name::before { content: "\2212 "; }
.provenance-panel__count { font-size: var(--text-1); color: var(--text-muted); }
.provenance-panel__name { font-weight: 600; }
.provenance-panel__licence { font-family: var(--font-body); font-size: var(--text-label); font-weight: 500; color: var(--text-muted); }
.provenance-panel__date { font-size: var(--text-1); color: var(--text-muted); }
.provenance-panel__meta { margin: var(--space-2) 0 0; font-size: var(--text-1); color: var(--text-muted); }
.provenance-panel__note { font-size: var(--text-1); color: var(--text-muted); margin: var(--space-1) 0 0; }
.provenance-panel__quote { font-size: var(--text-1); color: var(--text-muted); margin: var(--space-2) 0 0; }
.provenance-panel__link { flex: none; font-size: var(--text-1); }
/* Why a data-centre source counts the record as one (web/viewmodels.py::SELECT_BASIS_TEXT): its
   own line under the source name, outside the collapsed licence text, because it is the claim a
   reader checks first on a `load` record. Body colour, not muted: it is content, not metadata. */
/* Full row width so it always wraps under the name (a `max-width` would shrink the flex basis and
   let a short line sit beside the link); the end padding keeps the measure near 80ch instead. */
.provenance-panel__basis {
  flex: 1 0 100%; margin: 0; font-size: var(--text-1); color: var(--text);
  padding-inline-end: max(0px, calc(100% - 80ch));
}
.provenance-panel__empty { font-size: var(--text-1); color: var(--text-muted); }
/* A credit a licence requires on the page (web/source_credits.py VISIBLE): its own line under the name. */
.provenance-panel__credit--shown { flex: 1 0 100%; margin: 0; font-size: var(--text-1); color: var(--text-muted); }

/* ---------- 5. Status chip (D-25, never colour alone) ---------- */
.chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-1) var(--space-2); border-radius: var(--radius-1);
  font-size: var(--text-1); font-weight: 600; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.chip__icon { flex: none; }
.chip--neutral   { background: var(--family-neutral-fill);   color: var(--family-neutral-text); }
.chip--progress  { background: var(--family-progress-fill);  color: var(--family-progress-text); }
.chip--committed { background: var(--family-committed-fill); color: var(--family-committed-text); }
.chip--success   { background: var(--family-success-fill);   color: var(--family-success-text); }
.chip--danger    { background: var(--family-danger-fill);    color: var(--family-danger-text); }

/* Schedule slippage marker (services/api/slippage.py). Outlined, not filled: it must read as a
   second-order annotation on the status chip beside it, never as a competing status. `--quiet`
   (the `under_1y` bucket, 67 of 129 rows) carries no colour at all, only the words -- a few
   months' slip on a consented project is ordinary and colouring it is how a signal stops being
   read. D-25 holds either way: the label states the fact in words, colour only grades it. */
.slip-note {
  display: inline-flex; align-items: center; gap: var(--space-1);
  margin-left: var(--space-2);
  padding: 0 var(--space-2);
  border: 1px solid currentColor; border-radius: var(--radius-1);
  font-size: var(--text-1); font-weight: 500; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.slip-note__icon { flex: none; }
.slip-note__date { opacity: 0.8; }
.slip-note--quiet { color: var(--text-muted); }
.slip-note--warn  { color: var(--family-danger-text); }

/* ---------- 6. Filter bar as a control strip, not a form (D-17, API-3) ----------
   Underline-only inputs, sentence-case labels (C-2), single bottom rule for the whole strip -- read
   as a toolbar the reader scans left to right, not a bordered form panel. */
.filter-bar {
  display: flex; flex-wrap: wrap; gap: var(--space-5); align-items: end;
  padding: var(--space-3) 0; border-bottom: 1px solid var(--border); margin-bottom: var(--space-4);
}
.filter-field { display: flex; flex-direction: column; gap: var(--space-1); font-size: var(--text-2); }
.filter-field label, .filter-field__label {
  color: var(--text-muted); font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
}
.filter-field select, .filter-field input {
  font: inherit; padding: var(--space-1) 0; border: none; border-bottom: 1px solid var(--border);
  border-radius: 0; background: transparent; color: var(--text); min-height: 2.25rem;
}
.filter-field select:focus-visible, .filter-field input:focus-visible { border-bottom-color: var(--focus-ring); }
.filter-bar__range { display: flex; align-items: center; gap: var(--space-2); }
.filter-bar__range input { width: 5rem; }
.filter-field--checkbox { flex-direction: row; align-items: center; }
.filter-field--checkbox label {
  display: flex; align-items: center; gap: var(--space-2); color: var(--text);
  font-family: var(--font-body); font-size: var(--text-2); text-transform: none; letter-spacing: normal;
}
.filter-field--checkbox input[type="checkbox"] { width: 1.15rem; height: 1.15rem; min-height: 0; }

/* ADR 0008 placement control: a <fieldset> so its three checkboxes are grouped for assistive
   tech (docs/31 §7 WCAG 2.2 AA -- a related group of checkboxes needs a group label, which
   <label> alone does not give); reset to the filter-bar's own look rather than the UA fieldset
   chrome (border/padding), then laid out the same as the single-checkbox fields beside it. */
.filter-field--placement {
  border: none; margin: 0; padding: 0; gap: var(--space-2);
  flex-direction: row; align-items: center; flex-wrap: wrap;
}
.filter-field--placement legend {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500; color: var(--text-muted);
  padding: 0; margin-inline-end: var(--space-1);
}
.filter-field--placement label {
  display: flex; align-items: center; gap: var(--space-1); color: var(--text);
  font-family: var(--font-body); font-size: var(--text-2); text-transform: none; letter-spacing: normal;
}
.filter-field--placement input[type="checkbox"] { width: 1.15rem; height: 1.15rem; min-height: 0; }
.filter-bar__submit {
  /* Secondary button (docs/31 §5.16): outlined, sentence case. */
  font: inherit; font-size: var(--text-2);
  padding: var(--space-1) var(--space-4); border-radius: var(--radius-2);
  border: 1px solid var(--link); background: transparent; color: var(--link); cursor: pointer;
  min-height: 2.25rem;
}
.filter-bar__submit:hover { background: var(--link); color: var(--surface); }
.filter-bar__clear { align-self: center; font-size: var(--text-1); }
.result-count { color: var(--text-muted); font-size: var(--text-1); margin: 0 0 var(--space-3); }

/* ---------- 6.2 Filter notice: "showing N of M, and why" ----------
   Deliberately NOT `.view-notice` (small, muted, skimmable). A list narrowed by a default the
   reader did not ask for has to announce itself at body size in the text colour, or the reader
   concludes the coverage is thin rather than that a filter is on (owner brief, 2026-09-20). The
   accent rule is a reinforcing cue only -- the sentence carries the whole message (SC 1.4.1). */
.filter-notice {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: baseline;
  margin: var(--space-3) 0 var(--space-4); padding: var(--space-3) var(--space-4);
  border-inline-start: 3px solid var(--border); background: var(--surface);
  font-size: var(--text-2); color: var(--text);
}
.filter-notice--narrowed { border-inline-start-color: var(--link); }
.filter-notice__text { flex: 1 1 24rem; }
.filter-notice__undo { flex: none; font-weight: 600; white-space: nowrap; }

/* A phone's list at full height after the reader panned behind it (map.js `showListMoved`): one small chip at
   the list's top that counts the moved view; the list itself stays as it was opened. */
.ruler-moved {
  position: sticky; top: 0; z-index: 2; height: 0; display: flex; justify-content: center; align-items: flex-start;
}
.ruler-moved[hidden] { display: none; }
.ruler-moved__chip {
  margin-top: var(--space-2); padding: var(--space-1) var(--space-3); border: 1px solid var(--border);
  border-radius: 999px; background: var(--surface); color: var(--text); font: inherit; font-size: var(--text-1);
  font-weight: 600; box-shadow: var(--shadow-float); white-space: nowrap; flex: none; line-height: 1.4;
}

/* ---------- 5.x Ownership claims (company page, 2026-09-20) ----------
   The date and source that qualify "X is owned by Y". Set beside the name rather than in a
   footnote: the claim and its date are one fact, and an ownership claim with no date is the
   failure this markup exists to make visible, so the undated variant is marked, not hidden. */
.ownership-claim {
  display: block; margin-block-start: var(--space-1);
  font-size: var(--text-1); color: var(--text-muted);
}
.ownership-claim--undated { font-style: italic; }

/* ---------- 6.1 Count chips (the `/assets` index's by-type totals) ----------
   A row of filter links, not buttons: each one is a real URL a crawler can follow, which is the
   point of the index (docs/50 §4.4). Tokens only -- ink on surface, the selected one carrying the
   text colour rather than a fill, so it reads the same in both themes. `aria-current="page"` is
   what marks the selected chip; the border is the visible echo of it, never the only signal. */
.count-chips ul {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  list-style: none; margin: 0 0 var(--space-3); padding: 0;
}
.count-chips a {
  display: inline-flex; align-items: baseline; gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius-3);
  color: var(--text); text-decoration: none; font-size: var(--text-1);
}
.count-chips a:hover, .count-chips a:focus-visible { border-color: var(--link); color: var(--link); }
.count-chips a[aria-current="page"] { border-color: var(--text); font-weight: 600; }
.count-chips__n { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.count-chips a[aria-current="page"] .count-chips__n { color: var(--text); }

@media (max-width: 719px) {
  .filter-bar { flex-direction: column; align-items: stretch; }
  .filter-field select, .filter-field input, .filter-bar__submit { width: 100%; }
}

/* ---------- 7. Table (D-1, D-24) -- no card grid ---------- */
.record-table { width: 100%; border-collapse: collapse; font-size: var(--text-2); }
.record-table th, .record-table td { padding: var(--space-2) var(--space-3); text-align: left; border-bottom: 1px solid var(--border); }
.record-table th { position: sticky; top: 0; background: var(--bg); color: var(--text-muted); font-weight: 600; font-size: var(--text-1); }
.record-table td.num, .record-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.record-table .mono { font-family: var(--font-mono); font-size: var(--text-1); }
.record-table tbody tr:hover { background: var(--surface); }
.record-table a.row-link { color: var(--text); text-decoration: none; font-weight: 600; }
.record-table a.row-link:hover { color: var(--link); text-decoration: underline; }
/* `position: relative` makes the scroller the containing block of the visually hidden spans in its
   heads, so a wide table scrolls inside it and never widens the page (review of lane w1-nav: at
   720-723px the nowrap list heads pushed one 4px past the viewport). */
.table-scroll { overflow-x: auto; position: relative; }
/* Nested attribute values (_macros.html attribute_value): a mapping inside the asset attributes
   bag renders as a small key/value grid inside the value cell -- left-aligned, muted keys, one
   block per list item -- instead of a Python repr. */
.record-table td.record-table__nested { text-align: left; vertical-align: top; }
.attr-nested {
  display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-1) var(--space-3);
  margin: 0; font-size: var(--text-1); font-variant-numeric: tabular-nums;
}
.attr-nested dt { color: var(--text-muted); margin: 0; }
.attr-nested dd { margin: 0; overflow-wrap: anywhere; }
.attr-nested__item + .attr-nested__item { margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--border); }

@media (max-width: 719px) {
  .record-table thead { display: none; }
  .record-table, .record-table tbody, .record-table tr, .record-table td { display: block; width: 100%; }
  .record-table tr { border: 1px solid var(--border); border-radius: var(--radius-2); margin-bottom: var(--space-3); padding: var(--space-2); }
  .record-table td { border: none; display: flex; justify-content: space-between; gap: var(--space-3); padding: var(--space-1) var(--space-2); }
  .record-table td.num { text-align: right; }
  .record-table td::before { content: attr(data-label); color: var(--text-muted); font-size: var(--text-1); }
  .record-table td:empty { display: none; }
  .record-table td.record-table__nested { flex-direction: column; align-items: stretch; }
  .attr-nested { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .attr-nested dt { margin-top: var(--space-1); }
  .attr-nested dd { padding-left: var(--space-3); }
}

/* ---------- 7.1 Sortable headings (lane list-sort, 2026-10-22; web/list_sort.py, _macros.html sort_th) ----------
   A heading that sorts is a link over the whole cell: its label and an arrow. The column that
   sorts the view shows a solid arrow (down: largest, latest or Z first; up: the reverse) and its
   label in the text colour; every other sortable heading shows a faint double arrow that darkens
   on hover, so a reader can see which headings can be clicked. */
.record-table th.sortable { padding: 0; }
.sort-link {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-2) var(--space-3); color: inherit; text-decoration: none;
}
.sort-link:hover, .sort-link:focus-visible { color: var(--link); }
.sort-link:visited { color: inherit; }
.sort-link__icon { flex: none; }
.sort-link__icon--idle { opacity: 0.35; }
.sort-link:hover .sort-link__icon--idle { opacity: 1; }
.record-table th.is-sorted, .record-table th.is-sorted .sort-link:visited { color: var(--text); }
.sort-link__short { display: none; }
/* Words a column heading says in the table and the compact row must say itself ("MW", "Due"). */
.cell-unit { display: none; }
/* A long title's shortened twin, shown on the compact row instead of the whole title. */
.cell-text-short { display: none; }

/* ---------- 7.2 Compact two-line rows below 720px (docs/16 U-10, docs/17 M-8) ----------
   Amends docs/31 §3's 400-719px row for the record lists (`.record-table--compact`): no stacked
   label/value card, but two lines of text -- status and name, then the rest in the column order,
   joined by middle dots -- so `/proposals` at 390px is about a third as tall. The headings that sort
   become a "Sort by" row of links over the rows. Inline flow, not flex: the second line wraps at
   word boundaries and a separator never starts a line. Other `.record-table`s keep the cards. */
@media (max-width: 719px) {
  .record-table--compact thead { display: block; }
  .record-table--compact thead tr {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2);
    border: 0; border-radius: 0; margin: 0; padding: 0 0 var(--space-2);
  }
  .record-table--compact thead tr::before {
    content: "Sort by"; font-family: var(--font-body); font-size: var(--text-label); font-weight: 500; color: var(--text-muted);
  }
  .record-table--compact thead tr:not(:has(th.sortable)) { display: none; }
  .record-table--compact thead th { display: none; }
  .record-table--compact thead th.sortable {
    display: block; position: static; width: auto; padding: 0; border: 0; background: none; text-align: left;
  }
  .record-table--compact .sort-link {
    min-height: 2rem; padding: 0 var(--space-2); font-size: var(--text-1); color: var(--link);
    border: 1px solid var(--border); border-radius: var(--radius-2);
  }
  .record-table--compact th.is-sorted .sort-link { border-color: var(--text); color: var(--text); font-weight: 600; }

  .record-table--compact tbody tr {
    display: block; margin: 0; padding: var(--space-2) 0; border: 0; border-radius: 0;
    border-bottom: 1px solid var(--border); font-size: var(--text-1); line-height: 1.45;
  }
  .record-table--compact tbody tr:first-child { border-top: 1px solid var(--border); }
  .record-table--compact tbody td { display: inline; width: auto; padding: 0; border: 0; }
  .record-table--compact tbody td::before { content: none; }
  .record-table--compact td.cell-title { font-size: var(--text-2); }
  .record-table--compact td.cell-lead { margin-inline-end: var(--space-1); }
  /* The line break after the name; the rest of the row is the second line. */
  .record-table--compact td.cell-title::after { content: "\A"; white-space: pre; }
  .record-table--compact td.cell-meta { color: var(--text-muted); }
  /* An empty cell, and an optional one (`cell-opt`: a project's online date unless it sorts the
     view, a grid point's zero withdrawn or built count), stay off the line; the table still shows
     them. The separator follows a cell only when a shown cell comes after it. */
  .record-table--compact td.cell-meta:is(.is-empty, .cell-opt) { display: none; }
  .record-table--compact td.cell-meta:not(.is-empty, .cell-opt):has(~ td.cell-meta:not(.is-empty, .cell-opt))::after {
    content: "\00a0\00b7\0020";
  }
  .record-table--compact .cell-unit { display: inline; }
  /* An issuer printed as an agency code keeps "(agency code)" beside it on the line. */
  .record-table--compact td.cell-meta .field-grid__source-value { display: inline; }
  .record-table--compact .cell-text-full { display: none; }
  .record-table--compact .cell-text-short { display: inline; }
  /* "Capacity (MW)" and "Proposed online" are "Capacity" and "Online" in the Sort by row. */
  .record-table--compact .sort-link__long { display: none; }
  .record-table--compact .sort-link__short { display: inline; }
}
/* A technology label is two or three words ("Gas, combined cycle"); where the table has room it
   stays on one line rather than tripling the row height. */
@media (min-width: 1080px) { .record-table td.cell-nowrap-wide { white-space: nowrap; } }

/* ---------- 7.3 Figures in list cells (lane pages, 2026-10-23) ----------
   RFPs & funding Value: the amount in its own currency, the approximate US-dollar figure beside it
   (muted: it is ours, not the notice's), and what the figure is on the line under it. Companies:
   each figure is a link to the list that reproduces it, in the text colour with a dotted rule so a
   column of numbers stays a column of numbers. A zero is muted, a missing figure is a dash. */
/* The companies index's name search: the first control on the page, wider and larger than a filter,
   and outside the collapsible bar so it stays on screen at phone width. Its placeholder says what it
   is; the label is for assistive technology. */
.org-search { margin: var(--space-3) 0 var(--space-2); max-width: 40rem; }
.org-search__row { display: flex; gap: var(--space-2); }
.org-search__input {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: var(--text-3); min-height: 2.75rem;
  padding: var(--space-1) var(--space-3); color: var(--text); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-2);
}
.org-search__input:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
@media (max-width: 719px) { .org-search__input { font-size: var(--text-2); } }
.org-search__submit {
  font: inherit; min-height: 2.75rem; padding: 0 var(--space-4); cursor: pointer;
  color: var(--link); background: transparent; border: 1px solid var(--link); border-radius: var(--radius-2);
}
.org-search__submit:hover { background: var(--surface); }
/* The switch, its note and the count on one row over the companies table where they fit. */
.org-toolbar .scope-switch__note { flex: 0 1 auto; }
.org-toolbar .result-count { margin: 0 0 0 auto; }
@media (max-width: 719px) { .org-toolbar .result-count { margin-left: 0; } }
/* The companies table: the name column takes the room, the five figures stay narrow. */
@media (min-width: 720px) { .org-table td.cell-title { width: 40%; } }
.record-table td.cell-value { min-width: 8.5rem; }
.cell-value__amount { font-weight: 600; white-space: nowrap; }
.cell-value__usd { color: var(--text-muted); white-space: nowrap; }
.cell-value__kind { display: block; color: var(--text-muted); font-size: var(--text-1); }
.figure-link { color: inherit; text-decoration: underline dotted var(--border); text-underline-offset: 0.2em; }
.figure-link:visited { color: inherit; }
.figure-link:hover, .figure-link:focus-visible { color: var(--link); text-decoration: underline solid; }
.figure-zero { color: var(--text-muted); }
/* "from 1 of 47 assets": under a capacity fewer than half of the records behind it state. */
.figure-note { display: block; color: var(--text-muted); font-size: var(--text-1); font-weight: 400; }
.record-table td.cell-figure { white-space: nowrap; }
.cell-sub { display: block; margin-top: 2px; color: var(--text-muted); font-size: var(--text-1); font-weight: 400; }
@media (max-width: 719px) {
  .record-table--compact .cell-value__kind { display: inline; font-size: inherit; }
  .record-table--compact .cell-value__amount { font-weight: 400; }
  .record-table--compact .cell-sub { display: none; }
  .record-table--compact .figure-note { display: inline; font-size: inherit; }
}

/* ---------- 7.4 The asset list's plant figures (owner, 2026-11-01; web/asset_list_figures.py) ----------
   12-month generation, a five-point trend, capacity factor and owner. The trend is a small inline SVG:
   the history in the muted ink, the latest point as a dot in the one chart hue (docs/31 §4 `--chart-1`).
   A heading's (i) sits beside its sort link. On the phone the trend sits at the right of the name's
   line, the 12-month figure leads the grey second line with capacity factor and owner after it, and the
   (i)s stay in the table view only. The trend cell is not a `cell-meta`, so the line's separators skip it. */
.th-info { display: inline-flex; align-items: center; }
.record-table th.has-info .sort-link { padding-inline-end: var(--space-1); }
.th-info .map-info { margin-inline-end: var(--space-2); }
.spark { display: block; overflow: visible; }
.spark__line { fill: none; stroke: var(--text-muted); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.asset-table--figures { --spark-dot: var(--chart-1, #107656); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .asset-table--figures { --spark-dot: var(--chart-1, #34ad7e); } }
:root[data-theme="dark"] .asset-table--figures { --spark-dot: var(--chart-1, #34ad7e); }
.spark__dot { fill: var(--spark-dot, #107656); }
.record-table td.cell-trend { width: 1%; }
.cell-more { color: var(--text-muted); white-space: nowrap; }
@media (min-width: 720px) {
  .asset-table--figures td.cell-trend, .asset-table--figures th.cell-trend { padding-inline: var(--space-2); }
}
@media (max-width: 719px) {
  .record-table--compact .th-info .map-info { display: none; }
  .asset-table--figures .record-table--compact tbody tr { position: relative; }
  .asset-table--figures .record-table--compact td.cell-title { display: block; padding-inline-end: 4.5rem; }
  .asset-table--figures .record-table--compact td.cell-title::after { content: none; }
  .asset-table--figures .record-table--compact td.cell-trend {
    position: absolute; top: calc(var(--space-2) + 0.2rem); right: 3px; width: auto; line-height: 0;
  }
  .record-table--compact td.cell-trend.is-empty { display: none; }
}

/* RFPs & funding scope switch (docs/16 U-7): "Show: Energy-related 328 · All notices 624", the
   view-switch links with their counts, and one muted line saying what "energy-related" keeps. */
.scope-switch { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); margin: 0 0 var(--space-2); }
.scope-switch__n { color: var(--text-muted); font-weight: 400; margin-inline-start: var(--space-1); }
.view-switch__link[aria-current="page"] .scope-switch__n { color: var(--text); }
.scope-switch__note { margin: 0; font-size: var(--text-1); color: var(--text-muted); flex: 1 1 20rem; }
/* The count line, "Save this search as an alert" and the feed link on one row where they fit. */
.results-links { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--space-4); }
.list-page .results-links > p { margin-bottom: var(--space-2); }

.pager { display: flex; justify-content: space-between; padding: var(--space-4) 0; font-size: var(--text-2); }
.pager a { text-decoration: none; font-weight: 600; }
.pager__disabled { color: var(--text-muted); }

.empty-state, .error-state {
  padding: var(--space-7) var(--space-5); text-align: center; color: var(--text-muted);
  border: 1px dashed var(--border); border-radius: var(--radius-3);
}
.empty-state a { font-weight: 600; }

/* ---------- 8. Map page ---------- */
/* Owner, 2026-10-22 (docs/31 §5.19): the map takes the full content width, and one panel floating
   over its top right holds what is in view and the key. */
#map {
  height: 70vh; min-height: 24rem; border: 1px solid var(--border); border-radius: var(--radius-3);
  background: var(--surface);
}
.in-view-list { list-style: none; margin: 0; padding: 0; }
.in-view-list li { border-bottom: 1px solid var(--border); padding: var(--space-2) 0; }
.in-view-list a { text-decoration: none; color: var(--text); font-weight: 600; }
.in-view-list .meta { display: block; font-size: var(--text-1); color: var(--text-muted); }
/* docs/17 M-5: status families in words with the key's glyph (the panel's header, the overview and
   a region's summary in the drawer): the glyph takes the family's colour, the words the text's. */
.in-view-summary__family { white-space: nowrap; }
.in-view-summary__family .legend__icon { vertical-align: -1px; margin-inline-end: var(--space-1); }
.in-view-summary__family--neutral .legend__icon { color: var(--family-neutral-text); }
.in-view-summary__family--progress .legend__icon { color: var(--family-progress-text); }
.in-view-summary__family--committed .legend__icon { color: var(--family-committed-text); }
.in-view-summary__family--success .legend__icon { color: var(--family-success-text); }
.in-view-summary__family--danger .legend__icon { color: var(--family-danger-text); }
.unplaced-group summary { cursor: pointer; font-weight: 600; padding: var(--space-2) 0; }
/* The panel (home_map.html `#map-panel`; owner, 2026-10-22). From 720px it floats over the map's top
   right, inset 12px, 300px wide to 1079px and 340px from 1080px, never taller than the map: its
   body scrolls inside. Translucent: --surface at 88% over a light blur of the map. Every word on it
   keeps 4.5:1 or more whatever is drawn behind, measured against the surface mixed at 88% with
   black (light theme) or white (dark theme), the worst a map could put there
   (web/test_map_a11y.py): so its muted words take the darker grey of the neutral family (6.6:1 on
   white), and the key's words are --text beside their coloured glyph or swatch. A reader who asks
   for less transparency gets the plain surface. Below 720px it is a bar under the map (8.3). */
/* The panel and the drawer take their height from the map's own (#map: 70vh, at least 24rem), not
   from the frame, which also holds the basemap note under the canvas when the tiles fail. */
.map-frame { --map-panel-inset: var(--space-3); --map-panel-width: 18.75rem; --map-height: max(70vh, 24rem); }
@media (min-width: 1080px) { .map-frame { --map-panel-width: 21.25rem; } }
.map-panel {
  --text-muted: var(--family-neutral-text);
  /* The evergreen's small-text step on the translucent panel: #1d7356 falls to 4.37:1 where the map
     behind is black (light theme); #16624a holds 5.37:1 (brand lane, 2026-10-23; test_map_a11y.py). */
  --family-progress-text: var(--color-accent-deep);
  position: absolute; z-index: 3; top: var(--map-panel-inset); right: var(--map-panel-inset);
  height: calc(var(--map-height) - 2 * var(--map-panel-inset)); width: var(--map-panel-width);
  display: flex; flex-direction: column; overflow: hidden; color: var(--text);
  background: var(--surface);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  border: 1px solid var(--border); border-radius: var(--radius-3);
}
.map-panel.is-collapsed { height: auto; }
@media (prefers-reduced-transparency: reduce) {
  .map-panel { background: var(--surface); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
.map-panel__head {
  flex: none; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  gap: var(--space-1) var(--space-2); padding: var(--space-2) var(--space-3);
}
.map-panel:not(.is-collapsed) .map-panel__head { border-bottom: 1px solid var(--border); }
/* The panel's title (an h2, so the h3s inside follow the page's h1 in order) holds the header's
   button and looks like it: the button's words, not a heading's face. */
.map-panel__title {
  grid-column: 1; display: block; min-width: 0; margin: 0; font: inherit; font-weight: 600; line-height: inherit;
}
.map-panel__toggle {
  grid-column: 1; display: flex; align-items: center; gap: var(--space-2); min-height: 2.25rem; min-width: 0;
  width: 100%; padding: 0; border: 0; background: none; color: var(--text); font: inherit; font-weight: 600;
  text-align: left; cursor: pointer;
}
.map-panel__count { flex: 1 1 auto; min-width: 0; font-variant-numeric: tabular-nums; }
/* A chevron of two borders in currentColor, as a disclosure's: up while open (a click folds the body
   up into the header), down while collapsed (a click drops the body down). */
.map-panel__chevron {
  flex: none; width: 0.5em; height: 0.5em; margin: 0 0.2em; border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor; transform: translateY(0.15em) rotate(-135deg);
}
.map-panel.is-collapsed .map-panel__chevron { transform: translateY(-0.15em) rotate(45deg); }
.map-panel__keybtn {
  grid-column: 2; font: inherit; font-size: var(--text-1); min-height: 2.25rem; padding: 0 var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius-2); background: var(--surface);
  color: var(--text); cursor: pointer;
}
/* The thin bar by status family, in the map's own colours (the families' text hues, which are the
   markers' rings); 1px of panel between the parts. The words under it say the same counts. */
.map-panel__bar {
  grid-column: 1 / -1; display: flex; gap: 1px; height: 0.375rem; border-radius: var(--radius-1);
  overflow: hidden;
}
.map-panel__seg { display: block; min-width: 2px; }
.map-panel__seg--neutral { background: var(--family-neutral-text); }
.map-panel__seg--progress { background: var(--family-progress-text); }
.map-panel__seg--committed { background: var(--family-committed-text); }
.map-panel__seg--success { background: var(--family-success-text); }
.map-panel__seg--danger { background: var(--family-danger-text); }
/* Two lines are kept for the words from first paint, so the header is as tall before the data as
   after it (three families fit two lines at 300px) and the first fit, under a collapsed header,
   does not end behind it. */
.map-panel__families {
  grid-column: 1 / -1; margin: 0; display: flex; flex-wrap: wrap; align-content: flex-start;
  gap: 0 var(--space-3); min-height: 3em; font-size: var(--text-1); line-height: 1.5; color: var(--text);
}
.map-panel__body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.map-panel__tabs { flex: none; display: flex; gap: var(--space-2); padding: 0 var(--space-3); border-bottom: 1px solid var(--border); }
.map-panel__tab {
  font: inherit; font-size: var(--text-2); min-height: 2.5rem; padding: 0 var(--space-2); margin-bottom: -1px;
  border: 0; border-bottom: 2px solid transparent; background: none; color: var(--text-muted); cursor: pointer;
}
.map-panel__tab[aria-selected="true"] { color: var(--text); border-bottom-color: var(--text); font-weight: 600; }
.map-panel__scroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: var(--space-1) var(--space-3) var(--space-3);
}
.map-panel__heading {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500; color: var(--text-muted); margin: var(--space-3) 0 var(--space-1);
}
.map-panel__aside { text-transform: none; letter-spacing: normal; font-family: var(--font-body); }
/* Without scripts the panel shows its key; with them, nothing flashes before map.js lays it out:
   the body waits where the panel starts collapsed (below 1080px), the key tab where it starts open. */
.js .map-panel:not([data-ready]) #map-tabpanel-key { display: none; }
@media (max-width: 1079px) { .js .map-panel:not([data-ready]) .map-panel__body { display: none; } }
/* "In view" at national and multi-state views: rows of a name, a count and a meter of its share. */
.map-overview__rows { list-style: none; margin: 0; padding: 0; }
.map-overview__row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 0 var(--space-2);
  padding: var(--space-1) 0; font-size: var(--text-1);
}
.map-overview__name { min-width: 0; color: var(--text); }
.map-overview__name .legend__icon { vertical-align: -2px; }
.map-overview__count { color: var(--text-muted); white-space: nowrap; }
.map-overview__meter {
  grid-column: 1 / -1; display: block; height: 0.25rem; margin-top: 2px; border-radius: var(--radius-1);
  background: var(--border); overflow: hidden;
}
.map-overview__fill { display: block; height: 100%; background: var(--text-muted); }
/* Five rows kept for the busiest areas, each as tall as an area's row is drawn (its 24px button and
   4px above and below), so their answer landing moves nothing under them (review 2026-10-22: 140px
   were kept for five rows of 32px). */
.map-overview__areas { --map-area-row: calc(1.5rem + 2 * var(--space-1)); min-height: calc(5 * var(--map-area-row)); }
.map-overview__row--area { align-items: center; min-height: var(--map-area-row); }
.map-overview__area {
  font: inherit; font-size: var(--text-2); color: var(--link); background: none; border: 0; padding: 0;
  min-height: 1.5rem; text-align: left; text-decoration: underline; cursor: pointer;
}
.map-overview__empty, .map-overview__also, .map-overview__hint { font-size: var(--text-1); color: var(--text-muted); }
.map-overview__also { margin: var(--space-3) 0 0; }
/* The overview's first line: why there is no list at this zoom, and how to get one. */
.map-overview__hint { margin: var(--space-2) 0 0; font-weight: 600; color: var(--text); }
/* The key tab: the words a first visitor reads, a glyph or swatch beside each in the mark's hue. */
.map-key .legend { flex-direction: column; flex-wrap: nowrap; gap: var(--space-1); border: 0; margin: 0; padding: 0; }
.map-key .legend + .legend:not([hidden]) { border-top: 1px solid var(--border); margin-top: var(--space-3); }
.map-key .legend > .map-panel__heading:first-child { margin-top: var(--space-2); }
.map-key__intro { margin: 0 0 var(--space-1); font-size: var(--text-1); color: var(--text-muted); }
.map-key .legend__item { align-items: flex-start; gap: var(--space-2); padding: 2px var(--space-1); border-radius: var(--radius-2); }
.map-key .legend__item > .legend__icon, .map-key .legend__item > .legend__sample { margin-top: 2px; }
.map-key [data-highlight]:hover { background: var(--bg); }
.map-panel .legend__words { color: var(--text); }
.map-panel .legend__detail { color: var(--text-muted); }
.map-key .legend__group { gap: 0 var(--space-3); }
.map-key .legend__group-name { flex-basis: 100%; margin-top: var(--space-2); color: var(--text); }
.map-key .legend__note { padding-left: var(--space-1); }
/* The list in the panel's width: the status chip (or a row's kind) and Details on the first line,
   the name under them, then the muted line, so a long name never pushes Details onto a line alone. */
.map-panel .in-view-list li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 2px var(--space-2);
}
.map-panel .in-view-list li > :first-child { grid-column: 1; grid-row: 1; justify-self: start; }
.map-panel .in-view-list li > :not(:first-child):not(.details-btn) { grid-column: 1 / -1; }
.map-panel .in-view-list li > .details-btn { grid-column: 2; grid-row: 1; margin: 0; }
.map-panel .in-view-list li.in-view-list__group-name { display: block; }
.map-panel .in-view-list .chip-slot .chip { margin: 0; }
.in-view-list__unplaced { font-size: var(--text-1); color: var(--text-muted); padding: var(--space-2) 0; margin: 0; }
/* How many matches no map can place: from 720px the count line above the map says it (map.js
   `renderCountLine`); below 720px that line shares a row with the notice's short form, so there
   "In view" opens with it instead (8.3). */
.map-panel__unplaced { display: none; }
/* Legend: icon + label per family, never colour alone (D-5) -- reuses the chip icon set. */
.legend { display: flex; flex-wrap: wrap; gap: var(--space-4); padding: var(--space-3) 0; font-size: var(--text-1); border-top: 1px solid var(--border); margin-top: var(--space-2); }
.legend__item { display: flex; align-items: center; gap: var(--space-1); }
/* UX-5: the region row's sample and words take the region hue (5.3:1 on paper; docs/31 §5.7). */
.legend__item--region { color: var(--region-line); }
.legend__item--region[hidden] { display: none; }
.filter-field__note { color: var(--text-muted); font-size: var(--text-1); }
.feed-link { font-size: var(--text-1); margin: 0 0 var(--space-3); }
.nowrap { white-space: nowrap; }
/* The late sources behind the tier notice (expert review 2026-10-07): one closed line, names inside. */
.delayed-notice__stale { display: inline; }
.delayed-notice__stale > summary { display: inline; cursor: pointer; color: var(--link); }
.delayed-notice__stale[open] { display: block; margin-top: var(--space-1); }
.org-follow { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; margin: 0 0 var(--space-4); }
a.button-secondary { display: inline-flex; align-items: center; text-decoration: none; }
a.button-secondary:visited { color: var(--secondary-ink); }
.legend__icon { flex: none; }
.map-attribution { font-size: var(--text-1); color: var(--text-muted); padding-top: var(--space-2); }
/* One line under a map drawn on the outline alone (basemap.js `showFailedNote`, docs/16 §2 M-1):
   under the canvas on the home map, between a mini-map and its caption on the record pages. */
.map-basemap-note { font-size: var(--text-1); color: var(--text-muted); margin: var(--space-2) 0 0; }
.mini-map + .map-basemap-note { margin: 0 0 var(--space-1); }
.map-live-region { position: absolute; width: 1px; height: 1px; overflow: hidden; }
/* Hover cards (MapLibre popups) take the theme. MapLibre's stylesheet loads after this one and paints
   the card and its tip #fff while the text inherits --text, so in dark mode the text vanished (owner
   report, 2026-10-21); these selectors carry one class more than MapLibre's so load order is moot. */
.maplibregl-popup .maplibregl-popup-content { background: var(--surface); color: var(--text); }
.maplibregl-popup.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.maplibregl-popup.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.maplibregl-popup.maplibregl-popup-anchor-top-right .maplibregl-popup-tip { border-bottom-color: var(--surface); }
.maplibregl-popup.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.maplibregl-popup.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.maplibregl-popup.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip { border-top-color: var(--surface); }
.maplibregl-popup.maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--surface); }
.maplibregl-popup.maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--surface); }
/* A hover card never takes the pointer from the map (review of lane v2-polish). Drawn above a large mark,
   it opened under the pointer, the canvas lost the pointer to it and MapLibre closed the card it had just
   opened, so it flickered while the pointer was still on the mark. Its words hold no link. */
.maplibregl-popup.map-hover-card,
.map-hover-card .maplibregl-popup-content { pointer-events: none; }
/* docs/17 M-3: MapLibre's cooperative-gesture hint ("Use two fingers to move the map"), shown on a
   touch screen when one finger swipes the home map or a mini-map (map.js, asset_map.js). MapLibre
   paints a black wash with white 1.4em text; here the wash is gone and the words sit on a surface
   label, as a hover card does. One class more than MapLibre's selectors, as for the cards above.
   MapLibre keeps it 1s, then fades it over 1s; the reduced-motion rule makes the fade instant. */
.maplibregl-canvas-container .maplibregl-cooperative-gesture-screen {
  background: transparent; color: var(--text); font-size: var(--text-2); padding: var(--space-4);
}
.maplibregl-canvas-container .maplibregl-cooperative-gesture-screen > div {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2);
  box-shadow: var(--shadow-1); padding: var(--space-2) var(--space-3); text-align: center;
}
.map-controls { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-2); }
.map-controls button {
  font: inherit; min-width: 2.25rem; min-height: 2.25rem; border-radius: var(--radius-2);
  border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer;
}
/* docs/17 M-1, M-4, M-6, M-11 (lane m-layout): the wrappers the phone layout needs lay out as if
   absent from 720px, and the controls only a phone draws are not drawn, so the wide map page is as
   it was. The phone rules are in "8.3 The map page below 720px", further down. */
.map-overlay .map-overlay__rail { display: contents; }
.filter-bar__done--top, .map-intro__stop, .map-intro__about,
.map-notice__brief, .map-drawer__expand, .map-drawer__back { display: none; }

/* Existing-assets type picker (docs/00-PLAN.md 2026-09-19 option (a)): one checkbox per asset
   type, laid out like the placement fieldset so the two read as the same control family. A type
   listed but not yet loaded is disabled with its "(coming)" text, never silently absent. */
.filter-field--asset-types {
  border: none; margin: 0; padding: 0; gap: var(--space-2);
  flex-direction: row; align-items: center; flex-wrap: wrap;
}
.filter-field--asset-types legend {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500; color: var(--text-muted);
  padding: 0; margin-inline-end: var(--space-1);
}
.filter-field--asset-types label {
  display: flex; align-items: center; gap: var(--space-1); color: var(--text);
  font-family: var(--font-body); font-size: var(--text-2); text-transform: none; letter-spacing: normal;
}
.filter-field--asset-types label.is-disabled { color: var(--text-muted); }
.filter-field--asset-types input[type="checkbox"] { width: 1.15rem; height: 1.15rem; min-height: 0; }

/* Legend groups per visible asset type: each group hides with its type (map.js toggles `hidden`),
   so the legend only ever names what is drawn. Line samples carry the interstate/intrastate dash
   rule (D-5: dash + label, never hue alone). */
.legend--assets { flex-direction: column; gap: var(--space-2); }
.legend__group { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; }
.legend__group-name { font-weight: 600; color: var(--text-muted); }
.legend__sample { flex: none; }
/* A group's one-line caveat (ethanol: capacity-table plants at state grade are not points; RNG:
   farm digesters at county grade are not) -- muted text, never a second hue, and it wraps under
   the sample at phone width like every other legend item. */
.legend__note { color: var(--text-muted); font-size: var(--text-1); flex-basis: 100%; }
/* "× n units" beside a nearby/in-view proposal that EIA-860M lists once per generator unit
   (web/app.py::group_nearby_proposals, map.js groupProposalFeatures). */
.in-view-list__units { font-size: var(--text-1); color: var(--text-muted); font-weight: 400; white-space: nowrap; }

/* In-view list: proposals first (the accessible path's primary content, D-14), then region
   records and existing assets as their own labelled groups. A row that opens the map drawer does
   so through a real button (keyboard-reachable, SC 2.1.1; audit 2026-09-18: region records were
   not), beside the link to the record's own page where one exists. */
.in-view-list__group-name {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
  color: var(--text-muted); margin: var(--space-4) 0 var(--space-1);
}
.in-view-list__kind { font-size: var(--text-1); color: var(--text-muted); margin-inline-end: var(--space-1); }
.in-view-list .details-btn {
  /* Secondary button, compact (docs/31 §5.16): a row action, so smaller type, still sentence case. */
  font: inherit; font-size: var(--text-1);
  background: none; border: 1px solid var(--border); border-radius: var(--radius-2); color: var(--link);
  cursor: pointer; padding: 0 var(--space-2); min-height: 1.5rem; margin-inline-start: var(--space-2);
}
.in-view-list .details-btn:hover { border-color: var(--link); }

/* ---------- 8.2 Static asset / company maps (asset_detail.html, organization_detail.html) ----------
   Server-rendered SVG of the record's own geometry (no JS needed; docs/30 §3.1 asset page note),
   replaced by a MapLibre mini-map at a fixed fit when web/static/js/asset_map.js runs. */
.mini-map {
  position: relative; height: 40vh; min-height: 16rem; max-height: 32rem;
  border: 1px solid var(--border); border-radius: var(--radius-3); background: var(--map-water);
  overflow: hidden; margin: var(--space-4) 0;
  /* Its own stacking context: MapLibre's layers (the two-finger notice is z-index 99999) stay inside
     it, so a section heading held over it while the page scrolls stays on top (lane stacked-lists). */
  isolation: isolate;
}
.mini-map svg { display: block; width: 100%; height: 100%; background: var(--map-land); }
.mini-map__line { fill: none; stroke: var(--asset-gas-pipeline); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.mini-map__line--transmission { stroke: var(--asset-transmission); stroke-dasharray: 8 3 2 3; stroke-linecap: butt; }
.mini-map__line--intrastate { stroke-dasharray: 6 4; }
.mini-map__point { fill: var(--asset-gas-processing); stroke: var(--surface); stroke-width: 1; }
.mini-map__proposal { fill: var(--family-progress-text); stroke: var(--surface); stroke-width: 1; }
.mini-map__caption { font-size: var(--text-1); color: var(--text-muted); margin: 0 0 var(--space-4); }
.mini-map .maplibregl-canvas-container { height: 100%; }

/* The company page's stacked sections, asset groups and pipeline block gave way to its tabs (section 9.2,
   lane company-tabs, 2026-10-24). `.pipeline-table` stays: the brand tests hold its caption as a C-2 label. */
.pipeline-table { width: 100%; border-collapse: collapse; font-size: var(--text-2); }
.pipeline-table caption {
  text-align: left; font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
  color: var(--text-muted); padding-bottom: var(--space-1);
}
.pipeline-table th, .pipeline-table td {
  padding: var(--space-1) var(--space-2); border-bottom: 1px solid var(--border); text-align: left;
}
.pipeline-table thead th { color: var(--text-muted); font-size: var(--text-1); font-weight: 600; }
.pipeline-table tbody th { font-weight: 400; }
.pipeline-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pipeline-table tfoot th, .pipeline-table tfoot td { font-weight: 600; border-bottom: 0; }
.pipeline-table a { font-weight: 600; }
.pipeline-table__status { display: inline-flex; vertical-align: -1px; }
.org-links { list-style: none; margin: 0; padding: 0; }
.org-links li { padding: var(--space-1) 0; }

@media (max-width: 719px) {
  .mini-map { height: 34vh; min-height: 13rem; }
}

/* ---------- 8.1 Map detail drawer -- document panel, not a modal card (D-12, D-15) ---------- */
.map-drawer {
  position: fixed; top: 0; right: 0; height: 100%; width: min(26rem, 90vw);
  background: var(--surface); border-left: 1px solid var(--border); box-shadow: var(--shadow-float);
  padding: var(--space-6) var(--space-5); overflow-y: auto; transform: translateX(100%);
  transition: transform var(--motion-fast) ease-out; z-index: 50;
}
.map-drawer.is-open { transition-duration: var(--motion-base); transform: translateX(0); }
/* From 720px the drawer opens in the panel's place over the map (owner, 2026-10-22: the two never
   overlap), on the plain --surface (no blur on the drawer, D-7), with "Back to what's in view"
   beside Close. The covered panel keeps its tab and scroll for when the drawer closes. */
@media (min-width: 720px) {
  .map-frame > .map-drawer {
    position: absolute; top: var(--map-panel-inset); right: var(--map-panel-inset); bottom: auto;
    height: calc(var(--map-height) - 2 * var(--map-panel-inset)); width: var(--map-panel-width); z-index: 4;
    padding: 0 var(--space-4) var(--space-4);
    border: 1px solid var(--border); border-radius: var(--radius-3);
    transform: translateX(var(--space-3)); opacity: 0;
    transition: transform var(--motion-fast) ease-out, opacity var(--motion-fast) ease-out;
  }
  .map-frame > .map-drawer.is-open { transform: none; opacity: 1; transition-duration: var(--motion-base); }
  .map-panel.is-covered { visibility: hidden; }
  .map-drawer__bar {
    position: sticky; top: 0; z-index: 1; display: flex; align-items: center; justify-content: space-between;
    gap: var(--space-2); margin: 0 calc(-1 * var(--space-4)) var(--space-3); padding: var(--space-1) var(--space-3);
    background: var(--surface); border-bottom: 1px solid var(--border);
  }
  .map-frame > .map-drawer .map-drawer__close { padding: var(--space-2) 0; }
  .map-drawer__back {
    display: inline-flex; align-items: center; min-height: 2.25rem; padding: 0; border: 0; background: none;
    font: inherit; font-size: var(--text-1); color: var(--link); text-decoration: underline; cursor: pointer;
  }
}
@media (max-width: 1079px) {
  .map-frame > .map-drawer h2 { font-size: var(--text-4); }
}
.map-drawer__close {
  /* Quiet button (docs/31 §5.16). */
  font: inherit; font-size: var(--text-1);
  background: none; border: none; color: var(--text-muted); cursor: pointer; padding: 0 0 var(--space-4);
  display: block;
}
.map-drawer__close:hover { color: var(--text); }
.map-drawer h2 { font-size: var(--text-5); margin-bottom: var(--space-2); }
.drawer-fields { margin: var(--space-4) 0 0; border-top: 1px solid var(--border); }
.drawer-fields__row {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3);
  padding: var(--space-2) 0; border-bottom: 1px solid var(--border); font-size: var(--text-2);
}
.drawer-fields__row dt { color: var(--text-muted); font-size: var(--text-1); margin: 0; }
.drawer-fields__row dd { margin: 0; text-align: right; }
.drawer-source {
  font-size: var(--text-1); color: var(--text-muted); border-top: 1px solid var(--border);
  padding-top: var(--space-3); margin-top: var(--space-3);
}
.drawer-source__label {
  display: block; font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
  color: var(--text-muted); margin-bottom: var(--space-1);
}
.map-drawer .drawer-open-link { display: inline-block; margin-top: var(--space-4); font-weight: 600; }
/* A region's summary (docs/17 M-2): the count and its status parts, then "Open the list". A
   country with a quick view of its own also offers to show it on the map (`.button-secondary`). */
.drawer-region { margin: var(--space-4) 0 0; font-size: var(--text-2); line-height: 1.7; }
.drawer-region__jump { margin-top: var(--space-4); }

/* ---------- 9. Detail pages (D-18, D-26) ---------- */
.breadcrumbs { font-size: var(--text-1); color: var(--text-muted); margin-bottom: var(--space-3); }
.breadcrumbs a { color: var(--text-muted); }
.detail-header { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-3); }
.detail-header h1 { margin: 0; }
/* The register's own spelling of a name set in capitals, once, under the readable H1 (review
   2026-10-10 §2.6 item 7). */
.as-filed { font-size: var(--text-1); color: var(--text-muted); margin: var(--space-1) 0 0; }
/* The company line under a record's name (docs/16 U-2, U-20): who is behind the record, linked
   to its company page, on the record's first lines. Text on the paper, no chip or card (D-7). */
.record-company { margin: var(--space-2) 0 0; overflow-wrap: anywhere; }
.record-company__label { font-size: var(--text-1); color: var(--text-muted); margin-inline-end: var(--space-1); }
.record-company__none, .record-company__sep, .record-company__count { color: var(--text-muted); }
.record-company .mono { font-family: var(--font-mono); }
.record-company + .record-company__claim { margin-block-start: var(--space-1); }
.field-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--space-6);
  margin: var(--space-5) 0; border-top: 1px solid var(--border);
}
.field-grid > div { display: flex; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
.field-grid dt { color: var(--text-muted); font-size: var(--text-1); margin: 0; }
.field-grid dd { margin: 0; text-align: right; }
.field-grid .mono { font-family: var(--font-mono); }
.field-grid__source-value { display: block; font-size: var(--text-1); color: var(--text-muted); }
@media (max-width: 719px) { .field-grid { grid-template-columns: 1fr; } }
/* A company's public facts under its name (lane pages): website, headquarters and listing on one
   wrapping row, each value followed by its source in small muted type -- text on the paper, no card
   (D-7). The source names link to the statement read. */
.org-facts {
  list-style: none; margin: var(--space-2) 0 var(--space-3); padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-5);
}
.org-facts__item { overflow-wrap: anywhere; }
.org-facts__label { font-size: var(--text-1); color: var(--text-muted); margin-inline-end: var(--space-1); }
.fact-source {
  font-size: var(--text-1); color: var(--text-muted); margin-inline-start: var(--space-1);
  text-decoration: underline dotted; text-underline-offset: 0.2em; white-space: nowrap;
}
.fact-source:visited { color: var(--text-muted); }
.fact-source:hover, .fact-source:focus-visible { color: var(--link); }

/* A row across both columns: an opportunity's value, with its US-dollar figure, the other figures
   the notice states, where it was read and the ECB credit on lines of their own (lane pages). */
.field-grid > .field-grid__wide { grid-column: 1 / -1; }
.field-grid__wide dd { max-width: 44rem; }
@media (max-width: 719px) {
  .field-grid > .field-grid__wide { flex-direction: column; gap: var(--space-1); }
  .field-grid__wide dd { text-align: left; }
}
.value-figure { font-size: var(--text-3); font-weight: 600; }
.value-line, .value-source { display: block; margin-top: var(--space-1); }
.value-line { color: var(--text); }
.value-source { color: var(--text-muted); font-size: var(--text-1); }
.value-source .mono { font-family: var(--font-mono); }

/* Lifecycle timeline as a ruled ledger: date column in tabular figures (C-3), event column, hairline rules
   between rows -- a register entry, not a rounded-dot activity feed (docs/30 §1, D-26). */
.timeline { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--border); }
.timeline li {
  display: flex; gap: var(--space-5); padding: var(--space-3) 0; border-bottom: 1px solid var(--border);
  align-items: baseline;
}
.timeline time {
  flex: none; width: 7.5rem; font-family: var(--font-body); font-variant-numeric: tabular-nums;
  font-size: var(--text-1); color: var(--text-muted);
}
.timeline li .timeline__event { flex: 1; }
@media (max-width: 719px) {
  .timeline li { flex-direction: column; gap: var(--space-1); }
  .timeline time { width: auto; }
}
.raw-fields { font-family: var(--font-mono); font-size: var(--text-1); white-space: pre-wrap; word-break: break-word; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2); padding: var(--space-4); max-height: 20rem; overflow: auto; }
.raw-fields-details summary { cursor: pointer; font-weight: 600; }

/* ---------- 9.1 Record pages as URL tabs (2026-10-23, lane record-tabs; docs/30 §11.5, §11.8) ----------
   A project, a plant, pipeline or line, and a grid connection point: one header on every tab (breadcrumb,
   name with its status chip or type badge, who is behind it, key figures, the one primary action, the
   tier notice), then the tab bar, the tab, and its credits line. App-screen rules of the taste skill
   (references/app-screens.md): the title is 23-28px, key figures are type (a small grey label over the
   value), colour sits on data, status and the one primary action, and nothing here adds a treatment
   the skill bans (its lint and inspector pass this section with no new finding).
   Scoped to `.record-page`, so no other page changes. Below 720px the action is a full-width 44px
   button under the header and the tab bar scrolls sideways inside itself (it takes the section bar's
   row class, so site.js brings the current tab into view and fades a cut edge). */
.record-page [id] { scroll-margin-top: calc(var(--top-bar-h, 3rem) + var(--space-4)); }
.record-header {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--space-6);
  align-items: start; padding-top: var(--space-4);
}
.record-header > * { grid-column: 1 / -1; }
.record-header .breadcrumbs { margin: 0 0 var(--space-2); }
/* Previous / next through the list the reader came from: on the breadcrumb's line, right-aligned. */
.record-step { justify-self: end; display: flex; gap: var(--space-4); font-size: var(--text-1); }
@media (min-width: 721px) {
  .record-step { grid-row: 1; }
  .record-header .breadcrumbs:has(+ .record-step:not([hidden])) { grid-row: 1; padding-inline-end: 11rem; }
}
.record-step[hidden], .record-step__link[hidden] { display: none; }
.record-step__link { display: inline-flex; align-items: center; min-height: 1.5rem; color: var(--text-muted); text-decoration: none; }
.record-step__link:hover { color: var(--link); text-decoration: underline; }
.record-step__link[data-step="prev"]::before { content: "\2190\00a0"; }
.record-step__link[data-step="next"]::after { content: "\00a0\2192"; }
@media (max-width: 720px) {
  .record-step { gap: var(--space-2); }
  .record-step__link { min-height: 44px; min-width: 44px; justify-content: center; padding-inline: var(--space-2); }
}
.record-header > .detail-header { grid-column: 1; gap: var(--space-2) var(--space-3); }
.record-header .detail-header h1 { font-size: var(--text-5); line-height: 1.2; overflow-wrap: anywhere; }
.record-header__chip { display: inline-flex; align-items: center; min-height: 1.5rem; text-decoration: none; border-radius: var(--radius-1); }
.record-header__chip:hover .chip__label, .record-header__chip:focus-visible .chip__label { text-decoration: underline; }
.record-header__action { grid-column: 2; grid-row: 2; align-self: center; margin: 0; }
.record-action {
  display: inline-flex; align-items: center; justify-content: center; min-height: 2.5rem;
  padding: 0 var(--space-5); border-radius: var(--radius-2); white-space: nowrap;
  background: var(--text); color: var(--bg); font-weight: 600; text-decoration: none;
}
.record-action:hover, .record-action:focus-visible { background: var(--link); color: var(--surface); }
/* "Get owner & developer contacts" (owner, 2026-11-04): a quiet button on the Deal room; the panel is the (i) popover's. */
.record-contacts { margin: var(--space-4) 0 0; }
/* "Interested in this project?" in the map's drawer (coordinator, 2026-11-08; `_macros.html::contacts_cta`, compact):
   the record page's ask and its three buttons, one size down: the booking button filled, the other two outlined. */
.contacts-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); margin: var(--space-3) 0;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-2); background: var(--active); color: var(--text);
}
.contacts-card__line { margin: 0; font-size: var(--text-2); font-weight: 600; line-height: 1.45; }
.contacts-card__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; }
.contacts-card__actions a { min-height: 2rem; padding: 0 var(--space-3); font-size: var(--text-1); font-weight: 500; white-space: nowrap; }
.contacts-card a:is(.contacts-card__alert, .contacts-card__beta), .contacts-card a:is(.contacts-card__alert, .contacts-card__beta):visited {
  background: transparent; color: var(--text); border: 1px solid var(--control); border-radius: var(--radius-2);
}
.contacts-card a:is(.contacts-card__alert, .contacts-card__beta):hover { background: var(--active); }
.contacts-card a:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* "Who's behind this project" (owner, 2026-11-05; `_macros.html::contacts_cta`): on a record page, a part of the
   Details block under the Developer and Owner rows: its heading leads the rows; then one line, "Book a call" (the
   page's dark button) and "Join beta" (outlined). */
.contacts-cta { margin: var(--space-4) 0; }
.contacts-cta__title { margin: 0; font-size: var(--text-2); font-weight: 600; line-height: 1.35; }
.contacts-cta__line { margin: var(--space-1) 0 0; max-width: 68ch; font-size: var(--text-2); line-height: 1.5; color: var(--text-muted); }
.contacts-cta__beta-line { margin: var(--space-2) 0 0; font-size: var(--text-1); color: var(--text-muted); }
.contacts-cta__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: var(--space-3) 0 0; }
.contacts-cta__ask { margin: 0; font-size: var(--text-2); font-weight: 600; }
.contacts-cta a.contacts-cta__sales, .contacts-cta a.contacts-cta__beta, .contacts-cta a.contacts-cta__alert { min-height: 2.25rem; padding: 0 var(--space-4); font-size: var(--text-2); font-weight: 500; }
.contacts-cta a.contacts-cta__beta, .contacts-cta a.contacts-cta__beta:visited, .contacts-cta a.contacts-cta__alert, .contacts-cta a.contacts-cta__alert:visited {
  background: transparent; color: var(--text); border: 1px solid var(--control); border-radius: var(--radius-2);
}
.contacts-cta a:is(.contacts-cta__beta, .contacts-cta__alert):hover { background: var(--active); }
.contacts-cta__actions + .contacts-cta__line { margin-top: var(--space-2); }
.contacts-cta a:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.record-page [data-band] > .contacts-cta { padding: var(--space-3) var(--lg-px) var(--space-4); }
/* "Who's behind it" leads the rows it heads (owner, 2026-11-08). */
.contacts-cta__title--lead { margin: var(--space-4) 0 var(--space-2); }
.record-page [data-band] > .contacts-cta__title--lead { margin: 0; padding: var(--space-3) var(--lg-px) var(--space-2); }
.contacts-cta__none { margin: 0; font-size: var(--text-2); }
.contacts-cta__none + .contacts-cta__ask { margin-top: var(--space-2); }
.fact-table__none { color: var(--text-muted); }
.record-company__source { font-size: var(--text-1); color: var(--text-muted); margin-inline-start: var(--space-1); }
.record-header .delayed-notice { margin: var(--space-4) 0 0; }
.record-page .stamp-label { font-family: var(--font-body); font-size: var(--text-1); font-weight: 600; text-transform: none; letter-spacing: 0; }
/* The tab bar: plain links, the current one in ink at 600 with a 2px mark under it; no rule across. */
.record-tabs { margin: var(--space-5) 0 var(--space-5); }
.record-tabs__items { gap: var(--space-6); }
.record-tabs__items a { min-height: 2.75rem; }
.record-tabs__count { margin-inline-start: var(--space-1); color: var(--text-muted); font-weight: 400; font-variant-numeric: tabular-nums; }
/* The Overview's summaries of the other tabs: two columns from 1080px, each its own heading. */
.record-summaries { display: grid; gap: var(--space-7); margin: var(--space-7) 0 0; }
@media (min-width: 1080px) { .record-summaries { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; } }
.record-summary { margin: var(--space-7) 0 0; min-width: 0; }
.record-summaries .record-summary { margin: 0; }
.record-summary__title { font-size: var(--text-4); margin: 0 0 var(--space-3); }
.record-summary__more { margin: var(--space-3) 0 0; }
.record-summary__more a { font-weight: 600; }
.record-summary__empty { color: var(--text-muted); margin: 0; }
.record-summary__facts { display: grid; gap: var(--space-2); margin: 0; }
.record-summary__facts div { display: flex; justify-content: space-between; gap: var(--space-4); }
.record-summary__facts dt { color: var(--text-muted); }
.record-summary__facts dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.record-summary__list { list-style: none; margin: 0; padding: 0; }
.record-summary__list li { padding: var(--space-1) 0; overflow-wrap: anywhere; }
.record-summary__list .meta { font-size: var(--text-1); color: var(--text-muted); margin-inline-start: var(--space-1); }
/* Explanations on demand (declutter, 2026-10-23): "About this", "Record maintenance", attributes. */
.record-disclosure { margin: var(--space-5) 0; }
.record-disclosure > summary { cursor: pointer; color: var(--link); font-weight: 600; min-height: 1.5rem; }
.record-disclosure > p { max-width: 72ch; margin: var(--space-3) 0 0; }
.record-map { margin: var(--space-7) 0 0; }
/* A tab whose list is narrow keeps its notes or its map beside it from 1080px, so no half screen is empty. */
.record-split { display: grid; gap: var(--space-6) var(--space-8); }
.record-split > * { min-width: 0; }
.record-split .record-map, .record-split__aside > .record-disclosure:first-child { margin-top: 0; }
.timeline__note { margin: 0; font-size: var(--text-1); color: var(--text-muted); }
.timeline__note + .record-disclosure { margin-top: var(--space-2); }
@media (min-width: 1080px) { .record-split { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); align-items: start; } }
.record-attributes { margin-top: var(--space-7); }
.record-absent { margin: var(--space-6) 0; font-size: var(--text-3); }
.record-foot { margin-top: var(--space-8); }
.record-credits { max-width: 80ch; }
.record-foot__report { margin: var(--space-3) 0 0; font-size: var(--text-1); }
.record-page .timeline__mark { margin-inline-end: var(--space-1); font-weight: 600; color: var(--family-progress-text); }
.record-basis { list-style: none; margin: var(--space-3) 0 0; padding: 0; max-width: 80ch; }
.record-basis li + li { margin-top: var(--space-1); }
.record-basis__source { font-size: var(--text-1); color: var(--text-muted); margin-inline-start: var(--space-1); }
/* Shared idioms as they read on a record page, under the skill's bans: sentence-case badges, dates in the
   text face with tabular figures, and the Sources panel without the rules above and below it. */
.record-page .reuse-badge, .record-page .provenance-panel__licence { text-transform: none; letter-spacing: 0; }
.record-page .timeline time { font-family: var(--font-body); font-variant-numeric: tabular-nums; }
.record-page .provenance-panel { border-block: 0; padding-top: 0; margin-top: 0; }
.record-page .provenance-panel__name::before { font-family: var(--font-body); }
.record-page .maplibregl-map, .record-page .maplibregl-ctrl { font-family: var(--font-body); }
.record-page .report-problem .field label {
  font-family: var(--font-body); font-size: var(--text-2); text-transform: none; letter-spacing: 0;
}
@media (max-width: 719px) {
  .record-header { grid-template-columns: minmax(0, 1fr); }
  .record-header .detail-header h1 { font-size: var(--text-4); }
  .record-header__action { grid-column: 1; grid-row: auto; margin-top: var(--space-4); }
  .record-action { display: flex; width: 100%; min-height: 2.75rem; }
  .record-tabs { margin: var(--space-4) calc(-1 * var(--space-4)) var(--space-4); padding: 0 var(--space-4); }
  .record-summaries, .record-summary { margin-top: var(--space-6); }
}
/* ---------- end 9.1 Record pages as URL tabs ---------- */

/* ---------- 9.2 The company page as tabs (2026-10-24, lane company-tabs; docs/30 §11.5; web/org_tabs.py) ----------
   One header (name, type, place, one line of facts, the one action, the ownership scope), then one group per
   tab -- Projects, Assets, Ownership, Nearby, RFPs, Sources -- never lists stacked or side by side (owner,
   2026-10-24; docs/31-design-practices.md §2.2). Each tab opens with an analytics strip (one container split
   by hairlines: figures as type, then one-series column charts) and holds one table whose headings sort it.
   App-screen rules of the taste skill (references/app-screens.md): underline tabs on a full-width 1px rule, a
   2px mark under the open one; 12px grey sentence-case table headings with no band; colour only on the
   charts' columns (`--chart-1`, the chart-only token of docs/31-brand-identity.md §4, validated by the dataviz
   skill on both surfaces), the status chips and the one primary action.
   Grid at 1440: the canvas is the page's 1408px; the strip's figures take their own width (min 9rem) and the
   charts share what is left, so two charts land on the canvas's right edge. Below 720px the figures go two to
   a row and each chart takes the full width; the tab bar scrolls sideways inside itself. */
.org-page { --org-chart: var(--chart-1, #107656); --org-tab-gap: var(--space-6); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .org-page { --org-chart: var(--chart-1, #34ad7e); } }
:root[data-theme="dark"] .org-page { --org-chart: var(--chart-1, #34ad7e); }

/* The header: the facts line wraps as one row of label and value pairs; the scope is a quiet row of links. */
.org-header { padding-bottom: var(--space-2); }
.org-header .org-facts { margin: var(--space-3) 0 0; }
.org-header .org-facts__label { margin-inline-end: var(--space-1); }
.org-header .ownership-claim { display: inline; margin: 0 0 0 var(--space-1); }
.org-header #org-fact-parent > .ownership-claim:first-child { margin-left: 0; }
.org-header .mono { font-family: var(--font-mono); font-size: var(--text-1); }
.org-scope { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-4); margin: var(--space-3) 0 0; font-size: var(--text-1); }
.org-scope__label { color: var(--text-muted); }
.org-scope__item { display: inline-flex; align-items: center; min-height: 1.5rem; }
.org-scope__item[aria-current] { font-weight: 600; color: var(--text); }

/* The tab bar: plain words, the open one in ink at 600 with a 2px mark; counts in grey tabular figures. */
.org-tabs {
  display: flex; gap: var(--org-tab-gap); margin: var(--space-5) 0 0; padding: 0; border-bottom: 1px solid var(--border);
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none; scroll-snap-type: x proximity;
}
.org-tabs::-webkit-scrollbar { display: none; }
.org-tabs__tab {
  flex: none; display: inline-flex; align-items: center; gap: var(--space-2); min-height: 2.75rem; margin-bottom: -1px;
  color: var(--text-muted); text-decoration: none; white-space: nowrap; scroll-snap-align: start;
  border-bottom: 2px solid transparent;
}
.org-tabs__tab:visited { color: var(--text-muted); }
.org-tabs__tab:hover { color: var(--text); border-bottom-color: var(--border); }
.org-tabs__tab:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
/* The open tab: `aria-current` on the server's links, `aria-selected` once org_tabs.js makes them ARIA tabs. */
.org-tabs__tab[aria-current="page"],
.org-tabs__tab[aria-selected="true"] { color: var(--text); font-weight: 600; border-bottom-color: var(--select); }
.org-tabs__n { font-weight: 400; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* A panel: the strip, then its note lines, then the table. */
.org-panel { padding-top: var(--space-4); }
.org-panel[hidden] { display: none; }
/* A tab panel is in the Tab order (WAI-ARIA tabs: its first content is not focusable). */
.org-panel:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.org-panel__title { font-size: var(--text-4); margin: var(--space-6) 0 0; }
.org-panel__n { font-size: var(--text-3); font-weight: 400; color: var(--text-muted); }
.org-panel__note { margin: 0 0 var(--space-3); font-size: var(--text-1); color: var(--text-muted); max-width: 80ch; }
.org-panel__more { margin: var(--space-3) 0 0; font-size: var(--text-1); color: var(--text-muted); }
.org-panel__credits { margin-top: var(--space-6); max-width: 80ch; }
.org-panel__map { margin: 0 0 var(--space-4); }
.org-panel__map .mini-map { height: 15rem; min-height: 12rem; }
.org-panel__filters { align-items: center; margin-bottom: var(--space-3); }
.org-panel__why { flex-basis: 100%; }
.org-panel__why > summary { cursor: pointer; width: fit-content; min-height: 1.5rem; color: var(--link); font-size: var(--text-1); }
.org-panel__why > p { margin: var(--space-2) 0 0; }
.org-panel .provenance-panel { margin-top: 0; }

/* The analytics strip: one container split by 1px hairlines; a figure is a 12px grey label over the value
   (24px, regular, its unit a smaller grey suffix) and one grey line; charts share the rest of the row. */
.org-strip {
  display: flex; flex-wrap: wrap; align-items: stretch; gap: var(--space-3) 0; margin: 0 0 var(--space-4);
  padding: 0 0 var(--space-4); border-bottom: 1px solid var(--border);
}
.org-strip__tile { flex: 0 0 auto; min-width: 9rem; max-width: 18rem; padding: 0 var(--space-5); border-left: 1px solid var(--rule); margin: 0; }
.org-strip > .org-strip__tile:first-child { padding-left: 0; border-left: 0; }
.org-strip__k { margin: 0; font-size: var(--text-1); line-height: 1.25; color: var(--text-muted); }
.org-strip__v { margin: var(--space-1) 0 0; font-size: var(--text-4); line-height: 1.25; font-weight: 400; color: var(--text); white-space: nowrap; }
.org-strip__v a { color: inherit; text-decoration: underline dotted var(--border); text-underline-offset: 0.2em; }
.org-strip__v a:hover, .org-strip__v a:focus-visible { color: var(--link); text-decoration-style: solid; }
.org-strip__u { font-size: var(--text-1); color: var(--text-muted); }
.org-strip__s { margin: var(--space-1) 0 0; font-size: var(--text-1); line-height: 1.25; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A breakdown in words ("5 Open licence", "1 Open, credit required"): the figures in ink in a column of
   their own, right-aligned, and the words grey beside them, wrapping inside the figure's box. */
.org-strip__list {
  display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--space-2);
  margin: var(--space-1) 0 0; padding: 0; list-style: none; font-size: var(--text-2); line-height: 1.35;
}
.org-strip__list li { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; overflow-wrap: anywhere; }
.org-strip__w { color: var(--text-muted); }
.org-strip__f { color: var(--text); font-variant-numeric: tabular-nums; text-align: right; }

/* A chart: one series, a column per group in an equal slot; the column (20px, a 4px rounded data end) is the
   only coloured mark; its value sits on the cap in the text colour and its name under the baseline, which is
   the labels' shared top rule. A column with a list behind it is a link with a 24px+ target. */
.org-strip__charts { display: contents; }
/* Charts share a row: each grows from 12rem to its own columns' width and no further, so two short charts sit
   together and a long one narrows its columns rather than dropping to a line of its own. */
.org-chart { flex: 1 1 0; min-width: 12rem; max-width: max-content; }
.org-chart__cols { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 7.5rem); margin: var(--space-1) 0 0; padding: 0; list-style: none; }
.org-chart__col { min-width: 0; }
/* `position: relative` holds each column's words for screen readers (`.visually-hidden`, absolutely placed) in
   its column, so the row's sideways scroll clips them below 720px rather than widening the page. */
.org-chart__hit { position: relative; display: flex; flex-direction: column; align-items: stretch; min-height: 1.5rem; color: inherit; text-decoration: none; border-radius: var(--radius-1); }
a.org-chart__hit:hover .org-chart__l, a.org-chart__hit:focus-visible .org-chart__l { color: var(--link); text-decoration: underline; }
a.org-chart__hit:hover .org-chart__bar { opacity: 0.82; }
.org-chart__hit:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.org-chart__svg { display: block; width: 100%; height: 3.5rem; overflow: visible; }
.org-chart__bar { fill: var(--org-chart); }
.org-chart__v { font-family: var(--font-body); font-size: 12px; fill: var(--text); font-variant-numeric: tabular-nums; }
/* A name runs to two lines at most; the column's link title and its words for screen readers hold it whole. */
.org-chart__l {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  padding: var(--space-1) 2px 0; border-top: 1px solid var(--border); font-size: var(--text-1); line-height: 1.25;
  color: var(--text-muted); text-align: center; overflow-wrap: anywhere;
}

/* The tables: the record lists' own (`.record-table--compact`, two-line rows below 720px), set as the map's
   table is (lane ruler-lists v4): 12px grey headings at 400 with no band, the name in ink at 500, the other
   cells grey, figures right-aligned in tabular digits. */
.org-table th { font-weight: 400; background: var(--bg); }
.org-table th.is-sorted { font-weight: 600; }
.org-table td { padding-block: var(--space-2); border-bottom-color: var(--rule); vertical-align: baseline; }
.org-table td.cell-meta { color: var(--text-muted); }
.org-table td.cell-meta a { color: var(--text-muted); }
.org-table td.cell-meta a:hover, .org-table td.cell-meta a:focus-visible { color: var(--link); }
.org-table a.row-link { font-weight: 500; }
.org-table td.num { white-space: nowrap; }
/* Where the table has room, a figure, a date or a short field stays on one line and the name takes the rest. */
@media (min-width: 1080px) { .org-table td.cell-meta { white-space: nowrap; } }
.org-table .cell-sub { font-weight: 400; }
/* A table of four or five columns stops at about 60rem rather than spreading its figures across the canvas. */
.org-table--narrow { max-width: 60rem; }

@media (max-width: 719px) {
  .org-page { --org-tab-gap: var(--space-3); } /* four record kinds fit a 390px phone without a cut tab */
  /* The bar scrolls inside the page's gutter, so a tab it cuts off is cut 16px from the screen's edge, not at it
     (taste inspect `edge-text`: "Nearby" 1px from the right at 390 when the bar ran to the screen's edges). */
  .org-tabs { scroll-padding-inline: var(--space-2); }
  .org-strip { row-gap: var(--space-3); }
  .org-strip__tile { flex: 1 1 calc(50% - var(--space-5)); max-width: none; min-width: 0; padding: 0; border-left: 0; }
  .org-strip__tile:nth-child(even):not(.org-chart) { padding-left: var(--space-4); border-left: 1px solid var(--rule); }
  /* The charts are one row that scrolls sideways inside itself, the next chart's edge showing, so the
     table's first rows stay near the first screen; one chart takes the width. Snapping is `proximity`:
     `mandatory` pinned a lone chart wider than the screen to its start, so neither a finger nor the arrow
     keys could reach its last columns (review of lane company-tabs, 2026-10-24). */
  .org-strip__charts {
    position: relative; display: flex; flex-basis: 100%; gap: var(--space-4); overflow-x: auto; scrollbar-width: none;
    scroll-snap-type: x proximity; padding-top: var(--space-2); border-top: 1px solid var(--rule);
  }
  .org-strip__charts::-webkit-scrollbar { display: none; }
  /* A row with no link in it is itself in the Tab order, so the arrow keys scroll it. */
  .org-strip__charts:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
  /* A chart is as wide as its columns, and at least most of the row, so its box (and its snap area) holds
     every column. */
  .org-chart.org-strip__tile { flex: 0 0 auto; width: max-content; min-width: 86%; max-width: none; padding: 0; border: 0; scroll-snap-align: start; }
  /* A column keeps room for a one-word name ("Announced", 13px) rather than breaking it; a chart of many
     columns grows past the screen and the row scrolls. */
  .org-chart__cols { grid-auto-columns: minmax(4.5rem, 5.5rem); }
  .org-chart.org-strip__tile:only-child { min-width: 100%; }
  .org-chart__svg { height: 3rem; }
  .org-scope { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; white-space: nowrap; }
  .org-scope::-webkit-scrollbar { display: none; }
  .org-strip__v { font-size: var(--text-3); }
}
@media (prefers-reduced-motion: reduce) { .org-tabs { scroll-behavior: auto; } }
/* ---------- end 9.2 The company page as tabs ---------- */

/* ---------- 10. About page ---------- */
.source-table td, .source-table th { vertical-align: top; }
.reuse-badge { font-family: var(--font-body); font-size: var(--text-label); font-weight: 500; color: var(--text-muted); }

/* ---------- 11. Auth forms (Sprint 3 "login and registration surface") ----------
   Bordered inputs and a filled primary button, unlike the filter bar's underline-only strip
   (§6) -- a credential form reads as a form, not a toolbar. Tokens only, no new colours. */
.auth-form {
  display: flex; flex-direction: column; gap: var(--space-5);
  max-width: 26rem; margin: var(--space-6) 0;
}
.field { display: flex; flex-direction: column; gap: var(--space-1); }
.field label {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
  color: var(--text-muted);
}
.field input {
  font: inherit; font-size: var(--text-2); padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius-2); background: var(--surface);
  color: var(--text); min-height: 2.5rem;
}
.field input:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.field-hint { font-size: var(--text-1); color: var(--text-muted); margin: 0; }
/* SC 3.3.1: the error is carried by this text node, not by the input's border colour alone. */
.field__error { font-size: var(--text-1); color: var(--text); font-weight: 600; margin: 0; }
.form-actions { display: flex; gap: var(--space-3); }
.form-actions button {
  font: inherit; font-size: var(--text-2); padding: var(--space-2) var(--space-5);
  border-radius: var(--radius-2); border: 1px solid var(--link); background: var(--link);
  color: var(--surface); cursor: pointer; min-height: 2.5rem;
}
.form-actions button:hover { background: var(--link-visited); border-color: var(--link-visited); }
.notice {
  border: 1px solid var(--border); border-radius: var(--radius-2); padding: var(--space-3) var(--space-4);
  margin: var(--space-4) 0; font-size: var(--text-2);
}
/* Still identified by the text itself (role="alert"/"status" plus the message), not colour alone
   -- the border tint is a reinforcing cue for sighted users only (SC 3.3.1, SC 1.4.1). */
.notice--error { border-color: var(--family-danger-text); }
@media (max-width: 719px) {
  .auth-form { max-width: 100%; }
}

/* ---------- 12. Pricing page (`web/pricing.py`, docs/41) ----------
   Four ruled panels, not a card grid: the same hairline-and-rule idiom the record tables use
   (docs/31 §1.6, D-24), so the page reads as part of the register rather than as a marketing
   insert. Tokens only -- every colour below is already defined for both themes in §1, so the
   page inverts with the rest of the site and needs no dark-mode rules of its own. The grid
   collapses to one column below 720px and the panels have no fixed width, so the page holds at
   400px with no horizontal scroll (docs/31 §4). */
.coverage-line { font-size: var(--text-2); color: var(--text-muted); max-width: 68ch; }
.tier-list {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5);
  margin: var(--space-5) 0 var(--space-6); border-top: 1px solid var(--border); padding-top: var(--space-5);
}
.tier {
  display: flex; flex-direction: column; gap: var(--space-2);
  border: 1px solid var(--border); border-radius: var(--radius-2);
  padding: var(--space-4) var(--space-4) var(--space-5); background: var(--surface);
}
/* The tier the visitor picked before signing in (`/pricing?plan=pro`). The heavier border is the
   visible echo of the "This is the plan you picked" line, never the only signal (SC 1.4.1). */
.tier--selected { border-width: 2px; border-color: var(--link); }
/* docs/26 §3 precondition (i): visible but not on offer while the platform posture is
   `noncommercial`. A dashed border on the page ground, no new token, and never the sole signal --
   the "not currently offered" field-hint text in the CTA carries the fact. It was `opacity: 0.7`
   until 2026-09-30, which took the muted text under 4.5:1 (axe color-contrast, lane A1). */
.tier--inactive { border-style: dashed; background: transparent; }
.tier h2 { font-size: var(--text-4); margin: 0; }
.tier__price { font-size: var(--text-5); margin: 0; line-height: 1.1; }
.tier__period { display: block; font-size: var(--text-1); color: var(--text-muted); font-weight: 400; }
.tier__provisional { font-size: var(--text-1); color: var(--text); font-weight: 600; margin: 0; }
.tier__summary { margin: 0; color: var(--text-muted); }
.tier__includes { list-style: none; margin: var(--space-2) 0 0; padding: 0; border-top: 1px solid var(--border); }
.tier__includes li { padding: var(--space-2) 0; border-bottom: 1px solid var(--border); font-size: var(--text-2); }
.tier__selected-note { font-size: var(--text-1); font-weight: 600; margin: 0; }
/* Pushed to the bottom so the four panels' controls line up whatever the list lengths are. */
.tier__cta { margin-top: auto; padding-top: var(--space-4); }
.tier__cta .form-actions button { width: 100%; }
.tier__button {
  display: inline-block; width: 100%; box-sizing: border-box; text-align: center;
  font-size: var(--text-2); padding: var(--space-2) var(--space-4); min-height: 2.5rem;
  border: 1px solid var(--link); border-radius: var(--radius-2); background: var(--link);
  color: var(--surface); text-decoration: none; font-weight: 600;
}
.tier__button:visited { color: var(--surface); }
.tier__button:hover { background: var(--link-visited); border-color: var(--link-visited); }
.tier__button:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.tier__cta .field-hint { margin-top: var(--space-2); }
.inline-form { margin: var(--space-3) 0 0; }
.notice__title { font-weight: 600; margin: 0 0 var(--space-1); }
.notice__ref { font-size: var(--text-1); color: var(--text-muted); margin: var(--space-1) 0 0; }
.pricing-notes { border-top: 1px solid var(--border); padding-top: var(--space-4); max-width: 72ch; }
.pricing-notes ul { padding-left: var(--space-4); }
.pricing-notes li { padding: var(--space-1) 0; font-size: var(--text-2); color: var(--text-muted); }
@media (max-width: 719px) {
  .tier-list { grid-template-columns: 1fr; gap: var(--space-4); }
}

/* ---------- 13. Alerts (`web/alerts.py`, owner decision 2026-09-30; docs/31 §5.10) ----------
   The saved-search card is a list item in one column, never a tile grid (D-1): a hairline-ruled
   panel like the pricing tiers, tokens only, so it inverts with the rest of the site. State is
   carried by the status chip's words and icon and by the action's own label ("Resume", not a
   colour), never by colour alone (SC 1.4.1). Buttons are at least 2.25rem tall (SC 2.5.8). */
.save-alert { margin: 0 0 var(--space-3); font-size: var(--text-2); }
/* SC 2.5.8: at least 24px tall. Set in Geist the link's box is 21px, and at 390px on /proposals its
   neighbours sat close enough that axe flagged it (brand lane, 2026-10-23). */
.save-alert > a { display: inline-flex; align-items: center; min-height: 1.5rem; }
.save-alert__hint { color: var(--text-muted); font-size: var(--text-1); }
.alert-plan { max-width: 72ch; color: var(--text); }
.alert-toolbar {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); align-items: baseline;
  border-bottom: 1px solid var(--border); padding-bottom: var(--space-3); margin-bottom: var(--space-4);
}
.alert-toolbar p { margin: 0; }
.alert-quota { font-weight: 600; }
.alert-list { list-style: none; margin: 0 0 var(--space-6); padding: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.alert-card {
  border: 1px solid var(--border); border-radius: var(--radius-2); background: var(--surface);
  padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); min-width: 0;
}
.alert-card__head { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); align-items: baseline; }
.alert-card__name { font-size: var(--text-4); margin: 0; overflow-wrap: anywhere; }
.alert-card__meta { margin: 0; color: var(--text-muted); font-size: var(--text-1); }
.alert-card__filters {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); gap: var(--space-2) var(--space-4);
  margin: var(--space-2) 0; padding: 0;
}
.alert-card__filters dt {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
  color: var(--text-muted);
}
.alert-card__filters dd { margin: 0; overflow-wrap: anywhere; }
.alert-card__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; margin-top: var(--space-2); }
.alert-card__actions form { margin: 0; }
.alert-section-heading { font-size: var(--text-4); margin: var(--space-5) 0 var(--space-2); }
.button-secondary {
  font: inherit; font-size: var(--text-2); padding: var(--space-1) var(--space-4); min-height: 2.25rem;
  border-radius: var(--radius-2); border: 0; background: var(--secondary); color: var(--secondary-ink);
  cursor: pointer;
}
.button-secondary:hover { background: var(--border); }
.button-secondary:focus-visible, .button-link:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.button-secondary--danger { background: var(--family-danger-fill); color: var(--family-danger-text); }
.button-secondary--danger:hover { background: var(--family-danger-text); color: var(--surface); }
.button-link {
  display: inline-flex; align-items: center; min-height: 2.5rem; padding: var(--space-2) var(--space-5);
  border-radius: var(--radius-2); border: 0; background: var(--primary); color: var(--primary-ink);
  text-decoration: none; font-weight: 600;
}
.button-link:visited { color: var(--primary-ink); }
.button-link--secondary, .button-link--secondary:visited { background: var(--secondary); color: var(--secondary-ink); }
.field--choices { border: none; margin: 0; padding: 0; gap: var(--space-2); }
.field--choices legend {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
  color: var(--text-muted); padding: 0; margin-bottom: var(--space-1);
}
.field--choices label {
  display: flex; align-items: center; gap: var(--space-2); min-height: 2rem;
  font-family: var(--font-body); font-size: var(--text-2); text-transform: none; letter-spacing: normal; color: var(--text);
}
.field--choices input[type="radio"] { width: 1.15rem; height: 1.15rem; }
.field input[type="text"] { width: 100%; }
/* ---------- Retired and retiring plants (lane R1) ---------- */
.row-status { color: var(--text-muted); font-size: 0.875em; }
.retirement__subhead { font-size: 1rem; margin: var(--space-5, 1.5rem) 0 var(--space-2, 0.5rem); }
.retirement__list-intro { margin: var(--space-3, 0.75rem) 0 var(--space-1, 0.25rem); }
.retirement__note { border-left: 3px solid var(--asset-retiring); padding-left: var(--space-3, 0.75rem); max-width: 72ch; }
.retirement .record-table caption { text-align: left; font-weight: 600; padding-bottom: var(--space-1, 0.25rem); }


/* ---------- 2026-10-06 UX lane (audit 2026-09-30) ---------- */
/* Loader caveats under an asset's Attributes table (web/labels.py `data_notes`). */
.attribute-notes { margin-top: var(--space-3); font-size: var(--text-1); color: var(--text-muted); }
.attribute-notes summary { cursor: pointer; color: var(--text); }
.attribute-notes ul { margin: var(--space-2) 0 0; padding-inline-start: var(--space-5); }
.attribute-notes li { padding: var(--space-1) 0; max-width: 80ch; }
/* The map drawer's licence class beside its source (D-13) and the licence's own credit line. */
.drawer-source__licence { color: var(--text); }
.drawer-source__credit { display: inline-block; margin-top: var(--space-1); }
/* "Report a problem" (designer D-6): a disclosure with a short form, docs/31 §6 states. */
.report-problem { margin: var(--space-6) 0 var(--space-4); border-top: 1px solid var(--border); padding-top: var(--space-4); }
.report-problem > summary { cursor: pointer; font-weight: 600; color: var(--link); }
.report-problem form { display: grid; gap: var(--space-3); max-width: 40rem; margin-top: var(--space-3); }
.report-problem fieldset { border: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.report-problem legend { font-weight: 600; margin-bottom: var(--space-1); padding: 0; }
.report-problem label { display: flex; gap: var(--space-2); align-items: flex-start; }
.report-problem .field { display: grid; gap: var(--space-1); }
.report-problem .field label { display: block; font-weight: 600; }
.report-problem textarea, .report-problem input[type="email"] {
  font: inherit; color: var(--text); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-2); padding: var(--space-2); width: 100%; box-sizing: border-box;
}
.report-problem textarea { min-height: 7rem; }
.report-problem .field-hint { font-size: var(--text-1); color: var(--text-muted); margin: 0; }
.report-problem .form-error { color: var(--family-danger-text); font-weight: 600; margin: 0; }
.report-problem button[type="submit"] {
  /* Primary button (docs/31 §5.16), as `.form-actions button`. */
  font: inherit; justify-self: start; min-height: 2.5rem; padding: 0 var(--space-4); cursor: pointer;
  border: 1px solid var(--link); border-radius: var(--radius-2); background: var(--link); color: var(--surface);
}
.report-problem__trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.report-problem__status { margin: var(--space-3) 0 0; }

/* ---------- 2026-10-07 layout lane (audit 2026-09-30: D-3, D-4, D-8, D-11, F6, F7) ---------- */

/* Filter bars below 720px: a "Filters" disclosure (`.filter-toggle`). Every collapsed rule is keyed on
   `.js` (set in base.html before first paint), so without scripts the bars stay open. The header's
   "Menu" (`.nav-toggle`) is in the "Navigation v2 shell" section further down. */
.filter-toggle, .filter-bar__done { display: none; }
.nav-toggle, .filter-toggle, .filter-bar__done, .show-more-btn, .map-error__retry {
  font: inherit; font-size: var(--text-2); min-height: 2.5rem; padding: 0 var(--space-4);
  border: 1px solid var(--border); border-radius: var(--radius-2);
  background: var(--surface); color: var(--text); cursor: pointer;
}
.nav-toggle[aria-expanded="true"], .filter-toggle[aria-expanded="true"] { border-color: var(--text); font-weight: 600; }
.filter-toggle__count { font-variant-numeric: tabular-nums; margin-inline-start: 0.25em; }
@media (max-width: 719px) {
  /* Filter bars (docs/31 §5.9 "at-400px collapses to a single Filters button"): a disclosure that
     opens in place, so nothing is covered and focus never lands behind an overlay. */
  .js .filter-toggle { display: inline-flex; align-items: center; margin: 0 0 var(--space-3); }
  .js .filter-bar[data-collapse]:not(.is-open) { display: none; }
  .js .filter-bar[data-collapse].is-open .filter-bar__done { display: block; width: 100%; }
}

/* Section tabs (docs/16 §3.2): plain links in a row, the GitHub repository idiom. The current tab
   carries `aria-current="page"`, echoed by weight and a 2px rule in the text colour; the row's
   bottom rule is the page header's own, so a tabbed header draws no second one. */
.section-tabs ul {
  display: flex; flex-wrap: wrap; gap: 0 var(--space-5);
  list-style: none; margin: 0; padding: 0; border-bottom: 1px solid var(--border);
}
.section-tabs a {
  display: inline-block; padding: var(--space-2) 0; margin-bottom: -1px;
  border-bottom: 2px solid transparent; color: var(--text); text-decoration: none; font-size: var(--text-2);
}
.section-tabs a:hover, .section-tabs a:focus-visible { color: var(--link); border-bottom-color: currentColor; }
.section-tabs a[aria-current] { font-weight: 600; border-bottom-color: var(--text); }
.section-tabs a[aria-current]:hover { color: var(--text); }
.page-header--tabbed { padding-bottom: 0; border-bottom: 0; }
/* List pages (U-17): the H1 at the map page's size, a one-line standfirst and tighter spacing down
   to the table, so the first row starts higher at 1440px (before: 488-689px). Scoped to the five
   lists (`.list-page` on <main>, set in base.html), so no other page's header changes. */
.list-page .page-header { padding: var(--space-3) 0; margin-bottom: 0; }
.list-page .page-header h1 { font-size: var(--text-5); margin: 0 0 var(--space-1); }
.list-page .page-header p { margin: 0; max-width: none; }
.list-page .page-header p + p { margin-top: var(--space-1); }
.list-page .page-header--tabbed { padding-bottom: 0; }
.list-page .page-header--tabbed h1 { margin-bottom: var(--space-2); }
.list-lede { color: var(--text-muted); margin: var(--space-3) 0 var(--space-2); }
.list-page .delayed-notice { margin: var(--space-2) 0; padding-block: var(--space-1); }
.list-page .filter-bar { padding: var(--space-1) 0; margin-bottom: var(--space-2); }
/* The lines between the filters and the table (status notice, count, alert and feed links) keep
   their order and words; only the space between them closes up. The unlisted line still reads as
   the status notice's continuation. */
.list-page .view-notice { padding: 0; margin: 0 0 var(--space-2); }
.list-page .view-notice + .view-notice--unlisted { margin-top: calc(-1 * var(--space-1)); }
.list-page .result-count, .list-page .results-bar .result-count, .list-page .save-alert, .list-page .feed-link { margin-bottom: var(--space-2); }
/* `/assets`: the nine type chips fit one row at 1440px (docs/31 §5.14's tokens; 8px sides, not 12). */
.list-page .count-chips ul { margin-bottom: var(--space-2); }
.list-page .count-chips a { padding-inline: var(--space-2); }
.list-page .count-chips + .attribution-line { margin: 0 0 var(--space-2); }
/* Column heads on one line where the table is a table (at 400px rows are cards with their own
   labels): "Capacity (MW)" broke over two lines and made the head row 55px. */
@media (min-width: 720px) { .list-page .record-table th { white-space: nowrap; } }

/* The map page opens on the map (D-3, F6): one line saying what a dot is and what to do, the tier
   stamp, a one-row filter bar, one status row, then the map. No hero, no illustration (D-7). */
.map-intro { padding: var(--space-4) 0 0; }
.map-intro__title { font-size: var(--text-5); margin: 0 0 var(--space-1); }
.map-intro__lede { margin: 0; max-width: none; }
.map-intro__lede strong { font-weight: 600; }
/* The opening figures (web/headline.py): one line of live counts, each a link to its list. On a phone
   they stay on one line and scroll sideways rather than push the map down. */
.map-figures { display: flex; flex-wrap: wrap; gap: 0 var(--space-5); list-style: none; margin: var(--space-2) 0 0; padding: 0; }
.map-figures a { display: inline-flex; align-items: baseline; gap: 0.3em; min-height: 1.5rem; text-decoration: none; color: inherit; }
.map-figures a:hover span, .map-figures a:focus-visible span { text-decoration: underline; }
.map-figures strong { font-size: var(--text-3); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--link); }
.map-intro + .delayed-notice { margin: var(--space-3) 0; }
.filter-bar--map { gap: var(--space-3) var(--space-4); padding: var(--space-2) 0; margin-bottom: var(--space-2); }
/* Layers and placement change what else is drawn, not which proposals match: a second, closed
   row, opened by its summary (and open on arrival when the link turns a layer on). */
.filter-more { align-self: end; }
.filter-more > summary {
  cursor: pointer; min-height: 2.25rem; display: flex; align-items: center;
  color: var(--link); font-size: var(--text-2);
}
.filter-more[open] { flex-basis: 100%; }
.filter-more__body { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-5); align-items: end; padding-top: var(--space-2); }
.map-status {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-4);
  margin: 0 0 var(--space-2);
}
.map-status .result-count { margin: 0; }
/* The count's second sentence, how many matches no map can place (map.js `renderCountLine`), on a
   line of its own under "N projects match these filters." (not drawn below 720px, 8.3). */
.map-status__unplaced { display: block; }
/* "Open these in the list · Save this search as an alert" (owner, 2026-10-22: the view switch left
   the map; the alert page offers the same search as an RSS feed). */
.map-status__actions {
  margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--space-1); font-size: var(--text-1);
}
.map-status__actions a { display: inline-flex; align-items: center; min-height: 1.5rem; font-weight: 600; white-space: nowrap; }
.map-status__save { font-size: var(--text-1); }
.map-status #map-notice { flex: 1 1 28rem; }
.map-status .view-notice { padding: 0; margin: 0; }
.map-empty { margin-top: var(--space-2); font-size: var(--text-1); }
/* Zoom buttons, region jumps and the search field sit on the map, top left, as map controls do, so
   nothing stands between the filters and the canvas; from 720px they wrap short of the panel. */
.map-frame { position: relative; }
.map-overlay {
  position: absolute; top: var(--space-2); left: var(--space-2); right: var(--space-2); z-index: 2;
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-2); pointer-events: none;
}
@media (min-width: 720px) {
  .map-overlay { right: calc(var(--map-panel-width) + 2 * var(--map-panel-inset)); }
  /* The key is a tab of the panel: the rail's "Key" is a phone's (8.3). */
  .map-overlay .map-controls--key { display: none; }
  /* Beside "Key", the collapsed count wraps to two lines ("4,139 projects in view · 742.7 GW" in
     196px); both are kept from first paint ("Loading projects…"), so the header does not grow when
     the data lands and the national view, fitted under it, stays clear of it. */
  .map-panel.is-collapsed .map-panel__count { display: flex; align-items: center; min-height: 3em; }
}
/* The search field (owner, 2026-10-22): on the map, top left, from 720px, in the controls' row (the
   phone layout is in 8.3). The box is the map controls' height with the site's input outline in
   --text-muted, 5.5:1 on --surface (SC 1.4.11). Its suggestions open under it over the map, and
   close on a pick, Escape or a tap elsewhere. */
.map-search { position: relative; flex: 0 1 20rem; min-width: 14rem; pointer-events: auto; }
.map-search__input {
  display: block; width: 100%; box-sizing: border-box; min-height: 2.25rem; margin: 0;
  padding: 0 2.25rem 0 2rem; font: inherit; font-size: var(--text-2); color: var(--text);
  background: var(--surface); border: 1px solid var(--text-muted); border-radius: var(--radius-2);
  -webkit-appearance: none; appearance: none;
}
.map-search__input::placeholder { color: var(--text-muted); opacity: 1; }
/* The browser's own clear mark would sit beside the one drawn here. */
.map-search__input::-webkit-search-cancel-button,
.map-search__input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }
.map-search__icon { position: absolute; left: 0.625rem; top: 0.625rem; color: var(--text-muted); pointer-events: none; }
.map-search__clear {
  position: absolute; top: 0; right: 0; width: 2.25rem; height: 2.25rem; padding: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: none; color: var(--text-muted); cursor: pointer;
}
.map-search__clear:hover { color: var(--text); }
.map-search__list, .map-search__empty {
  position: absolute; top: calc(100% + var(--space-1)); left: 0; z-index: 6;
  width: max(100%, 22rem); max-width: calc(100vw - 2 * var(--space-4)); box-sizing: border-box;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2);
  box-shadow: var(--shadow-float);
}
/* Clipped to itself and its shadow: headless Chromium painted a copy of a scrolling panel's
   background below it, as it did for the compact key the panel replaced. */
.map-search__list {
  max-height: min(60vh, 28rem); overflow-y: auto; padding: var(--space-1) 0;
  clip-path: inset(-24px -24px -32px -24px round var(--radius-2));
}
.map-search__empty { margin: 0; padding: var(--space-2) var(--space-3); font-size: var(--text-1); color: var(--text); }
/* One list, no group headings (lane stacked-lists, 2026-10-24): each row names its kind in words at its
   right end, in the same place on every row, so places, companies and projects never stack as lists. */
.map-search__option {
  display: flex; flex-direction: column; justify-content: center; gap: 2px; min-height: 2.75rem;
  padding: var(--space-1) var(--space-3); cursor: pointer;
}
.map-search__option + .map-search__option { border-top: 1px solid var(--rule); }
.map-search__option:hover { background: var(--bg); }
.map-search__option.is-active { background: var(--active); }
.map-search__top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); }
.map-search__label { color: var(--text); font-weight: 600; font-size: var(--text-2); min-width: 0; }
.map-search__kind {
  flex: none; font-family: var(--font-body); font-size: var(--text-label); font-weight: 500; color: var(--text-muted);
}
.map-search__detail { color: var(--text-muted); font-size: var(--text-1); }
.map-search__detail .chip { padding: 0 var(--space-1); margin-inline-end: var(--space-1); }
.map-overlay .map-controls { margin: 0; pointer-events: auto; }
/* The rail's "Key" (below 720px; docs/17 M-1): it opens the panel's Key tab under the map. */
.map-controls--key button { padding: 0 var(--space-3); font-size: var(--text-1); }
.map-controls--key button[aria-expanded="true"] { border-color: var(--text); font-weight: 600; }
.map-intro + .preview-banner { margin-top: var(--space-3); }
/* docs/31 §6 map error: the problem title and request id, a retry and the list as a way on. */
.map-error {
  flex-basis: 100%; border-inline-start: 3px solid var(--family-danger-text);
  padding: var(--space-2) var(--space-4); background: var(--surface); font-size: var(--text-2);
}
.map-error p { margin: 0; }
.map-error .mono { font-family: var(--font-mono); font-size: var(--text-1); }
/* The figures' error, in the sheet under the stages (map.js `showError`): one line on the surface, the
   danger rule at its start, never over the map. */
.ruler-sheet .map-error { margin: 0; padding: var(--space-2) var(--space-4); font-size: var(--text-1); }
.ruler-sheet .map-error[hidden] { display: none; }
/* In-view list paging (D-4): a page of rows per group, then "Show N more". */
.in-view-list__more { border-bottom: none; padding: var(--space-3) 0; }
.show-more-btn { font-size: var(--text-1); width: 100%; }
.in-view-list__empty { color: var(--text-muted); }
/* What is in view, and the key, keep their place in the map frame's flow below 720px (8.3). */
@media (max-width: 719px) {
  #map { height: 58vh; min-height: 18rem; }
  /* 19.2px: the map's ten-word title holds two lines from 360px in Geist, which sets wider than Newsreader
     did at 23px (three lines at 390; taste skill: a headline is two lines or fewer). */
  .map-intro__title { font-size: var(--text-3); }
  .map-status { gap: var(--space-1) var(--space-3); }
  .map-status #map-notice { flex-basis: 100%; }
}

/* ---------- 8.3 The map page below 720px (2026-10-22, lane m-layout; docs/17 M-1, M-4, M-6, M-11) ----------
   docs/31 §3, §5.8 and §5.17 as built. Measured at 390x844 in docs/31 §3. */
@media (max-width: 719px) {
  /* M-1 (b): one column of 44x44 buttons on the map's right edge (SC 2.5.8 asks 24; 44 is the
     phone target, docs/17 §3.2): zoom in, zoom out, "Jump to", "Key". Reset gives way to "Whole map"
     in "Jump to". The region row, three rows of buttons and the key covered 38% of the map. */
  .map-frame { display: flex; flex-direction: column; }
  .map-overlay { display: contents; }
  /* Owner, 2026-10-22: the search field is a full-width bar above the canvas, so it covers none of
     the map; the column starts under it, 8px into the canvas as before. Its box and clear button are
     44px tall, the phone target. Suggestions open under the bar, over the map, while typing. */
  .map-search { order: -1; flex: none; width: 100%; min-width: 0; margin: 0 0 var(--space-2); }
  .map-search__input { min-height: 2.75rem; padding-left: 2.25rem; padding-right: 2.75rem; }
  .map-search__icon { top: 0.875rem; left: 0.75rem; }
  .map-search__clear { width: 2.75rem; height: 2.75rem; }
  .map-search__list, .map-search__empty { width: 100%; max-width: none; }
  .map-search__list { max-height: 50vh; }
  .map-overlay .map-overlay__rail {
    position: absolute; top: calc(2.75rem + 2 * var(--space-2)); right: var(--space-2); z-index: 2;
    display: flex; flex-direction: column; gap: var(--space-2); pointer-events: none;
  }
  .map-overlay__rail .map-controls { flex-direction: column; flex-wrap: nowrap; gap: var(--space-2); }
  .map-overlay__rail > .map-controls > button {
    width: 2.75rem; height: 2.75rem; min-width: 0; padding: 0; font-size: var(--text-1); line-height: 1.1;
  }
  .map-overlay__rail > .map-controls--zoom > button { font-size: var(--text-3); }
  /* Owner, 2026-10-22 (docs/17 M-1 (c) kept): the panel does not float on a phone. It is a bar under
     the map frame ("N projects in view", with "Key" while closed) that opens in the page, as the
     filters and the menu open in place (docs/31 §3), so it covers nothing and needs no inner scroll.
     After the canvas (and its basemap note). Closed from first paint, before map.js runs. */
  .map-panel, .map-panel.is-collapsed {
    position: static; order: 1; width: auto; height: auto; margin-top: var(--space-2); overflow: visible;
    background: var(--surface); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: none;
  }
  .map-panel__scroll { overflow: visible; }
  .js .map-panel:not([data-ready]) .map-panel__body { display: none; }
  .js .map-panel:not([data-ready]) .map-panel__bar, .js .map-panel:not([data-ready]) .map-panel__families,
  .map-panel.is-collapsed .map-panel__bar, .map-panel.is-collapsed .map-panel__families { display: none; }
  .map-panel__toggle, .map-panel__keybtn { min-height: 2.75rem; }
  .map-panel__keybtn { min-width: 2.75rem; }
  .map-panel__tab { min-height: 2.75rem; }
  /* The count line keeps one row with "Active only. Why?" (M-6), so how many matches no map can
     place is said where "In view" opens instead (review 2026-10-22). */
  .map-status__unplaced { display: none; }
  .map-panel__unplaced:not([hidden]) {
    display: block; margin: var(--space-2) 0 0; font-size: var(--text-1); color: var(--text);
  }

  /* M-4: the drawer is a bottom sheet, at most 45% of the screen: the record's name, status,
     capacity, place, source line and "Open full record" (a proposal's Technology row waits for
     "Expand"). "Expand" takes it to the full height; the map eases the tapped feature into the
     part above it (map.js `revealAboveSheet`). Same dialog, focus and 200/150ms motion. */
  .map-drawer {
    top: auto; bottom: 0; left: 0; right: 0; width: auto; height: auto;
    max-height: 45vh; max-height: 45dvh;
    border-left: 0; border-top: 1px solid var(--border); border-radius: var(--radius-3) var(--radius-3) 0 0;
    padding: 0 var(--space-4) var(--space-4); transform: translateY(100%);
  }
  .map-drawer.is-open { transform: translateY(0); }
  .map-drawer.is-expanded { top: 0; max-height: none; border-radius: 0; }
  .map-drawer__bar {
    position: sticky; top: 0; z-index: 1; display: flex; justify-content: space-between; align-items: center;
    margin: 0 calc(-1 * var(--space-4)); padding: var(--space-1) var(--space-2); background: var(--surface);
  }
  .map-drawer__close, .map-drawer__expand {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 2.75rem; min-height: 2.75rem; padding: 0 var(--space-3);
  }
  /* Close stays at the right when "Expand" is not drawn (map.js `syncExpand`). */
  .map-drawer__close { margin-inline-start: auto; }
  .map-drawer__expand {
    font: inherit; font-size: var(--text-1); background: none; border: 0; color: var(--link); cursor: pointer;
  }
  .map-drawer h2 { font-size: var(--text-4); }
  .map-drawer:not(.is-expanded) .drawer-fields__row--more { display: none; }
  .map-drawer .drawer-fields { margin-top: var(--space-3); }
  /* The last field's rule is the source line's top edge here (two rules 12px apart before). */
  .map-drawer .drawer-fields + .drawer-source { border-top: 0; margin-top: 0; }
  .map-drawer .drawer-source__label { display: inline; margin: 0 var(--space-2) 0 0; }
  .map-drawer .drawer-open-link { margin-top: var(--space-3); }

  /* M-6: the map into the first screen. The lede is its first sentence ("About this map" opens the
     rest); the count and the notice's short form share a line ("Why?" opens the notice); "Open these
     in the list" and the save link share the next. Keyed on `.js`: without scripts all of it shows. */
  .map-intro { padding-top: var(--space-3); }
  .map-figures { flex-wrap: nowrap; overflow-x: auto; white-space: nowrap; scrollbar-width: none; gap: 0 var(--space-4); margin-top: var(--space-1); }
  .map-figures strong { font-size: var(--text-2); }
  .map-figures span { font-size: var(--text-1); }
  .js .map-intro__more { display: none; }
  .js .map-intro__lede.is-open .map-intro__more { display: inline; }
  .js .map-intro__stop { display: inline; }
  .js .map-intro__lede.is-open .map-intro__stop { display: none; }
  .js .map-intro__about, .js .map-notice__why {
    display: inline-flex; align-items: center; min-height: 1.5rem; padding: 0; border: 0; background: none;
    font: inherit; color: var(--link); text-decoration: underline; cursor: pointer;
  }
  .map-status { gap: var(--space-1) var(--space-3); }
  .map-status #map-notice { display: contents; }
  .js .map-notice__brief { display: block; margin: 0; font-size: var(--text-1); color: var(--text-muted); }
  /* A coverage note (this ISO's queue is not covered; its rows come from EIA-860M) is never behind
     "Why?" (docs/17 §6): it takes its own line under the count and the short form. */
  .map-notice__detail, .map-status .map-empty, .map-status .view-notice--gap { flex-basis: 100%; }
  .js #map-notice:not(.is-why-open) .map-notice__detail { display: none; }
  .map-status .view-notice:last-child { padding-bottom: 0; }
  .map-status__actions { flex: 1 1 100%; }

  /* M-11: the bar's disclosures are full-width rows, left-aligned, each with its marker (they sat
     at the right edge, `align-self: end`, and read as stray links); "Show the map" is at the top of
     the open bar as well as its foot. The map's bar only: the proposal list's Status disclosure is
     the list lane's. */
  .filter-bar--map .filter-more { align-self: stretch; }
  .filter-bar--map .filter-more > summary {
    display: flex; align-items: center; gap: var(--space-3); list-style: none; min-height: 2.75rem;
    padding: var(--space-2) 0; line-height: 1.75rem; border-top: 1px solid var(--border);
  }
  /* The marker is drawn here rather than by the engine: Chromium and Firefox draw a summary's
     triangle as a list-item marker, WebKit as `::-webkit-details-marker`, so a rule for one could
     show two or none in the other (iOS Safari was not available to check; review 2026-10-22). Both
     native markers are off; a chevron of two borders points right when closed and down when open.
     Borders in currentColor, so it keeps its colour in forced-colours mode. It is `::after` moved
     first in the flex row (`order: -1`): a `::before` on a summary is what the Sources panel moved
     off it (UX-11, web/test_list_credits.py). */
  .filter-bar--map .filter-more > summary::-webkit-details-marker { display: none; }
  .filter-bar--map .filter-more > summary::after {
    content: ""; order: -1; flex: none; width: 0.45em; height: 0.45em; margin-inline: 0.15em 0.1em;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(-45deg);
  }
  .filter-bar--map .filter-more[open] > summary::after { transform: rotate(45deg); }
}
@media (min-width: 720px) {
  .js .filter-bar--map[data-collapse].is-open .filter-bar__done.filter-bar__done--top { display: none; }
}

/* "View as: Map · List" (D-8, docs/30 §2): two links beside the results, the current one marked
   by aria-current and, as its visible echo, a heavier rule and weight. */
.results-bar { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2) var(--space-4); }
.results-bar .result-count { margin-bottom: var(--space-3); }
.view-switch { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--text-2); }
.view-switch__label {
  font-family: var(--font-body); font-size: var(--text-label); font-weight: 500;
  color: var(--text-muted); margin-inline-end: var(--space-1);
}
.view-switch__link {
  display: inline-flex; align-items: center; min-height: 2rem; padding: 0 var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius-2); text-decoration: none; color: var(--link);
}
.view-switch__link:visited { color: var(--link); }
.view-switch__link[aria-current="page"] { border-color: var(--text); color: var(--text); font-weight: 600; }
/* Below 720px the "View as" text is visually hidden (the nav's aria-label still names the control)
   and the links take 8px side padding, 274px -> about 183px, so the switch fits a phone row (it sat
   in the map's status row until the map dropped it, owner 2026-10-22; the list keeps it). */
@media (max-width: 719px) {
  .view-switch__label {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
  }
  .view-switch__link { padding: 0 var(--space-2); }
}

/* Empty and invalid states (D-11, docs/31 §6 and §5.9). */
.empty-state__facets { list-style: none; margin: var(--space-3) auto; padding: 0; max-width: 46rem; text-align: left; }
.empty-state__facets li { padding: var(--space-2) 0; border-bottom: 1px solid var(--border); color: var(--text); }
.empty-state__facet { font-weight: 600; }
.empty-state__facets a { margin-inline-start: var(--space-2); white-space: nowrap; }
.empty-state__hint { font-size: var(--text-1); }
.empty-state__error, .filter-field__error {
  color: var(--text); font-weight: 600; border-inline-start: 3px solid var(--family-danger-text);
  padding-inline-start: var(--space-2);
}
.empty-state__error { display: inline-block; text-align: start; max-width: 46rem; }
.filter-field__error { font-size: var(--text-1); margin: var(--space-1) 0 0; max-width: 22rem; }
.filter-field input[aria-invalid="true"] { border-bottom-color: var(--family-danger-text); }

/* Proposal page location (D-8): one line, then a static locator (no script on this page). */
.proposal-location { margin: var(--space-5) 0 0; }
.proposal-location__heading { font-size: var(--text-4); margin-bottom: var(--space-2); }
.proposal-location__line { margin: 0 0 var(--space-3); }
.proposal-location__figure { margin: 0; max-width: 40rem; }
.mini-map--locator { height: 15rem; min-height: 0; margin: 0 0 var(--space-2); }
.mini-map__outline { fill: var(--map-land); stroke: var(--text-muted); stroke-width: 1.2; stroke-linejoin: round; }
.mini-map--locator svg { background: var(--map-water); }
.mini-map__site { fill: var(--family-progress-text); stroke: var(--surface); stroke-width: 2; }
.mini-map__centroid { fill: none; stroke: var(--family-progress-text); stroke-width: 2.5; }
/* One row at 1440px: the selects are as wide as a long option needs, not the longest one. */
@media (min-width: 720px) {
  .filter-bar--map select { max-width: 10rem; }
  .filter-bar--map input[type="text"] { width: 7rem; }
}

/* ---------- 8.4 Site finder (web/site_finder.py, site_finder.html, site_finder.js) ----------
   The home map's frame and drawer (8, 8.1, 8.3), with a shorter canvas so the count line under it
   shows in the first screen at 1440x900, the key in the map's bottom left, and a band's details in
   the drawer: over the map's right from 720px, a bottom sheet below. */
.sf-intro { padding-top: var(--space-4); }
.sf-intro__title { margin: 0 0 var(--space-1); }
.sf-intro__lede { margin: 0 0 var(--space-3); max-width: 72ch; color: var(--text); }
.sf-intro__how { color: var(--text-muted); }
.sf-criteria { gap: var(--space-3) var(--space-5); padding: var(--space-2) 0; margin-bottom: var(--space-3); }
.sf-range { min-width: 11rem; }
.sf-range input[type="range"] { width: 100%; min-height: 1.75rem; padding: 0; border: 0; accent-color: var(--sf-selected); }
.sf-range__value { color: var(--text); font-weight: 600; text-transform: none; letter-spacing: normal; font-family: var(--font-body); }
.sf-range__ends { display: flex; justify-content: space-between; font-size: var(--text-1); color: var(--text-muted); }
.sf-flags { border: 0; margin: 0; padding: 0; gap: var(--space-1); }
.sf-flags label {
  display: flex; align-items: center; gap: var(--space-2); color: var(--text); font-family: var(--font-body);
  font-size: var(--text-2); text-transform: none; letter-spacing: normal;
}
.sf-flags input[type="checkbox"] { width: 1.15rem; height: 1.15rem; min-height: 0; }
.sf-criteria select { max-width: 13rem; }
.js .sf-apply { display: none; }
.sf-frame { --map-height: max(56vh, 22rem); }
.sf-map {
  height: var(--map-height); border: 1px solid var(--border); border-radius: var(--radius-3);
  background: var(--surface);
}
.sf-map.is-unavailable::after {
  content: "The map needs scripts and WebGL; the list below has every band."; display: block;
  padding: var(--space-5); color: var(--text-muted);
}
.sf-map-note { margin: var(--space-2) 0 0; font-size: var(--text-1); color: var(--text); }
.sf-map-note[hidden] { display: none; }
.sf-key {
  position: absolute; left: var(--space-3); bottom: var(--space-5); z-index: 3; max-width: 15rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2);
  font-size: var(--text-1); color: var(--text);
}
.sf-key > summary { cursor: pointer; padding: var(--space-1) var(--space-3); font-weight: 600; min-height: 2rem; display: flex; align-items: center; }
.sf-key__list { list-style: none; margin: 0; padding: 0 var(--space-3) var(--space-2); }
.sf-key__list li { display: flex; align-items: center; gap: var(--space-2); padding: 2px 0; }
.sf-key__group { color: var(--text-muted); margin-top: var(--space-1); }
.sf-key__band { flex: none; width: 1.5rem; height: 0.75rem; border-radius: 0.375rem; background: var(--sf-band); opacity: 0.55; }
.sf-key__line { flex: none; width: 1.5rem; height: 0; border-top: 1.5px solid var(--sf-kv-69); }
.sf-key__line--115 { border-top: 2px solid var(--sf-kv-115); }
.sf-key__line--230 { border-top: 2.5px solid var(--sf-kv-230); }
.sf-key__line--345 { border-top: 3px solid var(--sf-kv-345); }
.sf-key__line--500 { border-top: 4px solid var(--sf-kv-500); }
.sf-key__line--unknown { border-top: 2px dashed var(--sf-kv-unknown); }
/* The class's usual nominal voltages, beside its exact range. */
.sf-key__eg { color: var(--text-muted); }
.sf-key__substation {
  flex: none; box-sizing: content-box; width: 0.6rem; height: 0.6rem; margin: 0 calc(0.45rem - 2.5px);
  border-radius: 50%; border: 1.5px solid var(--surface); outline: 1px solid var(--border);
  background: var(--sf-kv-230);
}
.sf-swatch {
  display: inline-block; width: 0.75rem; height: 0.2rem; margin-inline-end: var(--space-1); vertical-align: middle;
  border-radius: 1px; background: var(--sf-kv-69);
}
.sf-swatch--115 { background: var(--sf-kv-115); }
.sf-swatch--230 { background: var(--sf-kv-230); }
.sf-swatch--345 { background: var(--sf-kv-345); }
.sf-swatch--500 { background: var(--sf-kv-500); }
.sf-swatch--unknown { background: none; border-top: 2px dashed var(--sf-kv-unknown); height: 0; }
.sf-attribution { margin-bottom: var(--space-3); }
.sf-results { margin-top: var(--space-2); }
#sf-rows[aria-busy="true"] { opacity: 0.6; }
.sf-count strong { color: var(--text); }
.sf-count__asof, .sf-count__list { white-space: nowrap; }
.sf-count__list { font-weight: 600; }
.sf-summary .result-count { margin-bottom: var(--space-2); }
.sf-note { font-size: var(--text-1); color: var(--text); margin: calc(-1 * var(--space-2)) 0 var(--space-3); max-width: 80ch; }
/* Under the county picker when the bands span several states and none is chosen. */
.sf-hint { display: block; font-size: var(--text-1); color: var(--text-muted); margin-top: 2px; }
.sf-table .sf-operator { display: block; font-size: var(--text-1); color: var(--text-muted); font-weight: 400; }
.sf-table tr.is-selected { background: color-mix(in srgb, var(--sf-band) 12%, transparent); }
.sf-table tr.is-selected .sf-band-link { font-weight: 700; }
.sf-flood--unavailable { color: var(--text-muted); font-style: italic; }
.sf-empty p + p { margin-top: var(--space-2); }
.sf-about { margin: var(--space-5) 0 var(--space-4); max-width: 80ch; font-size: var(--text-2); }
.sf-about > summary { cursor: pointer; font-weight: 600; }
.sf-about__body p { margin: var(--space-2) 0 0; }
/* A band's details: one fact per row, its words then its source line, so a long value wraps. */
.sf-drawer__back, .sf-drawer .map-drawer__close { text-decoration: none; }
.sf-band__kicker { margin: var(--space-2) 0 0; font-size: var(--text-1); color: var(--text-muted); }
.sf-band__title { margin: var(--space-1) 0; overflow-wrap: anywhere; }
.sf-band__lede { margin: 0; font-size: var(--text-2); }
.sf-band__screening {
  margin: var(--space-3) 0 0; padding: var(--space-2) var(--space-3); font-size: var(--text-1);
  border-inline-start: 3px solid var(--sf-band); background: var(--bg);
}
.sf-band__heading { font-size: var(--text-2); margin: var(--space-4) 0 var(--space-1); }
.sf-band__aside { font-weight: 400; color: var(--text-muted); font-size: var(--text-1); }
.sf-facts { margin: var(--space-3) 0 0; border-top: 1px solid var(--border); }
.sf-fact { padding: var(--space-2) 0; border-bottom: 1px solid var(--border); font-size: var(--text-2); }
.sf-fact dt { color: var(--text-muted); font-size: var(--text-1); margin: 0 0 2px; }
.sf-fact dd { margin: 0; overflow-wrap: anywhere; }
.sf-fact__source { display: block; margin-top: 2px; font-size: var(--text-1); color: var(--text-muted); }
.sf-fact__source a { color: var(--text-muted); }
.sf-fact__not, .sf-fact__features { color: var(--text-muted); font-size: var(--text-1); }
.sf-flag { display: block; margin-top: var(--space-1); font-size: var(--text-1); font-weight: 600; }
.sf-list { margin: var(--space-1) 0 0; padding-inline-start: var(--space-4); }
.sf-list li { margin: 0 0 var(--space-1); }
.sf-list .sf-fact__source { display: inline; }
.sf-links { list-style: none; margin: 0; padding: 0; font-size: var(--text-2); }
.sf-links li { padding: var(--space-1) 0; }
.sf-links a { display: inline-flex; align-items: center; min-height: 1.75rem; }
.sf-popup .maplibregl-popup-content { padding: var(--space-2) var(--space-3); font-size: var(--text-1); }
.sf-popup__meta { color: var(--text-muted); }
@media (max-width: 719px) {
  .sf-intro { padding-top: var(--space-3); }
  .sf-intro__title { font-size: var(--text-4); }
  .sf-frame { --map-height: max(52vh, 18rem); }
  .sf-range { min-width: 0; width: 100%; }
  .sf-criteria select { max-width: none; }
  .sf-range input[type="range"] { min-height: 2.75rem; }
  .sf-flags label { min-height: 2.75rem; }
  /* The key does not cover a phone's map: a closed disclosure under it. */
  .sf-key { position: static; max-width: none; margin-top: var(--space-2); order: 1; }
  .sf-key > summary { min-height: 2.75rem; }
  .sf-key__list { columns: 2; column-gap: var(--space-4); }
  .sf-key__list li { break-inside: avoid; }
  .sf-drawer__back { display: none; }
  .sf-links a { min-height: 2.75rem; }
  .sf-table .sf-operator { display: inline; }
  .sf-table .sf-operator::before { content: "\00a0\00b7\0020"; }
}

/* ---------- Site finder: land parcels (lane parcels; web/site_finder.py `parcels_view`) ----------
   Texas parcel outlines on the map from zoom 12 (`--sf-parcel`, a brown apart from the gold voltage
   ramp and the teal bands: 5.43:1 on --map-land light, 7.45:1 dark), the two land criteria, and the
   drawer's holdings list: acres first (the figure a deal turns on), then parcels, land use, value per
   acre and the appraisal district's link. */
:root { --sf-parcel: #7a5a2f; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --sf-parcel: #e0b47a; }
}
:root[data-theme="dark"] { --sf-parcel: #e0b47a; }
.sf-land-field select { max-width: 11rem; }
.sf-key__parcel {
  flex: none; width: 1.1rem; height: 0.75rem; border: 1.25px solid var(--sf-parcel);
  background: color-mix(in srgb, var(--sf-parcel) 8%, transparent);
}
.sf-land { font-size: var(--text-2); border-top: 1px solid var(--border); padding-top: var(--space-2); }
.sf-land p { margin: 0 0 var(--space-2); }
.sf-land__lede strong { color: var(--text); }
.sf-land__missing { font-weight: 600; }
.sf-land__left-out { color: var(--text-muted); font-size: var(--text-1); }
.sf-land__note { color: var(--text); border-inline-start: 3px solid var(--sf-parcel); padding-inline-start: var(--space-2); }
.sf-holdings { margin: 0 0 var(--space-2); padding-inline-start: var(--space-4); }
.sf-holding { margin: 0 0 var(--space-1); overflow-wrap: anywhere; }
.sf-holding__acres { font-weight: 700; }
.sf-holding__meta, .sf-holding__hint { color: var(--text-muted); font-size: var(--text-1); }
.sf-holding__link { white-space: nowrap; }
.sf-muted { color: var(--text-muted); font-style: italic; }
@media (max-width: 719px) {
  .sf-land-field select { max-width: none; }
  .sf-holding__link { display: inline-flex; align-items: center; min-height: 2.75rem; }
}
/* ---------- end Site finder: land parcels ---------- */

/* ---------- Submit a project (US-1001, docs/30 §4.5; web/submit.py) ----------
   A full form, so its labels are --text-2 in the body face (docs/31 §1.3), not the filter bar's
   mono caption; one column up to 40rem, so 400px needs no rule of its own. Control borders are
   --text-muted (5.5:1 on --surface; SC 1.4.11), not --border (1.5:1), because here the border is
   what shows where an input is. An error is the text above its control; the thicker danger border
   repeats it, it never carries it alone (SC 1.4.1, 3.3.1). */
.intake-form { display: grid; gap: var(--space-7); max-width: 40rem; margin: var(--space-5) 0 var(--space-8); }
.intake-form fieldset { border: none; margin: 0; padding: 0; min-width: 0; display: grid; gap: var(--space-5); }
.intake-form legend {
  font-size: var(--text-3); font-weight: 600; color: var(--text); padding: 0; margin-bottom: var(--space-3);
}
.intake-form__optional { font-weight: 400; color: var(--text-muted); }
.intake-form .field label {
  font-family: var(--font-body); font-size: var(--text-2); font-weight: 600;
  text-transform: none; letter-spacing: normal; color: var(--text);
}
.intake-form .field input, .intake-form .field select, .intake-form .field textarea {
  font: inherit; font-size: var(--text-2); width: 100%; box-sizing: border-box; min-height: 2.5rem;
  padding: var(--space-2) var(--space-3); border: 1px solid var(--text-muted); border-radius: var(--radius-2);
  background: var(--surface); color: var(--text);
}
.intake-form textarea { min-height: 9rem; resize: vertical; }
/* Specific enough to beat `.intake-form .field input` above, which otherwise keeps the 1px border. */
.intake-form .field [aria-invalid="true"] { border-color: var(--family-danger-text); border-width: 2px; }
/* The site's error mark (as `.filter-field__error`): ink text, a danger rule beside it. */
.intake-form .field__error {
  font-size: var(--text-2); border-inline-start: 3px solid var(--family-danger-text); padding-inline-start: var(--space-2);
}
/* A tick box with its label beside it and its hint or error under the label. The box is 24px, the
   SC 2.5.8 minimum on its own, and one 16px x 1.5 line tall, so the label's first line sits level. */
.intake-form .check { display: grid; grid-template-columns: auto 1fr; gap: var(--space-1) var(--space-3); align-items: start; }
.intake-form .check input { width: 1.5rem; height: 1.5rem; margin: 0; accent-color: var(--link); }
.intake-form .check label { font-weight: 600; }
.intake-form .check .field-hint, .intake-form .check .field__error { grid-column: 2; }
/* 65px is Turnstile's own widget height (off the spacing scale), held open so the script's late
   arrival does not move the button. */
.intake-form__captcha .cf-turnstile { min-height: 65px; }
.intake-form__trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.submit-status { max-width: 40rem; }
.submit-status__list { margin: var(--space-2) 0 0; padding-inline-start: var(--space-5); }
.submit-status__list li { padding: var(--space-1) 0; }
.submit-ref { font-family: var(--font-mono); }
.submit-next { max-width: 68ch; padding-inline-start: var(--space-5); }
.submit-next li { padding: var(--space-1) 0; }

/* Sites (docs/21 §3.25): the proposal page's "At this site" panel and the site page's neighbour list. */
.site-panel { margin: var(--space-5) 0; }
.site-panel tr[aria-current="true"] { background: var(--surface); }
.site-panel__neighbours { margin-top: var(--space-3); }
.site-panel__neighbours > summary { cursor: pointer; font-weight: 600; padding: var(--space-2) 0; }
.site-panel__list { margin: var(--space-2) 0 0; padding-left: var(--space-4); }
.site-panel__list li { margin-bottom: var(--space-1); }
.record-table tr.site-row--unit td:first-child { padding-left: var(--space-5); }

/* ---------- 2026-10-10 lane F: the map's filter bar at 720-1079px ----------
   (docs/31 §5.9 as built; measured in docs/30 §5.1. Lane F's compact key went with the floating key,
   owner 2026-10-22: the key is a tab of the map's panel, which scrolls.) */

/* The map's filter bar at 720-1079px (designer D-3): two rows of filters put the map's top at
   634px of 768 at 1024x768 and 761px of 900 at 720x900. It is the "Filters (N active)"
   disclosure the narrow layout already uses (site.js), for the map page only: the list pages keep
   their bar open at these widths. The toggle is the one controlling `#map-filters`. */
@media (min-width: 720px) and (max-width: 1079px) {
  .js .filter-toggle[aria-controls="map-filters"] { display: inline-flex; align-items: center; margin: 0 0 var(--space-3); }
  .js .filter-bar--map[data-collapse]:not(.is-open) { display: none; }
  .js .filter-bar--map[data-collapse].is-open .filter-bar__done { display: inline-flex; align-items: center; }
}

/* Style attributes moved into classes (2026-10-10, docs/60 §2), so the content security policy needs no
   'unsafe-inline' for styles. Same values as the attributes they replace. Where the element already
   names its family or type in a data attribute the rule keys on that, so the template only drops its
   `style`; the plant swatches, the two retired-plant marks and the company pipeline's status icon
   take a class. `.svg-sprite` is base.html's icon sprite. */
.svg-sprite { display: none; }
.legend__item[data-legend-family="neutral"], .pipeline-table__status--neutral { color: var(--family-neutral-text); }
.legend__item[data-legend-family="progress"], .pipeline-table__status--progress { color: var(--family-progress-text); }
.legend__item[data-legend-family="committed"], .pipeline-table__status--committed { color: var(--family-committed-text); }
.legend__item[data-legend-family="success"], .pipeline-table__status--success { color: var(--family-success-text); }
.legend__item[data-legend-family="danger"], .pipeline-table__status--danger { color: var(--family-danger-text); }
.legend__item--plant-solar { color: var(--plant-solar); }
.legend__item--plant-wind { color: var(--plant-wind); }
.legend__item--plant-gas { color: var(--plant-gas); }
.legend__item--plant-oil { color: var(--plant-oil); }
.legend__item--plant-coal { color: var(--plant-coal); }
.legend__item--plant-nuclear { color: var(--plant-nuclear); }
.legend__item--plant-hydro { color: var(--plant-hydro); }
.legend__item--plant-storage { color: var(--plant-storage); }
.legend__item--plant-biomass { color: var(--plant-biomass); }
.legend__item--plant-geothermal { color: var(--plant-geothermal); }
.legend__item--plant-other { color: var(--plant-other); }
.legend__group[data-legend-type="gas_pipeline"] { color: var(--asset-gas-pipeline); }
.legend__group[data-legend-type="gas_processing_plant"] { color: var(--asset-gas-processing); }
.legend__group[data-legend-type="gas_storage"] { color: var(--asset-gas-storage); }
.legend__group[data-legend-type="lng_terminal"] { color: var(--asset-lng-terminal); }
.legend__group[data-legend-type="ethanol_plant"] { color: var(--asset-ethanol); }
.legend__group[data-legend-type="rng_project"] { color: var(--asset-rng); }
.legend__group[data-legend-type="transmission_line"] { color: var(--asset-transmission); }
.legend__item[data-legend-mark="retired-cluster"], .legend__item--retired { color: var(--asset-retired); }
.legend__item--retiring { color: var(--asset-retiring); }

/* Records no register lists any more (owner, 2026-10-11; web/unlisted.py). The box sits in the Status
   disclosure under the status groups, laid out as the single-checkbox fields are. Its note says the
   box has no effect while a status outside the default is ticked (such a view hides nothing); it
   shows only then, read from the boxes themselves as the reader ticks them, before the list's
   "Apply filters" and as the map redraws, with no script. A browser without `:has` keeps the note
   hidden. The hidden-records line sits under the lifecycle notice, as part of it. */
.filter-unlisted { display: flex; flex-direction: column; gap: var(--space-1); }
.filter-unlisted__note { display: none; margin: 0; }
.filter-status:has(input[name="lifecycle_state"]:not([data-default]):checked) .filter-unlisted__note { display: block; }
.view-notice + .view-notice--unlisted { margin-top: calc(-1 * var(--space-4)); padding-top: 0; }
.map-status .view-notice + .view-notice--unlisted { margin-top: 0; }

/* ---------- Private beta feedback (2026-10-11; web/beta.py, web/feedback.py, docs/65) ----------
   One line above the top bar on every public page while the beta's shared login is on
   (SITE_ACCESS=basic): what the site is, and the way to say what a reader was trying to do. It is
   shown at every width, is not sticky (it scrolls away under the top bar), and wraps rather than
   scrolling at 360px. Ink and copper link on --surface, as everywhere else (both themes through the
   tokens). The link is at least 24px tall (SC 2.5.8). The form itself reuses /submit's
   `.intake-form` rules. */
.beta-bar { background: var(--surface); border-bottom: 1px solid var(--border); }
.beta-bar__text {
  max-width: 1440px; margin: 0 auto; padding: var(--space-1) var(--space-5);
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--space-2);
  font-size: var(--text-1); color: var(--text);
}
.beta-bar__label { font-weight: 600; }
.beta-bar__link { display: inline-flex; align-items: center; min-height: 1.5rem; color: var(--link); }
.beta-bar__link[aria-current="page"] { font-weight: 600; }
.feedback-form { gap: var(--space-5); }
@media (max-width: 719px) {
  .beta-bar__text { padding: var(--space-1) var(--space-4); }
}

/* ---------- The navigation shell (2026-10-31, one-line desktop navigation; after Navigation v2, docs/30
   §11.2, §11.8) ----------
   The header of every public page is one bar: 48px, sticky at every width, the only sticky bar on the site.
   From 1024px it holds, on one line, the wordmark, the workflow (Explore -> My list -> Build a deal -> Get
   funded, a thin rule, About), then search, Alerts and the account. Each menu is a `<details>` disclosure;
   My list is a link. Below 1024px the workflow folds into Menu, a panel in place under the bar. The page or
   menu that holds this page carries `aria-current`; weight and a 2px rule are its visible echo, never colour
   alone (SC 1.4.1). Every colour is a token, so both themes hold. Collapsed states are keyed on `.js`
   (base.html sets it before first paint): without scripts the search field stays in the bar and the Menu
   panel stays open below 1024px. `--top-bar-h` is what the full-screen map subtracts (§11.6, §11.8).

   Widths, measured with Geist loaded (lane nav, 2026-10-31; web/test_e2e.py pins no overflow): signed in
   with every menu and a long page name the row needs about 1400px with the 20rem search field, so the field
   shows from 1440px and folds to its icon below; the page name is cut with an ellipsis past 11rem beside
   the field, 13rem from 1280px without it and 10rem from 1140px, and leaves below 1140px; below 1024px the
   workflow goes into Menu. */
:root { --top-bar-h: 3rem; }
/* An anchor jump or a focused control lands below the sticky bar, not under it (SC 2.4.11). */
html { scroll-padding-top: var(--top-bar-h); }

.top-bar { position: sticky; top: 0; z-index: 40; background: var(--bg); border-bottom: 1px solid var(--border); }
.top-bar__row {
  position: relative; max-width: 1440px; margin: 0 auto; padding: 0 var(--space-5);
  min-height: calc(var(--top-bar-h) - 1px); display: flex; align-items: stretch; gap: var(--space-6);
}
.top-bar .wordmark { display: flex; align-items: baseline; gap: 0; align-self: center; flex: none; line-height: 1; font-size: var(--text-4); }
.top-bar__nav { display: flex; align-items: center; gap: var(--space-1); min-width: 0; }
.top-bar__utils { margin-inline-start: auto; display: flex; align-items: center; gap: var(--space-5); }
/* A step of the workflow (a menu's button, or My list) and the utilities: 44px tall at least (SC 2.5.8 and
   the house 44px), the 2px rule under the current one. */
.top-bar__step, .top-bar__link {
  display: flex; align-items: center; align-self: stretch; min-height: 2.75rem; white-space: nowrap; cursor: pointer;
  color: var(--text); text-decoration: none; font-size: var(--text-2);
  border-top: 2px solid transparent; border-bottom: 2px solid transparent;
}
.top-bar__step { padding: 0 var(--space-2); }
.top-bar__step:hover, .top-bar__step:focus-visible,
.top-bar__link:hover, .top-bar__link:focus-visible { color: var(--link); border-bottom-color: currentColor; }
.top-bar__step[aria-current], .top-bar__link[aria-current] { font-weight: 600; border-bottom-color: currentColor; }
/* The arrows between the steps say "then"; they are drawn, not read (aria-hidden). */
.top-bar__arrow { flex: none; color: var(--text-muted); }
/* The thin rule that sets About apart from the workflow. */
.top-bar__rule { flex: none; align-self: center; width: 1px; height: 1.25rem; margin: 0 var(--space-3); background: var(--border); }

/* A menu (§11.2): a `<details>`, so it opens on click without scripts; site.js keeps one open at a time and
   closes it on Escape (focus back on its button) and on a click outside. Its rows are 40px. */
.nav-menu { position: relative; display: flex; align-self: stretch; }
.nav-menu__toggle { list-style: none; gap: var(--space-2); }
.nav-menu__toggle::-webkit-details-marker { display: none; }
.nav-menu__toggle::after, .account-menu__toggle::after {
  content: ""; flex: none; width: 0.4em; height: 0.4em; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: translateY(-25%) rotate(45deg);
}
.nav-menu[open] > .nav-menu__toggle::after, .account-menu[open] .account-menu__toggle::after { transform: translateY(25%) rotate(-135deg); }
/* The page's name after the current menu's ("Explore / Infrastructure"), from 1140px. */
.nav-menu__page {
  display: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 400; color: var(--text-muted);
}
@media (min-width: 1140px) { .nav-menu__page { display: inline-block; vertical-align: bottom; max-width: 10rem; } }
@media (min-width: 1280px) { .nav-menu__page { max-width: 13rem; } }
/* With the search field open in the bar (from 1440px) the name gives it room. */
@media (min-width: 1440px) { .nav-menu__page { max-width: 11rem; } }
.nav-menu__panel, .account-menu__list {
  position: absolute; top: 100%; z-index: 3; min-width: 13rem; margin: 0; padding: var(--space-1) 0;
  list-style: none; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2);
  box-shadow: var(--shadow-1);
}
.nav-menu__panel { left: 0; }
.nav-menu__panel ul { list-style: none; margin: 0; padding: 0; }
.nav-menu__heading {
  margin: var(--space-1) var(--space-4) 0; padding-top: var(--space-2); border-top: 1px solid var(--border);
  font-size: var(--text-1); color: var(--text-muted);
}
/* A page still being built (`sections.beta`): a quiet tag after its name, never a colour of its own. */
.nav-tag {
  margin-inline-start: var(--space-2); padding: 0 0.4em; border: 1px solid var(--border); border-radius: 999px;
  font-size: var(--text-1); line-height: 1.5; color: var(--text-muted);
}
.nav-menu__panel a, .account-menu__list a, .account-menu__list button {
  display: flex; align-items: center; width: 100%; min-height: 2.5rem; padding: 0 var(--space-4); white-space: nowrap;
  font: inherit; font-size: var(--text-2); color: var(--text); text-decoration: none; text-align: left;
  background: none; border: 0; cursor: pointer;
}
.nav-menu__panel a:hover, .nav-menu__panel a:focus-visible,
.account-menu__list a:hover, .account-menu__list a:focus-visible,
.account-menu__list button:hover, .account-menu__list button:focus-visible { background: var(--bg); color: var(--link); }
.nav-menu__panel a[aria-current], .account-menu__list a[aria-current] { font-weight: 600; box-shadow: inset 2px 0 0 currentColor; }
/* Inside the open panel the outline is drawn inward, so the panel's edge never clips it. */
.nav-menu__panel a:focus-visible { outline-offset: -2px; }

/* Search: a 20rem field from 1440px. Its placeholder is 264px in Geist 16px and 281px in "Geist Fallback"
   (brand lane, 2026-10-23); the field gives text all but its 12px left padding and the 40px magnifier, so
   the fallback face loses its last few pixels at this width, a trade made for one line (2026-10-31). Below
   1440px an icon button opens it over the bar, and Escape, Close, or focus or a click going elsewhere puts
   the bar back (site.js). */
.site-search { position: relative; display: flex; align-items: center; gap: var(--space-2); }
.site-search input {
  font: inherit; font-size: var(--text-2); width: 20rem; min-height: 2.25rem;
  padding: 0 2.5rem 0 var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-2);
  background: var(--surface); color: var(--text);
}
/* UX-15 (audit 2026-10-07): inputs keep the site-wide 2px focus outline (docs/31 §7, SC 2.4.11);
   the border darkens as well. */
.site-search input:focus-visible { border-color: var(--focus-ring); }
.site-search button {
  /* Secondary button (docs/31 §5.16): outlined, sentence case. */
  font: inherit; font-size: var(--text-2);
  padding: var(--space-1) var(--space-3); border-radius: var(--radius-2); min-height: 2.25rem;
  border: 1px solid var(--link); background: transparent; color: var(--link); cursor: pointer;
}
.site-search button:hover { background: var(--link); color: var(--surface); }
/* The magnifier inside the field submits it. */
.site-search .site-search__submit {
  position: absolute; right: 0; top: 0; bottom: 0; width: 2.5rem; padding: 0; border: 0;
  display: inline-flex; align-items: center; justify-content: center; color: var(--text-muted);
}
.site-search .site-search__submit:hover { background: transparent; color: var(--link); }
.site-search__close { display: none; }
.search-toggle {
  display: none; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; padding: 0;
  border: 0; border-radius: var(--radius-2); background: transparent; color: var(--text); cursor: pointer;
}
.search-toggle:hover, .search-toggle[aria-expanded="true"] { color: var(--link); }
@media (max-width: 1439px) {
  .site-search input { width: 12rem; }
  .js .search-toggle { display: inline-flex; }
  .js .site-search { display: none; }
  .js .site-search.is-open {
    display: flex; position: absolute; inset: 0; z-index: 2; padding: 0 var(--space-5); background: var(--bg);
  }
  .js .site-search.is-open input { flex: 1; width: auto; min-width: 0; }
  .js .site-search.is-open .site-search__submit { position: static; width: 2.75rem; height: 2.75rem; }
  .js .site-search.is-open .site-search__close { display: inline-flex; align-items: center; min-height: 2.75rem; }
}

/* The account (§11.2): a `<details>` menu like the others, its list at the bar's right edge. */
.account-menu { position: relative; display: flex; align-self: stretch; }
.account-menu__toggle { list-style: none; gap: var(--space-2); }
.account-menu__toggle::-webkit-details-marker { display: none; }
.account-menu__list { right: 0; min-width: 12rem; }
.account-menu__list form { margin: 0; }

/* Menu: only below 1024px. */
.nav-toggle { display: none; }
.site-menu { display: none; }

/* A record's tab row (partials/_record_tabs.html) keeps the class the old section bar's row had: it scrolls
   sideways inside itself whenever it is wider than the screen, never wraps; site.js brings the current tab
   into view and fades a cut edge (24px). */
.section-bar__items {
  position: relative; display: flex; align-items: stretch; gap: var(--space-5); flex: 0 1 auto; min-width: 0;
  margin: 0; padding: 0; list-style: none;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none; scroll-snap-type: x proximity;
}
.section-bar__items::-webkit-scrollbar { display: none; }
.section-bar__items li { display: flex; flex: none; scroll-snap-align: start; }
.section-bar__items a {
  display: flex; align-items: center; white-space: nowrap; color: var(--text-muted); text-decoration: none;
  font-size: var(--text-2); border-top: 2px solid transparent; border-bottom: 2px solid transparent;
}
/* Inside a scrolling row the outline is drawn inward, or the row would clip it. */
.section-bar__items a:focus-visible { outline-offset: -2px; }
.section-bar__items a:hover, .section-bar__items a:focus-visible { color: var(--link); border-bottom-color: currentColor; }
.section-bar__items a[aria-current] { color: var(--text); font-weight: 600; border-bottom-color: currentColor; }
.section-bar__items.is-cut-end, .ref-tabs ul.is-cut-end {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent); /* taste-skill-ignore: a fade mask on a scrolling tab row, not a fill */
  mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent); /* taste-skill-ignore: a fade mask on a scrolling tab row, not a fill */
}
.section-bar__items.is-cut-start, .ref-tabs ul.is-cut-start {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 1.5rem), transparent); /* taste-skill-ignore: a fade mask on a scrolling tab row, not a fill */
  mask-image: linear-gradient(to left, #000 calc(100% - 1.5rem), transparent); /* taste-skill-ignore: a fade mask on a scrolling tab row, not a fill */
}
.section-bar__items.is-cut-start.is-cut-end, .ref-tabs ul.is-cut-start.is-cut-end {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent); /* taste-skill-ignore: a fade mask on a scrolling tab row, not a fill */
  mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent); /* taste-skill-ignore: a fade mask on a scrolling tab row, not a fill */
}

/* Below 1024px (§11.8): the wordmark, the search button and Menu; Menu opens a panel in place under the bar,
   every row 44px, in the bar's order: each menu a group (the current one open), My list a row, then Alerts,
   the account and the freshness line. The panel scrolls inside itself, so a long one never runs under the
   bottom of the screen. */
@media (max-width: 1023px) {
  .top-bar__utils { gap: var(--space-2); }
  .top-bar__nav, .top-bar__link, .account-menu { display: none; }
  .js .nav-toggle { display: inline-flex; align-items: center; min-height: 2.75rem; }
  html:not(.js) .top-bar__row { flex-wrap: wrap; padding-block: var(--space-2); }
  html:not(.js) .top-bar__utils { flex-basis: 100%; }
  html:not(.js) .site-search, html:not(.js) .site-search input { width: 100%; }
  .site-menu {
    display: block; padding: 0 var(--space-5) var(--space-3); border-top: 1px solid var(--border);
    max-height: calc(100dvh - var(--top-bar-h)); overflow-y: auto; overscroll-behavior: contain;
  }
  .js .site-menu:not(.is-open) { display: none; }
  .site-menu ul { list-style: none; margin: 0; padding: 0; }
  .site-menu form { margin: 0; }
  .site-menu summary, .site-menu li > a, .site-menu button, .site-menu__step {
    display: flex; align-items: center; width: 100%; min-height: 2.75rem; padding: 0;
    font: inherit; font-size: var(--text-2); color: var(--text); text-decoration: none; text-align: left;
    background: none; border: 0; cursor: pointer;
  }
  .site-menu__group, .site-menu__step { border-bottom: 1px solid var(--border); }
  .site-menu__group > summary, .site-menu__step { font-weight: 600; }
  .site-menu__group > summary { list-style: none; justify-content: space-between; }
  .site-menu__group > summary::-webkit-details-marker { display: none; }
  .site-menu__group > summary::after {
    content: ""; width: 0.45em; height: 0.45em; margin-inline-end: var(--space-2);
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg);
  }
  .site-menu__group[open] > summary::after { transform: rotate(-135deg); }
  .site-menu__group ul { padding: 0 0 var(--space-2) var(--space-4); }
  .site-menu .nav-menu__heading { margin: 0 0 0 var(--space-4); padding: var(--space-2) 0 0; border-top: 0; min-height: 1.75rem; }
  .site-menu li > a[aria-current], .site-menu__step[aria-current] { font-weight: 600; box-shadow: inset 2px 0 0 currentColor; padding-inline-start: var(--space-3); }
  .site-menu__utils { padding-top: var(--space-2); }
}
@media (max-width: 719px) {
  .top-bar__row { padding: 0 var(--space-4); gap: var(--space-3); }
  .js .site-search.is-open { padding: 0 var(--space-4); }
  .site-menu { padding: 0 var(--space-4) var(--space-3); }
}

/* The footer's reference and legal links: one wrapping row, each at least 24px tall (SC 2.5.8). */
.site-footer__scope { margin: 0 0 var(--space-3); max-width: 60rem; }
/* The disclosure line (2026-11-09): who builds the site, one quiet line in the footer and on About. */
.compass-line { margin: 0 0 var(--space-3); max-width: 60rem; font-size: var(--text-1); color: var(--text-muted); }
.site-footer__links { display: flex; flex-wrap: wrap; gap: 0 var(--space-5); list-style: none; margin: 0 0 var(--space-3); padding: 0; }
.site-footer__links a { display: inline-flex; align-items: center; min-height: 1.5rem; }
/* ---------- end Navigation v2 shell ---------- */

/* ---------- Prices (2026-10-22; web/prices.py, docs/29 slice 1) ----------
   The glossary is four short definitions, two columns from 720px, one below. The two tables are
   the shared `.record-table--compact` list (two-line rows below 720px); `.cell-sub` puts market and
   kind under the location's name on wide screens and beside it on the compact row. A withheld or
   unpublished figure is muted text, never colour alone. Every colour comes from the tokens, so both
   themes hold. */
.price-glossary { display: grid; gap: var(--space-2) var(--space-5); margin: var(--space-3) 0 var(--space-5); }
.price-glossary div { margin: 0; }
.price-glossary dt { font-weight: 600; }
.price-glossary dd { margin: 0; color: var(--text-muted); }
@media (min-width: 720px) {
  .price-glossary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.price-table .cell-sub { display: block; font-size: var(--text-1); color: var(--text-muted); }
.price-table .price-window { white-space: nowrap; font-size: var(--text-1); }
.price-table .price-withheld,
.price-table .price-ref { color: var(--text-muted); font-style: italic; }
.price-flag { color: var(--text-muted); font-size: var(--text-1); }
.price-linkouts ul,
.price-credits ul,
.price-method ul { padding-inline-start: var(--space-5); }
.price-linkouts li,
.price-credits li,
.price-method li { margin-bottom: var(--space-2); }
.price-screening { margin: var(--space-4) 0; }
/* 2026-10-23: a figure resting on a short history says so in its cell, in muted text (SPP's 30 days
   beside twelve months); the method section reads as a short list like the credits. */
.price-table .price-short { color: var(--text-muted); font-size: var(--text-1); white-space: nowrap; }
.price-method { max-width: 72ch; }
@media (max-width: 719px) {
  .price-table .cell-sub { display: inline; }
  .price-table .price-window { white-space: normal; }
}

/* ---------- RFPs & funding: never blank (2026-10-23, lane rfp-view) ----------
   The default view is open and announced notices; an announced row says "Not open yet" beside its
   chip (the quiet slip-note above, words not colour). Under the list, "Recently closed (last 12
   months)" is a section of its own: a heading, then one compact row per notice. From 720px a row is
   one line (status, title, then issuer · deadline · source in muted text); below it, status and
   title, then the rest on a second line, like the list's two-line rows. It is a list, not a table,
   so it never reads as part of the table above. The empty state is the shared dashed box, its links
   one row that wraps. Every colour comes from the tokens, so both themes hold. */
.announced-note { margin-inline-start: var(--space-2); }
.rfp-empty__lead { color: var(--text); font-size: var(--text-3); margin-bottom: var(--space-2); }
.rfp-empty__links {
  list-style: none; margin: var(--space-4) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2) var(--space-5);
}
.rfp-empty__links a { display: inline-block; min-height: 1.5rem; }
.recent-closed { margin-top: var(--space-7); }
.recent-closed__title { font-size: var(--text-3); margin: 0 0 var(--space-1); }
.recent-closed__window { color: var(--text-muted); font-weight: 400; }
.recent-closed__note { margin: 0 0 var(--space-3); font-size: var(--text-1); color: var(--text-muted); }
.recent-closed__list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--border); }
.recent-closed__row {
  padding: var(--space-2) 0; border-bottom: 1px solid var(--border);
  font-size: var(--text-1); line-height: 1.45; overflow-wrap: anywhere;
}
.recent-closed__lead { display: block; font-size: var(--text-2); }
.recent-closed__lead .chip { margin-inline-end: var(--space-1); }
.recent-closed__meta { display: block; color: var(--text-muted); }
.recent-closed__more { margin: var(--space-3) 0 var(--space-2); }
.recent-closed__more a { font-weight: 600; }
@media (min-width: 720px) {
  .recent-closed__lead, .recent-closed__meta { display: inline; }
  .recent-closed__meta { margin-inline-start: var(--space-3); }
}
@media (max-width: 719px) {
  .recent-closed { margin-top: var(--space-6); }
  .recent-closed .cell-text-full { display: none; }
  .recent-closed .cell-text-short { display: inline; }
  .rfp-empty { padding: var(--space-6) var(--space-4); }
  .rfp-empty__lead { font-size: var(--text-2); font-weight: 600; }
}

/* ==========================================================================================================
   Lane V7, Navigation v2 (docs/30 §11.4, §11.10, 2026-10-23): Search, About, Sources & licences, the three
   Coverage & methodology tabs, and the Glossary. Every rule reaches only these pages' own classes
   (.search-*, .top-hit*, .ref-*, .about-*, .sources-*, .method-*, .state-def*, .gloss-*), on the site's
   tokens, which the brand lane swaps. Taste-skill house rules: no tracked capitals, no monospace labels, no
   hairlines outside tables and forms, no shadows at rest, no gradients, no glass; running text in the full
   ink; nothing meant to be read under 13px. Phone first: one column at 360px, more from 560, 900 and 1080px.
   ========================================================================================================== */

/* Reference pages (About, Sources & licences, Coverage & methodology, Glossary): one left edge, a title
   with one line under it, explanations behind a disclosure, sections apart by space alone. */
.ref-page { padding-block: var(--space-6) var(--space-9); }
.ref-page p, .ref-page li, .ref-page dd { color: var(--text); }
.ref-head { margin-bottom: var(--space-8); }
.ref-head h1 { margin: 0 0 var(--space-2); }
.ref-head__lede { font-size: var(--text-3); line-height: 1.45; margin: 0; max-width: 50rem; }
.ref-about { margin-top: var(--space-2); max-width: 75ch; }
.ref-about > summary { cursor: pointer; color: var(--link); padding-block: var(--space-2); width: fit-content; }
.ref-about > p { margin: 0 0 var(--space-3); }
.ref-page h2 { font-size: var(--text-5); margin: 0 0 var(--space-4); }
.ref-page h3 { font-size: var(--text-3); margin: var(--space-7) 0 var(--space-2); }
.ref-page section + section { margin-top: clamp(3rem, 7vw, 6rem); }
.ref-page .record-table th, .ref-page .record-table td::before { font-size: 0.8125rem; }
.ref-page .record-table td { vertical-align: top; }
.ref-index ul {
  display: flex; flex-wrap: wrap; gap: 0 var(--space-5);
  list-style: none; margin: 0 0 var(--space-8); padding: 0;
}
.ref-index a { display: inline-block; padding-block: var(--space-2); }
.ref-page.record-page .ref-index ul { margin-bottom: 0; }
/* The landed-on entry or row of an anchor link stands out by a step in tone, never a line. */
.ref-page :target:not([data-band], .record-section__title) { background: var(--surface); border-radius: var(--radius-3); }

/* The reference pages' URL tabs (Data & methodology, Sources & licenses): plain links; the current one carries weight and a 2px rule. One row
   at every width, as the search tabs are: on a phone narrower than the three labels the row scrolls
   sideways inside itself rather than leave one tab alone on a second line. */
.ref-tabs ul {
  display: flex; flex-wrap: nowrap; gap: 0 var(--space-5); list-style: none; margin: var(--space-5) 0 0; padding: 0;
  overflow-x: auto; scrollbar-width: none; position: relative;
}
.ref-tabs a:focus-visible { outline-offset: -2px; }
@media (max-width: 479px) { .ref-tabs ul { gap: 0 var(--space-4); } }
.ref-tabs a {
  display: inline-flex; align-items: center; min-height: 2.75rem; white-space: nowrap;
  color: var(--text); text-decoration: none; border-bottom: 2px solid transparent;
}
.ref-tabs a:hover, .ref-tabs a:focus-visible { color: var(--link); border-bottom-color: currentColor; }
.ref-tabs a[aria-current="page"] { font-weight: 600; border-bottom-color: var(--text); }
.ref-tabs a[aria-current="page"]:hover { color: var(--text); }

/* About: a title set large, then its sections in section style E (the ledger blocks, "Section style D" and "E"
   below, scoped by the article's `record-page` class). From 1080px the title and "Where it reaches" share the
   first screen. */
.about-head h1 { font-size: clamp(2.5rem, 4.8vw, 4.5rem); line-height: 1.02; letter-spacing: -0.02em; }
.about-reach__figure, .about-reach__figure:visited { color: var(--text); text-underline-offset: 0.2em; }
.about-reach__figure:hover { color: var(--link); }
.ref-page .about-reach__kinds { margin-inline-start: var(--space-2); color: var(--text-muted); font-size: var(--text-label); font-weight: 400; }
/* "Where it reaches" and "Who it's for" collapse under their bars (owner, 2026-11-08: "Collapse"): the block is a
   <details>, its bar the summary with a + that turns to − when open, its ledger the open rows. A details box
   holds its rows in its own content slot, so the block is not the label | value grid; the ledger takes its own
   columns. */
.record-page details.about-fold[data-band] { display: block; box-sizing: border-box; width: 100%; }
.record-page .about-fold[data-band] > .fact-table { grid-template-columns: fit-content(var(--lg-cap)) minmax(0, 1fr); }
.about-fold > summary { list-style: none; cursor: pointer; }
.about-fold > summary::-webkit-details-marker { display: none; }
.about-fold > summary::after { content: "+"; margin-inline-start: auto; font-weight: 400; color: var(--text-muted); }
.about-fold[open] > summary::after { content: "\2212"; }
.about-fold > summary:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
@media (min-width: 1080px) {
  .about-intro { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-8); align-items: start; }
  .about-intro .ref-head { margin-bottom: 0; }
  .about-intro > .about-reach { margin-top: 0; }
}

/* About's chain graphic (web/chain.py; owner, 2026-11-06): an E block (bar, lead, the chain) and one E panel per
   step and deal under it, each an ink bar over ledger rows. Steps are filled tiles on the page ground, the deals
   small tiles on the 2px line between them, the pressed one in ink like the bars; the accent marks only what
   Inframation maps (steps 1-3: the span under them, the panel chip). Without the script every panel shows;
   with it (`.is-live`) one. From 860px the chain is one row; below it stacks, the span a rail at its left. */
.about-chain__lead { max-width: 62ch; }
.about-chain .chain {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr) minmax(1.25rem, 0.42fr)) minmax(0, 1fr);
  align-items: stretch; row-gap: var(--space-2); padding-block: var(--space-4);
}
.about-chain .chain__focus {
  grid-row: 2; grid-column: 1 / 6; margin: 0; padding-top: var(--space-2); border-top: 3px solid var(--accent);
  color: var(--accent-deep); font-size: var(--text-label); font-weight: 600; line-height: 1.35;
}
.about-chain .chain__rail { display: none; }
.chain__step {
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 2px; min-width: 0;
  margin: 0; padding: var(--space-3) var(--space-1); border: 0; border-radius: var(--radius-3);
  background: var(--bg); color: var(--text); font: inherit; text-align: center; cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.chain__step svg { width: 2.75rem; height: 2.75rem; flex: none; margin-bottom: var(--space-1); }
.chain__step-t { font-size: var(--text-label); font-weight: 600; line-height: 1.25; overflow-wrap: anywhere; }
.chain__step-s { font-size: var(--text-label); line-height: 1.3; color: var(--text-muted); overflow-wrap: anywhere; }
.chain__step:hover { background: var(--active); }
.chain__step[aria-pressed="true"] { background: var(--primary); color: var(--primary-ink); }
.chain__step[aria-pressed="true"] .chain__step-s { color: inherit; }
.chain__link { position: relative; display: flex; align-items: center; justify-content: center; min-width: 0; }
.chain__link::before { content: ""; position: absolute; inset-inline: 0; top: 50%; height: 2px; margin-top: -1px; background: var(--text); }
.chain__deal {
  position: relative; display: grid; place-items: center; width: 2rem; height: 2rem; margin: 0; padding: 0;
  border: 2px solid var(--text); border-radius: var(--radius-2); background: var(--surface); color: var(--text); cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.chain__deal svg { width: 1rem; height: 1rem; }
.chain__deal:hover { background: var(--active); }
.chain__deal[aria-pressed="true"] { background: var(--primary); border-color: var(--primary); color: var(--primary-ink); }
:is(.chain__step, .chain__deal):focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.chain-panel .record-section__head .chain-panel__chip {
  flex: none; margin-inline-start: auto; padding: 2px var(--space-2); border-radius: var(--radius-1);
  background: var(--accent-deep); color: var(--accent-ink); font-size: var(--text-label); font-weight: 600; white-space: nowrap;
}
.chain-stages { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.ref-page .chain-stages li { padding: 1px var(--space-2); border-radius: var(--radius-2); background: var(--active); font-size: var(--text-label); }
.chain-live { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-5); margin: 0; padding: 0; list-style: none; }
.record-page .fact-table .chain-live a { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--space-2); color: inherit; text-decoration: none; }
.chain-live a:hover .chain-live__n, .chain-live a:focus-visible .chain-live__n { text-decoration: underline; text-underline-offset: 0.2em; }
.chain-live__k { color: var(--text-muted); font-size: var(--text-label); }
.chain-live__n { font-weight: 600; text-decoration: underline dotted; text-underline-offset: 0.2em; }
.chain-live__mw, .chain-live__none { color: var(--text-muted); font-size: var(--text-label); font-weight: 400; }
.ref-page .about-chain__foot { max-width: 75ch; margin: var(--space-3) 0 0; color: var(--text-muted); font-size: var(--text-label); }
@media (max-width: 859px) {
  .about-chain .chain { grid-template-columns: 3px minmax(0, 1fr); column-gap: var(--space-3); row-gap: 0; }
  .about-chain .chain__focus { grid-row: 1; grid-column: 1 / -1; padding: 0 0 var(--space-2); border-top: 0; }
  .about-chain .chain__rail { display: block; grid-row: 2 / 7; grid-column: 1; background: var(--accent); border-radius: 2px; }
  .chain__step, .chain__link { grid-column: 2; }
  .chain__step { flex-direction: row; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); text-align: start; }
  .chain__step svg { width: 2rem; height: 2rem; margin: 0; }
  .chain__step-t { flex: none; }
  .chain__step-s { flex: 1 1 auto; text-align: end; }
  .chain__link { min-height: 2.75rem; }
  .chain__link::before { inset-inline: auto; left: 50%; top: 0; bottom: 0; width: 2px; height: auto; margin: 0 0 0 -1px; }
}
@media (prefers-reduced-motion: reduce) { .chain__step, .chain__deal { transition: none; } }

/* Sources & licences: real tables (their lines are allowed), the register's operator and id under its name. */
.sources-table__sub { display: block; color: var(--text-muted); font-size: 0.875rem; }
.sources-table__id { display: block; color: var(--text-muted); font-size: 0.8125rem; overflow-wrap: anywhere; }
.sources-table__none { color: var(--text-muted); }
/* Below 720px a record-table cell is one row, its label then its value (`.record-table td`, display:flex).
   The Register and Licence cells hold several lines (name, operator, id; class, use, terms), so there the
   label sits above them and they stack, rather than squeeze side by side and break the id mid-word. */
@media (max-width: 719px) {
  .sources-table td.sources-table__stack { flex-direction: column; justify-content: flex-start; gap: 2px; }
}
.sources-withheld { margin-top: var(--space-4); }
.sources-withheld > summary { cursor: pointer; color: var(--link); padding-block: var(--space-2); width: fit-content; }
.sources-withheld ul { columns: 18rem 3; column-gap: var(--space-7); margin: var(--space-2) 0; padding-left: var(--space-5); }
.sources-withheld li { break-inside: avoid; padding-block: var(--space-1); }
/* One column grid for every region's table, so the columns line up down the page. */
@media (min-width: 720px) {
  .sources-table { table-layout: fixed; }
  .sources-table th:nth-child(1) { width: 34%; }
  .sources-table th:nth-child(2) { width: 18%; }
  .sources-table th:nth-child(3) { width: 15%; }
  .sources-table th:nth-child(5) { width: 9%; }
}

/* Coverage & methodology. Status definitions sit two to a row from 1080px: definitions, not cards. */
.method-lede, .method-notes { max-width: 75ch; }
.method-after { margin-top: var(--space-4); }
.method-notes { padding-left: var(--space-5); }
.method-notes li + li { margin-top: var(--space-2); }
.ref-page .method-muted, .method-muted { color: var(--text-muted); }
/* In a section style E block a part's own heading (an "On the other tabs" link, a dated note's headline) sits at
   the top of its row. */
.ref-page.record-page [data-band] > * > h3:first-child, .ref-page.record-page .coverage-note h3 { margin-top: 0; }
.method-elsewhere p { margin: 0 0 var(--space-2); }
.method-elsewhere__list { list-style: none; margin: 0; padding: 0; }
.method-elsewhere__list li { padding-block: var(--space-1); }
@media (min-width: 900px) {
  .method-notes { max-width: none; columns: 2 26rem; column-gap: var(--space-8); }
  .method-notes li { break-inside: avoid; }
}
.state-def { scroll-margin-top: calc(var(--top-bar-h) + var(--space-4)); }
.state-def h4 { font-family: var(--font-display); font-size: var(--text-3); margin: 0 0 var(--space-1); }
.state-def p { margin: 0 0 var(--space-2); }
.ref-page .state-def__count { color: var(--text-muted); }
.state-def__maps > summary { cursor: pointer; color: var(--link); padding-block: var(--space-1); width: fit-content; }
.state-def__maps ul { padding-left: var(--space-5); }
.coverage-note p { max-width: 75ch; }

/* Glossary (Data & methodology's fourth tab since 2026-11-06): a section style E ledger, the term in the label
   cell, what it means, why it matters and its links in the value cell. One label width on every group's block
   (14rem from 720px), so the terms line up down the page; below 720px the term sits over its words. */
.gloss-entry { scroll-margin-top: calc(var(--top-bar-h) + var(--space-4)); }
.gloss-entry dd { display: grid; gap: var(--space-2); }
.gloss-entry__means, .gloss-entry dd p { margin: 0; }
.record-page .gloss-entry__term { color: var(--text); font-size: var(--text-2); font-weight: 600; }
@media (min-width: 720px) {
  .record-page .gloss-group { --lg-cap: 14rem; }
  .record-page .gloss-list dt { min-width: 14rem; }
}
@media (max-width: 719px) {
  .record-page .gloss-group, .record-page .gloss-group > .gloss-list { display: block; }
  .record-page .gloss-list > div { display: block; }
  .record-page .gloss-list dt { border-inline-end: 0; }
}

/* Search (an app screen: docs/30 §11.4; lane stacked-lists, 2026-10-24): the field, then one kind at a
   time. Every kind with its count in a rail at the left from 900px (a row of chips that scrolls inside
   itself below), the open kind's rows at the right in the record lists' table, under a head that names
   the kind and its count and stays in view under the top bar while the rows scroll (owner: "maybe the
   title follows along with the information below it"). No kinds stacked under one another. */
.search-page { padding-block: var(--space-5) var(--space-9); }
.search-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-6); margin-bottom: var(--space-5); }
.search-head h1 { font-size: var(--text-4); margin: 0; }
.search-form { display: flex; flex: 1 1 20rem; min-width: 0; max-width: 42rem; gap: var(--space-2); }
.search-form input {
  flex: 1; min-width: 0; min-height: 2.75rem; padding: 0 var(--space-3); font: inherit;
  color: var(--text); background: var(--surface); border: 1px solid var(--control); border-radius: var(--radius-2);
}
.search-form input::placeholder { color: var(--text-muted); }
.search-form input:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.search-form button {
  min-height: 2.75rem; padding: 0 var(--space-5); font: inherit; font-weight: 600; cursor: pointer;
  color: var(--text); background: var(--family-neutral-fill); border: 0; border-radius: var(--radius-2);
}
.search-form button:hover { background: var(--border); }
.search-hint { margin: 0; max-width: 60ch; }
/* A focused row link scrolled into view clears the top bar, the list's head and the column heads
   (SC 2.4.11). */
html:has(.search-list) { scroll-padding-top: calc(var(--top-bar-h) + 6.5rem); }

.search-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 var(--space-8); align-items: start; }
/* Below 900px the kinds are chips that wrap, never a row that scrolls: every kind and its count stays
   in sight, so a reader on a phone sees that the RFP exists before choosing (a scrolled row hid the
   last kinds at 390px), and there is no scrolling box to reach from the keyboard. */
.search-kinds ul {
  display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; margin: 0 0 var(--space-5); padding: 0;
}
.search-kinds li > a, .search-kinds__none {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  min-height: 2.5rem; padding: 0 var(--space-3); border-radius: var(--radius-2);
  color: var(--text); text-decoration: none; white-space: nowrap;
}
.search-kinds__none { padding-inline: var(--space-2); }
.search-kinds li > a { background: var(--surface); border: 1px solid var(--border); }
.search-kinds li > a:hover { text-decoration: underline; }
.search-kinds li > a:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* The open kind: the grey of a selected item, its edge in ink. The ink fill stays the one primary action's. */
.search-kinds a[aria-current="page"] { background: var(--active); border-color: var(--text); font-weight: 600; }
.search-kinds a[aria-current="page"] .search-kinds__n { color: var(--text); }
/* A kind with no match is a word and a zero, not a link to an empty list. */
.search-kinds__none { color: var(--text-muted); }
.search-kinds__n { color: var(--text-muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.search-kinds__help { display: none; font-size: 0.875rem; color: var(--text-muted); margin: var(--space-5) var(--space-3) 0; }
.search-kinds__help--foot { display: block; margin: var(--space-6) 0 0; }
@media (min-width: 900px) {
  .search-layout { grid-template-columns: 13.5rem minmax(0, 1fr); }
  .search-kinds { position: sticky; top: calc(var(--top-bar-h) + var(--space-4)); }
  .search-kinds ul { display: block; margin: 0; }
  .search-kinds li + li { margin-top: 2px; }
  .search-kinds li > a, .search-kinds__none { min-height: 2.75rem; padding-inline: var(--space-3); }
  .search-kinds li > a { background: none; border-color: transparent; }
  .search-kinds li > a:hover { background: var(--surface); }
  /* In the rail the open kind is the selected row of a list: the grey of a selected nav item, no edge. */
  .search-kinds a[aria-current="page"] { background: var(--active); border-color: transparent; }
  .search-kinds__help { display: block; }
  .search-kinds__help--foot { display: none; }
  /* A table of five columns runs to about 960px, not the canvas: no void between a name and its figures. */
  .search-list:has(.search-table--companies, .search-table--infrastructure) { max-width: 60rem; }
}

.top-hit {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-4);
  background: var(--surface); border-radius: var(--radius-3); padding: var(--space-4) var(--space-5); margin-bottom: var(--space-6);
}
.top-hit__name { font-size: var(--text-3); margin: 0; }
.top-hit__kind { font-size: var(--text-label); font-weight: 500; color: var(--text-muted); margin-inline-end: var(--space-2); }
.top-hit__name a { color: var(--text); text-decoration: none; }
.top-hit__name a:hover { color: var(--link); text-decoration: underline; }
.top-hit__meta { color: var(--text-muted); margin: var(--space-1) 0 0; }
.top-hit__figures { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-7); margin: var(--space-3) 0 0; }
.top-hit__figures dt { color: var(--text-muted); font-size: 0.8125rem; }
.top-hit__figures dd { margin: 0; font-size: var(--text-3); font-variant-numeric: tabular-nums; }
.top-hit__open, .top-hit__open:visited {
  display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0 var(--space-5);
  color: var(--primary-ink); background: var(--primary); border-radius: var(--radius-2); font-weight: 600; text-decoration: none;
}
.top-hit__open:hover { background: var(--text); }

/* The list's head: the kind, its count and its full list, held under the top bar while the rows pass. */
.search-list__head {
  position: sticky; top: var(--top-bar-h); z-index: 2; background: var(--bg);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-4);
  padding: var(--space-2) 0 var(--space-3);
}
.search-list__head h2 { font-size: var(--text-4); margin: 0; }
.search-list__n { font-size: var(--text-2); font-weight: 400; color: var(--text-muted); margin-inline-start: var(--space-2); }
.search-list__all { margin-inline-start: auto; }
@media (max-width: 719px) { .search-list__head { border-bottom: 1px solid var(--border); } }
.search-table { margin-bottom: var(--space-3); }
.search-table th { position: static; }
.search-table td.cell-title { overflow-wrap: anywhere; }
@media (min-width: 720px) {
  .search-list__head { min-height: 3.5rem; }
  /* The column heads hold under the list's head. */
  .search-table thead th { position: sticky; top: calc(var(--top-bar-h) + 3.5rem); z-index: 1; }
  .search-table td { vertical-align: middle; }
  .search-table td.cell-lead { width: 1%; white-space: nowrap; }
  /* A register's short name and a place stay whole ("EIA-860M" never breaks at its hyphen). */
  .search-table td:is([data-label="Source"], [data-label="Where"], [data-label="Due"]) { white-space: nowrap; }
}
.search-empty, .search-range { color: var(--text-muted); margin: 0 0 var(--space-2); }
.search-none { color: var(--text); }

/* ---------- 8.5 The map landing (2026-10-24, lane map-c; docs/30 §11.6-§11.8) ----------
   Direction C, "the lifecycle ruler" (owner, 2026-10-24: tabs with a table). The map fills the viewport
   under the top bar and the section bar and the page does not scroll; there is no footer (its links and
   the endorsement are in the map's credits). Along the map's foot lies the sheet: its band is the h1, the
   ruler (Planned · Under construction · Operating, each stop a tab with its count) and, at its right end,
   Why? and List (closed) or the two height buttons (open). The sheet rests at three heights, set by
   `#map-landing[data-sheet]`: closed (the band alone), half (the band, the stage's analytics strip and the
   top of its table) and full (the map a 120px strip above it). Over the map, and only over it: the
   floating bar (Find, the type chips, the chosen place, Layers) at the top left, the zoom column under it
   and the credits chip at the bottom right, above the sheet. Every one is absolutely placed, so nothing on
   the landing moves another when data lands (docs/30 §11.7).

   Grid at 1440x900 (the mock's): band 88px, 352 | 1fr | 240 with 24px gaps and 16px gutters; strip 92px,
   176 | 216 | 560 | 1fr; half 524px; the table's rows 36px. Phone (below 720px): a bottom sheet, the
   stages as tabs on top of it, the table as two-line rows with sort and filters behind one control.

   --chart-1 is the brand accent snapped to the nearest step the dataviz validator passes on the same hue
   (light #1d7356 -> #107656; dark #5fcf9f -> #34ad7e), --chart-off the de-emphasis grey (--control, 3.74:1
   and 4.48:1 on the surface): the strip's one hue, scoped to the landing so no other chart changes. */

/* The page around the map: no footer, no padding; the top bar's search gives way to Find. */
body:has(#map-landing) main { max-width: none; margin: 0; padding: 0; }
body:has(#map-landing) .site-footer,
body:has(#map-landing) .top-bar .site-search,
body:has(#map-landing) .top-bar .search-toggle { display: none; }

.map-landing {
  --landing-inset: var(--space-3);
  --landing-bar-h: 3rem;
  --sheet-closed: 88px;
  --sheet-half: min(524px, calc(100% - 140px));
  /* At full the list takes nearly the whole screen (owner, 2026-10-25): 48px of map stays above it, a
     target to tap the map and lower the list, and the cue that the map is still there. */
  --map-strip: 48px;
  --chart-1: #107656;
  --chart-off: #7d8496;
  position: relative; overflow: hidden;
  height: calc(100vh - var(--top-bar-h));
  height: calc(100dvh - var(--top-bar-h));
  background: var(--map-water);
  font-variant-numeric: tabular-nums;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .map-landing { --chart-1: #34ad7e; --chart-off: #7b808b; }
}
:root[data-theme="dark"] .map-landing { --chart-1: #34ad7e; --chart-off: #7b808b; }
.map-landing .map-frame { position: absolute; inset: 0; display: block; }
.map-landing #map {
  position: absolute; inset: 0; height: auto; min-height: 0;
  border: 0; border-radius: 0; background: var(--map-water);
}
.map-landing .map-overlay { position: absolute; inset: 0; z-index: 2; display: block; pointer-events: none; }
.map-landing .map-overlay > * { pointer-events: auto; }

/* ---- the floating bar: Find, the type chips, the place, Layers ---- */
.map-float {
  position: absolute; top: var(--landing-inset); left: var(--landing-inset); right: var(--landing-inset);
  display: flex; align-items: center; gap: var(--space-2); pointer-events: none;
}
.map-float > * { pointer-events: auto; }
.map-landing .map-search {
  flex: 0 1 22rem; min-width: 12rem; margin: 0;
  background: var(--surface); border-radius: var(--radius-2);
}
/* Under 1440px the search gives the chip row the room its last chip and Clear need with a place chosen. */
@media (min-width: 1100px) and (max-width: 1439px) { .map-landing .map-search { flex-basis: 18rem; } }
.map-landing .map-search__input { min-height: 2.5rem; border-color: var(--control); }
.map-landing .map-search__icon { top: 0.75rem; }
.map-landing .map-search__clear { width: 2.5rem; height: 2.5rem; }
.map-chip {
  display: inline-flex; align-items: center; gap: var(--space-1); flex: none; min-height: 2.5rem; padding: 0 var(--space-3);
  border: 1px solid var(--border); border-radius: 999px; background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--text-2); cursor: pointer; white-space: nowrap;
}
.map-chip:hover { border-color: var(--control); }
.map-chip[aria-pressed="true"] { border-color: var(--text); outline: 1px solid var(--text); outline-offset: -2px; font-weight: 600; }
.map-chip--place { border-color: var(--text); font-weight: 600; }
.map-landing[data-sheet="full"] .map-float,
.map-landing[data-sheet="full"] .map-overlay__rail { display: none; }

/* Under the bar: the dev-preview label and an error, each on the surface, between the zoom column and the base
   map's button. */
.map-under {
  position: absolute; top: calc(var(--landing-inset) + var(--landing-bar-h) + var(--space-2));
  left: calc(2 * var(--landing-inset) + 2.5rem); width: min(38rem, calc(100% - 5 * var(--landing-inset) - 5rem));
  display: flex; flex-direction: column; gap: var(--space-2);
}
.map-under:empty { display: none; }
.map-under .preview-banner, .map-under .map-error {
  margin: 0; padding: var(--space-2) var(--space-3); font-size: var(--text-1); color: var(--text);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2);
}

/* ---- the zoom column, under the bar at the left edge: zoom (with a mouse), and Reset once the map has moved ---- */
.map-landing .map-overlay__rail {
  position: absolute; z-index: 1; top: calc(var(--landing-inset) + var(--landing-bar-h) + var(--space-2)); left: var(--landing-inset);
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); pointer-events: none;
}
.map-landing .map-overlay__rail .map-controls { flex-direction: column; flex-wrap: nowrap; gap: var(--space-2); margin: 0; pointer-events: auto; }
.map-landing .map-overlay__rail .map-controls[hidden] { display: none; }
.map-landing .map-overlay__rail .map-controls button { min-width: 2.5rem; min-height: 2.5rem; border-color: var(--control); }
/* + and - only for a mouse: a phone or a touch screen pinches and double-taps (owner, 2026-11-02: "get rid of
   our plus and minus signs. People know to zoom with their fingers just like on google"). */
@media (max-width: 719px), (hover: none) and (pointer: coarse) {
}
/* The base map's button: round, at the map's top right under Find, as Google's layers button (owner,
   2026-11-02: "Let's do top right like Google"). Its three choices open under it as a popover placed by map.js
   (`placeBasePop`), above the sheet and every other control. */
.map-landing .map-controls--base {
  position: absolute; z-index: 1; top: calc(var(--landing-inset) + var(--landing-bar-h) + var(--space-2)); right: var(--landing-inset);
}
.map-landing .map-controls--base button {
  display: inline-flex; align-items: center; justify-content: center; width: 2.5rem; height: 2.5rem; min-width: 0; padding: 0;
  border-color: var(--control); border-radius: 50%;
}
.map-landing .map-controls--base button:hover,
.map-landing .map-controls--base button[aria-expanded="true"] { border-color: var(--text); }
.map-landing[data-sheet="full"] .map-controls--base { display: none; }
.map-base-pop {
  position: fixed; inset: auto; margin: 0; padding: var(--space-1) 0; min-width: 8.5rem; max-width: calc(100vw - 16px);
  color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2); box-shadow: var(--shadow-float);
}
.map-base-pop label { display: flex; align-items: center; gap: var(--space-2); min-height: 2.75rem; padding: 0 var(--space-3); cursor: pointer; font-size: var(--text-2); }
.map-base-pop label:has(input:checked) { font-weight: 600; }
.map-base-pop input { width: 1rem; height: 1rem; margin: 0; accent-color: var(--text); }
.map-landing .map-controls--reset button { padding: 0 var(--space-3); font-size: var(--text-1); }

/* ---- the credits chip: the canvas's bottom right, above the sheet ---- */
.map-landing .map-credits {
  position: absolute; right: var(--landing-inset); bottom: calc(var(--sheet-closed) + var(--landing-inset)); margin: 0;
  max-width: calc(100% - 2 * var(--landing-inset));
}
.map-landing[data-sheet="half"] .map-credits { bottom: calc(var(--sheet-half) + var(--landing-inset)); }
.map-landing[data-sheet="full"] .map-credits { bottom: auto; top: var(--space-2); }
.map-landing .map-overlay:has(.map-credits[open]) { z-index: 7; }
.map-credits__toggle {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: 2rem; box-sizing: border-box;
  padding: 0 var(--space-2) 0 var(--space-3); list-style: none; cursor: pointer; font-size: var(--text-1); color: var(--text);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2);
}
.map-credits__toggle::-webkit-details-marker { display: none; }
.map-credits__toggle:hover, .map-credits[open] .map-credits__toggle { border-color: var(--text); }
.map-credits__icon { flex: none; }
.map-credits__body {
  position: absolute; right: 0; bottom: calc(100% + var(--space-2)); box-sizing: border-box;
  width: min(24rem, calc(100vw - 2 * var(--landing-inset))); max-height: min(30rem, 60vh);
  overflow-y: auto; overscroll-behavior: contain; padding: var(--space-3) var(--space-4); font-size: var(--text-1); color: var(--text);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-3); box-shadow: var(--shadow-float);
}
.map-landing[data-sheet="full"] .map-credits__body { bottom: auto; top: calc(100% + var(--space-2)); }
.map-credits:not([open]) .map-credits__body { display: none; }
.map-credits__body .map-attribution { margin: 0; padding: 0; font-size: var(--text-1); color: var(--text); }
.map-credits__links {
  list-style: none; margin: var(--space-3) 0 0; padding: var(--space-3) 0 0; border-top: 1px solid var(--border);
  display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--space-4);
}
.map-credits__links a { display: flex; align-items: center; min-height: 2rem; font-size: var(--text-2); }
.map-credits__endorse { margin: var(--space-2) 0 0; color: var(--text-muted); }
.map-landing .map-basemap-note {
  position: absolute; z-index: 2; left: 50%; bottom: calc(var(--sheet-closed) + 3.5rem); transform: translateX(-50%); margin: 0;
  max-width: 24rem; padding: var(--space-1) var(--space-2); background: var(--surface); border-radius: var(--radius-2); color: var(--text);
  pointer-events: none;
}

/* OpenStreetMap's credit as MapLibre's compact attribution at every width (owner, 2026-10-31: "Collapse open
   street view into the I on the bottom right"): a small (i) in the corner, no box, that opens every credit and
   link on one click or tap (ODbL: the credit stays one action away, and the (i) is a focusable summary). */
.map-landing .map-credits__toggle {
  justify-content: center; width: 2.75rem; height: 2.75rem; min-height: 2.75rem; padding: 0; border: 0; border-radius: 50%; background: none;
}
.map-landing .map-credits__icon { box-sizing: content-box; width: 16px; height: 16px; padding: 4px; border-radius: 50%; background: var(--surface); }
.map-landing .map-credits[open] .map-credits__icon { outline: 1.5px solid var(--text); }
.map-landing .map-credits__osm { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.map-landing .map-credits { right: 2px; }

/* ---- popovers: Why?, the sources and Layers ---- */
.map-pop {
  width: min(24rem, calc(100vw - 2rem)); max-height: min(32rem, calc(100dvh - 4rem)); overflow-y: auto; box-sizing: border-box;
  margin: auto; padding: var(--space-4); color: var(--text); font-size: var(--text-2);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-3); box-shadow: var(--shadow-float);
}
.map-pop h2, .map-pop .map-pop__title { margin: 0 0 var(--space-2); font-size: var(--text-3); font-weight: 600; }
.map-pop ul { margin: 0 0 var(--space-3); padding-inline-start: 1.1rem; }
.map-pop li { margin: 0 0 var(--space-1); }
.map-pop p { margin: 0 0 var(--space-2); }
.map-pop__note { color: var(--text-muted); font-size: var(--text-1); }
.map-switch { display: flex; align-items: center; gap: var(--space-2); min-height: 2.5rem; cursor: pointer; }
.map-switch input { width: 1.125rem; height: 1.125rem; margin: 0; accent-color: var(--text); }
.map-hub-popup .maplibregl-popup-content { padding: var(--space-2) var(--space-3); color: var(--text); background: var(--surface); font-size: var(--text-1); }
.map-hub-popup .maplibregl-popup-tip { display: none; }
.map-hub-popup b { display: block; font-size: var(--text-2); }
/* The reader's own items (home_map.html `#map-mine-chip` and `#map-mine`, static/js/my_pins.js; docs/19 §2.7):
   outline pins in the ink (owner, 2026-11-03), never a circle, a fill or a hue, so a private item never reads as a
   public record; a plain pin is yours, one with a centre ring shared with you. A chip in the floating bar names the list
   and counts what it draws (muted
   while hidden), and opens the popover: the switch, the key (only the kinds on the map) and the privacy
   notice. The card a mark opens is the hub card's surface. */
.map-chip--mine .map-chip__n { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.map-chip--mine.is-off { color: var(--text-muted); }
.map-chip--mine.is-off .map-mine__mark { stroke: var(--text-muted); }
.map-pop--mine { width: min(22rem, calc(100vw - 2rem)); }
.map-mine__key { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); margin: var(--space-1) 0 var(--space-3); font-size: var(--text-1); color: var(--text-muted); }
.map-mine__mark { flex: none; vertical-align: -2px; margin-right: var(--space-1); fill: none; stroke: var(--text); stroke-width: 1.4; stroke-linejoin: round; }
.map-mine__notice { padding-top: var(--space-3); border-top: 1px solid var(--border); }
.map-mine__open a { display: inline-flex; align-items: center; min-height: 2.75rem; }
.map-mine-popup .maplibregl-popup-content { padding: var(--space-2) var(--space-5) var(--space-2) var(--space-3); color: var(--text); background: var(--surface); font-size: var(--text-1); }
.map-mine-popup .maplibregl-popup-tip { display: none; }
.map-mine-card p { margin: 0 0 2px; }
.map-mine-card__whose { color: var(--text-muted); }
.map-mine-card__title { font-size: var(--text-2); font-weight: 600; overflow-wrap: anywhere; }
.map-mine-card__meta { color: var(--text-muted); }
.map-mine-card__open { display: inline-flex; align-items: center; min-height: 2.75rem; color: var(--link); }

/* ---- the key: the canvas's bottom left, above the sheet (lane map-d; four lines since 2026-11-02) ----
   Power and Loads, the stage fills, idle or retiring and retired, and "Bigger = more MW" where size varies
   (map.js `drawKeyMarks`). Folded behind "Key". The card is the plain surface with a 1px edge, as the
   credits chip is; the marks are the only colour in it. */
.map-landing .map-key {
  position: absolute; left: var(--landing-inset); bottom: calc(var(--sheet-closed) + var(--landing-inset)); margin: 0;
  display: flex; flex-direction: column; align-items: flex-start;
}
.map-landing[data-sheet="half"] .map-key { bottom: calc(var(--sheet-half) + var(--landing-inset)); }
.map-landing[data-sheet="full"] .map-key { display: none; }
.map-key__toggle {
  display: none; align-items: center; gap: var(--space-2); min-height: 2.75rem; box-sizing: border-box; padding: 0 var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius-2); background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--text-1); cursor: pointer;
}
.map-key__toggle:hover, .map-key__toggle[aria-expanded="true"] { border-color: var(--text); }
.map-key__glyph { flex: none; color: var(--dot); }
.map-key__body {
  box-sizing: border-box; min-width: 11.5rem; padding: var(--space-2) var(--space-3);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2); color: var(--text);
}
/* The record canvas's scale draws the power mark: its colour from here. */
.map-key__scale-marks { --mark-edge: var(--text); color: var(--text); }

/* ---- US · GB: one joined pair under Layers at the top right (beside Key on a phone) ---- */

/* ---- the (i): beside the stages and on each Layers switch, a 32px target that opens a popover ---- */
.map-info {
  display: inline-flex; align-items: center; justify-content: center; flex: none; width: 2rem; height: 2rem; padding: 0;
  border: 0; border-radius: 50%; background: none; color: var(--text-muted); cursor: pointer;
}
.map-info:hover, .map-info:focus-visible { color: var(--text); background: var(--raised); }
.map-switch-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.map-pop--about h3 { margin: var(--space-3) 0 2px; font-size: var(--text-2); }
.map-pop--about .map-about__src { color: var(--text-muted); font-size: var(--text-1); }
.map-pop--about .map-about__src ul { margin: 2px 0 0; padding-inline-start: 1rem; }
.map-pop--about .map-about__src b { font-weight: 500; color: var(--text); }

/* ---- the sheet ---- */
.ruler-sheet {
  position: absolute; z-index: 6; left: 0; right: 0; bottom: 0; height: var(--sheet-closed);
  display: flex; flex-direction: column; box-sizing: border-box;
  background: var(--surface); border-top: 1px solid var(--border); color: var(--text);
  transition: height 220ms cubic-bezier(.2, 0, 0, 1);
}
.map-landing[data-sheet="half"] .ruler-sheet { height: var(--sheet-half); }
.map-landing[data-sheet="full"] .ruler-sheet { height: calc(100% - var(--map-strip)); }
@media (prefers-reduced-motion: reduce) { .ruler-sheet { transition: none; } }
/* The map's loading state (owner, 2026-11-02: "could we make the 'updating the map' more prominent so user know
   they just need to wait?"): a thin bar along the map's top edge while a read is under way (map.js `refresh` sets
   aria-busy; `marksUpdating` while the marks follow the list), where it was a small pill under Find. A segment
   sweeps it, moved by transform only; under reduced motion the bar stands still at full width. It appears after
   300ms, so a fast answer shows nothing. Out of the flow and 3px tall: nothing shifts, nothing is covered. The
   words stay for a text browser, hidden from sight (assistive technology reads aria-busy). */
.map-updating {
  position: absolute; top: 0; left: 0; right: 0; z-index: 4; height: 3px; margin: 0; overflow: hidden;
  background: color-mix(in srgb, var(--accent) 22%, transparent); color: transparent; font-size: 0; line-height: 0;
  pointer-events: none; visibility: hidden; transition: visibility 0s linear 0s;
}
.map-updating::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 40%; background: var(--accent);
  transform: translateX(-100%); animation: map-updating-sweep 1.1s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes map-updating-sweep { to { transform: translateX(250%); } }
.map-landing[aria-busy="true"] .map-updating { visibility: visible; transition-delay: 300ms; }
@media (prefers-reduced-motion: reduce) {
  .map-updating { background: var(--accent); opacity: 0.6; }
  .map-updating::before { animation: none; display: none; }
}
/* The list's first rows while they are read (map.js `showSkeleton`; owner, 2026-11-02: "much like LinkedIn
   shows a shimmering blank screen on load"): grey bars in the rows' own cells, at the rows' pitch (36px table
   rows, 56px two-line rows on a phone), so the answer lands without moving anything. A soft light passes over
   them, by transform only; under reduced motion they are flat. */
.skel {
  position: relative; display: inline-block; vertical-align: middle; max-width: 100%; height: 10px; border-radius: 3px;
  background: var(--active); overflow: hidden;
}
.skel::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 40%;
  background: var(--skel-band); /* a flat lighter band, no gradient (the taste skill's lint) */
  transform: translateX(-100%); animation: skel-shimmer 1.4s ease-in-out infinite;
}
@keyframes skel-shimmer { to { transform: translateX(250%); } }
.skel--1 { width: 62%; } .skel--2 { width: 48%; } .skel--3 { width: 74%; } .skel--4 { width: 40%; }
.skel--5 { width: 56%; } .skel--6 { width: 68%; } .skel--7 { width: 44%; } .skel--8 { width: 52%; }
.skel--cell { width: 64%; } .skel--full { width: 100%; }
.ruler-dt tbody tr.ruler-skel:hover td { background: none; }
.ruler-skel .ruler-row { cursor: default; }
.ruler-skel .ruler-row__meta .skel { height: 8px; }
@media (prefers-reduced-motion: reduce) { .skel::after { animation: none; display: none; } }
.ruler-sheet__grab {
  position: absolute; top: 6px; left: 50%; width: 36px; height: 4px; margin-left: -18px; border-radius: 2px; background: var(--border);
}
.ruler-band {
  flex: none; position: relative; height: 88px; box-sizing: border-box;
  display: grid; grid-template-columns: 352px minmax(0, 1fr) 240px; gap: 24px; align-items: center; padding: 0 16px;
}
.map-landing:not([data-sheet="closed"]) .ruler-band { border-bottom: 1px solid var(--border); }
.ruler-band__title { margin: 0; font-size: 1.5rem; line-height: 30px; font-weight: 600; letter-spacing: -0.01em; }
.ruler-band__side { display: flex; gap: var(--space-3); justify-content: flex-end; align-items: center; }

/* The ruler: a track with three stops, each a tab. Closed, no stop is selected and every stage is on the
   map; a stop opens the sheet on its stage. Open, the selected stop takes the 2px line on the band's rule. */
.ruler { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); height: 88px; }
.ruler::before {
  content: ""; position: absolute; left: 8px; right: calc(33.333% - 8px); top: 21px; height: 2px; background: var(--border);
}
.ruler__stop {
  position: relative; justify-self: start; display: grid; grid-template-rows: 30px 34px; align-content: start; justify-items: start;
  min-width: 0; height: 88px; padding: 14px 0 0; border: 0; background: none; cursor: pointer; text-align: left;
  color: var(--text); font: inherit;
}
.ruler__pin {
  position: relative; display: block; width: 16px; height: 16px; border-radius: 50%; background: var(--surface);
}
.ruler__pin::after { content: ""; position: absolute; border-radius: 50%; }
/* The stages' pins are the map's stage fills in the ink, as the key draws them (colour is the fuel family, not
   the stage): a ring in development, a ring with its centre dot under construction, a solid disc operating
   (map.js STAGE_FILL). */
.ruler__pin--planned::after { inset: 3px; border: 1.5px solid var(--text); }
.ruler__pin--under_construction::after { inset: 3px; padding: 2px; border: 1.5px solid var(--text); background: var(--text) content-box; }
.ruler__pin--operating::after { inset: 3px; border: 1px solid var(--text); background: var(--text); }
.ruler__lbl { display: flex; align-items: baseline; gap: 10px; white-space: nowrap; color: var(--text-muted); }
.ruler__count { font-size: 1.5rem; line-height: 30px; font-weight: 400; color: var(--text); min-width: 3ch; }
.ruler__name { font-size: var(--text-2); }
.ruler__stop:hover .ruler__count { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; }
.ruler__stop[aria-selected="true"] .ruler__lbl { color: var(--text); }
.ruler__stop[aria-selected="true"] .ruler__count { font-weight: 500; }
.ruler__stop[aria-selected="true"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--select); }
.ruler__stop[aria-selected="true"] .ruler__pin { outline: 1.5px solid var(--text); outline-offset: 2px; }
.ruler__stop:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.ruler-why {
  min-height: 2.5rem; padding: 0 var(--space-1); border: 0; background: none; color: var(--text); font: inherit; font-size: var(--text-2);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.ruler-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 2.5rem; padding: 0 var(--space-3);
  border: 1px solid var(--control); border-radius: var(--radius-2); background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--text-2); cursor: pointer;
}
.ruler-btn:hover { background: var(--raised); }
.ruler-btn:disabled { color: var(--text-muted); border-color: var(--border); cursor: default; background: var(--surface); }
.ruler-btn--icon { width: 2.5rem; padding: 0; }
/* Start over: its slot is held while it has nothing to undo, so the buttons beside it never move (CLS 0). */
.ruler-btn--reset[data-off] { visibility: hidden; }

.ruler-panel { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.map-landing[data-sheet="closed"] .ruler-panel { display: none; }
.ruler-sheet.has-record .ruler-panel { visibility: hidden; }

/* ---- the analytics strip: one container split by hairlines; figures are type, the chart one hue ---- */
/* The strip holds its filled height from the first paint (100px here, 145px on a phone), so the table
   under it never moves when the first answer fills it (D-31 CLS; review of lane map-c: 0.11-0.15 on a
   phone for a link that opens the sheet). */
.ruler-strip {
  flex: none; display: grid; grid-template-columns: 176px 216px minmax(0, 560px) minmax(0, 1fr); min-height: 100px; margin: 0 16px;
}
.ruler-tile { min-width: 0; padding: 10px 16px 6px; border-left: 1px solid var(--rule); }
.ruler-tile:first-child { padding-left: 0; border-left: 0; }
.ruler-tile__k {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-2);
  font-size: var(--text-1); line-height: 16px; color: var(--text-muted); white-space: nowrap;
}
.ruler-tile__v { font-size: 1.5rem; line-height: 30px; font-weight: 400; white-space: nowrap; }
.ruler-tile__v small { margin-left: 4px; font-size: var(--text-2); color: var(--text-muted); }
/* The count's own unit ("1,145 projects") is printed where the tile has no label above it: on a phone. */
.ruler-tile__ph { display: none; }
.ruler-tile__s { font-size: var(--text-1); line-height: 18px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ruler-tile__line { font-size: var(--text-1); line-height: 18px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ruler-tile__line b { font-weight: 500; color: var(--text); }
/* A licence's required words never cut off with an ellipsis; the (i) fits the 16px label row. */
.ruler-tile__must { white-space: normal; }
.ruler-tile__k .map-info { width: 1.5rem; height: 1.5rem; margin: -4px 0; }
.ruler-link {
  min-height: 1.5rem; padding: 0; border: 0; background: none; color: var(--text); font: inherit; font-size: var(--text-1);
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.ruler-tile--wait .ruler-tile__v::before { content: ""; display: inline-block; width: 5ch; height: 0.9em; border-radius: var(--radius-1); background: var(--border); }
.ruler-chart { display: block; width: 100%; height: 64px; overflow: visible; }
.ruler-chart text { font: 400 12px/1 var(--font-body); fill: var(--text-muted); }
.ruler-chart text.cap { fill: var(--text); }
.ruler-chart .bar { fill: var(--chart-1); }
.ruler-chart .bar.off { fill: var(--chart-off); }
.ruler-chart .base { stroke: var(--border); stroke-width: 1; }
.ruler-chart [role="button"] { cursor: pointer; }
.ruler-chart [role="button"]:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.ruler-chart rect.hit { fill: transparent; }
/* The chart's table for assistive technology sits in the peek too (on a phone and from 720px): its figures
   right-aligned, as in any table. */
.ruler-strip table th + th, .ruler-strip table td + td { text-align: right; }
/* Generation at the top of the list (owner, 2026-11-02): one header line (the title, then the range, the unit and
   the (i) at the right), a line of small swatches, and the chart at the block's whole width. It scrolls with the
   rows; the table's head sticks over it. */
.ruler-gen { margin: 0 16px; padding: var(--space-2) 0 var(--space-3); border-bottom: 1px solid var(--rule); }
.ruler-gen[hidden] { display: none; }
.ruler-gen__head { display: flex; align-items: center; gap: var(--space-2); min-height: 2rem; }
.ruler-gen__title { flex: 1 1 auto; min-width: 0; margin: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-2); font-weight: 500; color: var(--text); }
.ruler-gen__ctl { display: flex; flex: none; align-items: center; gap: var(--space-2); }
.ruler-gen .ruler-gen__range { margin: 0; }
.ruler-gen .ruler-gen__range button { min-width: 2.25rem; min-height: 1.75rem; padding: 0 var(--space-2); }
.ruler-gen__ctl .map-info { width: 1.75rem; height: 1.75rem; }
.ruler-gen__body { min-width: 0; }
.ruler-gen .ruler-gen__legend { gap: 2px var(--space-3); margin: 2px 0 var(--space-1); }
.ruler-gen .ruler-gen__legend .ops-legend__key { width: 0.5rem; height: 0.5rem; }
.ruler-gen__chart { margin: 0; }
.ruler-gen__chart .ops-chart__plot { height: 8.5rem; }
@media screen and (max-width: 719px) {
  .ruler-gen .ruler-gen__range button { min-height: 2.25rem; }
  .ruler-gen__ctl .map-info { width: 2.25rem; height: 2.25rem; }
  /* A phone has no room for both on one line: the title, then the controls under it. */
  .ruler-gen__head { flex-wrap: wrap; row-gap: 2px; }
  .ruler-gen__title { flex-basis: 100%; font-size: var(--text-1); }
}
.ruler-chart g:hover .bar { opacity: .82; }
.ruler-tip {
  position: fixed; z-index: 30; pointer-events: none; padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius-1);
  background: var(--surface); box-shadow: var(--shadow-float); font-size: var(--text-1); line-height: 16px; color: var(--text-muted); white-space: nowrap;
}
.ruler-tip b { display: block; font-size: var(--text-2); line-height: 20px; color: var(--text); font-weight: 600; }
.ruler-tip[hidden] { display: none; }

/* ---- the table: sortable headers and a filter row under them; rows 36px ---- */
.ruler-tools:empty { display: none; }
.ruler-table { flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain; }
.ruler-dt { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: var(--text-2); }
/* The columns' widths, by class (map.js COLS): a style attribute would break the site's policy. */
.ruler-dt col.ruler-col--type { width: 168px; }
.ruler-dt col.ruler-col--capacity_mw { width: 120px; }
.ruler-dt col.ruler-col--use { width: 92px; }
.ruler-dt col.ruler-col--state { width: 96px; }
.ruler-dt col.ruler-col--company { width: 18%; }
.ruler-dt col.ruler-col--online { width: 124px; }
.ruler-dt col.ruler-col--what { width: 104px; }
.ruler-dt col.ruler-col--status { width: 136px; }
.ruler-dt col.ruler-col--source_id { width: 136px; }
/* Under 1440px the narrower columns give Name its room (2026-11-02: at 1280 the fixed columns left Name about
   25px, none once Use was wider). */
@media (max-width: 1439px) {
  .ruler-dt col.ruler-col--type { width: 132px; }
  .ruler-dt col.ruler-col--company { width: 16%; }
  .ruler-dt col.ruler-col--online { width: 96px; }
  .ruler-dt col.ruler-col--status { width: 112px; }
  .ruler-dt col.ruler-col--source_id { width: 104px; }
}
@media (max-width: 1279px) {
  .ruler-dt col.ruler-col--type { width: 112px; }
  .ruler-dt col.ruler-col--company { width: 12%; }
  .ruler-dt col.ruler-col--online { width: 80px; }
  .ruler-dt col.ruler-col--status { width: 96px; }
  .ruler-dt col.ruler-col--source_id { width: 88px; }
}
.ruler-dt th, .ruler-dt thead td {
  position: sticky; z-index: 2; background: var(--surface); text-align: left; font-weight: 400; color: var(--text-muted); padding: 0 8px;
}
.ruler-dt thead tr.ruler-dt__h th { top: 0; height: 36px; font-size: var(--text-1); }
.ruler-dt th:first-child, .ruler-dt td:first-child { padding-left: 16px; }
.ruler-dt th:last-child, .ruler-dt td:last-child { padding-right: 16px; }
.ruler-dt .r { text-align: right; }
.ruler-dt th button {
  display: inline-flex; align-items: center; gap: 4px; min-height: 28px; padding: 0; border: 0; background: none;
  color: inherit; font: inherit; cursor: pointer;
}
.ruler-dt th[aria-sort] button { color: var(--text); font-weight: 500; }
.ruler-dt th button .arr { display: inline-block; width: 10px; text-align: center; }
.ruler-dt tbody td {
  height: 36px; padding: 0 8px; border-bottom: 1px solid var(--rule); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-muted);
}
.ruler-dt tbody td.nm a { color: var(--text); font-weight: 500; text-decoration: none; }
.ruler-dt tbody td.nm a:hover, .ruler-dt tbody td.nm a:focus-visible { text-decoration: underline; }
.ruler-dt tbody td.mw { color: var(--text); }
.ruler-dt tbody td small { margin-left: 3px; font-size: var(--text-1); color: var(--text-muted); }
.ruler-dt tbody tr:hover td, .ruler-dt tbody tr.is-hover td { background: var(--raised); }
/* The whole row opens its record (map.js, the table's click), so the whole row says so (owner, 2026-10-31:
   "the select areas appear to be tiny, smaller than the icons or text"). */
.ruler-dt tbody tr[data-i] { cursor: pointer; }
.ruler-dt tbody tr[aria-current="true"] td { background: var(--active); }
.ruler-cell {
  display: inline-flex; align-items: center; gap: 8px; max-width: 100%; min-width: 24px; min-height: 28px; padding: 0; border: 0; background: none;
  color: inherit; font: inherit; text-align: left; cursor: pointer; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.ruler-cell:hover { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.ruler-cell span { overflow: hidden; text-overflow: ellipsis; }
.ruler-ico { flex: none; width: 16px; height: 16px; color: var(--text-muted); }
.ruler-dash { color: var(--text-muted); }
.ruler-foot { flex: none; margin: 0; padding: 8px 16px 12px; border-top: 1px solid var(--rule); font-size: var(--text-1); }
.ruler-foot:has(> [hidden]) { display: none; }
.ruler-foot .ruler-link { display: inline-flex; align-items: center; min-height: 1.5rem; }
.ruler-more { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); padding: 10px 16px 14px; color: var(--text-muted); font-size: var(--text-1); }
.ruler-asof:empty { display: none; }
.ruler-asof { padding: 0 16px 14px; }
.ruler-asof .as-of-line, .ruler-record .as-of-line { margin: 0 0 var(--space-2); }
.ruler-empty { margin: 16px; padding: 10px 12px; border: 1px dashed var(--border); border-radius: var(--radius-2); color: var(--text-muted); }

/* ---- a record over the sheet's body, with Back ---- */
.ruler-record {
  position: absolute; z-index: 3; left: 0; right: 0; top: 88px; bottom: 0; overflow-y: auto; overscroll-behavior: contain;
  background: var(--surface); border-top: 1px solid var(--border);
}
.ruler-record[hidden] { display: none; }
/* The band's Back is a phone's alone; from 720px the record's own bar holds Back. */
.ruler-band__back { display: none; }
.ruler-record__bar { position: sticky; top: 0; display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) 16px; background: var(--surface); }
.ruler-record__body { max-width: 60rem; padding: 0 16px var(--space-5); }
/* the record itself is section style E: see "The map's record preview" at the end of this file */

/* ---- a tablet or a narrow window ---- */
@media (max-width: 1099px) {
  .ruler-band { grid-template-columns: 184px minmax(0, 1fr) auto; gap: 16px; }
  .ruler-band__title { font-size: var(--text-2); line-height: 20px; }
  /* Count over name, each on one line: "Under construction" fits a third of the ruler from 720px. */
  .ruler__lbl { flex-direction: column; align-items: flex-start; gap: 0; line-height: 16px; }
  .ruler__count { font-size: 1.25rem; line-height: 26px; }
  .ruler__name { font-size: 0.8125rem; }
  .ruler__stop { grid-template-rows: 26px auto; padding-top: 10px; }
  .map-landing:not([data-sheet="closed"]) .ruler-band { grid-template-columns: minmax(0, 1fr) auto; }
  .map-landing:not([data-sheet="closed"]) .ruler-band__title {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .ruler-strip { grid-template-columns: 140px 170px minmax(0, 1fr); min-height: 130px; }
  .ruler-tile--src { grid-column: 1 / -1; padding: 2px 0 6px; border-left: 0; border-top: 1px solid var(--rule); }
  .ruler-tile--src .ruler-tile__k { display: inline-flex; margin-right: var(--space-1); vertical-align: middle; }
  .ruler-tile--src .ruler-tile__line { display: inline; }
  .ruler-tile--src .ruler-tile__line + .ruler-tile__line::before { content: " · "; }
}

/* ---- a phone or a short window: the size key folds behind "Key", and opens above it ---- */
@media (max-width: 719px), (max-height: 37.5rem) {
  .map-key__toggle { display: inline-flex; }
  .map-key:not(.is-open) .map-key__body { display: none; }
  .map-landing .map-key.is-open { z-index: 2; }
  /* Folded, the key opens as a card floating over the map, as the credits do: an overlay, so it casts the
     float shadow. Its height is capped to the map's room (below), so a card that cannot show every row
     scrolls, and map.js lets the keyboard reach it then (axe scrollable-region-focusable). */
  .map-key__body { position: absolute; left: 0; bottom: calc(100% + var(--space-2)); overflow-y: auto; overscroll-behavior: contain; box-shadow: var(--shadow-float); } /* taste-skill-ignore */
}

/* ---- a short window from 720px (a phone on its side, 844x390): the zoom column is a row under the bar,
   so the sheet's band never lies over Reset ---- */
@media (min-width: 720px) and (max-height: 37.5rem) {
  .map-landing .map-overlay__rail, .map-landing .map-overlay__rail .map-controls { flex-direction: row; }
  .map-under { top: calc(var(--landing-inset) + 2 * var(--landing-bar-h) + var(--space-3)); }
  /* The key opens beside Key, never above the floating bar (review of lane map-d, finding 2: at 750x342
     it opened under the section bar, its title and two counts unreadable): its foot is Key's, and its
     height the room from Key's foot up to the bar's, the landing's height less the sheet, the insets
     and the bar. Open, the sheet leaves the map too thin a strip for it, as on a phone. */
  /* Key is as wide as the zoom pair above it (2 x 2.5rem and its gap), so the card clears both buttons. */
  .map-key__toggle { width: 5.5rem; justify-content: center; }
  /* Scoped past the every-width fold's ".map-key.is-open .map-key__body" (lane 2a), which would otherwise
     open the card above Key, under the floating bar, again. */
  .map-key__body, .map-landing .map-key.is-open .map-key__body {
    left: calc(100% + var(--space-2)); bottom: 0;
    max-height: calc(100vh - var(--top-bar-h) - var(--sheet-closed) - 2 * var(--landing-inset) - var(--landing-bar-h) - var(--space-2));
    max-height: calc(100dvh - var(--top-bar-h) - var(--sheet-closed) - 2 * var(--landing-inset) - var(--landing-bar-h) - var(--space-2));
  }
  .map-landing:not([data-sheet="closed"]) .map-key { display: none; }
}

/* ---- phones: a bottom sheet; the three stages are tabs on top of it; the table is two-line rows ---- */
@media (max-width: 719px) {
  .map-landing {
    --landing-inset: var(--space-2);
    --sheet-closed: 120px;
    --sheet-half: min(560px, calc(100% - 184px));
  }
  /* On a phone the site's header gives way too, so the list fills the screen up to the map strip. */
  body:has(#map-landing[data-sheet="full"]) .top-bar { display: none; }
  .map-landing[data-sheet="full"] { height: 100vh; height: 100dvh; }
  /* The credits chip (44px on touch) sits inside the 48px strip, never under the sheet's edge. */
  .map-float { flex-wrap: wrap; row-gap: var(--space-2); }
  .map-landing .map-search { flex: 1 1 100%; min-width: 0; }
  .map-chip { min-height: 2.75rem; }
  .map-landing:not([data-sheet="closed"]) .map-chip--place { display: none; }
  /* The base map's button under Find, a row lower while a place or filters chip row lies under it, and Reset
     under the button (+ and - are not drawn on a phone). */
  .map-landing { --float-rows: 1; }
  .map-landing .map-controls--base { top: calc(var(--landing-inset) + var(--float-rows) * (2.75rem + var(--space-2))); }
  .map-landing .map-controls--base button { width: 2.75rem; height: 2.75rem; }
  .map-landing:not([data-sheet="closed"]) .map-controls--base { display: none; }
  .map-landing .map-overlay__rail { top: calc(var(--landing-inset) + (var(--float-rows) + 1) * (2.75rem + var(--space-2))); left: auto; right: var(--landing-inset); align-items: flex-end; }
  .map-landing .map-overlay__rail .map-controls button { min-width: 2.75rem; min-height: 2.75rem; }
  .map-landing .map-overlay__rail > .map-controls > button { width: 2.75rem; height: 2.75rem; padding: 0; }
  .map-landing:not([data-sheet="closed"]) .map-overlay__rail { display: none; }
  /* US · GB sits beside Key on the row above the sheet, over the Gulf, not over the lower 48's coast. */
  .map-key__toggle { width: 5rem; justify-content: center; }
  /* Open, the sheet leaves the map a strip: the key and the pair go with the rail, and come back on closing. */
  .map-landing:not([data-sheet="closed"]) .map-key { display: none; }
  /* The key opens above Key, its height capped to the room between Key and the floating bar's two rows
     (6.25rem, where the zoom column starts); where a phone on its side leaves less than that, it may lie
     over the chips, up to 7rem, but never above the map's top. */
  .map-key__body {
    max-height: max(
      calc(100vh - var(--top-bar-h) - var(--sheet-closed) - 2 * var(--landing-inset) - 9rem - var(--space-2)),
      min(7rem, calc(100vh - var(--top-bar-h) - var(--sheet-closed) - 2 * var(--landing-inset) - 2.75rem - var(--space-2)))
    );
    max-height: max(
      calc(100dvh - var(--top-bar-h) - var(--sheet-closed) - 2 * var(--landing-inset) - 9rem - var(--space-2)),
      min(7rem, calc(100dvh - var(--top-bar-h) - var(--sheet-closed) - 2 * var(--landing-inset) - 2.75rem - var(--space-2)))
    );
  }
  .map-under { left: var(--landing-inset); right: calc(2 * var(--landing-inset) + 2.75rem); width: auto; top: calc(var(--landing-inset) + var(--float-rows) * (2.75rem + var(--space-2))); }
  .map-credits__toggle { min-height: 2.75rem; }
  .ruler-sheet { border-radius: 16px 16px 0 0; border: 1px solid var(--border); border-bottom: 0; }
  .ruler-band { height: auto; display: block; padding: 14px 16px 0; }
  .map-landing:not([data-sheet="closed"]) .ruler-band { padding-top: 34px; }
  .ruler-band__title { font-size: 1rem; line-height: 22px; margin: 0 8.75rem 4px 0; }
  .map-landing:not([data-sheet="closed"]) .ruler-band__title {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; margin: 0;
  }
  .ruler-band__side { position: absolute; top: 8px; right: 12px; gap: var(--space-2); }
  .ruler-why { display: none; }
  .ruler-band__side .map-info { width: 2.75rem; height: 2.75rem; }
  .map-landing:not([data-sheet="closed"]) .ruler-band__side .map-info { height: 1.75rem; }
  .map-switch-row .map-info { width: 2.75rem; height: 2.75rem; }
  .ruler-btn { min-height: 2.75rem; }
  .ruler-btn--icon { width: 2.75rem; }
  .map-landing:not([data-sheet="closed"]) .ruler-band__side { top: 4px; }
  /* Open, the two height buttons sit above the tabs, 44px wide and 28px tall (SC 2.5.8's 24px and more). */
  .map-landing:not([data-sheet="closed"]) .ruler-btn--icon { min-height: 1.75rem; height: 1.75rem; }
  .ruler { height: 60px; }
  .ruler::before { display: none; }
  .ruler__stop { justify-self: stretch; grid-template-rows: auto; height: 60px; padding: 6px 0 0; }
  .ruler__pin { display: none; }
  .ruler__count { font-size: 1.125rem; line-height: 24px; }
  .ruler__name { font-size: 0.8125rem; line-height: 16px; }
  .ruler__stop[aria-selected="true"]::after { right: 8px; }
  .ruler-strip { grid-template-columns: auto minmax(0, 1fr); min-height: 145px; box-sizing: border-box; column-gap: 16px; padding-top: 8px; align-content: start; }
  .ruler-tile { padding: 0 0 0 12px; }
  .ruler-tile:first-child { padding-left: 0; }
  .ruler-tile:nth-child(-n + 2) .ruler-tile__k { display: none; }
  .ruler-tile__v { font-size: 1.25rem; line-height: 26px; }
  .ruler-tile:nth-child(-n + 2) .ruler-tile__s { display: none; }
  .ruler-tile__v .ruler-tile__ph { display: inline; }
  .ruler-tile--chart { grid-column: 1 / -1; padding: 4px 0 0; border-left: 0; }
  .ruler-chart { height: 56px; }
  .ruler-tile--src { padding: 4px 0; border-top: 0; }
  .ruler-tile--src { display: none; } /* its (i) is reached from the stages' (i), whose freshness line names the sources */
  .ruler-tile--src .ruler-tile__line + .ruler-tile__line::before { content: none; }
  /* "Sort and filter" holds its row from the first paint too (61px: the 44px button, its padding and rule). */
  .ruler-tools, .ruler-tools:empty { display: flex; align-items: center; gap: var(--space-2); min-height: 61px; box-sizing: border-box; padding: var(--space-2) 16px; border-bottom: 1px solid var(--border); }
  .ruler-rows { list-style: none; margin: 0; padding: 0; }
  .ruler-row {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(3rem, auto) auto; grid-template-rows: 20px 18px; column-gap: 12px; row-gap: 2px;
    align-content: center; min-height: 56px; padding: 0 16px; border-bottom: 1px solid var(--rule); color: var(--text); text-decoration: none;
  }
  .ruler-row__nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
  .ruler-row__mw { white-space: nowrap; text-align: right; }
  .ruler-row__use { white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; }
  .ruler-row__mw small, .ruler-row__use small { margin-left: 3px; font-size: var(--text-1); color: var(--text-muted); }
  .ruler-row__meta { grid-column: 1 / -1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.8125rem; color: var(--text-muted); }
  .ruler-foot { padding: 0 16px; }
  .ruler-foot .ruler-link { min-height: 2.75rem; }
  .ruler-record { top: 82px; }
}
/* ---- lane landing-and-map (2026-10-30): Filters, the filters on, the drill chips, the examples, the
   headline and method line, the imagery note. One quiet surface style throughout; the marks keep the only
   colour. Every piece is absolutely placed over the map or inside the sheet's own rows, so nothing moves
   another when data lands (docs/30 §11.7). ---- */
.map-chip__n { color: var(--text-muted); font-weight: 400; font-variant-numeric: tabular-nums; }

/* Two tracks that may shrink below their content (`minmax(0, 1fr)`) and controls that fill them: a plain `1fr` track's
   floor is its content's min-content width, a number input's default (about 236px in Chromium), so the pairs were
   about 500px wide in a 358px panel on a phone, which then scrolled sideways (owner, 2026-11-01, iPhone: "the mobile
   filter list moves left and right"). */

/* The drill chips over All: one row per facet, each chip with its count; a row scrolls sideways on a phone. */

/* The hover card (map.js `hoverAt`): beside the mark under a mouse or a pen, placed with a transform so nothing
   moves; the record panel's type scale; a float, so the one float shadow the app screens allow. */
.map-hover {
  position: absolute; left: 0; top: 0; z-index: 4; box-sizing: border-box; max-width: 16rem; padding: var(--space-2) var(--space-3);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2); color: var(--text);
  box-shadow: var(--shadow-float); font-size: var(--text-1); line-height: 18px; cursor: pointer; pointer-events: auto;
}
.map-hover[hidden] { display: none; }
.map-hover p { margin: 0; }
.map-hover__name { font-size: var(--text-2); line-height: 20px; font-weight: 600; }
.map-hover__meta { color: var(--text-muted); }
.map-hover__mw { font-variant-numeric: tabular-nums; }
.map-hover p.map-hover__hint { margin-top: var(--space-1); color: var(--text-muted); }
/* The named examples: a short label on its dot, placed by map.js with a transform (no layout shift). */
.map-examples { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; overflow: hidden; }
.map-landing .map-overlay > .map-examples { pointer-events: none; z-index: 0; }
/* Half open on a laptop the map is a short strip: the folded key gives way to Jump to and Reset. */
@media (max-height: 1000px) { .map-landing[data-sheet="half"] .map-key { display: none; } }
.map-landing .map-float { z-index: 3; }
.map-examples:not(.is-placed) { visibility: hidden; }
.map-landing:not([data-sheet="closed"]) .map-examples { display: none; }
.map-example { position: absolute; left: 0; top: 0; pointer-events: none; will-change: transform; }
.map-example.is-off { visibility: hidden; }
.map-example a {
  position: absolute; left: 6px; bottom: 4px; display: block; width: max-content; max-width: 15rem; pointer-events: auto;
  padding: 3px 8px 4px; border: 1px solid var(--control); border-radius: var(--radius-2); background: var(--surface);
  color: var(--text); font-size: var(--text-1); line-height: 16px; font-weight: 500; text-decoration: none;
}
.map-example a:hover { border-color: var(--text); }
.map-example a:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.map-example__k { display: block; font-weight: 400; color: var(--text-muted); }


/* The headline and the method line, in the band's first column. */
.ruler-band__head { min-width: 0; }
.map-landing .ruler-band__title { font-size: 1.125rem; line-height: 24px; letter-spacing: -0.005em; }
.ruler-band__method { margin: 2px 0 0; font-size: var(--text-1); line-height: 18px; color: var(--text-muted); }
.map-landing .ruler { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.map-landing .ruler::before { right: calc(25% - 8px); }
/* Idling or retired: the faintest fade step in the ink, its rim full (the key's "Rarely runs"). */
.ruler__pin--idle::after {
  inset: 3px; background: color-mix(in oklab, var(--text) 30%, var(--map-land)); border: 1px solid var(--text);
}
/* The size key folds behind Key at every width: its rows are a click away, and the landing keeps its word
   budget (decisions log 2026-10-29, Cleanview practices (3)). */
.map-key__toggle { display: inline-flex; }
.map-key:not(.is-open) .map-key__body { display: none; }
.map-key.is-open .map-key__body { position: absolute; left: 0; bottom: calc(100% + var(--space-2)); box-shadow: var(--shadow-float); } /* taste-skill-ignore */
@media (max-width: 1099px) {
  .map-landing .ruler-band__title { font-size: var(--text-2); line-height: 20px; }
  .ruler-band__method { display: none; }
}
@media (max-width: 719px) {
  .map-examples { display: none; }
  /* Key is its glyph on a phone, its name kept for assistive technology (the 30-word budget). */
  .map-key__word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .map-key__toggle { width: 2.75rem; padding: 0; }
}

/* The handle: from 720px the pill on the sheet's top edge, a 48x24 button; on a phone it leads the row. */
.ruler-sheet__grab {
  position: absolute; z-index: 1; top: 0; left: 50%; width: 3rem; height: 1.5rem; margin: 0 0 0 -1.5rem; padding: 0;
  display: flex; align-items: flex-start; justify-content: center; border: 0; border-radius: var(--radius-2); background: none; color: var(--text-muted); cursor: pointer;
}
.ruler-sheet__grab:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.ruler-sheet__pill { display: block; width: 36px; height: 4px; margin-top: 6px; border-radius: 2px; background: var(--border); }
.ruler-sheet__grab:hover .ruler-sheet__pill { background: var(--control); }
.ruler-sheet__chev { display: none; }
/* The drag's three heights, read off these probes (map.js `snapHeights`): a finger on a phone, a mouse from 720px. */
.ruler-sheet.is-dragging { transition: none; }
.ruler-sheet__probe { position: absolute; left: 0; bottom: 0; width: 0; visibility: hidden; pointer-events: none; }
.ruler-sheet__probe--closed { height: var(--sheet-closed); }
.ruler-sheet__probe--half { height: var(--sheet-half); }
.ruler-sheet__probe--full { height: calc(100% - var(--map-strip)); }
.ruler-strip { min-height: 128px; }
.map-about__fresh { color: var(--text-muted); }
.map-about__fresh:empty { display: none; }
.top-bar__here { display: none; }
@media (max-width: 479px) {
}
@media (max-width: 1099px) {
  .ruler-strip { min-height: 158px; }
}

/* ---- the map on a phone, decluttered (owner, 2026-10-30: "Could we move the two tiered top bar into one?
   Remove the big open street map box? Move the filters to the top of the slider? Maybe collapse all this
   info on scroll to maximize space for the list?") ---- */
@media (max-width: 719px) {
  /* One top bar: the wordmark, the page's name and Menu; the section's pages are in Menu, and Find on the
     map is the search directly under the bar. */
  body:has(#map-landing) .search-toggle { display: none; }
  body:has(#map-landing) .top-bar__here {
    display: block; align-self: center; margin-inline-start: var(--space-3); padding-inline-start: var(--space-3); border-inline-start: 1px solid var(--border);
    font-size: var(--text-2); line-height: 20px; font-weight: 500; color: var(--text);
  }
  /* The closed sheet is the peek (owner, 2026-10-31: "the list doesn't really appear at all. It would be nice
     to make it more prominent and be able to flick it up and scroll"): the band's row, the stage switch and
     the first three and a half rows (61 + 52 + 3.5 x 57px; direction D), under half a short phone. The
     strip waits for the half and full heights; at the peek the list does not scroll, so a drag on it moves the
     sheet (map.js, the sheet's drag). Every height is drawn from first paint, so nothing shifts (CLS 0). */
  .map-landing { --sheet-closed: min(313px, 46dvh); }
  .map-landing[data-sheet="closed"] .ruler-band { border-bottom: 1px solid var(--border); }
  .map-landing[data-sheet="closed"] .ruler-panel { display: block; overflow: hidden; }
  .map-landing[data-sheet="closed"] .ruler-strip {
    position: absolute; width: 1px; height: 1px; min-height: 0; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .map-landing .ruler-band__title { margin: 0; }
  /* While a finger drags the sheet it follows at once; the settle after it slides (none under reduced motion). */
  .map-landing .ruler-band,
  .map-landing:not([data-sheet="closed"]) .ruler-band {
    display: flex; align-items: center; gap: 2px; height: 61px; padding: 8px var(--space-2) 8px var(--space-1);
  }
  .map-landing .ruler-band__head { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .map-landing .ruler-sheet__grab {
    position: static; flex: none; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    width: 2.75rem; height: 2.75rem; margin: 0; color: var(--text-muted);
  }
  .map-landing .ruler-sheet__pill { width: 20px; margin: 0; }
  .map-landing .ruler-sheet__chev { display: block; }
  .map-landing[data-sheet="full"] .ruler-sheet__chev { transform: rotate(180deg); }
  .map-landing .ruler-band__side,
  .map-landing:not([data-sheet="closed"]) .ruler-band__side { position: static; flex: none; gap: 0; }
  .map-landing .ruler-band__side .map-info,
  .map-landing:not([data-sheet="closed"]) .ruler-band__side .map-info { width: 2.75rem; height: 2.75rem; }
  /* The handle does the height buttons' job on a phone, so start over takes their place at the row's right end. */
  .map-landing .ruler-btn--reset,
  .map-landing:not([data-sheet="closed"]) .ruler-btn--reset { width: 2.75rem; height: 2.75rem; min-height: 2.75rem; border-color: var(--border); }
  /* The body scrolls as one: the strip goes up with the list, under the band and the stage switch. */
  .map-landing .ruler-panel { display: block; overflow-y: auto; overscroll-behavior: contain; }
  .map-landing .ruler-table { overflow: visible; }
  .map-landing .ruler-tools, .map-landing .ruler-tools:empty { display: none; }
  .map-landing .ruler-tile--src { display: none; }
  .map-landing .ruler-strip { min-height: 112px; }
  .map-landing .ruler-record { top: 62px; }
  /* With the list peeking, the key has less height above it: on a phone it takes the screen's width and sets
     the stages two to a row, so it still shows every row without scrolling. */
  .map-landing .map-key__body { width: calc(100vw - 2 * var(--landing-inset)); max-width: 24rem; }
  .map-landing .map-key .map-key__kinds { grid-template-columns: 1fr; }
}

/* ---- stage apart from type, size and state (direction D; owner, 2026-10-31: "I feel like we should consider
   separating stage from type and scale and region") ----
   Stage is a four-part switch, a radio group: from 720px a segmented track in the band, on a phone the sheet's
   figures row under the band's one row. Type, size and state sit behind one button that names what is on.
   Every cell's size is fixed from first paint, so a count or a GW figure arriving moves nothing (CLS 0). */
.ruler-stagebar {
  display: grid; grid-template-columns: repeat(4, auto); gap: 2px; justify-self: start; min-width: 0; padding: 2px;
  border: 1px solid var(--border); border-radius: var(--radius-2); background: var(--raised);
}
.ruler-stagebar__cell {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 2.25rem; padding: 0 var(--space-3);
  border: 1px solid transparent; border-radius: var(--radius-1); background: none; color: var(--text-muted);
  font: inherit; font-size: var(--text-2); white-space: nowrap; cursor: pointer;
}
.ruler-stagebar__cell:hover { color: var(--text); }
.ruler-stagebar__cell[aria-pressed="true"] { background: var(--surface); border-color: var(--control); color: var(--text); font-weight: 600; }
.ruler-stagebar__cell:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.ruler-stagebar__n { font-weight: 500; color: var(--text); font-variant-numeric: tabular-nums; }
.ruler-stagebar__cell[aria-pressed="true"] .ruler-stagebar__n { font-weight: 600; }
.ruler-stagebar .ruler__pin { flex: none; }
.ruler-stagebar .ruler__name { font-size: inherit; }
.ruler__short { display: none; }
/* The Type · size · state button: what is on, cut with an ellipsis, and how many. */
/* The band's one row: the track and the sheet's own button (start over). The headline and the method line are
   for assistive technology only at every width, as on a phone (owner, 2026-11-02: "Could we apply the recent
   mobile updates to the desktop version?"). With four counted stops (Idling or retired the longest) the track's
   full form (pins, "Under construction") needs 1536px (measured 2026-10-31). */
.map-landing .ruler-band,
.map-landing:not([data-sheet="closed"]) .ruler-band { grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--space-3); }
.map-landing .ruler-band__head { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
@media (max-width: 1535px) {
  .ruler-stagebar .ruler__pin { display: none; }
  .ruler-stagebar__cell { padding: 0 var(--space-2); }
  .ruler__long { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .ruler__short { display: inline; }
}
/* Idling or retired keeps its full name on a desktop, from 1024px; a phone and a tablet show "Idling" (owner,
   2026-10-31: "Let's do 'idling or retired' on desktop"). */
@media (min-width: 1024px) and (max-width: 1535px) {
  .ruler__name--phone .ruler__long { position: static; width: auto; height: auto; overflow: visible; clip-path: none; }
  .ruler__name--phone .ruler__short { display: none; }
}
@media (max-width: 1279px) {
  .ruler-stagebar__cell { padding: 0 6px; }
}
/* The panel: Type, size and state first, each group named over its counted choices, then the State list. */
@media (max-width: 719px) {
  /* The band: the handle, the button, the (i) and the × on one row; the switch, edge to edge, under them. */
  .map-landing .ruler-band,
  .map-landing:not([data-sheet="closed"]) .ruler-band,
  .map-landing[data-sheet="closed"] .ruler-band { flex-wrap: wrap; row-gap: 8px; height: auto; padding-bottom: 0; border-bottom: 0; }
  .map-landing .ruler-stagebar {
    order: 9; flex: none; box-sizing: border-box; width: calc(100% + var(--space-1) + var(--space-2)); margin: 0 calc(-1 * var(--space-2)) 0 calc(-1 * var(--space-1));
    grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; padding: 0;
    border: 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); border-radius: 0; background: var(--surface);
  }
  .map-landing .ruler-stagebar__cell,
  .map-landing .ruler-stagebar__cell[aria-pressed="true"] {
    position: relative; flex-direction: column-reverse; align-items: flex-start; justify-content: center; gap: 0; min-width: 0; height: 50px;
    padding: 4px 10px; border: 0; border-radius: 0; background: none; font-weight: 400; text-align: left;
  }
  .map-landing .ruler-stagebar__n { font-size: var(--text-3); line-height: 1.15; }
  .map-landing .ruler-stagebar .ruler__name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; font-size: var(--text-1); line-height: 1.3; }
  .map-landing .ruler-stagebar__cell[aria-pressed="true"] .ruler__name { color: var(--text); }
  .map-landing .ruler-stagebar__cell + .ruler-stagebar__cell::before {
    content: ""; position: absolute; left: 0; top: 12px; bottom: 12px; width: 1px; background: var(--rule);
  }
  .map-landing .ruler-stagebar__cell[aria-pressed="true"]::after {
    content: ""; position: absolute; left: 10px; right: 10px; bottom: -1px; height: 2px; background: var(--text);
  }
  .map-landing .ruler-stagebar__cell:focus-visible { outline-offset: -2px; }
  /* The first figure lines up with the rows' 16px margin under it. */
  .map-landing .ruler-stagebar__cell:first-child { padding-left: 16px; padding-right: 4px; }
  .map-landing .ruler-stagebar__cell:first-child::after { left: 16px; }
}
@media (max-width: 379px) {
  .map-landing .ruler-stagebar__cell, .map-landing .ruler-stagebar__cell[aria-pressed="true"] { padding-inline: 6px; }
  .map-landing .ruler-stagebar__cell:first-child { padding-left: 12px; padding-right: 2px; }
  .map-landing .ruler-stagebar__cell[aria-pressed="true"]::after { left: 6px; right: 6px; }
  .map-landing .ruler-stagebar__cell:first-child::after { left: 12px; }
}
/* ---- the list's peek from 720px (owner, 2026-10-31: "should we do the same update to desktop as we did for
   mobile? Hinting at the lower list, maybe after first clicking a tab or doing a search?") ----
   Closed, the sheet is the band (no "List" row, owner 2026-11-02: the phone's simplification on the desktop)
   and the list's first rows (owner, 2026-11-02: "make a 2-3 list records appear at the bottom, bellow the
   summary"): the table's head and two whole rows, 1 + 88 + 36 + 2 x 36 = 197px at every height. The head is
   drawn at the peek too, so opening the sheet moves no row inside it (CLS 0); hover over the rows opens it to
   half and the map closes it again (map.js `hoverSheet`). The strip waits for the half and full heights and
   stays for assistive technology, as on a phone. The first stage chosen or search made opens the list to half
   (map.js `opensForResults`). Every height is drawn from first paint, so the rows arriving move nothing (CLS 0).
   A short window (600px tall or less) keeps the band alone: its map is thin enough already. */
@media (min-width: 720px) and (min-height: 37.51rem) {
  .map-landing { --sheet-closed: 197px; }
  /* The taller closed sheet lifts the open key; its height is capped to the room under the zoom column
     (Zoom, Jump to and Reset end about 19rem below the canvas's top), and it scrolls inside beyond that, so
     it never covers Reset. */
  .map-landing[data-sheet="closed"] .map-key__body {
    /* The peek's height written against the viewport: --sheet-closed's 20% would read as 20% of the key's
       own box here. */
    max-height: calc(100vh - var(--top-bar-h) - 197px - 2 * var(--landing-inset) - 19rem);
    max-height: calc(100dvh - var(--top-bar-h) - 197px - 2 * var(--landing-inset) - 19rem);
    overflow-y: auto; overscroll-behavior: contain;
  }
  .map-landing[data-sheet="closed"] .ruler-band { border-bottom: 1px solid var(--border); }
  .map-landing[data-sheet="closed"] .ruler-panel { display: flex; overflow: hidden; }
  .map-landing[data-sheet="closed"] .ruler-strip {
    position: absolute; width: 1px; height: 1px; min-height: 0; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .map-landing[data-sheet="closed"] .ruler-table { overflow: hidden; }
  .map-landing[data-sheet="closed"] .ruler-more,
  .map-landing[data-sheet="closed"] .ruler-asof,
  .map-landing[data-sheet="closed"] .ruler-foot { display: none; }
}
/* ---- the chip row under Find (map filters, direction A; owner, 2026-11-02: "Let's go with A") ----
   Power and Loads are split chips (the body filters, the arrow opens the groups), with the map key's dot;
   Size, Date, Owner and Source open the one dropdown. A chip that is on is the ink, its label what is on.
   One line that scrolls sideways where it does not fit; every chip drawn from first paint (CLS 0). */
.map-chiprow {
  display: flex; align-items: center; gap: var(--space-2); flex: 1 1 0; min-width: 0;
  overflow-x: auto; scrollbar-width: none; pointer-events: auto;
}
.map-chiprow::-webkit-scrollbar { display: none; }
.map-chiprow__tokens { display: contents; }
.fchip {
  display: inline-flex; align-items: center; gap: 6px; flex: none; box-sizing: border-box; height: 2.5rem; padding: 0 var(--space-3);
  border: 1px solid var(--control); border-radius: 999px; background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--text-2); white-space: nowrap; cursor: pointer;
}
.fchip:hover { border-color: var(--text); }
.fchip[hidden] { display: none; }
.fchip svg { flex: none; }
.fchip[data-on] { background: var(--text); border-color: var(--text); color: var(--surface); }
.fchip__label { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; }
.fchip--split { gap: 0; padding: 0; }
.fchip--split > button {
  display: inline-flex; align-items: center; gap: 6px; height: 100%; margin: 0; border: 0; background: none; color: inherit;
  font: inherit; cursor: pointer;
}
.fchip__body { padding: 0 var(--space-2) 0 var(--space-3); border-radius: 999px 0 0 999px; }
.fchip__arrow { padding: 0 var(--space-3) 0 var(--space-2); border-left: 1px solid var(--border) !important; border-radius: 0 999px 999px 0; }
.fchip[data-on] .fchip__arrow { border-left-color: var(--text-muted) !important; }
.fchip--split > button:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.fchip__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text); } /* power is every family: the ink, not one hue */
.fchip__dot--loads { background: var(--mark-load); }
.fchip--token { border-color: var(--text); font-weight: 500; }
.fchip--clear { border-color: transparent; background: none; text-decoration: underline; text-underline-offset: 3px; }
.fchip--clear:hover { border-color: transparent; }

/* ---- the chip row's dropdown: a popover under its chip from 720px, a bottom sheet on a phone ---- */
.map-drop {
  position: fixed; inset: auto; margin: 0; padding: 0; box-sizing: border-box; width: min(20rem, calc(100vw - 16px));
  max-height: min(32rem, calc(100dvh - 8rem)); display: none; flex-direction: column; overflow: hidden;
  color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-3); box-shadow: var(--shadow-float); /* taste-skill-ignore: an overlay, the dropdown over the map */
}
.map-drop:popover-open { display: flex; }
.map-drop__grip { display: none; }
.map-drop__title { flex: none; margin: 0; padding: var(--space-3) var(--space-4) var(--space-1); font-size: var(--text-1); font-weight: 600; color: var(--text-muted); }
.map-drop__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 0 var(--space-2); }
.map-drop__foot {
  flex: none; display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-2) var(--space-4); border-top: 1px solid var(--border);
}
.map-drop__show {
  min-height: 2.25rem; padding: 0 var(--space-3); border: 1px solid var(--control); border-radius: var(--radius-2);
  background: var(--surface); color: var(--text); font: inherit; font-size: var(--text-1); font-weight: 500; cursor: pointer;
}
.drop-row, .drop-pick {
  display: flex; align-items: center; gap: var(--space-3); box-sizing: border-box; width: 100%; min-height: 2.5rem; margin: 0;
  padding: 0 var(--space-4); border: 0; background: none; color: var(--text); font: inherit; font-size: var(--text-2); text-align: left; cursor: pointer;
}
.drop-row:hover, .drop-pick:hover { background: var(--raised); }
.drop-row input { width: 1.125rem; height: 1.125rem; margin: 0; flex: none; accent-color: var(--text); }
.drop-row__k { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.drop-n { margin-inline-start: auto; color: var(--text-muted); font-size: var(--text-1); font-variant-numeric: tabular-nums; }
.drop-row--all { font-weight: 600; border-bottom: 1px solid var(--rule); }
.drop-row--has-subs { padding-right: 3rem; }
.drop-row--sub { padding-left: calc(var(--space-4) + 1.75rem); padding-right: 3rem; }
.drop-group { position: relative; }
.drop-more {
  position: absolute; top: 0; right: var(--space-1); display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--text-muted); cursor: pointer;
}
.drop-more[aria-expanded="true"] svg { transform: rotate(180deg); }
.drop-subs[hidden] { display: none; }
.drop-pick[aria-pressed="true"] { background: var(--active); font-weight: 600; }
.drop-list { display: flex; flex-direction: column; }
.drop-sub { margin: var(--space-3) var(--space-4) var(--space-1); font-size: var(--text-1); font-weight: 600; color: var(--text-muted); }
.drop-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); padding: var(--space-2) var(--space-4) 0; }
.drop-field { display: flex; flex-direction: column; gap: 2px; min-width: 0; font-size: var(--text-1); color: var(--text-muted); }
.drop-field--wide { padding: var(--space-2) var(--space-4) 0; }
.drop-field input, .drop-field select {
  min-width: 0; width: 100%; height: 2.5rem; box-sizing: border-box; padding: 0 var(--space-2); border: 1px solid var(--control); border-radius: var(--radius-2);
  background: var(--surface); color: var(--text); font: inherit; font-size: var(--text-2); font-variant-numeric: tabular-nums;
}
.drop-seg { display: inline-flex; margin: var(--space-1) 0 0 var(--space-4); border: 1px solid var(--control); border-radius: var(--radius-2); overflow: hidden; vertical-align: middle; }
.drop-seg label { position: relative; display: inline-flex; align-items: center; min-height: 2.5rem; padding: 0 var(--space-3); cursor: pointer; font-size: var(--text-2); }
.drop-seg label + label { border-left: 1px solid var(--control); }
.drop-seg input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.drop-seg label:has(input:checked) { background: var(--active); font-weight: 600; }
.drop-seg label:has(input:focus-visible) { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.drop-info { vertical-align: middle; margin-inline-start: var(--space-1); }
.drop-none { margin: var(--space-2) var(--space-4); color: var(--text-muted); font-size: var(--text-1); }

/* ---- the layers popover: the base map's three choices and the Layers switches ---- */
.map-base-pop { min-width: 15rem; overflow-y: auto; overscroll-behavior: contain; }
.map-base-pop__group + .map-base-pop__group { border-top: 1px solid var(--border); }
.map-base-pop .map-switch-row { padding: 0 var(--space-1) 0 var(--space-3); }
.map-base-pop .map-switch { min-height: 2.75rem; font-size: var(--text-2); }
/* Colour: Status · Use, one row: the word, then the two choices as one segmented control. */
.map-paint { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-height: 3.25rem; padding: 0 var(--space-3); }
.map-paint__word { font-size: var(--text-2); }
.map-base-pop .map-paint .drop-seg { margin: 0; }
.map-base-pop .map-paint .drop-seg label { min-height: 2.5rem; padding: 0 var(--space-3); }
.map-base-pop .map-paint .drop-seg input { width: auto; height: auto; }

/* ---- what is counted, in the map's one (i) with the credits (owner, 2026-11-02) ---- */
.map-about { margin: 0 0 var(--space-3); padding: 0 0 var(--space-3); border-bottom: 1px solid var(--border); }
.map-about__title { margin: 0 0 var(--space-1); font-size: var(--text-2); font-weight: 600; }
.map-about p { margin: 0 0 var(--space-2); }
.map-about__stage summary { display: flex; align-items: center; min-height: 2rem; cursor: pointer; font-weight: 500; }
.map-about__src { color: var(--text-muted); }
.map-about__src ul { margin: 2px 0 var(--space-2); padding-inline-start: 1rem; }
.map-about__src b { font-weight: 500; color: var(--text); }

/* ---- sort on a phone's one line: Name and Size (owner, 2026-11-02) ---- */
.ruler-sort { display: none; }


@media (max-width: 719px) {
  .map-landing { --float-rows: 2; }
  .map-chiprow { flex: 1 1 100%; }
  .map-landing:not([data-sheet="closed"]) .map-chiprow { display: none; }
  .fchip { height: 2.75rem; }
  /* The dropdown is a bottom sheet over a dimmed map, its foot's button closing it. */
  .map-drop {
    left: 0; right: 0; bottom: 0; top: auto; width: 100%; max-width: none; max-height: 80dvh;
    border: 0; border-top: 1px solid var(--border); border-radius: 16px 16px 0 0;
  }
  .map-drop::backdrop { background: rgba(11, 16, 35, 0.32); }
  .map-drop__grip { display: block; flex: none; width: 36px; height: 4px; margin: 8px auto 0; border-radius: 2px; background: var(--border); }
  .map-drop__title { padding: var(--space-3) var(--space-4) var(--space-2); font-size: var(--text-3); color: var(--text); }
  .drop-row, .drop-pick, .drop-seg label, .drop-more { min-height: 2.75rem; }
  .drop-more { height: 2.75rem; width: 2.75rem; }
  .drop-field input, .drop-field select { height: 2.75rem; }
  .map-drop__foot { padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom)); }
  .map-drop__show { flex: 1 1 auto; min-height: 3rem; border-color: var(--text); background: var(--text); color: var(--surface); font-size: var(--text-2); font-weight: 600; }
  /* The column titles on their own line right over the rows, under the stage figures (owner, 2026-11-02:
     "Could you move the titles about the columns?"): Name over the names, Size's right edge on the rows' MW
     figures; the handle and start over keep the band's top line. */
  .map-landing .ruler-sort {
    order: 10; display: flex; align-items: center; flex: none; box-sizing: border-box; min-width: 0;
    width: calc(100% + var(--space-1) + var(--space-2)); margin: 0 calc(-1 * var(--space-2)) 0 calc(-1 * var(--space-1));
    padding: 0 calc(2.75rem + 5px + 16px) 0 8px; border-bottom: 1px solid var(--border); background: var(--surface);
  }
  /* A record open: Back on the top line beside the handle, the record over the stage figures and the titles,
     and no second Back bar (owner, 2026-11-02: "Move the navigation to the top bar"). */
  .map-landing .ruler-band__back:not([hidden]) { display: inline-flex; align-items: center; gap: 4px; height: 2.25rem; min-height: 2.25rem; }
  .map-landing .ruler-sheet.has-record .ruler-record { top: 64px; }
  .map-landing .ruler-sheet.has-record .ruler-record__bar { display: none; }
  /* The stage figures take the band's top line, start over at its right end (owner, 2026-11-02, with a
     screenshot: "Remove or utilize the big white space with the tabs. Don't leave big white space like this");
     the handle is the pill on the sheet's top edge, and still steps the sheet by a tap or a swipe. */
  .map-landing .ruler-band,
  .map-landing:not([data-sheet="closed"]) .ruler-band,
  .map-landing[data-sheet="closed"] .ruler-band { position: relative; padding-top: 14px; row-gap: 0; }
  .map-landing .ruler-sheet__grab {
    position: absolute; z-index: 1; top: 0; left: 50%; transform: translateX(-50%); width: 72px; height: 16px;
  }
  .map-landing .ruler-sheet__pill { width: 36px; height: 4px; }
  .map-landing .ruler-sheet__chev { display: none; }
  .map-landing .ruler-stagebar {
    order: 1; border-top: 0;
  }
  /* Start over at the right end of the titles' line, in the room right of Size, so the four figures keep the
     whole top line; while a record is open it sits on the top line, across from Back. */
  .map-landing .ruler-band__side,
  .map-landing:not([data-sheet="closed"]) .ruler-band__side { position: absolute; top: auto; right: var(--space-2); bottom: 1px; z-index: 1; height: 2.25rem; align-items: center; }
  .map-landing .ruler-sheet.has-record .ruler-band__side { bottom: auto; top: 21px; }
  .map-landing .ruler-btn--reset,
  .map-landing:not([data-sheet="closed"]) .ruler-btn--reset { height: 2.25rem; min-height: 2.25rem; }
  /* While a record is open, Back holds the top line in the stage figures' place. */
  .map-landing .ruler-sheet.has-record .ruler-stagebar { visibility: hidden; }
  .map-landing .ruler-band__back:not([hidden]) { position: absolute; left: var(--space-3); top: 21px; z-index: 1; }
  .ruler-sort__btn {
    display: inline-flex; align-items: center; gap: 2px; min-height: 2.25rem; padding: 0 var(--space-2); border: 0; background: none;
    color: var(--text-muted); font: inherit; font-size: var(--text-1); cursor: pointer;
  }
  .ruler-sort__btn[aria-pressed="true"] { color: var(--text); font-weight: 600; }
  /* The (i) before Use, so the word sits over the rows' use figures. */
  .ruler-sort__btn--use { order: 2; padding-right: 0; margin-inline-end: 10px; }
  .ruler-sort__info { order: 1; margin-inline-start: auto; width: 2rem; height: 2.25rem; }
  .ruler-sort__btn--size { order: 3; }
  .ruler-sort__btn--size { padding-right: 0; }
  .ruler-sort__arr { display: inline-block; min-width: 0.75em; text-align: center; }
  .ruler-sort__btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
  .ruler-row__mw { margin-right: calc(2.75rem + 5px); }
  /* The one (i): a round button on the map just above the sheet's top right, as the layers button is; it moves
     with the sheet and goes while the sheet is full. */
  .map-landing .map-credits__toggle { border: 1px solid var(--control); background: var(--surface); }
  .map-landing .map-credits__icon { padding: 0; background: none; }
  .map-landing[data-sheet="full"] .map-credits { display: none; }
  .map-landing .map-credits { right: var(--landing-inset); }
}
/* ---------- end 8.5 The map landing ---------- */

/* ---------- 9.3 A plant's USGS wind and solar sections (2026-10-25, lane usgs-live; DA-14 step 7; web/usgs_blocks.py) ----------
   The facts reuse the record page's own heading and field grid; the notes and the credit line under them keep
   the measure of the page's credits line (.record-credits), so a long acknowledgment does not run 1,400px wide. */
.record-usgs > .attribution-line { max-width: 80ch; margin: var(--space-2) 0 0; }
.record-usgs > .field-grid { margin-bottom: var(--space-3); }
/* The turbine models row runs long: its value sits under its label, left-aligned at a readable measure,
   at every width (the field grid's own phone layout), not pushed 1,200px from its label at 1440. */
.record-usgs .field-grid > .field-grid__wide { flex-direction: column; gap: var(--space-1); }
.record-usgs .field-grid__wide dd { text-align: left; max-width: 72ch; }
/* ---------- end 9.3 A plant's USGS sections ---------- */

/* The list's and the key's marks, the map's own (map.js `markGlyph`; coordinator, 2026-10-31): a circle in its
   side's colour (power or loads), its stage the fill. */
.ruler-dt td.kind { white-space: nowrap; }
.kind-mark { --mark-edge: var(--text); display: inline-block; vertical-align: -1px; margin-right: var(--space-1); overflow: visible; color: var(--text); }
.kind-mark--load { --mark-edge: var(--mark-load-edge); color: var(--mark-load); }
/* A power mark in its fuel family (map.js FAMILY_OF_GROUP): its rim and ring the family's full colour. */
.kind-mark--combustion { --mark-edge: var(--fam-combustion); color: var(--fam-combustion); }
.kind-mark--clean_firm { --mark-edge: var(--fam-clean-firm); color: var(--fam-clean-firm); }
.kind-mark--wind_solar { --mark-edge: var(--fam-wind-solar); color: var(--fam-wind-solar); }
.kind-mark--storage { --mark-edge: var(--fam-storage); color: var(--fam-storage); }
.kind-mark--bioenergy { --mark-edge: var(--fam-bioenergy); color: var(--fam-bioenergy); }
.kind-mark--unspecified { --mark-edge: var(--fam-unspecified); color: var(--fam-unspecified); }
/* Underused's plants with no use figure: the context slate. */
.kind-mark--ctx { --mark-edge: var(--ctx); color: var(--ctx); }
/* A ring in the edge hue, a filled mark with its rim in the edge hue (the family's full colour). */
.kind-mark__ring { fill: none; stroke: var(--mark-edge); stroke-width: 1.4; }
.kind-mark__dash { stroke-dasharray: 2.4 1.8; }
.kind-mark__solid { fill: currentColor; stroke: var(--mark-edge); stroke-width: 0.8; }
.kind-mark__core { fill: var(--mark-edge); }
/* Retiring, standby and out of service: the solid mark with a thin halo in the ink, as on the map. */
.kind-mark__bar { stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; fill: none; }
/* Retired (map.js RETIRED_SHARE): 12% of the colour toward the land, no rim. */
.kind-mark__retired { fill: color-mix(in oklab, currentColor 12%, var(--map-land)); stroke: none; }
/* The key's fade strip (map.js FADE_STEPS): full, 60% and 30% of the colour toward the land, each with its
   full rim; under Underused the same strip reads Underused to Busy. */
.map-key__fade { margin-right: var(--space-1); }
.map-key__fade circle { fill: color-mix(in oklab, currentColor var(--t, 100%), var(--map-land)); stroke: currentColor; stroke-width: 0.8; }
.map-key__fade circle:nth-child(2) { --t: 60%; }
.map-key__fade circle:nth-child(3) { --t: 30%; }
/* The key's stage fills, drawn in the ink: the stage, not a family (the first line says the families). */
.kind-mark--ink { --mark-edge: var(--text); color: var(--text); }
.map-key .map-key__kinds { grid-template-columns: 1fr; }
.map-key__kinds li { display: flex; align-items: center; gap: 2px var(--space-3); flex-wrap: nowrap; white-space: nowrap; }
.map-key__kinds li > span { display: inline-flex; align-items: center; white-space: nowrap; }
.map-key__kinds li[hidden] { display: none; }
/* The families wrap: seven short words over two or three lines. */
.map-key__kinds li[data-key-line="families"] { flex-wrap: wrap; max-width: 17rem; }
.map-key__kinds .map-key__scale-marks { margin-right: var(--space-1); }
.map-key__kinds .map-key__scale-marks .kind-mark__ring { stroke: var(--text); stroke-width: 1; fill: none; }
.map-key__info { width: 1.5rem; height: 1.5rem; margin-left: auto; }
.map-key__kinds { list-style: none; margin: var(--space-1) 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 2px var(--space-2); font-size: var(--text-1); color: var(--text); }
.map-key__scale { display: flex; align-items: center; gap: var(--space-2); margin: var(--space-1) 0 var(--space-2); padding-bottom: var(--space-2); border-bottom: 1px solid var(--border); font-size: var(--text-1); color: var(--text-muted); }
.map-key__scale-marks { flex: none; overflow: visible; }
.ruler-ns { color: var(--text-muted); font-size: var(--text-1); white-space: nowrap; }
@media (max-width: 719px) {
  /* 44px touch targets on a phone (owner, 2026-10-31: "the select areas appear to be tiny"). */
  .map-landing .map-search__input { min-height: 2.75rem; }
  .map-landing .map-search__icon { top: 0.875rem; }
  .map-landing .map-search__clear { width: 2.75rem; height: 2.75rem; }
}


/* ==========================================================================================================
   R3. Record pages: the map on top, the lead, the key facts, Operations and the holdings tree
   (lane pages, 2026-10-31; decisions log 2026-10-29 "One plant page", 2026-10-30 "The map is the canvas on
   every page" and "Pages: the map sits on top"). One anatomy for the asset, company, project and data-centre
   pages: the map, full width; the name; the headline figure beside one plain sentence; a row of key facts;
   the tabs, one list each with its analytics strip; sources last.
   Grid arithmetic at 1440: the canvas bleeds over main's 20px gutters (1440 wide); the content runs
   1400 = 20 + 1400 + 20. The key facts share one row, `grid-auto-columns: 1fr`, so six facts are 6 x 233.3
   and any shorter row still closes on both edges; below 720px they fold to two columns.
   ========================================================================================================== */
.record-page {
  --canvas-h: 22.5rem;   /* 360px */
  --band-h: 2.75rem;     /* 44px: the slim band the map collapses to */
  --chart-1: #107656;    /* docs/31-brand-identity.md §4, charts only; dataviz validator: PASS on #ffffff */
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .record-page { --chart-1: #34ad7e; } }
:root[data-theme="dark"] .record-page { --chart-1: #34ad7e; } /* PASS on #17181b */
@media (max-width: 719px) { .record-page { --canvas-h: 15rem; --band-h: 3.75rem; --main-gutter: var(--space-4); } }

/* The canvas: sticky with a negative offset, so it scrolls up under the top bar until only the band is left.
   Nothing moves in the flow (CLS 0) and no script runs. */
/* The page's map scrolls with the page (owner, 2026-11-02: "remove its stick on the scroll"); its notes and the
   basemap credit are behind its (i), on the map. */
.record-canvas {
  position: relative; z-index: 1;
  display: grid; grid-template-rows: minmax(0, 1fr); height: calc(var(--canvas-h) - var(--band-h));
  margin: 0 calc(-1 * var(--main-gutter, var(--space-5))); background: var(--map-water); /* main's own gutter */
}
.record-canvas__map { position: relative; min-height: 0; }
/* "Show on map" on the page's map, top right (owner, 2026-11-02), styled as the primary map's floating buttons. */
.record-canvas__open {
  position: absolute; z-index: 3; top: var(--space-3); right: var(--space-3); display: inline-flex; align-items: center; gap: 6px;
  min-height: 2.5rem; padding: 0 var(--space-3); border: 1px solid var(--control); border-radius: 999px;
  background: var(--surface); color: var(--text); font-size: var(--text-1); font-weight: 500; text-decoration: none;
  box-shadow: none; /* flat over the map, as the mock-ups (taste-skill button-fx) */
}
.record-canvas__open:hover { border-color: var(--text); }
.record-canvas__open:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* The map's base map, Map · Satellite · Auto (asset_map.js, asset pages), top left, as flat as "Show on map". */
.record-canvas__base.drop-seg {
  position: absolute; z-index: 3; top: var(--space-3); left: var(--space-3); margin: 0;
  border-radius: 999px; background: var(--surface); color: var(--text);
}
.record-canvas__base.drop-seg label { min-height: 2.5rem; padding: 0 var(--space-3); font-size: var(--text-1); }
/* "Zoom to site" (owner, 2026-11-08), under "Show on map" at the map's top right: the map preview's "Open project
   page" button (`.ruler-record__open`: the deep-accent fill, 44px), the map's one filled control. A county- or
   state-placed record says "Exact site not public" in the same corner, one muted line on the page's surface. */
.record-canvas__site.button-link {
  position: absolute; z-index: 3; top: var(--space-3); right: var(--space-3);
  justify-content: center; gap: var(--space-2); min-height: 2.75rem;
  background: var(--accent-deep); color: var(--accent-ink); font: inherit; font-weight: 600; cursor: pointer;
}
.record-canvas__site.button-link:hover { filter: brightness(1.12); } /* the accent never fills a button (test_brand C6) */
.record-canvas__open ~ .record-canvas__site, .record-canvas__open ~ .record-canvas__nosite { top: calc(var(--space-3) + 2.5rem + var(--space-2)); }
.record-canvas__nosite {
  position: absolute; z-index: 3; top: var(--space-3); right: var(--space-3); margin: 0;
  padding: var(--space-1) var(--space-3); border-radius: 999px; background: var(--surface);
  color: var(--text-muted); font-size: var(--text-1);
}
.record-canvas .mini-map {
  height: 100%; min-height: 0; max-height: none; margin: 0; border: 0; border-radius: 0;
}
.record-canvas__locator svg { width: 100%; height: 100%; }
.record-canvas__info { position: absolute; z-index: 3; right: var(--space-2); bottom: var(--space-2); }
.record-canvas__info > .map-info { width: 2.5rem; height: 2.5rem; border: 1px solid var(--control); border-radius: 50%; background: var(--surface); }
.record-canvas__band {
  display: flex; align-items: center; gap: var(--space-4); min-width: 0;
  padding: 0 var(--main-gutter, var(--space-5)); background: var(--surface); border-bottom: 1px solid var(--border);
}
.record-canvas__caption {
  margin: 0; min-width: 0; font-size: var(--text-1); line-height: 1.4; color: var(--text-muted);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
@media (max-width: 719px) { .record-canvas__caption { -webkit-line-clamp: 3; } }
.record-canvas__id { display: none; margin: 0; min-width: 0; gap: var(--space-3); align-items: baseline; }
.record-canvas__name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.record-canvas__figure { color: var(--text-muted); white-space: nowrap; }
.record-canvas__unmapped { white-space: nowrap; }
/* A project's EIA generators, one line per plant, behind the field grid's (i). */
.eia-generators { display: block; margin: 0; overflow-wrap: anywhere; }
.eia-generators + .eia-generators { margin-top: var(--space-1); }
.eia-generators__plant { display: block; color: var(--text-muted); }
/* The canvas's key (partials/_record_canvas.html; web/page.py `map_key_rows`): the primary map's marks and
   words (home_map.html `map-key__kinds`, the `.kind-mark` glyphs), only the rows this map draws, shown on the
   map at its bottom left as the primary map's key card is, never behind an (i) (owner, 2026-11-01). */
.canvas-key {
  position: absolute; left: var(--space-2); bottom: var(--space-2); z-index: 2; max-width: calc(100% - 2.5rem - 3 * var(--space-2)); /* clear of the (i) at the bottom right at every width (owner, 2026-11-03) */
  box-sizing: border-box; padding: var(--space-1) var(--space-2);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-2);
}
.canvas-key__kinds {
  list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 2px var(--space-3);
  font-size: var(--text-1); line-height: 18px; color: var(--text);
}
.canvas-key__kinds li { flex: none; display: inline-flex; align-items: center; white-space: nowrap; }
.canvas-key__kinds .kind-mark { vertical-align: 0; }
.canvas-key__kinds .kind-mark + .kind-mark { margin-left: -2px; }
.canvas-key__scale { color: var(--text-muted); }
.canvas-key__scale .map-key__scale-marks { flex: none; margin-right: var(--space-1); overflow: visible; }
/* On a phone the strip is not drawn (owner, 2026-11-03: "On mobile the map key overlaps and clips"): the same
   key is behind the map's (i). The (i)'s copy wraps in the popover's own flow on every width. */
@media (max-width: 719px) {
  .canvas-key { display: none; }
}
.canvas-key__kinds--pop { position: static; flex-wrap: wrap; overflow: visible; margin: 0 0 var(--space-2); }
.record-foot__source { margin: var(--space-2) 0 0; font-size: var(--text-1); }
.record-foot__source a { color: var(--text-muted); }


/* The grey context (map.js `--ctx`: pipelines, lines, other assets) and another company's receded project. */
.kind-mark--ctx { --mark-edge: var(--ctx); color: var(--ctx); }
.kind-mark--dim { opacity: 0.45; }
.kind-mark__group { fill-opacity: 0.85; stroke: none; }
.record-canvas__credit { white-space: nowrap; color: var(--text-muted); }
/* The server's SVG map (no script), in the same grammar: colour by side, fill by stage, the grey context, the
   open record ringed in ink (asset_map.js draws the same with MapLibre). */
.mini-map .mini-map__line { stroke: var(--ctx); stroke-width: 1.2; stroke-opacity: 0.85; }
.mini-map .mini-map__line--subject { stroke: var(--text); stroke-width: 2.5; stroke-opacity: 1; }
.mini-map__mark--combustion { --mark: var(--fam-combustion); --mark-edge: var(--fam-combustion); }
.mini-map__mark--clean_firm { --mark: var(--fam-clean-firm); --mark-edge: var(--fam-clean-firm); }
.mini-map__mark--wind_solar { --mark: var(--fam-wind-solar); --mark-edge: var(--fam-wind-solar); }
.mini-map__mark--storage { --mark: var(--fam-storage); --mark-edge: var(--fam-storage); }
.mini-map__mark--bioenergy { --mark: var(--fam-bioenergy); --mark-edge: var(--fam-bioenergy); }
.mini-map__mark--unspecified { --mark: var(--fam-unspecified); --mark-edge: var(--fam-unspecified); }
.mini-map__mark--load { --mark: var(--mark-load); --mark-edge: var(--mark-load-edge); }
.mini-map__mark--ctx { --mark: var(--ctx); --mark-edge: var(--ctx); }
.mini-map .mini-map__mark--solid { fill: var(--mark); stroke: var(--mark-edge); stroke-width: 0.8; }
.mini-map .mini-map__mark--retired { fill: color-mix(in oklab, var(--mark) 12%, var(--map-land)); stroke: none; }
.mini-map .mini-map__mark--ring, .mini-map .mini-map__mark--core, .mini-map .mini-map__mark--bar { fill: var(--map-land); stroke: var(--mark-edge); stroke-width: 1.4; }
.mini-map .mini-map__mark--subject { stroke: var(--text); stroke-width: 2; }
.mini-map__cluster { fill: var(--ctx); fill-opacity: 0.85; stroke: var(--surface); stroke-width: 1.5; }
.record-canvas + .record-header, .record-canvas ~ .record-header { padding-top: var(--space-5); }

/* ---------- R4. Record pages as one sheet (direction A; decisions log 2026-11-03, "Record pages take direction
   A" and "Record pages end with a visually separate band") ----------
   One column, top to bottom: the map (scrolls with the page), the title row (name, status, tier tag, the one
   action at its right), the kind line, one line of figures (the headline figure largest), the relations
   line, the record's own sections, the timeline at the foot, the Sources line; then, below the record and
   on its own ground, the band "Around this {noun}". App-screen rules of the taste skill
   (references/app-screens.md): 28px title, figures as type, quiet rules between sections, colour only on
   status and data. Measured at 1440: the sheet keeps to 65rem (1040px) of the 1400px content, the mock-ups'
   reading measure; the map and the band take the full width. */
.record-sheet, .org-page { --sheet-w: 65rem; }
.record-sheet > :not(.record-canvas, .record-around, .record-pin), .org-page > :not(.record-canvas, .record-around, .record-pin) { max-width: var(--sheet-w); }
/* the record's sheet wrapper (E-b) is no box of its own unless the sheet is on, so its children keep the measure */
.record-body { display: contents; }
/* The pinned title (owner, 2026-11-09: "make the title of the page we are on stick to the top";
   partials/_record_pin.html, site.js "pinned title"). One line under the top bar, full width like it: the
   name in the title face, cut with an ellipsis, then the kind word, muted. Fixed, so showing it moves
   nothing; hidden until the h1 has scrolled up out of view, and never shown without scripts. Under the top
   bar's layer (z 40), so the phone Menu and the open search field cover it. While it shows, an anchor jump
   lands below it too. */
:root { --record-pin-h: 2.5rem; }
.record-pin {
  position: fixed; top: var(--record-pin-top, var(--top-bar-h)); left: 0; right: 0; z-index: 30;
  background: var(--bg); border-bottom: 1px solid var(--border);
  visibility: hidden; opacity: 0; pointer-events: none;
  transition: opacity var(--motion-fast) ease-out, visibility 0s linear var(--motion-fast);
}
.record-pin.is-shown { visibility: visible; opacity: 1; pointer-events: auto; transition: opacity var(--motion-fast) ease-out; }
/* The name starts where the H1 does: on a sheet (`--sheet-w`, inherited) the sheet's measure, centred as the
   sheet is; elsewhere main's 1440px. */
.record-pin__row {
  max-width: calc(var(--sheet-w, 1400px) + 2 * var(--space-5)); margin: 0 auto; padding: 0 var(--space-5); min-height: calc(var(--record-pin-h) - 1px);
  display: flex; align-items: baseline; gap: var(--space-3); padding-block: var(--space-2); box-sizing: border-box;
}
.record-pin__name, .record-pin__kind { margin: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.record-pin__name { flex: 0 1 auto; font-family: var(--font-display); font-size: var(--text-2); font-weight: 600; letter-spacing: -0.01em; line-height: 1.5rem; color: var(--text); }
.record-pin__kind { flex: 0 10 auto; max-width: 40%; font-size: var(--text-1); color: var(--text-muted); }
/* On a phone the line is the name's alone: a kind word cut to "Deve…" says nothing. */
@media (max-width: 719px) { .record-pin__row { padding-inline: var(--space-4); } .record-pin__kind { display: none; } }
@media (prefers-reduced-motion: reduce) { .record-pin, .record-pin.is-shown { transition: none; } }
html:has(.record-pin.is-shown) { scroll-padding-top: calc(var(--top-bar-h) + var(--record-pin-h)); }
.record-page:has(> .record-pin) [id] { scroll-margin-top: calc(var(--top-bar-h) + var(--record-pin-h) + var(--space-4)); }
:is(.record-sheet, .org-page) > .record-body > :not(.record-around) { max-width: var(--sheet-w); }
/* The title row: the name, its chip, the tier tag, then the action pushed to the right. */
.record-page .record-header { display: block; padding-top: var(--space-5); }
.record-page .record-header > .detail-header {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: var(--space-2) 0 0;
}
.record-page .record-header .detail-header h1 { font-size: 1.75rem; font-weight: 600; letter-spacing: -0.015em; line-height: 1.2; }
.record-page .detail-header > .record-header__action { margin: 0 0 0 auto; }
.record-page .detail-header > .delayed-notice {
  margin: 0; padding: 0 var(--space-2); border: 1px solid var(--border); border-radius: var(--radius-1);
  background: transparent; font-size: var(--text-1); display: inline-flex; align-items: center; gap: var(--space-1); min-height: 1.5rem;
}
.record-page .detail-header > .delayed-notice a { color: var(--text-muted); }
.record-page .detail-header > .preview-banner { order: 1; flex-basis: 100%; margin: var(--space-2) 0 0; } /* dev only: under the title row */
.record-page .record-action { min-height: 2.25rem; padding: 0 var(--space-4); font-weight: 500; }
.record-kind { margin: var(--space-1) 0 0; font-size: var(--text-1); color: var(--text-muted); }
/* The lead: the headline figure, the page's one large number, then the key facts as a fact table. */
.record-lead { margin: var(--space-5) 0 0; }
/* The headline figure: the lead's first ledger row, its value set one step larger (section style D). */
.record-headline { margin: 0; }
.record-headline { display: grid; grid-template-columns: fit-content(var(--lg-cap)) minmax(0, 1fr); }
.record-headline > div { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; }
.record-headline dt {
  min-width: 7rem; display: flex; align-items: center; margin: 0; padding: var(--lg-py) var(--lg-px); background: var(--bg);
  border-inline-end: 1px solid var(--border); color: var(--text-muted); font-size: var(--text-label);
}
.record-headline dt a { color: inherit; text-decoration: underline dotted; text-underline-offset: 0.2em; }
.record-headline dd { margin: 0; padding: var(--lg-py) var(--lg-px); background: var(--surface); color: var(--text); white-space: nowrap; }
.record-headline__value { font-size: var(--text-3); font-weight: 600; line-height: 1.3; letter-spacing: -0.01em; }
.record-headline__unit { margin-inline-start: 0.25em; font-size: var(--text-1); color: var(--text-muted); }
@media (max-width: 719px) { .record-headline dt { font-size: var(--text-1); } }
/* Fact table (partials/_fact_table.html; owner, 2026-11-03: label next to value), as a ledger (section style D,
   owner 2026-11-05): one label | value pair per row and never two (two pairs brought back the mid-row gap the
   owner disliked), the label cell on the ground tint (--bg), the value cell on --surface, 1px --border rules
   between rows and between label and value, no gutter. The label column stays a column on a phone: the
   pair never stacks. */
:root {
  --lg-cap: 40%;            /* the label column's widest: it sizes to its longest label up to this */
  --lg-label: 38%;          /* a phone table's label cell (a fixed share: its rows are separate tables) */
  --lg-px: var(--space-3);  /* a cell's inline padding */
  --lg-py: 6px;             /* a cell's block padding: ~32px rows */
  --lg-bar-h: 2.25rem;      /* a section's ink bar */
  --lg-gap: var(--space-6); /* between sections */
}
@media (max-width: 719px) { :root { --lg-cap: 45%; --lg-label: min(7.5rem, 45%); --lg-px: var(--space-2); } }
/* The label column is as wide as its longest label (owner, 2026-11-05: "remove some the the blank space between
   the columns. like in capacity and 1000mws"), at least 7rem and at most --lg-cap; the rows are subgrids of the
   table, so every row shares that one width. */
.fact-table { display: grid; grid-template-columns: fit-content(var(--lg-cap)) minmax(0, 1fr); margin: 0; }
.fact-table > div { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; gap: 0; margin: 0; padding: 0; }
.fact-table > div + div { border-top: 1px solid var(--border); }
.fact-table dt {
  min-width: 7rem; margin: 0; padding: var(--lg-py) var(--lg-px); background: var(--bg); border-inline-end: 1px solid var(--border);
  color: var(--text-muted); font-size: var(--text-label); line-height: calc(var(--text-2) * 1.45); overflow-wrap: anywhere;
}
.fact-table dd {
  margin: 0; padding: var(--lg-py) var(--lg-px); background: var(--surface); color: var(--text);
  font-size: var(--text-2); font-weight: 500; line-height: 1.45; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; min-width: 0;
}
.fact-table dt a, .fact-table dd a { color: inherit; text-decoration: underline dotted; text-underline-offset: 0.2em; }
.fact-table dt a:hover, .fact-table dt a:focus-visible, .fact-table dd a:hover { color: var(--link); }
.fact-table .field-grid__source-value, .fact-table__note { display: inline; margin-inline-start: var(--space-1); font-size: var(--text-1); color: var(--text-muted); }
.fact-table--empty dd, .fact-table__none { color: var(--text-muted); font-weight: 400; }
@media (max-width: 719px) { .fact-table dt { font-size: var(--text-1); } }


.record-page .record-header .record-company { margin: var(--space-4) 0 0; }
.record-page .record-header .org-facts { margin-top: var(--space-4); }
/* The record's own sections: one rule above each, a heading with an aside at its right. */
.record-section { margin: 0; padding: var(--space-6) 0; border-top: 1px solid var(--border); min-width: 0; }
.record-header + .record-section, .record-tabs + .record-section { margin-top: var(--space-6); }
.record-section__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-3); margin: 0 0 var(--space-4); }
.record-section__title { margin: 0; font-size: 1.0625rem; font-weight: 600; letter-spacing: -0.005em; }
.record-section__aside { margin-inline-start: auto; font-size: var(--text-1); color: var(--text-muted); }
.record-section__head .ops-range { margin: 0 0 0 auto; }
.record-section .ops-charts { margin-bottom: var(--space-4); }
.record-more { margin: var(--space-3) 0 0; }
.record-more > summary { cursor: pointer; min-height: 1.5rem; color: var(--text-muted); font-size: var(--text-1); }
.record-more > summary:hover { color: var(--text); }
.record-more[open] > summary { margin-bottom: var(--space-2); }
.record-section .record-table { margin-top: var(--space-4); }
.record-section .timeline li .timeline__source { color: var(--text-muted); }
.record-sheet .record-foot, .org-page .record-foot { margin-top: 0; padding-top: var(--space-5); border-top: 1px solid var(--border); }
.record-sheet .track-block { margin: 0; padding: var(--space-6) 0; border-top: 1px solid var(--border); }
.record-sheet .site-panel { margin: 0; padding: var(--space-6) 0; border-top: 1px solid var(--border); }
/* The band below the record: full width, its own ground (the surface on the paper page) between two full rules,
   so it reads as not part of the record. Its content keeps the sheet's left edge and measure. */
.record-around {
  margin: var(--space-8) calc(-1 * var(--main-gutter, var(--space-5))) 0;
  padding: var(--space-6) var(--main-gutter, var(--space-5)) var(--space-8);
  background: var(--surface); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.record-around__inner { max-width: var(--sheet-w, 65rem); }
.record-around__title { margin: 0 0 var(--space-4); font-size: 1.0625rem; font-weight: 600; }
.record-around .record-section { border-top: 0; padding: 0; }
.record-around__table td .chip { margin-inline-start: var(--space-2); }
@media (max-width: 719px) {
  .record-page .record-header .detail-header h1 { font-size: 1.5rem; flex-basis: 100%; }
  .record-page .detail-header > .record-header__action { flex-basis: 100%; margin: var(--space-2) 0 0; }
  .record-around__table .cell-opt { display: none; }
  .record-around__table td[data-label="MW"]:not(:empty)::after { content: " MW"; color: var(--text-muted); }
}


/* Operations: the strip, four charts in two pairs, then the year list. */
.ops-strip {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); margin: 0 0 var(--space-6);
}
.ops-strip > div { padding: 0 var(--space-4); border-left: 1px solid var(--rule); }
.ops-strip > div:first-child { padding-left: 0; border-left: 0; }
.ops-strip dt { font-size: var(--text-1); color: var(--text-muted); }
.ops-strip dd { margin: var(--space-1) 0 0; font-size: 1.5rem; line-height: 1.2; font-weight: 400; color: var(--text); }
.ops-strip .is-missing dd { font-size: var(--text-2); color: var(--text-muted); }
.ops-strip__unit { margin-inline-start: 0.3em; font-size: var(--text-1); color: var(--text-muted); }
.ops-charts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-7) var(--space-8); margin: 0 0 var(--space-7); }
.ops-chart { margin: 0; min-width: 0; }
.ops-chart__head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: var(--space-1) var(--space-4); margin: 0 0 var(--space-2); }
.ops-chart__title { font-weight: 600; color: var(--text); }
.ops-chart__window { font-size: var(--text-1); color: var(--text-muted); }
.ops-chart__plot { height: 11rem; }
.ops-charts--sparse .ops-chart__plot { height: 7rem; }
.ops-charts--sparse { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-6); }
.ops-chart__plot svg { display: block; overflow: visible; }
.chart-bar { fill: var(--chart-1); }
.chart-bar.is-on, .chart-seg.is-on { stroke: var(--text); stroke-width: 1.5; }
/* The monthly charts take the full width: about 310 months from 2001 need every pixel (2026-11-01). */
.ops-chart--wide { grid-column: 1 / -1; }
.ops-chart--wide .ops-chart__plot { height: 13rem; }
.ops-legend { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-5); margin: var(--space-2) 0 0; padding: 0; list-style: none; font-size: var(--text-1); color: var(--text-muted); }
.ops-legend li { display: inline-flex; align-items: center; gap: var(--space-2); }
.ops-legend__key { display: inline-block; width: 0.625rem; height: 0.625rem; border-radius: 2px; }
/* One range control over both monthly charts, above them: a segmented track like the map's region switch. */
.ops-range { display: inline-flex; margin: 0 0 var(--space-5); }
.ops-range[hidden] { display: none; }
.ops-range button {
  min-width: 2.75rem; min-height: 2.25rem; padding: 0 var(--space-3); margin: 0;
  border: 1px solid var(--control); background: var(--surface); color: var(--text); font: inherit; font-size: var(--text-1); cursor: pointer;
}
.ops-range button:first-child { border-radius: var(--radius-2) 0 0 var(--radius-2); }
.ops-range button:last-child { border-radius: 0 var(--radius-2) var(--radius-2) 0; }
.ops-range button + button { margin-left: -1px; }
.ops-range button:hover { background: var(--raised); }
.ops-range button[aria-pressed="true"] { position: relative; border-color: var(--text); background: var(--active); font-weight: 600; }
.ops-range button:focus-visible { position: relative; z-index: 1; }
@media (max-width: 719px) { .ops-range button { min-height: 2.75rem; } }
.chart-grid { stroke: var(--rule); stroke-width: 1; }
.chart-base { stroke: var(--control); stroke-width: 1; }
.chart-tick { fill: var(--text-muted); font-size: 11px; font-family: var(--font-body); font-variant-numeric: tabular-nums; }
.chart-hit { fill: transparent; cursor: default; }
.chart-tip {
  position: absolute; z-index: 60; max-width: 18rem; padding: var(--space-1) var(--space-2);
  background: var(--surface); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius-2);
  font-size: var(--text-1); font-variant-numeric: tabular-nums; pointer-events: none;
  box-shadow: var(--shadow-float); /* taste-skill-ignore: a tooltip floats over the chart */
}
.ops-table { max-width: 52rem; }
.ops-table th[scope="row"] { font-weight: 600; text-align: left; }
/* A plant's two monthly charts on its Overview, after the header; the rest is one link away (owner, 2026-11-01). */
.record-ops { margin: var(--space-6) 0 var(--space-7); }
.record-section.record-ops { margin: var(--space-6) 0 0; }
.record-ops .ops-charts { margin-bottom: var(--space-3); }
.record-ops__more { margin: 0; font-size: var(--text-1); }
/* A company's output chart under the map band: title and coverage on one line, the controls, one wide chart. */
.org-ops { margin: var(--space-6) 0 var(--space-7); }
.org-ops__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-1) var(--space-4); margin: 0 0 var(--space-3); }
.org-ops__title { margin: 0; font-size: var(--text-3); font-weight: 600; }
.org-ops__band { margin: 0; font-size: var(--text-1); color: var(--text-muted); }
.ops-controls { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); }
.org-ops .ops-chart { margin-bottom: var(--space-4); }
.org-ops__years { margin: 0 0 var(--space-3); }
.org-ops__years .ops-table { max-width: 52rem; }
/* Every fuel's stack segment and legend key, and a plant's own single-series chart, in the one fuel palette
   (`--fuel-*`, :root; each group keeps its slot whatever else is present, so a colour always means one fuel). */
.chart-seg--gen-gas, .ops-legend__key--gen-gas { fill: var(--fuel-gas); background: var(--fuel-gas); }
.chart-seg--gen-coal, .ops-legend__key--gen-coal { fill: var(--fuel-coal); background: var(--fuel-coal); }
.chart-seg--gen-oil, .ops-legend__key--gen-oil { fill: var(--fuel-oil); background: var(--fuel-oil); }
.chart-seg--gen-nuclear, .ops-legend__key--gen-nuclear { fill: var(--fuel-nuclear); background: var(--fuel-nuclear); }
.chart-seg--gen-hydro, .ops-legend__key--gen-hydro { fill: var(--fuel-hydro); background: var(--fuel-hydro); }
.chart-seg--gen-geothermal, .ops-legend__key--gen-geothermal { fill: var(--fuel-geothermal); background: var(--fuel-geothermal); }
.chart-seg--gen-wind, .ops-legend__key--gen-wind { fill: var(--fuel-wind); background: var(--fuel-wind); }
.chart-seg--gen-solar, .ops-legend__key--gen-solar { fill: var(--fuel-solar); background: var(--fuel-solar); }
.chart-seg--gen-storage, .ops-legend__key--gen-storage { fill: var(--fuel-storage); background: var(--fuel-storage); }
.chart-seg--gen-bio, .ops-legend__key--gen-bio { fill: var(--fuel-bio); background: var(--fuel-bio); }
.chart-seg--gen-load, .ops-legend__key--gen-load { fill: var(--fuel-load); background: var(--fuel-load); }
.chart-seg--gen-other, .ops-legend__key--gen-other { fill: var(--fuel-other); background: var(--fuel-other); }
.ops-chart--gen-gas .chart-bar { fill: var(--fuel-gas); }
.ops-chart--gen-coal .chart-bar { fill: var(--fuel-coal); }
.ops-chart--gen-oil .chart-bar { fill: var(--fuel-oil); }
.ops-chart--gen-nuclear .chart-bar { fill: var(--fuel-nuclear); }
.ops-chart--gen-hydro .chart-bar { fill: var(--fuel-hydro); }
.ops-chart--gen-geothermal .chart-bar { fill: var(--fuel-geothermal); }
.ops-chart--gen-wind .chart-bar { fill: var(--fuel-wind); }
.ops-chart--gen-solar .chart-bar { fill: var(--fuel-solar); }
.ops-chart--gen-storage .chart-bar { fill: var(--fuel-storage); }
.ops-chart--gen-bio .chart-bar { fill: var(--fuel-bio); }
.ops-chart--gen-load .chart-bar { fill: var(--fuel-load); }
.ops-chart--gen-other .chart-bar { fill: var(--fuel-other); }
@media (max-width: 719px) {
  .ops-strip { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4) 0; }
  .ops-strip > div:nth-child(odd) { padding-left: 0; border-left: 0; }
  .ops-charts, .ops-charts--sparse { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
}

/* The holdings tree: indent by level with one guide rule, a 44px row, the name over its relationship and
   share, what it holds on the right. The page's own company sits on the selected-row fill. */
.htree, .htree__list { list-style: none; margin: 0; padding: 0; }
.htree { max-width: 60rem; }
.htree__list { margin-left: 0.6rem; padding-left: var(--space-5); border-left: 1px solid var(--border); }
.htree__row {
  display: flex; justify-content: space-between; align-items: center; gap: var(--space-2) var(--space-5);
  min-height: 2.75rem; padding: var(--space-2) var(--space-3); border-radius: var(--radius-2);
}
summary.htree__row { cursor: pointer; list-style: none; }
summary.htree__row::-webkit-details-marker { display: none; }
summary.htree__row::before {
  content: ""; flex: none; width: 0.45rem; height: 0.45rem; margin-right: calc(-1 * var(--space-2));
  border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted);
  transform: rotate(-45deg); transition: transform var(--dur-fast, 120ms) ease;
}
details[open] > summary.htree__row::before { transform: rotate(45deg); }
summary.htree__row:hover { background: var(--raised); }
.htree__row--leaf { padding-left: calc(var(--space-3) + 0.45rem + var(--space-3)); }
.htree__who { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.htree__name { font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
a.htree__name { color: var(--link); }
.htree__rel { font-size: var(--text-1); color: var(--text-muted); }
.htree__figs { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-1) var(--space-5); color: var(--text); }
.htree__fig { white-space: nowrap; }
.htree__fig--none, .htree__fig--note { color: var(--text-muted); font-size: var(--text-1); }
.htree__unit { color: var(--text-muted); }
.htree .is-subject > .htree__row, .htree .is-subject > details > summary.htree__row { background: var(--active); }
@media (max-width: 719px) {
  .htree__row { flex-wrap: wrap; align-items: flex-start; }
  .htree__figs { justify-content: flex-start; width: 100%; padding-left: var(--space-3); font-size: var(--text-1); }
  .htree__list { padding-left: var(--space-3); }
}
@media (prefers-reduced-motion: reduce) { summary.htree__row::before { transition: none; } }

/* lane cleanup-lists: start */
/* Minimum visible text on lists, indexes and reading pages (owner, 2026-11-01; docs/31-design-practices.md
   §2.6): a short tag or line, its explanation behind the (i) (`_macros.html::tip_pop`, `warn_tag`). */
.tag-line { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--space-2); margin: var(--space-1) 0 var(--space-2); font-size: var(--text-1); color: var(--text); }
.tag-line .map-info, .list-lede .map-info, .method-lede .map-info, .results-bar__count .map-info,
.attribution-line .map-info, .linkout-list .map-info, .org-toolbar > .map-info, .scope-switch > .map-info {
  width: 1.75rem; height: 1.75rem; margin-block: -0.25rem; vertical-align: middle;
}
.tip-pop .view-notice { padding: 0; margin: 0 0 var(--space-2); font-size: var(--text-2); color: var(--text); }
.tip-pop .view-notice + .view-notice--unlisted { margin-top: 0; }
.tip-pop .scope-switch__note { margin: 0 0 var(--space-2); color: var(--text); font-size: var(--text-2); }
/* The count, then what the default view leaves out as one quiet tag. */
.results-bar__count { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--space-2); }
.results-bar__count .result-count { margin: 0; }
.list-page .results-bar .results-bar__count { margin-bottom: var(--space-2); }
.list-scope {
  display: inline-flex; align-items: center; padding: 0 var(--space-2); font-size: var(--text-1); color: var(--text-muted);
  background: var(--raised); border-radius: var(--radius-1); white-space: nowrap;
}
.count-chips li.count-chips__info { display: inline-flex; align-items: center; }
.count-note .tag-line strong { font-weight: 600; }
/* Link-out markets: one line of links, each reason behind its (i). */
.price-linkouts .linkout-list { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-5); list-style: none; padding: 0; margin: 0 0 var(--space-5); }
.price-linkouts .linkout-list li { display: inline-flex; align-items: center; gap: 2px; margin: 0; }
.price-terms { margin-bottom: var(--space-4); }
.price-terms .price-glossary { margin-bottom: var(--space-2); }
@media (min-width: 720px) { .price-terms .price-glossary { grid-template-columns: minmax(0, 1fr); max-width: 75ch; } }
/* A dated coverage note folds under its headline; the heading keeps its size inside the summary. */
.coverage-note__body > summary { cursor: pointer; list-style-position: outside; margin-inline-start: 1rem; }
.coverage-note__body > summary h3 { display: inline; margin: 0; }
.coverage-note__body[open] > summary { margin-bottom: var(--space-2); }
.coverage-note { margin: var(--space-3) 0; }
/* Reading pages: prose at a readable measure (45 to 75 characters, docs/31-design-practices.md §2.2). */
.method-page .method-section > p, .method-page .method-section li, .method-elsewhere p, #gazetteers > p, #gazetteers li,
#basemap li, #context-layers li, .page-header > p, .about-tiers p, .about-who p { max-width: 58ch; }
/* lane cleanup-lists: end */

/* lane cleanup-records: start */
/* Record pages, minimum text (owner, 2026-11-01; docs/31 §2.6): explanations sit behind an (i), whose popover is
   the map's (`.map-pop`); a data-quality warning is a short outlined tag in the as-of tag's idiom. */
.rc-tagline { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--space-2); margin: var(--space-1) 0; font-size: var(--text-1); color: var(--text); }
.rc-tag {
  display: inline-flex; align-items: center; padding: 0 var(--space-2);
  border: 1px solid currentColor; border-radius: var(--radius-1); font-weight: 500; white-space: nowrap;
}
.rc-tag--quiet { border-color: var(--border); color: var(--text-muted); font-weight: 400; }
/* An (i) in running text: the 28px target of the as-of line, pulled into the line box so it adds no height. */
.rc-tagline .map-info, .rc-inline .map-info, .record-company .map-info, .rc-tier .map-info,
.field-grid .map-info, .rc-head .map-info, .mini-map__caption .map-info, .record-canvas__caption .map-info,
.value-line .map-info, .attribution-line .map-info, .org-panel__note .map-info, .org-panel__more .map-info,
.filter-notice .map-info, .proposal-location__line .map-info, .org-facts .map-info, .detail-header .map-info {
  width: 1.75rem; height: 1.75rem; margin-block: -0.25rem; vertical-align: middle;
}
.rc-pop { font-weight: 400; text-align: start; white-space: normal; }
.rc-pop .map-pop__title { display: block; }
.rc-pop > span:not(.map-pop__title) { display: block; color: var(--text-muted); font-size: var(--text-1); }
.rc-pop > span:not(.map-pop__title) + span { margin-block-start: var(--space-2); }
.rc-tier { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--space-2); }
.rc-tier .stamp-label { margin-inline-end: 0; }
/* A heading with its (i) beside it. */
.rc-head { display: flex; align-items: center; gap: var(--space-1); }
.rc-head > h2, .rc-head > h3 { margin-block-end: 0; }
.rc-head + * { margin-block-start: var(--space-2); }
.rc-inline { display: inline-flex; align-items: center; gap: var(--space-1); }
.proposal-location__line .rc-inline { margin-inline-end: 0.2em; }
.org-facts .rc-tag { font-size: var(--text-1); }
/* lane cleanup-records: end */

/* ---- the band's one row from 720px (owner, 2026-11-02: "Id like the keep the arrows up and down and top
   summary of results with the bars ... Remove or tuck away records totalt, capacity total and stick capacity by
   type next to stage tabs") ----
   The stage switch, the bars (GW by type, fuel or year, one hue, about the switch's height), then the down and
   up arrows and the ×, then the table. The strip's totals are a line in the map's (i). The bars' box is the
   grid's middle track and 48px tall from first paint, so nothing moves when they draw (D-31 CLS). A phone
   keeps its strip. */
.ruler-bars { display: flex; align-items: center; gap: var(--space-3); min-width: 0; height: 48px; }
/* The key keeps one width whatever it names, so the bars beside it never move when the stage changes. */
.ruler-bars__k { flex: none; width: 9rem; overflow: hidden; text-overflow: ellipsis; font-size: var(--text-1); line-height: 16px; color: var(--text-muted); white-space: nowrap; }
.ruler-bars__plot { flex: 1 1 0; min-width: 0; max-width: 560px; height: 48px; }
.ruler-bars .ruler-chart { height: 48px; }
.ruler-bars .ruler-chart text { font-size: 11px; font-variant-numeric: tabular-nums; }
.ruler-heights { display: inline-flex; gap: var(--space-1); }
.ruler-must { flex: none; margin: 0; padding: 8px 16px; font-size: var(--text-1); line-height: 18px; color: var(--text-muted); }
@media (min-width: 720px) {
  .map-landing .ruler-strip { display: none; }
}
@media (min-width: 720px) and (min-height: 37.51rem) {
  .map-landing[data-sheet="closed"] .ruler-must { display: none; }
}
@media (max-width: 719px) {
  .ruler-bars, .ruler-heights { display: none; }
  .map-landing[data-sheet="closed"] .ruler-must { display: none; }
}
/* The band's and the strip's bars in each fuel's colour (`--fuel-*`, the one palette); the pipeline is a light
   tint of the same hue over the solid operating part. A type filtered out keeps the grey. */
.ruler-chart .bar.chart-seg--gen-gas { fill: var(--fuel-gas); }
.ruler-chart .bar.chart-seg--gen-coal { fill: var(--fuel-coal); }
.ruler-chart .bar.chart-seg--gen-oil { fill: var(--fuel-oil); }
.ruler-chart .bar.chart-seg--gen-nuclear { fill: var(--fuel-nuclear); }
.ruler-chart .bar.chart-seg--gen-hydro { fill: var(--fuel-hydro); }
.ruler-chart .bar.chart-seg--gen-geothermal { fill: var(--fuel-geothermal); }
.ruler-chart .bar.chart-seg--gen-wind { fill: var(--fuel-wind); }
.ruler-chart .bar.chart-seg--gen-solar { fill: var(--fuel-solar); }
.ruler-chart .bar.chart-seg--gen-storage { fill: var(--fuel-storage); }
.ruler-chart .bar.chart-seg--gen-bio { fill: var(--fuel-bio); }
.ruler-chart .bar.chart-seg--gen-load { fill: var(--fuel-load); }
.ruler-chart .bar.chart-seg--gen-other { fill: var(--fuel-other); }
.ruler-chart .bar--pipe { fill-opacity: 0.4; }
.ruler-chart .bar.off { fill: var(--chart-off); }
.ruler-bars__sw { display: inline-block; width: 0.5rem; height: 0.5rem; margin-inline-end: 3px; border-radius: 1px; background: var(--text-muted); vertical-align: 0; }
.ruler-bars__sw--pipe { opacity: 0.4; }

/* lane build-a-deal (2026-11-03): Build a deal's landing page for My projects' invite-only beta
   (web/templates/build.html). A page people read: the title at display size beside one large picture (the
   map from the social card, cropped to its map and its credit), three plain lines, then the form on a
   filled field. No rules, cards or shadows; the parts rise in once, and stay put with reduced motion. */
.build-page { padding-block: var(--space-9) var(--space-10); }
.build-hero { display: grid; gap: var(--space-8); align-items: center; }
.build-hero h1 {
  margin: 0; font-family: var(--font-display); font-size: clamp(2.5rem, 5.6vw, 5rem);
  line-height: 1; letter-spacing: -0.035em; max-width: 12ch;
}
.build-hero__lede { margin: var(--space-6) 0 0; font-size: var(--text-4); line-height: 1.4; max-width: 32ch; color: var(--text); }
.build-hero__lede .map-info { vertical-align: middle; }
.build-benefits { margin: var(--space-7) 0 0; padding: 0; list-style: none; max-width: 46ch; }
.build-benefits li { margin: 0 0 var(--space-3); font-size: var(--text-3); line-height: 1.45; color: var(--text); }
.build-hero__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-6); margin: var(--space-7) 0 0; }
.build-hero__signin { font-size: var(--text-2); }
.build-hero__map { margin: 0; overflow: hidden; background: #0b1020; }
.build-hero__map img { display: block; width: 100%; height: auto; aspect-ratio: 600 / 630; object-fit: cover; object-position: right center; }
.build-join { margin-top: var(--space-10); padding: var(--space-9) var(--space-7); background: var(--raised); }
.build-join h2 { margin: 0; font-size: var(--text-7); letter-spacing: -0.02em; line-height: 1.1; }
.build-join__lede { margin: var(--space-4) 0 var(--space-6); font-size: var(--text-3); max-width: 52ch; }
.build-join__lede .map-info { vertical-align: middle; }
.build-join__thanks { margin-top: var(--space-6); max-width: 40rem; }
.build-form { display: grid; gap: var(--space-5) var(--space-6); max-width: 52rem; }
.build-form .field { margin: 0; }
.build-form .field label { font-size: var(--text-2); color: var(--text); }
.build-form .field-hint { font-size: var(--text-2); }
.build-form select {
  font: inherit; padding: var(--space-2) var(--space-3); border: 1px solid var(--border);
  border-radius: var(--radius-2); background: var(--surface); color: var(--text); min-height: 2.5rem;
}
.build-form select:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.build-form input[type="text"], .build-form input[type="email"], .build-form select { width: 100%; font-size: var(--text-2); }
.build-form .field--check { display: flex; flex-direction: row; align-items: center; gap: var(--space-3); }
.build-form .field--check input { width: 1.25rem; height: 1.25rem; min-height: 0; margin: 0; }
.build-form .field--check label { font-size: var(--text-2); text-transform: none; letter-spacing: normal; color: var(--text); }
.build-form p { margin: 0; }
@media (min-width: 720px) {
  .build-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .build-form__email, .build-form__wide { grid-column: 1 / -1; }
  .build-form__email input { max-width: 26rem; }
}
@media (min-width: 960px) {
  .build-hero { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: var(--space-10); }
  .build-join { padding: var(--space-10); }
}
@media (prefers-reduced-motion: no-preference) {
  .build-hero h1, .build-hero__lede, .build-benefits li, .build-hero__actions, .build-hero__map, .build-join h2, .build-join__lede, .build-form .field {
    animation: build-rise 560ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
  .build-hero__lede { animation-delay: 70ms; }
  .build-benefits li:nth-child(1) { animation-delay: 140ms; }
  .build-benefits li:nth-child(2) { animation-delay: 210ms; }
  .build-benefits li:nth-child(3) { animation-delay: 280ms; }
  .build-hero__actions { animation-delay: 350ms; }
  .build-hero__map { animation: build-rise 720ms cubic-bezier(0.2, 0.7, 0.2, 1) 120ms both; }
  .build-hero__map img { transition: transform 900ms cubic-bezier(0.2, 0.7, 0.2, 1); }
  .build-hero__map:hover img { transform: scale(1.03); }
  .build-join h2 { animation-delay: 200ms; }
  .build-join__lede { animation-delay: 260ms; }
  .build-form .button-link { transition: transform 120ms ease; }
  .build-form .button-link:active, .build-hero__actions .button-link:active { transform: translateY(1px); }
}
@keyframes build-rise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
/* end lane build-a-deal */

/* A phone's sheet is the stage figures and the rows (owner, 2026-11-03): the summary strip (records, GW and the
   capacity bars) and the generation block are desktop's. */
@media (max-width: 719px) { .ruler-strip { display: none; } }

/* ---------- Section style D, "ledger" (owner, 2026-11-05: "D looks much better"; docs/31-design-practices.md §2.2) ----------
   Record pages (plant, project, connection point, their Sources and Operations pages) and company pages: every
   section is one bordered block (1px --border, no radius, no shadow) on --surface, under an ink title bar
   (--primary ground, --primary-ink text, 16px/600, 36px tall) with its count or status at the bar's right.
   The lead's bar carries the record's status chip, the one accent. Inside a block, each part (a fact table, a
   table, a chart, a line of text) is a row closed by a hairline; fact tables are label | value ledgers (above).
   The bar titles the section; a table's column headers stay unbanded, quiet on --surface. This departs on
   purpose from the taste skill's app-screen "no header bands" rule (app-screens.md §7.2, §13): the owner
   chose it. The Deal room's join block is direction B, "title strip" (below), not this. The blocks are the
   `data-band` hooks (lead, section, panel, foot) and the band's Nearby. */
.record-page :is([data-band="lead"], [data-band="section"], [data-band="foot"], [data-band="panel"]:not([hidden]), .record-around .record-section) {
  margin: var(--lg-gap) 0 0; padding: 0; background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: 0; min-width: 0;
}
/* a block's parts: no margins of their own, a hairline between each two */
.record-page :is([data-band], .record-around .record-section) > * { margin-block: 0; max-width: none; }
.record-page :is([data-band], .record-around .record-section) > :not(.record-section__head, .visually-hidden, [popover], script, link, template, [hidden], h2:first-child, :empty)
  ~ :not(.record-section__head, .visually-hidden, [popover], script, link, template, [hidden]) { border-top: 1px solid var(--border); }
/* a part that is text (a line, a list, a chart, a card) takes the cell padding; tables and ledgers run edge to edge */
.record-page :is([data-band], .record-around .record-section) > :not(.record-section__head, dl, .table-scroll, .record-more, .visually-hidden, [popover], script, link, template, .provenance-panel, :empty) {
  padding: var(--space-3) var(--lg-px);
}
/* a chart in a block: room on the left for its y labels ("200 MWh"), which hang past the plot's edge */
.record-page :is([data-band], .record-around .record-section) > :is(.ops-chart, .ops-charts) { padding-inline-start: calc(var(--lg-px) + var(--space-5)); }
/* a timeline in a block: its rows' rules only between entries; the block draws the edges */
.record-page [data-band] .timeline { border-top: 0; }
.record-page [data-band] .timeline li:last-child { border-bottom: 0; }
.record-page :is([data-band], .record-around .record-section) > dl:not(:has(> div)) { display: none; }
/* a block that holds ledgers is itself the two-column grid, so its ledgers (the headline, the key facts, the
   developer and owner, the details) share one label width: the block's longest label */
.record-page [data-band]:has(> :is(.fact-table, .record-headline)) { display: grid; grid-template-columns: fit-content(var(--lg-cap)) minmax(0, 1fr); }
.record-page [data-band]:has(> :is(.fact-table, .record-headline)) > * { grid-column: 1 / -1; }
.record-page [data-band] > :is(.fact-table, .record-headline) { grid-template-columns: subgrid; }

/* ----- The bar ----- */
.record-page :is([data-band], .record-around .record-section) > .record-section__head,
.record-page .provenance-panel > h2:not(.visually-hidden) {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3);
  min-height: var(--lg-bar-h); margin: -1px -1px 0; padding: var(--space-1) var(--lg-px);
  background: var(--primary); color: var(--primary-ink);
  font-size: var(--text-2); font-weight: 600; letter-spacing: 0; line-height: 1.25;
  -webkit-print-color-adjust: exact; print-color-adjust: exact;
}
.record-page .record-section__head .record-section__title { margin: 0; color: inherit; font: inherit; letter-spacing: inherit; }
/* a one-kind company's panel title carries its count: the title fills the bar, the count at its right */
.org-page .org-panel__head .org-panel__title { display: flex; flex: 1; align-items: baseline; gap: var(--space-3); margin: 0; color: inherit; font: inherit; }
.org-page .org-panel__head .org-panel__n { margin-inline-start: auto; color: var(--border); font-size: var(--text-1); font-weight: 400; }
/* the count, unit or source at the bar's right: the border tone reads quiet on the ink in both themes */
.record-page .record-section__head .record-section__aside {
  margin: 0 0 0 auto; color: var(--border); font-size: var(--text-1); font-weight: 400; font-variant-numeric: tabular-nums;
}
.record-page .record-section__head :is(a, a:visited, .map-info) { color: inherit; }
.record-page .record-section__head .ops-range { margin: 0 0 0 auto; }
.record-page .record-section__head .ops-range button {
  min-height: 1.625rem; padding-block: 0; background: transparent; color: var(--border); border-color: var(--border); font-size: var(--text-1);
}
.record-page .record-section__head .ops-range button[aria-pressed="true"] { background: var(--primary-ink); color: var(--primary); border-color: var(--primary-ink); }
/* the lead's status chip: the bar's one accent, at its right; a status note ("ran 11% of 2025") just before it */
.record-lead__head .record-lead__note + :is(.chip, .record-header__chip) { margin-inline-start: 0; }
.record-lead__head > :is(.chip, .record-header__chip) { margin-inline-start: auto; flex: none; }
.record-lead__head .record-header__chip { text-decoration: none; }
.record-lead__head .chip { font-weight: 600; white-space: nowrap; }

/* ----- Rows in a block ----- */
.record-page [data-band] .record-headline + .fact-table, .record-page [data-band] .fact-table + .fact-table { border-top: 1px solid var(--border); }
/* a plant's "Operated by" and a company's "Registered in" or "Parent": rows of the lead's ledger */
.record-page .fact-table > :is(.record-company, .org-facts__item) { margin: 0; }
.record-page .fact-table .record-company__label, .record-page .fact-table .org-facts__label { margin: 0; font-size: var(--text-label); }
.record-page .fact-table :is(.record-company, .org-facts__item) a { text-decoration: underline dotted; text-underline-offset: 0.2em; }
@media (max-width: 719px) { .record-page .fact-table .record-company__label, .record-page .fact-table .org-facts__label { font-size: var(--text-1); } }
/* "N more fields": a summary row; its fields a ledger under it */
.record-page [data-band] > .record-more > summary { display: list-item; list-style-position: inside; min-height: 0; padding: var(--lg-py) var(--lg-px); line-height: 1.45; }
.record-page [data-band] > .record-more[open] > summary { margin: 0; border-bottom: 1px solid var(--border); }
.record-page [data-band] > .record-more > :not(summary) { margin: 0; }
.record-page [data-band] > .record-more > :not(summary, .fact-table, .table-scroll) { padding: var(--space-3) var(--lg-px); }
.record-page [data-band] > .record-more--none { padding: var(--lg-py) var(--lg-px); color: var(--text-muted); font-size: var(--text-1); }
/* the contacts line: a full-width row */
.record-page [data-band] > .contacts-card { border-radius: 0; background: var(--surface); padding: var(--space-2) var(--lg-px); }
/* the Sources foot: the bar says "Sources", so the line's own label is for assistive technology */
.record-page .record-foot .credits__k { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.record-page .record-foot > :is(.credits, .record-foot__source, .record-foot__report) { max-width: none; padding: var(--space-2) var(--lg-px); }
/* a provenance panel inside a block whose bar names it (a company's Sources tab) adds no frame of its own */
.record-page [data-band] > .provenance-panel { margin: 0; padding: 0 var(--lg-px) var(--space-3); border: 0; background: none; }
.record-page .provenance-panel > h2:not(.visually-hidden) { margin: -1px -1px var(--space-2); }
.record-page .provenance-panel:not([data-band] [data-band]) > :not(h2, .record-section__head) { padding-inline: var(--lg-px); }

/* ----- Tables in a block: rules and alignment; the header row quiet on --surface, no band ----- */
.record-page [data-band] .table-scroll, .record-page .record-around .record-section .table-scroll { margin: 0; }
.record-page :is([data-band], .record-around .record-section) .record-table { margin: 0; font-size: var(--text-2); }
.record-page :is([data-band], .record-around .record-section) .record-table th {
  position: static; background: var(--surface); color: var(--text-muted); font-size: var(--text-label); font-weight: 500;
  padding: var(--lg-py) var(--lg-px); border-bottom: 1px solid var(--border);
}
.record-page :is([data-band], .record-around .record-section) .record-table th.sortable { padding: 0; }
.record-page :is([data-band], .record-around .record-section) .record-table td { padding: var(--lg-py) var(--lg-px); border-bottom: 1px solid var(--border); font-variant-numeric: tabular-nums; }
.record-page :is([data-band], .record-around .record-section) .record-table tbody tr:last-child td { border-bottom: 0; }
.record-page :is([data-band], .record-around .record-section) .record-table tbody tr:hover { background: var(--bg); }
/* columns as wide as their content (owner, 2026-11-05), the last one taking what is left; numbers stay
   right-aligned in their own column. A table too wide for the block scrolls in its frame. The reference pages'
   tables (Sources & licences, Coverage & methodology) keep their own column widths. */
@media (min-width: 720px) {
  .record-page:not(.ref-page) [data-band] > .table-scroll > .record-table:not(.record-table--compact) :is(th, td):not(:last-child) { width: 1%; white-space: nowrap; }
}

/* ----- A company's tabs: the strip is the bar, the open panel the block under it ----- */
.org-page .org-tabs {
  --org-tab-gap: var(--space-5);
  margin: var(--lg-gap) 0 0; padding: 0 var(--lg-px); min-height: var(--lg-bar-h); align-items: stretch;
  background: var(--primary); border: 1px solid var(--primary); border-bottom: 0;
}
.org-page .org-tabs__tab, .org-page .org-tabs__tab:visited {
  min-height: var(--lg-bar-h); margin: 0; color: var(--border); font-size: var(--text-2); border-bottom: 2px solid transparent;
}
.org-page .org-tabs__tab:hover { color: var(--primary-ink); border-bottom-color: transparent; }
.org-page .org-tabs__tab:focus-visible { outline-color: var(--primary-ink); }
.org-page .org-tabs__tab[aria-current="page"], .org-page .org-tabs__tab[aria-selected="true"] { color: var(--primary-ink); font-weight: 600; border-bottom-color: var(--primary-ink); }
.org-page .org-tabs__n { color: inherit; opacity: 0.8; }
.org-page .org-tabs + .org-panel:not([hidden]), .org-page .org-tabs ~ .org-panel:not([hidden]) { margin-top: 0; border-top: 0; }
.org-page .org-panel > .org-strip { padding: var(--space-3) var(--lg-px); }
.org-page .org-ops__head { justify-content: flex-start; }

/* ----- Phone: the pair stays two columns; a table becomes one small ledger per row ----- */
@media (max-width: 719px) {
  .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) tr {
    margin: 0; padding: 0; border: 0; border-radius: 0; border-bottom: 1px solid var(--border);
  }
  .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) tbody tr:last-child { border-bottom: 0; }
  .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) td {
    display: block; position: relative; min-height: calc(var(--text-2) * 1.45 + 2 * var(--lg-py));
    padding: var(--lg-py) var(--lg-px) var(--lg-py) calc(var(--lg-label) + var(--lg-px));
    background: var(--surface); border-bottom: 1px solid var(--border); text-align: left;
  }
  .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) tr td:last-child { border-bottom: 0; }
  /* the label cell, drawn from the cell's data-label: the ground tint, its own rule on the right */
  .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) td::before {
    position: absolute; inset: 0 auto 0 0; width: var(--lg-label); box-sizing: border-box; padding: var(--lg-py) var(--lg-px);
    background: var(--bg); border-inline-end: 1px solid var(--border);
    font-size: var(--text-1); line-height: calc(var(--text-2) * 1.45); color: var(--text-muted);
  }
  /* the first cell (the company, the generator) heads its row's ledger: full width on the tint, no label */
  .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) td:first-child,
  .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) td[colspan] {
    padding-inline-start: var(--lg-px); background: var(--bg); font-weight: 600;
  }
  .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) :is(td:first-child, td[colspan])::before { content: none; }
  /* the compact lists (a company's projects, Nearby) keep their two-line rows, inside the block's padding */
  .record-page :is([data-band], .record-around .record-section) .record-table--compact thead tr,
  .record-page :is([data-band], .record-around .record-section) .record-table--compact tbody tr { padding-inline: var(--lg-px); }
  .record-page :is([data-band], .record-around .record-section) .record-table--compact thead tr { padding-top: var(--space-2); }
  .record-page :is([data-band], .record-around .record-section) .record-table--compact tbody tr:first-child { border-top: 1px solid var(--border); }
  .record-page :is([data-band], .record-around .record-section) .record-table--compact tbody tr:last-child { border-bottom: 0; }
  .org-page .org-tabs { --org-tab-gap: var(--space-4); }
}

/* ---------- The Deal room's join block: direction B, "title strip" (owner, 2026-11-05: "I love d for everything
   except the beta for which I think the strip is best") ----------
   On /build only: one bordered block on --surface; its heading and line sit in a tinted strip (--active) on the
   left, a 1px --border on its right, the form on the surface beside it. Under 720px the strip is a bar over
   the form. */
.build-page .build-join {
  display: block; margin-top: var(--space-10); padding: 0; background: var(--surface);
  border: 1px solid var(--border); border-radius: 0;
}
.build-page .build-join__head { padding: var(--space-6); background: var(--active); }
.build-page .build-join__head h2 { margin: 0; font-size: var(--text-5); letter-spacing: -0.01em; line-height: 1.2; }
.build-page .build-join__lede { margin: var(--space-2) 0 0; max-width: none; font-size: var(--text-2); line-height: 1.6; color: var(--text-muted); }
.build-page .build-join__body { padding: var(--space-6); min-width: 0; background: var(--active); }
/* The fields pop on the darker body (owner, 2026-11-06: "darken the backdrop so the fields pop"): white inputs
   with a firmer edge; the strip steps one shade darker again so it still reads as the title. */
.build-page .build-join__head { background: var(--border); }
.build-page .build-form input[type="text"], .build-page .build-form input[type="email"], .build-page .build-form select {
  background: var(--surface); border-color: var(--control);
}
/* Three rows from 960px (owner, 2026-11-06: "maybe just convert 4 rows to 3"): email, name and company; role and
   what you'd use it for; the email-me box and the button. */
@media (min-width: 960px) {
  .build-page .build-form { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: none; align-items: start; }
  /* The note's hint (legal-pinned copy) drops under its box, so the row's labels and boxes line up. */
  .build-page .build-form__note { display: flex; flex-direction: column; }
  .build-page .build-form__note .field-hint { order: 3; margin-top: var(--space-1); }
  .build-page .build-form__consent, .build-page .build-form__submit { align-self: center; }
  .build-page .build-form__email { grid-column: auto; }
  .build-page .build-form__email input { max-width: none; }
  .build-page .build-form__note { grid-column: span 2; }
  .build-page .build-form__consent { grid-column: span 2; }
  .build-page .build-form__submit { grid-column: auto; justify-self: end; }
}
.build-page .build-join__body > .notice { margin-top: 0; }
@media (min-width: 720px) {
  .build-page .build-join { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); }
  .build-page .build-join__head { padding: var(--space-9) var(--space-6); border-inline-end: 1px solid var(--border); }
}
@media (max-width: 719px) {
  .build-page .build-join__head { padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border); }
  .build-page .build-join__body { padding: var(--space-5); }
}


/* ---------- Section style E (owner, 2026-11-05: "I like it, don't make the top bar so thick. Keep it to one
   line if we can"): D underneath, with five aspects, each behind its own attribute on <html> (base.html sets
   all five). With every attribute off the page is D. docs/31-design-practices.md §2.2. ---------- */
/* the bar's subtitle exists in the markup (rt.bar `sub`) but is E-a's */
.record-section__sub { display: none; }
/* a sourced figure (E-d) is a real button opening its source's popover; off, it reads as the plain figure */
.sourced-fig {
  appearance: none; margin: 0; padding: 0; border: 0; background: none; color: inherit; font: inherit;
  letter-spacing: inherit; line-height: inherit; text-align: inherit; cursor: pointer;
}
.sourced-fig:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
@supports (anchor-name: --a) {
  .sourced-fig { anchor-name: --sourced-fig; }
  .sourced-pop { position-anchor: --sourced-fig; inset: auto; top: anchor(bottom); left: anchor(left); margin: var(--space-1) 0 0; }
}

/* E-a, the one-line bar: the title at most 1.125rem/600, its subtitle after it on the same line, muted and cut
   with an ellipsis, the chip or count at the right; a phone drops the subtitle rather than wrap. */
html[data-e-a] .record-page .record-section__head { flex-wrap: nowrap; column-gap: var(--space-3); }
html[data-e-a] .record-page .record-section__head .record-section__title { flex: 0 1 auto; min-width: 0; font-size: 1.125rem; }
html[data-e-a] .record-page .record-section__head > :is(.record-section__aside, .chip, .record-header__chip, .ops-range, .map-info) { flex: none; }
html[data-e-a] .record-page .record-section__sub {
  display: block; flex: 0 1000 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: color-mix(in srgb, var(--primary-ink) 72%, var(--primary)); font-size: var(--text-label); font-weight: 400;
}
/* a count the subtitle already says ("4 companies") leaves the right of the bar */
html[data-e-a] .record-page .record-section__head:has(> .record-section__sub) > .record-section__aside--count { display: none; }
/* the kind line is the Key facts subtitle on a wide screen */
@media (min-width: 720px) {
  html[data-e-a] .record-page .record-header:has(.record-lead__head > .record-section__sub) > .record-kind {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
}
@media (max-width: 719px) {
  html[data-e-a] .record-page .record-section__sub { display: none; }
  html[data-e-a] .record-page .record-section__head:has(> .record-section__sub) > .record-section__aside--count { display: inline; }
}

/* E-b, the sheet: header to last section on one white sheet (--surface, a 1px --border edge) on the --bg ground,
   at the sheet's measure plus its padding; edge to edge on a phone. */
html[data-e-b] .record-page > .record-body {
  --e-sheet-pad: var(--space-7);
  display: block; max-width: calc(var(--sheet-w, 65rem) + 2 * var(--e-sheet-pad) + 2px); margin: var(--space-5) 0 0;
  padding: var(--space-1) var(--e-sheet-pad) var(--e-sheet-pad); background: var(--surface); border: 1px solid var(--border);
}
html[data-e-b] .record-page > .record-body > .record-header { padding-top: var(--space-5); }
@media (max-width: 719px) {
  html[data-e-b] .record-page > .record-body {
    --e-sheet-pad: var(--main-gutter, var(--space-4));
    margin-inline: calc(-1 * var(--e-sheet-pad)); border-inline: 0;
  }
}

/* E-c, ledger numbers: values at 600 in tabular lining figures; numeric table cells right-aligned (left in a
   phone's per-row ledger); ledger values stay left-aligned. Green and red are for difference figures only, and
   these pages print none. */
html[data-e-c] .record-page :is(.fact-table, .record-headline) dd { font-weight: 600; font-variant-numeric: tabular-nums lining-nums; }
html[data-e-c] .record-page :is(.fact-table__none, .fact-table--empty dd) { font-weight: 400; }
/* a ledger whose values are sentences (About's "What you can do here") keeps them at the text weight */
html[data-e-c] .record-page .fact-table--prose dd { font-weight: 400; }
html[data-e-c] .record-page .record-table :is(td, th).num { text-align: right; font-variant-numeric: tabular-nums lining-nums; }
html[data-e-c] .record-page .record-table td.num { font-weight: 600; }
@media (max-width: 719px) {
  html[data-e-c] .record-page [data-band] .record-table:not(.record-table--compact) td.num { text-align: left; }
  html[data-e-c] .record-page [data-band] .record-table:not(.record-table--compact) td.num::before { font-weight: 400; }
}

/* E-d, sourced figures: a dotted accent underline marks a figure whose source opens on hover, tap or keyboard;
   dotted means sourced only, so the ledgers' other links take a solid underline. */
html[data-e-d] .record-page .sourced-fig {
  text-decoration: underline dotted var(--accent); text-decoration-thickness: 2px; text-underline-offset: 0.22em; cursor: help;
}
html[data-e-d] .record-page :is(.fact-table, .record-headline) a { text-decoration-style: solid; text-decoration-thickness: 1px; }
/* in print a popover cannot open, so the source follows its figure in small type */
@media print {
  html[data-e-d] .record-page .sourced-pop {
    display: inline; position: static; inset: auto; width: auto; max-height: none; overflow: visible; margin: 0 0 0 var(--space-2);
    padding: 0; border: 0; background: none; color: var(--text-muted); font-size: var(--text-1); font-weight: 400;
  }
  html[data-e-d] .record-page .sourced-pop > .map-pop__title { display: none; }
  html[data-e-d] .record-page .sourced-pop > span { display: inline; }
  html[data-e-d] .record-page .sourced-pop > span + span::before { content: " · "; }
}

/* E-e, the status chip: the lead's chip solid in the accent (tokens only). D's greys stay as they are (owner,
   2026-11-05: "keep the grey background of D"): the label cells on --bg, the page ground, /build's grey strip. */
html[data-e-e] .record-lead__head :is(.chip--success, .chip--progress) { background: var(--accent-deep); color: var(--accent-ink); }

/* Datasets tab and footer status dot */
/* The dot is a mark plus a word, never colour alone. Green and red reuse the status families; amber is the
   transmission amber (light) and its lifted twin (dark); grey is the muted text. */
.status-dot { --dot: var(--text-muted); display: inline-flex; align-items: center; gap: var(--space-2); white-space: nowrap; }
.status-dot__mark { flex: none; width: 0.625rem; height: 0.625rem; border-radius: 50%; background: var(--dot); }
.status-dot--ok { --dot: var(--family-progress-text); }
.status-dot--late { --dot: #8a6300; }
.status-dot--down { --dot: var(--family-danger-text); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .status-dot--late { --dot: #e0b44a; } }
:root[data-theme="dark"] .status-dot--late { --dot: #e0b44a; }
a.status-dot { color: inherit; min-height: 1.5rem; }
/* Who it's for: a title and five links in one wrapping row, like the reference links above it. */
.site-footer__for { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--space-5); margin: 0 0 var(--space-3); }
.site-footer__for-title { margin: 0; color: var(--text-muted); }
.site-footer__for ul { display: flex; flex-wrap: wrap; gap: 0 var(--space-5); list-style: none; margin: 0; padding: 0; }
.site-footer__for a { display: inline-flex; align-items: center; min-height: 1.5rem; }
.datasets-status { margin: var(--space-4) 0; }
.datasets-table td .map-info { vertical-align: middle; margin-inline-start: var(--space-1); }
/* Below 720px a cell is a label and its value on one row; the coverage cell's two lines stack instead. */
@media (max-width: 719px) {
  .datasets-table td.datasets-table__stack { flex-direction: column; justify-content: flex-start; gap: 2px; }
}
@media (min-width: 720px) {
  .datasets-table { table-layout: auto; width: 100%; }
  .datasets-table td, .datasets-table th { vertical-align: top; }
}
/* Persona pages (/for/*) (web/personas.py; coordinator, 2026-11-06): About's section style E. A one-line title,
   then ledger blocks; a count is a link to the map on its view, its MW quiet beside it. The title is set as
   About's and holds one line from 720px (every persona title is 33 characters or fewer). */
.persona-head h1 { font-size: clamp(2.25rem, 4.8vw, 4.5rem); line-height: 1.02; letter-spacing: -0.02em; }
/* a job's and an example's name is what the row is for: set at body size, not as a quiet label */
.record-page :is(.persona-jobs__list, .persona-examples__list) :is(dt, dd) { font-size: var(--text-2); }
.persona-counts__figure, .persona-counts__figure:visited { color: var(--text); text-underline-offset: 0.2em; }
.persona-counts__figure:hover { color: var(--link); }
.ref-page .persona-counts__mw { margin-inline-start: var(--space-2); color: var(--text-muted); font-weight: 400; }
.ref-page .persona-counts__none { color: var(--text-muted); }
.ref-page .persona-next__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
/* Generation charts and API prompt */
/* One chart component for net generation and fuel burned (web/static/js/record_charts.js `series`; owner,
   2026-11-06): a filled area by month with no gaps, stacked by fuel, a 1.5px surface line between layers, a
   crosshair and a readout; Yearly keeps the columns. The map's summary stacks five groups in the map's kind
   hues (`--gen5-*`), each a chart step validated with the dataviz validator as stacked neighbours and on every
   pair, in light (on #ffffff) and dark (on #17181b and #0e0f11): decisions log 2026-11-06. */
:root {
  --gen5-fossil: #254dac;
  --gen5-clean-firm: #56bfd4;
  --gen5-wind-solar: #367646;
  --gen5-storage: #a672dc;
  --gen5-other: #cfa024;
  --chart-ground: var(--surface);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --gen5-fossil: #0c68c2;
    --gen5-clean-firm: #35a2b7;
    --gen5-wind-solar: #1c7b5a;
    --gen5-storage: #8184f1;
    --gen5-other: #ac8622;
  }
}
:root[data-theme="dark"] {
  --gen5-fossil: #0c68c2;
  --gen5-clean-firm: #35a2b7;
  --gen5-wind-solar: #1c7b5a;
  --gen5-storage: #8184f1;
  --gen5-other: #ac8622;
}
.chart-seg--gen5-fossil, .ops-legend__key--gen5-fossil { fill: var(--gen5-fossil); background: var(--gen5-fossil); }
.chart-seg--gen5-clean-firm, .ops-legend__key--gen5-clean-firm { fill: var(--gen5-clean-firm); background: var(--gen5-clean-firm); }
.chart-seg--gen5-wind-solar, .ops-legend__key--gen5-wind-solar { fill: var(--gen5-wind-solar); background: var(--gen5-wind-solar); }
.chart-seg--gen5-storage, .ops-legend__key--gen5-storage { fill: var(--gen5-storage); background: var(--gen5-storage); }
.chart-seg--gen5-other, .ops-legend__key--gen5-other { fill: var(--gen5-other); background: var(--gen5-other); }

/* The area: a plant's single series in its fuel's colour, as its columns were. */
.chart-area { stroke: none; }
.chart-area--one { fill: var(--chart-1); }
.ops-chart--gen-gas .chart-area--one { fill: var(--fuel-gas); }
.ops-chart--gen-coal .chart-area--one { fill: var(--fuel-coal); }
.ops-chart--gen-oil .chart-area--one { fill: var(--fuel-oil); }
.ops-chart--gen-nuclear .chart-area--one { fill: var(--fuel-nuclear); }
.ops-chart--gen-hydro .chart-area--one { fill: var(--fuel-hydro); }
.ops-chart--gen-geothermal .chart-area--one { fill: var(--fuel-geothermal); }
.ops-chart--gen-wind .chart-area--one { fill: var(--fuel-wind); }
.ops-chart--gen-solar .chart-area--one { fill: var(--fuel-solar); }
.ops-chart--gen-storage .chart-area--one { fill: var(--fuel-storage); }
.ops-chart--gen-bio .chart-area--one { fill: var(--fuel-bio); }
.ops-chart--gen-load .chart-area--one { fill: var(--fuel-load); }
.ops-chart--gen-other .chart-area--one { fill: var(--fuel-other); }
.chart-area__gap { fill: none; stroke: var(--chart-ground); stroke-linejoin: round; }
.chart-cross { stroke: var(--text); stroke-width: 1; pointer-events: none; }
.chart-cross__dot { fill: var(--text); stroke: var(--chart-ground); stroke-width: 2; pointer-events: none; }
.chart-hit:not(.chart-hit--bar) { cursor: crosshair; touch-action: pan-y; }
.ops-chart__plot:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; border-radius: 2px; }

/* The readout: the period and its total, then a row per fuel (a short line key, the share, the name, the
   amount), then the plant's capacity factor under a rule. Values lead and wear the text ink. */
.chart-tip:has(.chart-tip__head) { display: grid; gap: 2px; min-width: 11rem; padding: var(--space-2) var(--space-3); }
.chart-tip__head { display: flex; justify-content: space-between; gap: var(--space-4); }
.chart-tip__when { color: var(--text-muted); }
.chart-tip__total { font-weight: 600; }
.chart-tip__caption { margin-top: 2px; font-size: 11px; color: var(--text-muted); }
.chart-tip__row { display: grid; grid-template-columns: 0.75rem 3.25rem minmax(0, 1fr) auto; align-items: center; gap: var(--space-2); }
.chart-tip__key { width: 0.75rem; height: 3px; border-radius: 2px; }
:where(.chart-tip__key) { background: var(--text-muted); }
.chart-tip__value { font-weight: 600; text-align: right; white-space: nowrap; }
.chart-tip__label { color: var(--text-muted); }
.chart-tip__note { color: var(--text-muted); text-align: right; white-space: nowrap; }
.chart-tip__row--foot { grid-template-columns: minmax(0, 1fr) auto; margin-top: 2px; padding-top: var(--space-1); border-top: 1px solid var(--rule); }
.chart-tip__row--foot .chart-tip__label { color: var(--text-muted); }

/* The map's summary: the plot never shrinks below its minimum, and the desktop peek (the list's 108px under the
   band) shows the block's header line only, so a plot is never cut to its tops; half and full draw it whole. */
.ruler-gen { --chart-ground: var(--surface); }
.ruler-gen__chart .ops-chart__plot { height: 8.5rem; min-height: 8.5rem; }
@media (min-width: 720px) and (min-height: 37.51rem) {
  .map-landing[data-sheet="closed"] .ruler-gen__body,
  .map-landing[data-sheet="closed"] .ruler-gen__ctl { display: none; }
  .map-landing[data-sheet="closed"] .ruler-gen { padding-bottom: var(--space-2); }
  .map-landing[data-sheet="closed"] .api-prompt { display: none; }
}

/* The "Get live data / API" prompt: one line, muted, with its dismiss button (web/static/js/api_prompt.js on a
   record page's foot; map.js under the list once the reader is past its first fifty rows). */
.api-prompt { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-1); color: var(--text-muted); }
.api-prompt[hidden] { display: none; }
.api-prompt__text { flex: 1 1 auto; min-width: 0; margin: 0; }
.api-prompt__text a { color: var(--text); }
.api-prompt__close {
  flex: none; display: inline-flex; align-items: center; justify-content: center; width: 1.75rem; height: 1.75rem; margin: 0; padding: 0;
  border: 0; border-radius: var(--radius-2); background: none; color: var(--text-muted); cursor: pointer;
}
.api-prompt__close:hover { background: var(--raised); color: var(--text); }
.api-prompt__close:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.ruler-panel > .api-prompt { flex: none; padding: var(--space-1) 16px var(--space-2); border-top: 1px solid var(--rule); }
.record-foot .api-prompt { margin: var(--space-3) 0 0; }
@media (max-width: 719px) {
  .api-prompt__close { width: 2.75rem; height: 2.75rem; }
  .ruler-panel > .api-prompt { padding: 0 16px; }
}
/* Estimate badges */
/* "Estimate" (services/api/estimates.py; `_macros.html::estimate_chip`, map.js `estimateChip`): a small outlined
   chip right after an inferred value, quieter than the value, a button that opens its popover. Tokens only. */
.estimate-chip {
  appearance: none; display: inline-flex; align-items: center; margin: 0 0 0 var(--space-1); padding: 0 var(--space-1);
  border: 1px solid var(--text-muted); border-radius: var(--radius-1); background: none; color: var(--text-muted);
  font: 500 var(--text-label)/1.4 var(--font-body); letter-spacing: 0; white-space: nowrap; vertical-align: baseline;
  cursor: pointer;
}
.estimate-chip:hover { color: var(--text); border-color: currentColor; }
.estimate-chip:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.estimate-pop a { white-space: nowrap; }
@media print { .estimate-chip { border: 0; padding: 0; } }
/* Companies sector filter and company search */
/* The Companies tab's sector chips (owner, 2026-11-06): the map's chips as links, one line that scrolls
   sideways where it does not fit, so the row never wraps or shifts the list below it. */
.org-sectors {
  display: flex; gap: var(--space-2); margin: 0 0 var(--space-3); overflow-x: auto; scrollbar-width: none;
}
.org-sectors::-webkit-scrollbar { display: none; }
.org-sectors__chip { text-decoration: none; }
.org-sectors__chip[data-on]:hover { color: var(--surface); }
.org-sectors__chip:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* The map's company chip (`org`): a token chip whose name may be long; the x stays on screen. */
.fchip--token[data-off="org"] .fchip__label { max-width: 12rem; }
/* The map's record preview (#ruler-record) */
/* Section style E, as the record pages wear it (owner, 2026-11-06: "Could you reformat the list page preview in
   the same style as E and the other pages"; docs/31-design-practices.md §2.2): one block on --surface with a 1px
   --border edge and no radius; a one-line ink bar (the name as its title, linked; kind · type muted after it;
   the solid status chip at the right); then label | value rows on D's greys, the label column on --bg and as
   wide as the longest label (7rem to --lg-cap), values at 600 in tabular figures; the contacts line and the foot
   (the source and its (i), the record's page) as full-width rows. No card island around it. map.js `recordBar`,
   `fact`, `recordFoot`. */
.ruler-record__block { margin: var(--space-2) 0 0; background: var(--surface); border: 1px solid var(--border); border-radius: 0; min-width: 0; }
.ruler-record__head {
  display: flex; flex-wrap: nowrap; align-items: baseline; column-gap: var(--space-3);
  min-height: var(--lg-bar-h); margin: -1px -1px 0; padding: var(--space-1) var(--lg-px);
  background: var(--primary); color: var(--primary-ink); line-height: 1.25;
  -webkit-print-color-adjust: exact; print-color-adjust: exact;
}
/* the title is the record's name: it wraps rather than cut (a subtitle gives way first) */
.ruler-record__title {
  flex: 0 1 auto; min-width: 0; margin: 0; padding-block: calc((var(--lg-bar-h) - 2 * var(--space-1) - 1.25em) / 2);
  color: inherit; font-size: 1.125rem; font-weight: 600; letter-spacing: 0; line-height: 1.25; overflow-wrap: anywhere;
}
.ruler-record__title a, .ruler-record__title a:visited { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
.ruler-record__title a:focus-visible { outline: 2px solid var(--primary-ink); outline-offset: 2px; }
.ruler-record__sub {
  flex: 0 1000 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: color-mix(in srgb, var(--primary-ink) 72%, var(--primary)); font-size: var(--text-label); font-weight: 400;
}
.ruler-record__chip { display: inline-flex; flex: none; align-items: center; gap: var(--space-1); margin-inline-start: auto; align-self: center; }
.ruler-record__chip .chip { font-weight: 600; }
/* E-e: the status chip solid in the accent, as the lead's on a record page */
html[data-e-e] .ruler-record__chip :is(.chip--success, .chip--progress) { background: var(--accent-deep); color: var(--accent-ink); }
/* a stage estimate's chip reads quiet on the ink, as the bar's count does */
.ruler-record__chip .estimate-chip { margin: 0; color: var(--border); border-color: var(--border); }
.ruler-record__chip .estimate-chip:hover { color: var(--primary-ink); }
/* "Status not current", the loading and the error line: full-width rows under the bar */
.ruler-record__block > :is(.as-of-line, .ruler-record__line) { margin: 0; padding: var(--lg-py) var(--lg-px); border-bottom: 1px solid var(--border); }
.ruler-record__block > .ruler-record__line:last-child { border-bottom: 0; }
/* the ledger: D's fact table (`.fact-table`), E-c's figures */
.ruler-record .ruler-record__facts { margin: 0; }
.ruler-record .ruler-record__facts dd { font-weight: 600; font-variant-numeric: tabular-nums lining-nums; }
.ruler-record .ruler-record__facts dd :is(.ruler-dash, .estimate-chip) { font-weight: 400; }
.ruler-record .ruler-record__facts dd .map-info { vertical-align: middle; margin-block: -0.25rem; }
.ruler-record .ruler-record__facts dd a { text-decoration-style: solid; text-decoration-thickness: 1px; }
/* the Type row is the bar's subtitle from 720px; a phone, which drops the subtitle, keeps the row */
@media (min-width: 720px) { .ruler-record .ruler-record__facts > .ruler-record__type { display: none; } }
/* "Interested in this project?": a full-width part, no tone or radius of its own */
.ruler-record__block > .contacts-card { margin: 0; border-radius: 0; border-top: 1px solid var(--border); background: var(--surface); padding: var(--space-2) var(--lg-px) var(--space-3); }
/* the foot: the source line (its (i) holds licence, credit and date) at the left, the record's page at the right */
.ruler-record__foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-1) var(--space-4);
  padding: var(--space-2) var(--lg-px); border-top: 1px solid var(--border);
}
.ruler-record__foot > .ruler-record__source { flex: 1 1 auto; min-width: 0; margin: 0; font-size: var(--text-1); color: var(--text-muted); }
/* the record's page: the block's one filled button, under the facts, above the source line (owner, 2026-11-08) */
.ruler-record__go { margin: 0; padding: var(--space-3) var(--lg-px); border-top: 1px solid var(--border); }
.ruler-record__go a.ruler-record__open, .ruler-record__go a.ruler-record__open:visited {
  justify-content: center; gap: var(--space-2); min-height: 2.75rem; background: var(--accent-deep); color: var(--accent-ink);
}
.ruler-record__go a.ruler-record__open:hover { filter: brightness(1.12); } /* the accent never fills a button (test_brand C6) */
.ruler-record__block:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
@media (max-width: 719px) {
  .map-landing .ruler-sheet.has-record .ruler-record__block { margin-top: var(--space-3); }
  .ruler-record__sub { display: none; }
  .ruler-record__go a.ruler-record__open { display: flex; width: 100%; }
}
/* Opportunities in E */
/* RFPs, tenders and funding in section style E (owner, 2026-11-06: "also rework opportunities according to our
   new style"; docs/31-design-practices.md §2.2). The list's rows and its recently closed notices are D's ledger
   blocks (`.opp-list.record-page`, `data-band`): the count is the one-line ink bar's title, the scope switch a
   strip of label | bold figure cells on D's greys, the table the block's rows. The record page is a record
   sheet (`.opp-page`): Key facts with the status chip and the value as its sourced headline, the Summary, the
   Status timeline as dated ledger rows and the Sources foot. Every rule sits behind one E switch, so with the
   switches off the page is D. */
/* E-a: the bar's title is the view's count, one line; the strip's parts on one row */
html[data-e-a] .opp-list .opp-results__head .result-count { margin: 0; color: inherit; font-size: 1.125rem; font-weight: 600; line-height: 1.25; }
html[data-e-a] .opp-list .opp-strip { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-5); padding: var(--space-2) var(--lg-px); }
html[data-e-a] .opp-list .opp-strip > :is(p, .scope-switch) { margin: 0; }
html[data-e-a] .opp-list .opp-strip .view-switch { gap: 0; border: 1px solid var(--border); }
html[data-e-a] .opp-list .opp-strip .view-switch__label {
  align-self: stretch; display: inline-flex; align-items: center; margin: 0; padding: 0 var(--space-3);
  background: var(--bg); border-inline-end: 1px solid var(--border); font-size: var(--text-1); font-weight: 400;
}
html[data-e-a] .opp-list .opp-strip .view-switch__link {
  margin: 0; border: 0; border-radius: 0; background: var(--bg); color: var(--text-muted); font-weight: 400;
}
html[data-e-a] .opp-list .opp-strip .view-switch__link + .view-switch__link { border-inline-start: 1px solid var(--border); }
html[data-e-a] .opp-list .opp-strip .view-switch__link[aria-current="page"] { background: var(--surface); color: var(--text); font-weight: 600; }
html[data-e-a] .opp-list .opp-strip .view-switch__link:hover { color: var(--text); }
html[data-e-a] .opp-list .opp-results > .pager { padding: var(--space-2) var(--lg-px); }
html[data-e-a] .opp-list .opp-results > .empty-state { margin: 0; border: 0; border-radius: 0; background: var(--surface); }
/* the recently closed block: its bar, then one row per notice */
html[data-e-a] .opp-list .recent-closed { margin-top: var(--lg-gap); }
html[data-e-a] .opp-list .recent-closed__title { margin: 0; color: inherit; font-size: 1.125rem; font-weight: 600; line-height: 1.25; }
html[data-e-a] .opp-list .recent-closed__window { color: color-mix(in srgb, var(--primary-ink) 72%, var(--primary)); font-size: var(--text-label); }
html[data-e-a] .opp-list .recent-closed > .recent-closed__list { padding: 0; border-top: 1px solid var(--border); }
html[data-e-a] .opp-list .recent-closed__row { padding: var(--lg-py) var(--lg-px); }
html[data-e-a] .opp-list .recent-closed__row:last-child { border-bottom: 0; }
html[data-e-a] .opp-list .recent-closed > .recent-closed__more { margin: 0; padding: var(--space-2) var(--lg-px); }
/* E-c: the counts and the amounts bold in tabular figures; what an amount is, and its dollar figure, at text weight */
html[data-e-c] .opp-list .scope-switch__n { margin-inline-start: var(--space-2); color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums lining-nums; }
html[data-e-c] .opp-list .record-table td.cell-value :is(.cell-value__kind, .cell-value__usd) { font-weight: 400; }
html[data-e-c] .opp-list .record-table td.cell-title { font-weight: 600; }
html[data-e-c] .opp-page .record-headline__unit { font-weight: 400; }
html[data-e-c] .opp-page .record-headline__unit a { color: inherit; }
/* E-a, the record: a long title shows two lines (the Title row prints it whole); the summary a row */
html[data-e-a] .opp-page .detail-header h1.opp-title--long {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; font-size: 1.5rem;
}
html[data-e-a] .opp-page .opp-summary { max-width: 75ch; }
html[data-e-a] .opp-page details.opp-summary > summary { cursor: pointer; }
html[data-e-a] .opp-page details.opp-summary[open] > summary { display: none; }
html[data-e-a] .opp-page details.opp-summary > p { margin: 0; }
html[data-e-a] .opp-page .record-foot > .provenance-panel { padding-top: var(--space-2); }
html[data-e-a] .opp-page .record-foot > .report-problem { margin: 0; padding: var(--space-2) var(--lg-px); }
@media (max-width: 719px) {
  html[data-e-a] .opp-list .opp-strip { gap: var(--space-2) var(--space-3); }
  /* the phone's two-line rows: the block's cell padding stays off them, as on the plain list */
  html[data-e-a] .opp-list.record-page .record-table--compact tbody td { padding: 0; border: 0; }
  html[data-e-a] .opp-page .detail-header h1.opp-title--long { font-size: 1.25rem; }
}
html[data-e-c] .opp-page .opp-title-row dd { font-weight: 400; }

/* Centred measure on desktop (owner, 2026-11-06: "center align the container box on desktop view to avoid the
   white space imbalance"): record, company and opportunity pages keep their 65rem sheet, and the map's record
   preview its 60rem, but centred in the width they have instead of hugging the left edge. The map, the band
   and full-width blocks stay edge to edge; a phone is unchanged. */
@media (min-width: 720px) {
  .record-sheet > :not(.record-canvas, .record-around), .org-page > :not(.record-canvas, .record-around),
  :is(.record-sheet, .org-page) > .record-body > :not(.record-around),
  html[data-e-b] .record-page > .record-body,
  .record-around__inner,
  .ruler-record__body { margin-inline: auto; }
  /* the E blocks set their own margin (`margin: var(--lg-gap) 0 0`, same selector list): centre them too */
  .record-page :is([data-band="lead"], [data-band="section"], [data-band="foot"], [data-band="panel"]:not([hidden]), .record-around .record-section) {
    margin-inline: auto;
  }
  /* the preview's Back keeps to the centred block's left edge (the body is 60rem with 16px padding) */
  .ruler-record__bar { padding-inline: max(16px, calc((100% - 60rem) / 2 + 16px)); }
}

/* ---------- Refined E (owner, 2026-11-07: "still looks a bit dated ... a pass modernizing the UI"; of the review
   page's three directions, "I like the container boxes", then "I like the style of A but the added contrast of what
   we have today. Could you combine them?") ----------
   Today's contrast is kept: the ink title bars, the tinted label column, values at 600, the solid lead chip and the
   company's ink tab strip. A's refinements are added: blocks and rows divided by the lighter --rule (no cell grid,
   no vertical label rule), roomier rows (9-10px), the headline figure at 24px, names and values without an
   underline until hovered, filled filter fields at one height and radius with the button, a segmented scope
   switch, the quiet tag and the Live stamp as words, and the taste gate's two phone FAILs fixed. Every rule is
   `html:root`-scoped so it lands over D and E. */
/* the tokens below (--m-*) are read by these rules */
html:root .record-page :is([data-band="lead"], [data-band="section"], [data-band="foot"], [data-band="panel"]:not([hidden]), .record-around .record-section),
html:root .ruler-record__block {
  background: var(--m-block-bg); border: var(--m-block-edge); border-top: var(--m-block-cap); border-radius: var(--m-radius);
}
/* rows: one rule token between parts, rows and table rows; the label column loses its tint and its rule */
html:root .record-page :is([data-band], .record-around .record-section) > :not(.record-section__head, .visually-hidden, [popover], script, link, template, [hidden], h2:first-child, :empty)
  ~ :not(.record-section__head, .visually-hidden, [popover], script, link, template, [hidden]) { border-top: var(--m-part-rule); }
html:root .fact-table > div + div { border-top: var(--m-row-rule); }
html:root .record-page [data-band] .record-headline + .fact-table, html:root .record-page [data-band] .fact-table + .fact-table { border-top: var(--m-part-rule); }
html:root :is(.fact-table, .record-headline) dt {
  background: var(--m-label-bg); border-inline-end: 0; padding-block: var(--m-py); padding-inline: var(--m-label-px, var(--lg-px)) var(--space-5);
  font-size: var(--m-label-size); color: var(--text-muted);
}
html:root :is(.fact-table, .record-headline) dd { padding-block: var(--m-py); background: var(--m-block-bg); }
html:root .fact-table dd { font-size: var(--m-value-size); }
html:root[data-e-c] .record-page :is(.fact-table, .record-headline) dd,
html:root .ruler-record .ruler-record__facts dd { font-weight: var(--m-value-weight); }
html:root[data-e-c] .record-page .record-headline dd, html:root .record-headline__value { font-weight: 600; }
html:root .record-headline__value { font-size: var(--m-figure-size); letter-spacing: var(--m-figure-track); line-height: 1.15; }
html:root .record-page [data-band] > .record-more[open] > summary { border-bottom: var(--m-row-rule); }
html:root .record-page :is([data-band], .record-around .record-section) .record-table th {
  background: transparent; border-bottom: var(--m-head-rule); font-weight: 400; color: var(--text-muted); padding-block: var(--space-2);
}
html:root .record-page :is([data-band], .record-around .record-section) .record-table td { border-bottom: var(--m-row-rule); padding-block: var(--m-td-py); }
html:root .record-page :is([data-band], .record-around .record-section) .record-table tbody tr:hover { background: var(--m-hover); }
html:root .record-page [data-band] > .contacts-card, html:root .ruler-record__block > .contacts-card { background: transparent; border-top: var(--m-part-rule); }
html:root .ruler-record__foot { border-top: var(--m-part-rule); }
html:root .ruler-record__block > :is(.as-of-line, .ruler-record__line) { border-bottom: var(--m-row-rule); }
@media (max-width: 719px) {
  html:root .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) tr { border-bottom: var(--m-part-rule); }
  html:root .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) td { background: transparent; border-bottom: 0; }
  html:root .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) td::before { background: transparent; border-inline-end: 0; }
  html:root .record-page :is([data-band], .record-around .record-section) .record-table:not(.record-table--compact) :is(td:first-child, td[colspan]) { background: transparent; }
}
/* links: names and values are ink without an underline until hovered; a link inside running text (the footer, a
   record foot's "Want this as data?" line) keeps its underline, so it is never told apart by colour alone (axe
   link-in-text-block, CI) */
html:root a { text-decoration-color: var(--m-link-line); }
html:root a:hover { text-decoration-color: currentColor; }
html:root :is(.fact-table, .record-headline, .record-table, .ruler-record__facts, .breadcrumbs, .opp-strip, .ruler-record__foot) a:not(:hover, :focus-visible),
html:root .fact-table :is(.record-company, .org-facts__item) a:not(:hover, :focus-visible),
html:root[data-e-d] .record-page :is(.fact-table, .record-headline) a:not(:hover, :focus-visible) { text-decoration-line: var(--m-data-link-line); }
/* the status chip: the family's pale pair everywhere, the lead's included (E-e's solid fill is the tell) */
html:root .chip { border-radius: var(--m-chip-radius); font-weight: 500; }
/* the scope switch on Opportunities: a segmented track, no inner rules */
html:root[data-e-a] .opp-list .opp-strip .view-switch { border: 0; background: var(--active); border-radius: var(--m-control-radius); padding: 2px; }
html:root[data-e-a] .opp-list .opp-strip .view-switch__label { background: transparent; border: 0; }
html:root[data-e-a] .opp-list .opp-strip .view-switch__link { background: transparent; border-radius: max(0px, calc(var(--m-control-radius) - 2px)); }
html:root[data-e-a] .opp-list .opp-strip .view-switch__link + .view-switch__link { border-inline-start: 0; }
html:root[data-e-a] .opp-list .opp-strip .view-switch__link[aria-current="page"] { background: var(--surface); }
html:root[data-e-a] .opp-list .recent-closed > .recent-closed__list { border-top: var(--m-part-rule); }
/* filter fields: a filled control, one height and radius with the button */
html:root .filter-field select, html:root .filter-field input {
  padding-inline: var(--m-field-px); background: var(--m-field-bg); border: var(--m-field-edge); border-bottom: var(--m-field-under);
  border-radius: var(--m-control-radius); min-height: 2.25rem;
}
html:root .filter-bar { border-bottom-color: var(--m-filter-rule); }
html:root .filter-bar__submit { border-radius: var(--m-control-radius); min-height: 2.25rem; }
/* a quiet tag ("No parent recorded") is muted words, not a box */
html:root .record-page .rc-tag--quiet { border-color: transparent; padding-inline: 0; background: none; }
/* the record header's Live stamp: a quiet line, not a boxed widget */
html:root .record-page .detail-header > .delayed-notice { border: 0; padding: 0; background: none; }
html:root .record-page .record-header .detail-header h1 { font-family: var(--m-title-font); font-size: var(--m-h1-size); font-weight: var(--m-h1-weight); letter-spacing: var(--m-h1-track); }

/* the tokens: E's blocks kept, the ink bar becomes a 3px ink cap, rules only between rows */
html:root {
  --m-block-bg: var(--surface); --m-block-edge: 1px solid var(--border); --m-block-cap: 1px solid var(--border); --m-radius: 0;
  --m-head-cap: 3px solid var(--text); --m-bar-margin: -1px -1px 0;
  --m-bar-h: 2.75rem; --m-bar-pad: var(--space-2) var(--lg-px); --m-bar-rule: 0;
  --m-title-font: var(--font-display); --m-title-size: 1rem; --m-title-weight: 600; --m-title-track: -0.005em;
  --m-part-rule: 1px solid var(--rule); --m-row-rule: 1px solid var(--rule); --m-head-rule: 1px solid var(--border);
  --m-label-bg: var(--bg); --m-label-size: var(--text-label); --m-py: 9px; --m-td-py: 10px;
  --m-value-size: var(--text-2); --m-value-weight: 600; --m-figure-size: 1.5rem; --m-figure-track: -0.015em;
  --m-hover: var(--raised); --m-link-line: color-mix(in srgb, currentColor 35%, transparent); --m-data-link-line: none;
  --m-chip-radius: var(--radius-1); --m-control-radius: var(--radius-2); --m-tabs-rule: 1px solid var(--rule);
  --m-h1-size: 1.75rem; --m-h1-weight: 600; --m-h1-track: -0.02em;
  --m-field-px: var(--space-3); --m-field-bg: var(--surface); --m-field-edge: 1px solid var(--border); --m-field-under: 1px solid var(--border); --m-filter-rule: transparent;
}

/* the taste gate's two standing FAILs at 390px */
@media (max-width: 719px) {
  /* the phone list's meta line ends inside the row's 16px margin: one clamped line, not a clipped run */
  html:root .ruler-row__meta { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; line-clamp: 1; white-space: normal; overflow-wrap: anywhere; }
  /* an opportunity's title fits two lines at a phone's width, set at the card-title size, never cut */
  html:root .opp-page .record-header .detail-header h1 { font-size: 1.125rem; line-height: 1.3; letter-spacing: -0.01em; }
}

/* ---------- A with a label break (owner, 2026-11-07: "Could we do A (with the thin top line) plus the darker visual
   break between left and right columns, subject and content") ----------
   Replaces the ink title bars with A's thin top line: each block's title sits on the block's surface under a 3px
   ink cap, in ink, with its count, unit and source muted at the right. The status chip, the estimate chip and a
   company's tab strip follow A (pale chip, tabs underlined on the cap). What A dropped and the owner kept: the
   label column stays tinted (--bg) and gains a 1px --border rule between label and value, a darker line than the
   --rule between rows, so subject and content read as two columns. Values stay at 600. */
html:root .record-page :is([data-band], .record-around .record-section) > .record-section__head,
html:root .record-page .provenance-panel > h2:not(.visually-hidden),
html:root .ruler-record__head {
  min-height: var(--m-bar-h); margin: var(--m-bar-margin, 0); padding: var(--m-bar-pad); background: transparent; color: var(--text);
  border-top: var(--m-head-cap, 0); border-bottom: var(--m-bar-rule); font-family: var(--m-title-font); font-size: var(--m-title-size); font-weight: var(--m-title-weight);
  letter-spacing: var(--m-title-track);
}
html:root[data-e-a] .record-page .record-section__head .record-section__title,
html:root .ruler-record__title { font-size: var(--m-title-size); font-weight: var(--m-title-weight); letter-spacing: var(--m-title-track); }
html:root .ruler-record__title { font-family: var(--m-title-font); padding-block: 0; }
html:root .ruler-record__title a, html:root .ruler-record__title a:visited { color: var(--text); text-decoration: none; }
html:root .ruler-record__title a:hover { text-decoration: underline; }
html:root .ruler-record__title a:focus-visible { outline-color: var(--focus-ring); }
html:root[data-e-a] .record-page .record-section__sub, html:root .ruler-record__sub,
html:root[data-e-a] .opp-list .recent-closed__window {
  color: var(--text-muted); font-family: var(--font-body); letter-spacing: 0;
}
html:root .record-page .record-section__head .record-section__aside,
html:root .org-page .org-panel__head .org-panel__n { color: var(--text-muted); font-family: var(--font-body); }
html:root .record-page .record-section__head .ops-range button { color: var(--text-muted); border-color: var(--border); font-family: var(--font-body); }
html:root .record-page .record-section__head .ops-range button[aria-pressed="true"] { background: var(--text); color: var(--surface); border-color: var(--text); }
html:root .ruler-record__chip .estimate-chip { color: var(--text-muted); border-color: var(--text-muted); }
html:root .ruler-record__chip .estimate-chip:hover { color: var(--text); }
html:root .record-page .record-section__head .map-info { color: var(--text-muted); }
/* the status chip: the family's pale pair everywhere, the lead's included (E-e's solid fill is the tell) */
html:root .chip { border-radius: var(--m-chip-radius); font-weight: 500; }
html:root[data-e-e] .record-lead__head :is(.chip--success, .chip--progress),
html:root[data-e-e] .ruler-record__chip :is(.chip--success, .chip--progress) { background: var(--family-success-fill); color: var(--family-success-text); }
html:root[data-e-e] .record-lead__head .chip--progress, html:root[data-e-e] .ruler-record__chip .chip--progress { background: var(--family-progress-fill); color: var(--family-progress-text); }
html:root .record-lead__head .chip, html:root .ruler-record__chip .chip { font-weight: 500; }
/* a company's tab strip: its open tab underlined on the bar's rule, no fill */
html:root .org-page .org-tabs { background: transparent; border: 0; border-bottom: var(--m-tabs-rule); padding: 0 var(--m-tabs-px, var(--lg-px)); }
html:root .org-page .org-tabs__tab, html:root .org-page .org-tabs__tab:visited { color: var(--text-muted); font-family: var(--m-title-font); font-size: var(--m-tab-size, var(--text-2)); }
html:root .org-page .org-tabs__tab:hover { color: var(--text); }
html:root .org-page .org-tabs__tab:focus-visible { outline-color: var(--focus-ring); }
html:root .org-page .org-tabs__tab[aria-current="page"], html:root .org-page .org-tabs__tab[aria-selected="true"] { color: var(--text); border-bottom-color: var(--text); }
html:root .org-page .org-tabs__n { font-family: var(--font-body); color: var(--text-muted); opacity: 1; }
html:root .org-page .org-tabs ~ .org-panel:not([hidden]) { border-top: 0; }
/* the tab strip carries the block's cap, so the open panel reads as the block under it */
html:root .org-page .org-tabs { background: var(--surface); border: 1px solid var(--border); border-top: 3px solid var(--text); border-bottom: 1px solid var(--rule); }
/* the label break: the tinted label column ends on a darker rule than the rows between */
html:root :is(.fact-table, .record-headline) dt { border-inline-end: var(--m-label-break); }
html:root .ruler-record .ruler-record__facts dt { background: var(--m-label-bg); border-inline-end: var(--m-label-break); }
html:root { --m-label-break: 1px solid var(--border); }
/* the type scale (owner, 2026-11-07: "Text sizing might be a bit off"): measured on a plant page, block titles and
   values were both 16/600 (the title did not lead its rows), small text ran at two near sizes (12.8 and 13px) and
   "Around this project" at a stray 17px. One step each now (small text on record screens only, so the map's notes keep their fit): 13 labels and small text, 15 values and cells, 18 block
   titles, 24 the headline figure, 28 the page title. */
html:root { --m-title-size: 1.125rem; --m-value-size: 0.9375rem; }
html:root :is(.record-page, .ruler-record) { --text-1: 0.8125rem; }
html:root .ruler-record .ruler-record__facts dd,
html:root .record-page :is([data-band], .record-around .record-section) .record-table td { font-size: var(--m-value-size); }
html:root .record-page .record-around__title { font-size: var(--m-title-size); }
html:root .fact-table .fact-table__none { font-size: var(--m-value-size); }
