/*
  Design tokens.

  The page runs dark → light → dark: an immersive black hero, three sections of
  light grey paper under it, a white editorial body, then dark again for the
  platform panel and the closing call to action. Rather than hard-coding two sets
  of rules, every section declares
  `data-theme="dark"` or `data-theme="light"` and the blocks below rebind one set
  of semantic variables. Components then reference only `--bg`, `--fg`, `--line`
  and friends, so the same component works in both.

  ── One white, and neutral greys ─────────────────────────────────────────────

  The light half of the page is #FFFFFF. It used to be a warm off-white with a
  warm grey family on top of it, which is not the brand's palette: the light
  sections read as beige. So the surfaces are white and every grey is a true
  neutral, chosen at the luminance of the warm grey it replaced — the tonal steps
  of the page are unchanged, only the hue is gone.

  Nothing here is tinted, with one exception that is declared where it is defined:
  the `--paper-*` family below, the three light-grey surfaces under the hero. If a
  warm hex turns up anywhere else in this file, in a paper drawing or in a diagram,
  it is a leftover, not a decision.

  ── Contrast ─────────────────────────────────────────────────────────────────

  Measured against the section background it is used on, WCAG AA (4.5:1):

    light   --fg      #080808 on #FFFFFF   20.0:1
            --fg-sub  #616161 on #FFFFFF    6.3:1
            --fg-soft #6D6D6D on #FFFFFF    5.2:1
            --info    #2855F6 on #FFFFFF    5.7:1
            --network #7C3AED on #FFFFFF    5.7:1
    dark    --fg      #FFFFFF on #080808   19.7:1
            --fg-sub  72% white on #080808 10.2:1
            --fg-soft 55% white on #080808  6.0:1
            --accent  #F15A2A on #080808    6.0:1
            --network #B49BFF on #080808    8.6:1

  Two colours are NOT usable for body text and are only ever applied to display
  type, rules, dots and diagram strokes:

    --signal #F15A2A on white        3.4:1
    --fg-faint (both themes)         ~2.5:1

  Signal orange on the light background fails at text sizes. It is the brand
  colour, so the temptation is real — put it on a headline, a numeral or a line,
  never on a sentence.
*/

:root {
  /* ── The Library of Trade colour system ───────────────────────────────────
     THE canonical palette. Black and white are the brand; colour communicates
     meaning. At rest the interface is black, white and grey — the five accents are
     not decoration, they are states, and a surface with no state carries no colour.

     Nothing may introduce a sixth accent or a second shade of one of these five.
     A lighter or darker version of an accent is that accent at an opacity, which is
     why `color-mix(in srgb, var(--lot-blue) 20%, transparent)` is the pattern and a
     hand-picked tint is a defect.

     ── Semantics. The mapping is the system; the hexes are just how it is spelled ──

       BLUE    intelligence · AI · selected · recommended · computed
               an AI-selected supplier, a recommended route, an analysed option
       GREEN   verified · passed · healthy · completed
               supplier verified, QC passed, compliance approved, shipment delivered
       YELLOW  pending · attention · awaiting action
               quote pending, sample awaiting review, approval required
       ORANGE  active physical execution · movement
               production running, shipment in transit, live supplier interaction
       RED     exception · risk · failure · critical
               delay, QC failure, compliance risk, production exception

     Two rules on top of the mapping, and they are what keep it from becoming a
     rainbow:

       1. Colour only ever marks a state that is really true of that object. There is
          no decorative use of an accent, anywhere, at any opacity.
       2. About 90% of any view stays monochrome. One accent is active at a time; two
          only while a transition is being explained.

     ── One surface is exempt from both rules, by name ───────────────────────

     The hero globe's arcs, and nothing else. Every lane there carries one of the five
     accents, cycled on the lane's index in content/network.js, and the colour reports
     no state at all. That is a direct reversal, decided on 2026-09-03, and both rules
     stand everywhere else on this site and in the portals.

     The history is worth having, because this is the third position on it and each one
     was taken by looking at a render. Rule 2 was briefly deleted after a globe built
     to it was judged too white and too quiet; what the deletion produced was exactly
     what the rule exists to prevent — five accents on eighteen nodes and twenty-seven
     lanes, at which point a red exception is one more colour on a map rather than the
     thing you cannot miss. So the rule came back, stricter, and the globe went to a
     grey lane field with six lit lanes driven through a timed sequence. That version
     was judged to read as "mostly nothing is happening", which for a hero is fatal:
     the one job of that image is to look like a live global trade network, and it had
     three quarters of its lanes drained of colour to say so.

     What is actually being traded away is the rule's premise. Rules 1 and 2 protect a
     *reader of an operator's screen*, where a colour is a fact about a shipment and a
     red one has to survive being the only red. Nobody reads the hero for facts about
     shipments. So the exception is scoped to the object where the premise does not
     hold, and the fence is that the exception names one surface: purple is still
     fenced off, the location nodes are still all white, `ROUTE_STATE` is still the
     vocabulary everywhere else, and no other section on this site may cite this
     paragraph.

     Outside the hero, the way to make a quiet view carry more is still to make it
     *change*, not to colour more of it in. A state that arrives and leaves is read; a
     state painted on permanently is wallpaper.

     js/color-system.js reads these six of these values back out of this file at
     runtime, so a WebGL layer and a CSS surface cannot drift apart. That module is
     the JS half of this definition and is meant to be lifted into the portals as-is
     — sourcing, materials, suppliers, samples, production, quality, logistics.

     ── This is not yet the page's palette ───────────────────────────────────

     The tokens below this block (`--ink`, `--signal`, `--route`, `--pure-white` and
     the greys the sections bind) are the palette the marketing pages were built in,
     and they are *close* to these values without being them: #080808 against
     --lot-black #050505, #ffffff against --lot-white #F5F5F2, #f15a2a against
     --lot-orange #FF571F. They are deliberately left alone. Re-pointing `--ink` and
     friends at the canonical values repaints every dark section, the top bar, the
     footer and five pages of diagrams in one commit, and that is a migration with
     its own screenshots, not a side effect of restyling the globe.

     What uses the canonical system today: the hero globe — its land field, its
     location nodes, its labels and its routes — and the hero's primary call to action,
     which is `--lot-blue` because the thing on the other side of it is the estimator,
     and blue means computed here.
  */

  /* Core */
  --lot-black: #050505;
  --lot-white: #f5f5f2;

  /* Neutral hierarchy */
  --lot-grey-900: #121212;
  --lot-grey-800: #1d1d1d;
  --lot-grey-700: #2b2b2b;
  /*
    Unconsumed, and kept as a rung rather than deleted. It was the hero globe's land
    field — arrived as `--lot-grey-landmass: #555555` from the brief that asked the
    continents to become readable, filed as a numbered step because it lands exactly
    where a 600 belongs. The next brief moved the land field two rungs brighter still
    (see `--lot-landmass` below), so nothing points here now. A ramp with a hole in it
    is worse than a ramp with a spare rung.
  */
  --lot-grey-600: #555555;
  /**
   * Route with no state. See `--route-inactive`.
   *
   * No longer the hero globe's lane field — that field is gone, and a grey route is now
   * banned outright on the globe. This is the value a portal table's stateless route row
   * uses, and it is the hex to grep for if a neutral arc ever reappears in the hero.
   */
  --lot-grey-500: #666666;
  --lot-grey-400: #858585;
  --lot-grey-300: #a8a8a5;

  /*
    The hero globe's land field, and the one role-named colour in the neutral set.

    Five levels off `--lot-grey-400` #858585 and deliberately not folded into it. Two
    reasons, and the second is the real one. The brief names this hex twice, once as a
    canonical value and once inside a section marked VERY IMPORTANT, so the number is
    the specification rather than an implementation choice. And `--lot-grey-400`'s
    neighbour in the ramp is what the route field was tuned against — pointing the
    continents at a ramp rung means the next person who retunes that rung silently
    moves the land, which is the single value on this globe that has now been argued
    four times in both directions. It gets its own name so it can only be moved on
    purpose. js/globe.js is the only consumer; see GRADE there.
  */
  --lot-landmass: #8a8a8a;

  /* Functional accents. Never decorative — see the mapping above. */
  --lot-blue: #2b8fc2;
  --lot-green: #087f68;
  --lot-yellow: #ffb640;
  --lot-orange: #ff571f;
  --lot-red: #f42b2f;
  /*
    A sixth, and the only one that is not in the state vocabularies below.

    It exists because the benefit-card markers need six distinguishable colours for six
    outcomes and the functional set has five. That is a labelling job, not a status one:
    `Save time & effort` is not a state anything can be in, so there was no honest fifth
    state to reuse and inventing one would have put a meaning on a colour that the globe
    would then have to honour.

    So it is deliberately fenced. The globe brief bans purple outright, and this value is
    absent from `--location-*` and `--route-*` for that reason — nothing that reports a
    status can reach it. #6B3FC4 rather than `--violet` #7C3AED, which is the marketing
    palette's purple and a different colour.

    It now has no consumer at all: `--benefit-*` was the only one, and it went with the
    corner markers when the benefit panels went monochrome. It stays declared because the
    palette is a record of six accents and the sixth did not stop existing — but it is the
    one value on this page nothing reads, and the fence above is the reason it must not be
    handed to the first component that wants a colour.
  */
  --lot-purple: #6b3fc4;

  /*
    The state mapping, once, by name. Components reference these rather than the
    accents directly: a node is `--state-execution` because it is executing, and the
    day orange changes it changes in one place.
  */
  --state-neutral: var(--lot-white);
  --state-ai: var(--lot-blue);
  --state-pending: var(--lot-yellow);
  --state-execution: var(--lot-orange);
  --state-verified: var(--lot-green);
  --state-exception: var(--lot-red);

  /*
    ── Two vocabularies, because a place and a leg do not mean the same thing ──

    The six accents above are the alphabet. These are the two words it spells, and
    they are deliberately separate lists rather than one list used twice:

      A LOCATION answers  what is the status AT this place?
      A ROUTE answers     what is happening BETWEEN two places?

    A factory that is producing and a container that is sailing are both "orange",
    and they are not the same statement — which is why the state of a node and the
    state of a leg are set independently and neither is inferred from the other. A
    document pending at a factory yellows the node and leaves the lane grey. A
    shipment held at customs reddens the lane and leaves the factory alone.

    Defaults carry no accent at all: a location with nothing happening is white, a
    leg with nothing happening is grey. That is the majority of every view.

    ── The hero globe uses neither of these two lists ──────────────────────────

    Both are unconsumed on this site, and neither is an oversight.

    The five accented `--location-*` values went first: on a rotating globe a ring around
    a 12px dot cannot say *which* of six things it means, so a viewer reads five hues
    scattered across eighteen ports as decoration — reported back, in exactly those
    words, as "some nodes get seemingly random coloured rings". Every location on the
    globe is the same white.

    `--route-*` went with the pass after it, and that one is the harder call. State moved
    onto the lanes because a line between two places is long enough to carry a colour and
    a direction at once, which was true — but 21 of 27 lanes had no state, so most of what
    a visitor saw was `--route-inactive`, and what they read from it was that mostly
    nothing was happening. The hero's arcs now cycle the five accents on the lane's index
    and no lane is grey. That is the named exception to rules 1 and 2 at the top of this
    block; the argument is there and at the head of js/globe.js.

    Both lists stay because neither is the globe's list. They are the vocabulary a portal
    table, a supplier row or a facility card states its status in, where a coloured chip
    sits beside a label that says what it means. See js/color-system.js, which is meant to
    be lifted as-is.
  */
  --location-default: var(--lot-white);
  --location-ai-selected: var(--lot-blue);
  --location-active: var(--lot-orange);
  --location-pending: var(--lot-yellow);
  --location-success: var(--lot-green);
  --location-error: var(--lot-red);

  /*
    #666666 rather than #858585, and it is one rung down for a reason that is about the
    other five. A stateless lane is the field these accents are read against: 27 arcs
    at the old grey summed to a bright wireframe, and a network whose default is loud
    has no headroom left for the four or five lanes that are actually doing something.

    That tuning was done on the hero globe, which no longer has a stateless lane and must
    not get one back. What the value is for now is a portal route row with no state, where
    the field really is most of the table.
  */
  --route-inactive: var(--lot-grey-500);
  --route-recommended: var(--lot-blue);
  --route-in-transit: var(--lot-orange);
  --route-pending: var(--lot-yellow);
  --route-completed: var(--lot-green);
  --route-exception: var(--lot-red);

  /*
    ── A third vocabulary was here, and it is deleted ──────────────────────────

    `--benefit-gift` … `--benefit-speed` mapped the six benefit cards' `icon` keys to the
    six accents, for a 34px marker in each panel's corner. They were index colours rather
    than status ones — "which of six", not "what is happening" — and the note here spent a
    paragraph insisting nobody read `--benefit-quality`'s red as an exception.

    Why Library of Trade is now monochrome by instruction: off-white ground, black
    heading, graphite panels, off-white titles, muted copy, white marks, and no accent
    anywhere in the six. See advantage.css and `advCorner` in build.mjs, both of which
    lost the same feature.

    So the six aliases go rather than sit here with no consumer. A colour vocabulary that
    nothing reads is one an unrelated component eventually reaches for, and its name would
    promise a section that no longer wants it. The six accents themselves are untouched
    above; `--lot-purple` is now unconsumed outright, which is recorded on its own note.
  */

  /* ── Palette ─────────────────────────────────────────────────────────── */

  --ink: #080808;
  --charcoal: #181818;
  --pure-white: #ffffff;

  /** Physical product flow, and the brand accent. */
  --signal: #f15a2a;
  /** Information and control — the other half of the configurator's legend. */
  --route: #2855f6;
  /*
    The supply network itself: factories, material suppliers, logistics partners,
    the connections between them and what we have learned about them.

    The one hue the page did not already have, added for the network section,
    where three things have to stay distinguishable at the size of a 3px dot —
    the network, the software evaluating it (route blue) and the people
    overruling it (signal orange). Picked at route blue's contrast rather than by
    eye, so the two read as siblings and neither wins on brightness: 5.70:1 on
    white against route's 5.64:1.
  */
  --violet: #7c3aed;
  /** Arc heads and the warm edge of the globe's limb. */
  --yellow: #f2c45b;

  /** Body grey on white. Neutral at the luminance the old warm slate had. */
  --slate: #616161;
  /*
    The light page's hairline. Lightened with the background it sits on: the old
    #D9D5CC was 30 levels under a #F6F3EC page, and this is 30 under white, so the
    rules carry the same weight rather than suddenly drawing harder.
  */
  --line-grey: #e1e1e1;

  /* ── Paper: the three sections under the hero ─────────────────────────────

     The page's light half is white (see the note at the top of this file). These
     three are not: they are the band directly under a black hero, and a black
     screen ending in a white one is a cut rather than a transition. So they are
     printed on paper instead — two tones of light grey, alternating, with the
     white sections beginning after them. The rhythm is black → grey → near-white
     → grey → white, and each step is small enough that no boundary needs a rule
     to explain it.

     The alternation is what the two tones are for, and the category rail in the
     middle of it inverts inside: grey ground with near-white cards on it. Why
     Library of Trade was the other half of that swap — near-white with grey panels
     in it — until its panels went graphite. It keeps the near-white ground and the
     rail keeps the grey one, so the page's alternation is untouched; what changed is
     one surface inside one section. See `--paper-panel`.

     These are the one place in this file with a warm cast, and it is 2 to 4 levels
     of it: #ECECEA against a neutral #ECECEC. That is below the threshold anyone
     can see, and it is here because it was specified rather than because the page
     needs it — the paragraph above about warm hexes still holds for everything
     else. Neutralising the family is a matter of levelling the last digit of each
     value; nothing else references these except the three sections that bind them.

     Measured against the surface each is used on (AA is 4.5:1):

       --paper-sub  #686864 on --paper-grey  #ECECEA  4.7:1
       --paper-sub  #686864 on --paper-white #FAFAF8  5.4:1
       --paper-draw #555550 on --paper-grey  #ECECEA  6.6:1
       --ink        #080808 on either of them       > 18:1

     `--paper-panel` is graphite and is measured against separately, on its own two
     values — it is a dark surface inside a light family and none of the four above
     may be printed on it.

     Two surfaces, and there used to be four. A lighter tile for grey grounds and a
     darker one for near-white grounds were both retired when the two sections inverted:
     a card standing on grey is now the near-white the next section is printed on, and a
     panel standing on near-white is now this section's grey. Nothing needed a third
     value once each tone had a chance to be both a ground and a block.

     One border colour, not three. The brief that asked for these surfaces named
     #D4D4CF, #D5D5D0 and #D6D6D1 for the three components that carry a hairline;
     they are within two levels of each other, which is a single decision written
     down three times. It is written once here.
  */

  /*
    Section surface: the category rail, and Process. It was also the benefit panels in
    Why Library of Trade until those were given a value of their own — see
    `--paper-panel` below for why that swap-without-a-new-value argument no longer holds
    for all three sections.
  */
  --paper-grey: #ececea;
  /*
    The benefit panels, and only those. Not a tone in this family at all any more — it is
    graphite, 9 levels off the page's own `--ink`, standing on the family's lightest
    ground. The whole of the Why Library of Trade section is that one inversion.

    It was #F1F1EF: five levels up from `--paper-grey`, specified by the brief that put a
    coloured marker in each panel's corner, and argued here as a contrast gain for the
    type printed on it — `--paper-sub` 4.73 → 4.95:1, `--ink` 16.93 → 17.71:1.

    Both halves of that argument are gone. The corner markers are deleted (the section is
    monochrome now — see advantage.css), and no light-family value is printed on this
    surface any more: a graphite panel takes `--paper-panel-fg` and `--paper-panel-sub`
    below, which exist because `--paper-sub` #686864 on #212426 is 2.8:1 and fails AA
    outright.

    What the step buys and costs has inverted with it. Panel-against-ground was 1.08:1,
    a seam you had to look for; it is now 14.9:1, so the six panels are unmistakably six
    and the 6px between them is a bright line rather than a hairline. That is the point of
    the dark treatment, and it is why nothing below needs a border.
  */
  --paper-panel: #212426;
  /*
    Type on the graphite panel: the title, and the muted sentence under it.

    Off-white rather than `--pure-white`, because #FFFFFF on #212426 is 15.6:1 and reads
    as a screen rather than as print — the family's whole cast is warm-neutral paper, and
    a title set in pure white on it is the one value that looks like it came from a
    different page. #F5F5F2 measures 14.2:1, which is past every threshold that exists.

    The sentence is the same off-white at 62% rather than a grey of its own, and that is
    deliberate: one ink, one dilution, so the two never drift apart the way a hardcoded
    #A8AAAA would the moment the panel moved. Over #212426 it composites to #A4A6A4 —
    6.4:1, a clear step under the title's 14.2 and still well above AA for the only
    explanation in the section.
  */
  --paper-panel-fg: #f5f5f2;
  --paper-panel-sub: rgba(245, 245, 242, 0.62);
  /*
    Section surface: Why Library of Trade. A visible step lighter than the last, and the
    other half of the swap — the cards on the category rail are this, so the rail and the
    section under it are the same two tones in opposite roles.
  */
  --paper-white: #fafaf8;
  --paper-line: #d5d5d0;
  /*
    The family's near-black, and the only one: the edge of a control that is meant to
    be pressed, and the fill it takes when it is hovered. `--charcoal` was doing this
    and it is the page's hardest value — #181818 drawn round a 48px square on grey
    reads as a printed rule rather than as a button. This is 18 levels softer with the
    family's own warm cast, which is what the brief asked for and what a control drawn
    on paper wants.
  */
  --paper-edge: #2a2a28;
  /** Hairlines that have to be seen: a hover, a rule under a link, a control. */
  --paper-line-strong: #b9b9b3;
  /*
    Ink for a drawing rather than for an edge, and the one paper value darker than
    the type it sits beside is muted to. The process ring is a 1.3px circle 440px
    across: at `--paper-line-strong` it measured 1.35:1 against its own section and
    disappeared, because a hairline colour is calibrated for a line that has a whole
    panel behind it. This is what a technical drawing is drawn in — the circle, and
    the outline of every node standing on it.
  */
  --paper-draw: #555550;
  /** Secondary type. Every muted word in the three sections is this one grey. */
  --paper-sub: #686864;

  /* ── Type ────────────────────────────────────────────────────────────── */

  /*
    Figtree throughout. It is already the brand's own wordmark face, so
    promoting it to display and body makes the page one voice instead of three.
    It is a geometric-humanist grotesk: confident at 78px, still comfortable at
    16px, and warm rather than technical — which is the half of the brief that
    the monospace does not cover.
  */
  --font-display: 'Figtree', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-body: var(--font-display);
  /*
    IBM Plex Mono carries the control-room half: coordinates, route labels,
    stage numbers, chapter markers, section eyebrows, buttons. Uppercase is
    reserved for this voice — headlines and body copy are always sentence case.
  */
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /*
    The wordmark only — one lockup in the top bar, nothing else on the site. Kept
    separate from `--font-display` because a logotype is artwork with a name in it,
    not the page's voice, and it is the one place a different face is not an
    inconsistency.

    Neue Haas Grotesk Display Bold is the specified face and **there is no font file
    for it in this repo**: it is licensed, there is nothing free to fetch, and none of
    Figtree, Helvetica or Arial is it. So this stack names it first and falls through
    to Helvetica Neue — which is the face Neue Haas Grotesk was redrawn from, and is
    already installed on every Mac and iOS device. Drop the licensed woff2 into
    `assets/fonts/`, add an @font-face for it, and the first name starts resolving with
    no other change anywhere. Until then the lockup is a very close relative, not the
    real thing, and on Windows it is Arial Bold — further off again.
  */
  --font-wordmark: 'Neue Haas Grotesk Display', 'Helvetica Neue', Helvetica, Arial,
    sans-serif;

  /*
    Fluid, and deliberately not a ratio scale — the display size climbs far
    faster than body copy so the editorial contrast holds at every width.
  */
  --t-display: clamp(40px, 6.2vw, 76px);
  --t-h2: clamp(31px, 4.3vw, 54px);
  --t-h3: clamp(20px, 1.9vw, 26px);
  --t-lead: clamp(17px, 1.3vw, 19px);
  --t-body: 16.5px;
  --t-small: 14px;
  --t-mono: 12px;
  --t-mono-sm: 10.5px;

  /*
    Body copy measure, in em so it tracks font-size: 33em ≈ 64 characters,
    inside the 60–68 the brief asks for. --measure-tight is for copy sitting
    beside a diagram or a photograph.

    --measure-lead is wider than either, and only for the sentence under a section
    headline. That sentence sits alone across the full width of the page, so at 33em
    it broke after a third of the line and left the rest of the row empty; a
    standfirst is allowed to run longer than a paragraph a reader has to stay inside
    for ten lines.
  */
  --measure: 33em;
  --measure-tight: 26em;
  --measure-lead: 42em;

  /* ── Space ───────────────────────────────────────────────────────────── */

  --gutter: clamp(22px, 5vw, 64px);
  --section-y: clamp(76px, 8vw, 132px);
  --shell: 1240px;
  --topbar-h: 92px;

  /* ── Shape ───────────────────────────────────────────────────────────── */

  /* Restrained on purpose. 18px reads as a printed card, not a pill. */
  --r-sm: 10px;
  --r: 18px;
  --r-pill: 999px;

  /*
    Almost square. Enough to take the bite off a corner at 1px, not enough to be
    seen as a curve — for controls that should read as fields in a toolbar rather
    than as tags floating on it.
  */
  --r-xs: 4px;

  /* ── Motion ──────────────────────────────────────────────────────────── */

  /*
    Everything lands between 300 and 700ms unless it is tied to scroll
    position. Faster reads as a glitch, slower as a wait.
  */
  --dur-fast: 220ms;
  --dur: 420ms;
  --dur-slow: 680ms;
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
  /* For anything that travels a distance — arcs, the ring, panel entrances. */
  --ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
}

/* ── Themes ────────────────────────────────────────────────────────────── */

[data-theme='dark'] {
  --bg: var(--ink);
  --bg-raised: var(--charcoal);
  --fg: var(--pure-white);
  --fg-sub: #ffffffb8;
  --fg-soft: #ffffff8c;
  /** Non-text only: hairline marks, inactive dots, diagram scaffolding. */
  --fg-faint: #ffffff52;
  --line: #ffffff1f;
  --line-strong: #ffffff45;
  --accent: var(--signal);
  /*
    Route blue at full saturation is too dark to read on ink, so the dark theme
    lightens it. Same hue, same meaning — information and control.
  */
  --info: #8fa6ff;
  /* Lifted for the same reason, and to the same weight as the blue beside it. */
  --network: #b49bff;
  --shadow: none;
}

[data-theme='light'] {
  --bg: var(--pure-white);
  /*
    The same white. The page separates with hairlines, not with elevation, so a
    panel is a bordered area of the page rather than a lighter card floating on a
    darker ground — which is what it had to be while the ground was beige. Every
    surface using this has its own `1px solid var(--line)`; the dot haloes that
    punch a ring of it out of the map still match the panel they sit on.
  */
  --bg-raised: var(--pure-white);
  --fg: var(--ink);
  --fg-sub: var(--slate);
  --fg-soft: #6d6d6d;
  /** Non-text only — see the contrast note above. */
  --fg-faint: #a5a5a5;
  --line: var(--line-grey);
  --line-strong: #c9c9c9;
  --accent: var(--signal);
  --info: var(--route);
  --network: var(--violet);
  /* Barely there. The page separates with hairlines, not with elevation. */
  --shadow: 0 1px 2px rgba(8, 8, 8, 0.04), 0 12px 32px rgba(8, 8, 8, 0.05);
}
