/* Colour themes (SPEC.md §Colour themes, CF-THEME-001 to CF-THEME-010).

   Every colour the client draws is named here and used nowhere else as a
   literal. A theme is one block of these variables; adding a fourth means
   adding a block and a name to THEMES in theme.js, and touching no rule
   that actually draws anything.

   The names say what a colour is *for*, never what it looks like:
   `--flow-casing`, not `--blue-400`. High contrast makes an active flow a
   saturated blue on white, and the light theme inverts which end of the
   scale each part sits at — a variable named for a hue would be lying in
   one theme or the other, which is the drift that stops a colour system
   being one.

   The variables, by role:

     surface-*   backgrounds, from the page down to a control
     border-*    outlines of things that are not plumbing
     text-*      type, from primary reading down to the quietest total
     icon-*      the subject icons' stroke
     pipe-*      plumbing at rest: casing, bore, and the sockets on it
     flow-*      plumbing carrying power, and the segments moving in it
     soc-*       the battery's charge bar

   A theme reaches the page by two routes: the OS media query, so first
   paint is right before any script runs, and the `data-theme` attribute
   that theme.js sets, so an explicit choice wins over the OS.

   Where a theme has both routes it is written in two steps — a `--light-*`
   palette holding the values once, and two thin blocks assigning the drawing
   variables from it. The indirection buys one place to change a colour.
   Plain CSS with no build step (README, Stack) has no mixins and no
   nesting, and the two routes need different selectors (see the media
   query below), so they cannot simply share one rule body; without the
   palette the values would be duplicated, and a theme written twice is one
   that eventually gets updated in only one of them.

   Dark and high contrast need no palette: dark is the `:root` default and
   high contrast is never automatic, so each has a single route and states
   its values directly. */

/* --- Dark: the default, and what the picture was designed against. ---

   `:root` bare is in this list, so dark is also what an unrecognised
   `data-theme` value falls back to. That is a backstop, not the mechanism:
   theme.js resolves an unknown stored preference to `system` before it
   ever reaches the attribute (CF-THEME-009). */
:root,
:root[data-theme='dark'] {
  --surface-page: #111;
  --surface-card: #17191b;
  /* An Overview widget. Its own step rather than `--surface-card`, which
     sits so close to the page (#111) that a widget read as a faint smudge —
     reported 2026-09-23 as too little contrast in both themes. A card on
     another page is framed by its layout; a widget is a free-standing
     square on a bare page and has only its fill to show its edge. */
  --surface-widget: #23262b;
  --surface-panel: #101214;
  /* The page bar's own band. A step off the page rather than a colour of
     its own: the bar is the same surface seen as separate, and anything
     more than a step reads as a panel sitting on the page rather than as
     an edge of it. Lighter than the page in a dark theme and darker in a
     light one — in both, a little way towards the other end. */
  --surface-bar: #1a1c1e;

  --border-card: #3a536b;
  --border-control: #2f3336;

  --text-primary: #eee;
  --text-label: #d8dee3;
  --text-muted: #9fb8cc;
  --text-panel: #c9d6e0;

  --icon-stroke: #c9d6e0;
  --soc-bar: #4a7bb0;
  /* How full a solar panel's cell is drawn (CF-PWR-078). Warm rather than the
     blue the battery's charge uses: the two are both "how full", and reading
     them apart at a glance is easier when the quantity being filled differs in
     hue as well as in shape. */
  --solar-fill: #c9922e;

  /* Plumbing at rest. The bore is darker than the casing so a pipe reads
     as a tube seen end-on rather than as a flat band. */
  --pipe-casing: #2c2c2c;
  --pipe-bore: #1b1b1b;
  --socket-fill: #16181a;
  --socket-stroke: #2c2c2c;

  /* Plumbing carrying power: the casing is the bright edge, the bore the
     lit interior behind it. */
  --flow-casing: #4a7bb0;
  --flow-bore: #26425a;

  /* The moving segments. One matches the lit bore, the other is a shade
     darker — deliberately low contrast, so the movement and its direction
     read without the pattern drawing the eye (CF-PWR-022). */
  --flow-segment-even: #26425a;
  --flow-segment-odd: #101d28;

  --text-hub-total: #cfe6ff;
  --text-reading-idle: #a9b6c0;
  --text-reading-active: #eaf3ff;
  --text-reading-total: #93a0aa;

  /* The histograms. The band sits a shade off the page so its extent is
     readable while empty. The two directions are told apart by hue rather
     than by shade: import keeps the plumbing's blue, export takes a green.
     Two shades of one hue would leave a battery's day ambiguous about
     which half was charging, which is the one thing its graph exists to
     say. State of charge takes a third hue again, since it is a level
     rather than either direction of flow. */
  --histogram-surface: #16181a;
  --histogram-border: #2c2c2c;
  --histogram-import: #5b9bd8;
  --histogram-export: #57c98a;
  --histogram-soc: #d9a441;
  --histogram-day-line: #55636e;
  --scrub-line: #8fa3b3;

  /* What has not happened yet (CF-HIST-085). A wash in the page's own
     colour laid over the predicted stretch, which takes the colour out of
     what is under it without needing every series drawn a second time in
     grey. The alpha is how grey: enough that a glance separates the two
     stretches, not so much that the forecast becomes unreadable — it is
     still the thing somebody switched to this window to look at. */
  --forecast-wash: #111;
  --forecast-wash-alpha: 0.62;
  /* The seam where measurement stops (CF-HIST-086). Brighter than the day
     lines, which are calendar furniture; this one is a statement about the
     data and is meant to be found rather than merely available. */
  --forecast-boundary: #8fa3b3;

  /* A command that did not take (CF-PWR-099). An amber rather than a red:
     the house is not in danger and nothing is broken — an instruction did
     not arrive, and the equipment goes on doing what it was doing before.
     Red is kept in reserve for a state that needs acting on, and spending
     it here would leave nothing louder for that. Shares a hue with the
     state-of-charge bar, the nearest thing this palette has to a colour
     meaning "look at this". */
  --failure-mark: #d9a441;
  --failure-surface: #2a2113;
  --failure-text: #f0dcb4;

  /* The mock marker's colour (CF-DATA-029): the bar's edge and the chip's
     dot, which are one statement in two places.

     Deliberately neither of the two colours that already mean something
     urgent. Amber is the failure mark above, and red is held in reserve for
     a state that needs acting on — and showing a guest the application is
     neither a fault nor something to act on. This is the export green, which
     in this palette already reads as "fine, just not the usual case", so the
     marker states the fact without dressing it as a problem. */
  --sample-edge: #57c98a;

  /* The A/C thermometers (CF-AC-010, CF-AC-011). The mercury shares the
     state-of-charge amber: both are "how full is this", and reusing the hue
     is what keeps one palette rather than two.

     The two out-of-range colours are their own, because they answer a
     question nothing else here asks — the scale has run out, and in which
     direction. Amber is already the failure mark, so a room merely hotter
     than the A/C can be set to must not borrow it: that is a fact about
     summer, not a fault. */
  --aircon-mercury: #d9a441;
  --aircon-over: #d2603c;
  --aircon-under: #5b9bd8;
  /* How strongly the flames and the cold draught show behind a unit's
     controls (SPEC-AIRCON.md §Flames and a draught). On a dark panel a glow
     can be bright and still leave the controls readable; on a light one the
     same strength would wash them out. */
  --aircon-ambience: 0.8;
  /* The flame's hot heart and the bright colour in its moving edge, and the
     draught's streaks. Yellow-orange glows on a dark panel; on a white one
     the same colour, faded, is pastel — which is why the light themes take
     their own, deeper colours rather than a weaker version of these. */
  --aircon-flame-core: rgba(255, 190, 70, 0.85);
  --aircon-flame-body: color-mix(in srgb, var(--aircon-over) 55%, transparent);
  --aircon-flame-bright: #f0a040;
  --aircon-draught-core: rgba(210, 230, 255, 0.5);
  /* A soft halo round the text over the flames or the draught. Nothing is
     needed on a dark panel, where the text is light and the effect lightens
     the panel only a little; on a light panel it is what keeps dark text
     readable over a deep red. */
  --aircon-text-halo: none;
  /* The muted text colour to use over an effect. The dark theme's own muted
     grey reads fine over its flames, so it is itself. */
  --aircon-muted-over-effect: var(--text-muted);

  /* The Gas page (SPEC-GAS.md). The flame keeps its colours in every theme
     apart from the glow behind it: a flame is the one thing on screen whose
     colour is a fact about the world rather than a choice, and a candle
     flame burns blue at its base and yellow through its body whatever the
     page is painted. The bars are the flame's orange, so the graphs and the flame
     read as one subject; it is not the import blue, because a gas bar is not
     electricity and should not be mistaken for it at a glance. */
  --gas-flame-root: #2f6fe8;
  --gas-flame-body: #ff7a1a;
  --gas-flame-tip: #ffc23d;
  --gas-flame-heart: #fff0b8;
  --gas-flame-glow: rgb(255 140 40 / 0.22);
  --gas-bar: #e0883e;
  /* Behind the shader flame, which was made for a dark scene: none here,
     where the page already is one. */
  --gas-flame-backdrop: transparent;

  /* The Water page: a chrome tap lit from above, and water a clear blue
     that is not the import blue — a water bar is not electricity and should
     not be mistaken for it — nor the gas orange. The edge keeps the metal's
     outline where its light end meets a light page. */
  --water-metal-light: #eef2f6;
  --water-metal-mid: #a9b4bf;
  --water-metal-dark: #56616c;
  --water-metal-edge: #2c3339;
  /* The stream's two colours, as the shader reads them: the deep blue its
     edges carry, and the light within. Six-digit hex only — the shader
     parses these itself. Variation A's, as the reader chose it. */
  --water-stream: #1a73ad;
  --water-stream-core: #bfebff;
  --water-bar: #3ab0d8;

  /* The Power page's Bars view emblem (CF-PWR-169): the one warm colour in
     it — the sun, a lit window, the charging bolt. The subject's own icon
     keeps `--icon-stroke`, and what flows along a cable takes the import or
     export colour the timelines draw that direction in. */
  --emblem-warm: #ffc23d;

  /* The floor plans (SPEC-LIGHTS.md §The map is the page). A plan is a
     backdrop: it says where a reader is, and every light drawn on it has to
     read as brighter than anything structural. So the wall is the most
     present thing here and still quiet, and the furniture is quieter again —
     it orients a reader towards one end of a room without being something to
     look at.

     Glazing is its own colour rather than a thinner wall, because a window
     is where the daylight comes from and this page is about darkness. */
  --plan-wall: #4a5560;
  --plan-room: #191c1f;
  --plan-room-hover: #21262b;
  --plan-glazing: #5b9bd8;
  --plan-door: #5a666f;
  --plan-furniture: #262b30;
  --plan-furniture-line: #3a424a;
  --plan-roof: #141618;

  /* Devices on the plan. A lamp is drawn in the furniture's line colour
     while it is off or unknown — present, not asserted — and turns to
     `--plan-lamp-on` when it is lit, which is the one thing on this page
     that should catch the eye from across a room.

     The glow and the sensor's field are the same colours at low alpha. They
     are separate variables rather than the paint colour with opacity
     applied, because a halo's alpha is part of how strong the light reads
     and a theme may want to change one without the other. */
  --plan-lamp: #3a424a;
  --plan-lamp-on: #f5c542;
  --plan-lamp-glow: rgb(245 197 66 / 0.28);
  --plan-sensor: #6ba3d8;
  /* Stronger than it first looks it should be. A sensor's wedge is clipped
     to the room it watches, and in a small room most of it is cut away — so
     the alpha has to carry on the fraction that survives, not on the wedge
     as drawn. At 0.16 the hall's sensor was invisible. */
  --plan-sensor-field: rgb(107 163 216 / 0.3);
  --plan-device-selected: #f5f7fa;
  /* A name written on the plan — a group's, which is the only thing named
     there. **Not `--plan-lamp`**: that is a line colour for a drawn symbol,
     and text in it measured as barely legible against the room. A name is
     read rather than recognised, so it wants text contrast. */
  --plan-label: #c3ccd6;
  /* How much of that colour a group's name actually spends (plan.css
     §.plan-device-label). Per theme because fading towards a dark room and
     fading towards a white one are not the same move: one shared figure
     left the light themes at a third of the contrast this one keeps. */
  --plan-label-fade: 0.55;

  /* Towards the dark page: dimmer. */
  --stale-brightness: 0.7;

  /* What the platform draws its own widgets with: checkboxes, dropdown
     popups, scrollbars. Set from the theme rather than left to the OS, so
     a light theme on a dark OS does not keep dark native controls. */
  --control-scheme: dark;
}

/* --- Light: for a lit room, and what the OS asks for by day. ---

   Not the dark theme inverted. The plumbing keeps its shape by reversing
   which end of the scale each part sits at: on a light page a resting pipe
   is a mid grey that recedes, and a lit one is a *deeper* blue than the
   page rather than a brighter one, since against white it is darkness that
   reads as presence. Inverting the dark values directly would give pale
   blue pipes on a near-white page, which vanish.

   The casing/bore relation flips with it: dark has a bright casing round a
   deep bore, light has a deep casing round a pale one. In both the casing
   is the edge and the bore the interior, which is what makes the pipe read
   as a tube in either.

   These `--light-*` names are the palette, held once; the `--surface-*`
   and `--flow-*` names are what the client actually draws with. Both
   routes into the light theme assign from this block.

   It is declared unconditionally, in every theme. Custom properties that
   nothing references cost nothing to leave sitting there, and declaring it
   only where it is used would put it back inside the two branches this
   indirection exists to unify. */
:root {
  --light-surface-page: #f4f6f8;
  --light-surface-card: #fff;
  /* Darker than the page, as the bar is and for the same reason: white on
     this page was the step that could barely be seen. */
  --light-surface-widget: #e3e8ed;
  --light-surface-panel: #fff;
  /* Darker than the page here, where the dark theme's is lighter: the step
     is towards the opposite end of the scale in each, so the bar reads as
     separated in both rather than as separated in one and invisible in the
     other. */
  --light-surface-bar: #e6eaee;

  --light-border-card: #9db3c8;
  --light-border-control: #c6ced6;

  --light-text-primary: #16202a;
  --light-text-label: #24313d;
  --light-text-muted: #4d6376;
  --light-text-panel: #2b3947;

  --light-icon-stroke: #34495e;
  --light-soc-bar: #3d7ab5;
  --light-solar-fill: #b4801f;

  --light-pipe-casing: #c3ccd4;
  --light-pipe-bore: #e4e9ee;
  --light-socket-fill: #eef2f5;
  --light-socket-stroke: #c3ccd4;

  --light-flow-casing: #2f6ea8;
  --light-flow-bore: #bcd6ec;

  --light-flow-segment-even: #bcd6ec;
  --light-flow-segment-odd: #9dc2e0;

  --light-text-hub-total: #123a5c;
  --light-text-reading-idle: #5a6b7a;
  --light-text-reading-active: #10314f;
  --light-text-reading-total: #6b7a87;

  --light-histogram-surface: #eef2f5;
  --light-histogram-border: #c3ccd4;
  --light-histogram-import: #2f6ea8;
  --light-histogram-export: #1f9d5c;
  --light-histogram-soc: #b07d12;
  --light-histogram-day-line: #94a3b0;
  --light-scrub-line: #56687a;

  /* The wash is the page's colour in either theme, which here is white —
     so the predicted stretch goes pale rather than dark, and reads as
     provisional the way a faded print does. A shade less alpha than the
     dark theme: white over colour lifts it faster than black sinks it, so
     equal alphas would leave the light theme's forecast the fainter of
     the two. */
  --light-forecast-wash: #fff;
  --light-forecast-wash-alpha: 0.55;
  --light-forecast-boundary: #56687a;

  /* The same amber, darkened so it carries on white. The dark theme's mark
     would be a pale yellow here and would fail against the panel. */
  --light-failure-mark: #b07d12;
  --light-failure-surface: #fdf4e0;
  --light-failure-text: #5c4310;

  /* The same green, darkened so a 1px rule and a 6px dot carry on white.
     The dark theme's is a mint that all but disappears at this size. */
  --light-sample-edge: #1f8f56;

  /* The A/C thermometers, darkened so a bar and a small figure carry on
     white. The dark theme's red in particular is a coral that reads as pink
     against a light page. */
  --light-aircon-mercury: #b07d12;
  --light-aircon-over: #b8451f;
  --light-aircon-under: #2f6ea8;
  --light-aircon-ambience: 1;
  --light-aircon-flame-core: rgba(248, 96, 18, 1);
  --light-aircon-flame-body: rgba(218, 40, 22, 0.8);
  --light-aircon-flame-bright: #e0461f;
  --light-aircon-draught-core: rgba(40, 105, 175, 0.55);
  /* Tight: a wide halo left pale smears round every line of text, which
     washed the flames out as much as a weak flame did. */
  --light-aircon-text-halo: 0 0 2px #fff, 0 0 3px rgba(255, 255, 255, 0.7);
  /* The quiet grey text, one step darker while an effect is behind it: on
     white it passes, on a deep orange it would not. */
  --light-aircon-muted-over-effect: var(--light-text-label);

  /* The Gas page: the flame as in the dark theme, with a fainter glow that
     does not muddy white, and the bars a darker orange that carries a thin
     bar and its figure on a light page. */
  --light-gas-flame-glow: rgb(255 140 40 / 0.16);
  --light-gas-bar: #c0621a;
  /* The shader flame is a flame in the dark, and on white it washes out to
     a pale smear in a pink fog. So on a light page it burns in a small dark
     window of its own. */
  --light-gas-flame-backdrop: #16181a;

  /* The Water page on white: the metal a step darker so it is not a pale
     ghost, and the water and the bars a deeper blue that carries on paper. */
  --light-water-metal-light: #f6f8fa;
  --light-water-metal-mid: #aeb8c2;
  --light-water-metal-dark: #5f6a75;
  --light-water-metal-edge: #4a545e;
  --light-water-stream: #126ba8;
  --light-water-stream-core: #8cd1f5;
  --light-water-bar: #1b7fa8;
  --light-emblem-warm: #d08a00;

  /* The floor plans, inverted in the sense the whole light theme is: the
     room becomes the paper and the wall a dark line on it, which is what an
     architect's drawing looks like and what a reader expects of a plan.
     Furniture stays a step quieter than the wall in both themes — the
     relation is what carries, not the values. */
  --light-plan-wall: #4a5560;
  --light-plan-room: #fff;
  --light-plan-room-hover: #eef2f6;
  --light-plan-glazing: #2f6ea8;
  --light-plan-door: #8d99a4;
  --light-plan-furniture: #e4e9ee;
  --light-plan-furniture-line: #c2ccd5;
  --light-plan-roof: #e9edf1;

  /* On white, a lit lamp needs a deeper yellow to read as lit at all:
     `#f5c542` on `#fff` is barely a change. The glow is correspondingly
     stronger, since a pale wash over white vanishes. */
  --light-plan-lamp: #8d99a4;
  --light-plan-lamp-on: #d99b00;
  --light-plan-lamp-glow: rgb(217 155 0 / 0.22);
  --light-plan-sensor: #2f6ea8;
  --light-plan-sensor-field: rgb(47 110 168 / 0.26);
  --light-plan-device-selected: #1b2126;
  /* Dark on the white room, for the same contrast the dark theme gets from
     a pale grey — and deeper than the colour a full-strength label wanted,
     because this one is going to be faded towards white and will lose more
     of itself doing so than the dark theme's pale grey loses towards black. */
  --light-plan-label: #2b333c;
  /* Faded less, for the same reason. Colour and fade were chosen together
     to land at 5.8:1, against the dark theme's 6.2:1 — the two themes'
     names then read as equally quiet, which is the thing being matched
     rather than either number on its own.

     **Both figures assume the light theme's white room, which the plans do
     not currently paint.** Measured 2026-09-22: a plan keeps the dark
     theme's `--plan-room` whatever the theme says, so this label renders at
     about 1.2:1 today and is effectively invisible in the light themes.
     That is a pre-existing fault in the plans rather than in these values,
     and these are what the theme should have once it is fixed — so they are
     deliberately correct-for-the-fix rather than tuned to the broken state,
     which would have to be undone twice. */
  --light-plan-label-fade: 0.75;

  /* Towards the light page: washed out, not dimmed. */
  --light-stale-brightness: 1.35;
  --light-control-scheme: light;
}

/* Following the OS. Guarded on the attribute being absent so that an
   explicit dark or high-contrast choice is not overridden by an OS set to
   light — the attribute rules that follow cannot win on order alone
   against a media query the browser has already matched. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --surface-page: var(--light-surface-page);
    --surface-card: var(--light-surface-card);
    --surface-widget: var(--light-surface-widget);
    --surface-panel: var(--light-surface-panel);
    --surface-bar: var(--light-surface-bar);

    --border-card: var(--light-border-card);
    --border-control: var(--light-border-control);

    --text-primary: var(--light-text-primary);
    --text-label: var(--light-text-label);
    --text-muted: var(--light-text-muted);
    --text-panel: var(--light-text-panel);

    --icon-stroke: var(--light-icon-stroke);
    --soc-bar: var(--light-soc-bar);
    --solar-fill: var(--light-solar-fill);

    --pipe-casing: var(--light-pipe-casing);
    --pipe-bore: var(--light-pipe-bore);
    --socket-fill: var(--light-socket-fill);
    --socket-stroke: var(--light-socket-stroke);

    --flow-casing: var(--light-flow-casing);
    --flow-bore: var(--light-flow-bore);

    --flow-segment-even: var(--light-flow-segment-even);
    --flow-segment-odd: var(--light-flow-segment-odd);

    --text-hub-total: var(--light-text-hub-total);
    --text-reading-idle: var(--light-text-reading-idle);
    --text-reading-active: var(--light-text-reading-active);
    --text-reading-total: var(--light-text-reading-total);

    --histogram-surface: var(--light-histogram-surface);
    --histogram-border: var(--light-histogram-border);
    --histogram-import: var(--light-histogram-import);
    --histogram-export: var(--light-histogram-export);
    --histogram-soc: var(--light-histogram-soc);
    --histogram-day-line: var(--light-histogram-day-line);
    --scrub-line: var(--light-scrub-line);

    --forecast-wash: var(--light-forecast-wash);
    --forecast-wash-alpha: var(--light-forecast-wash-alpha);
    --forecast-boundary: var(--light-forecast-boundary);

    --failure-mark: var(--light-failure-mark);
    --failure-surface: var(--light-failure-surface);
    --failure-text: var(--light-failure-text);

    --sample-edge: var(--light-sample-edge);

    --aircon-mercury: var(--light-aircon-mercury);
    --aircon-over: var(--light-aircon-over);
    --aircon-under: var(--light-aircon-under);
    --aircon-ambience: var(--light-aircon-ambience);
    --aircon-flame-core: var(--light-aircon-flame-core);
    --aircon-flame-body: var(--light-aircon-flame-body);
    --aircon-flame-bright: var(--light-aircon-flame-bright);
    --aircon-draught-core: var(--light-aircon-draught-core);
    --aircon-text-halo: var(--light-aircon-text-halo);
    --aircon-muted-over-effect: var(--light-aircon-muted-over-effect);

    --gas-flame-glow: var(--light-gas-flame-glow);
    --gas-bar: var(--light-gas-bar);
    --gas-flame-backdrop: var(--light-gas-flame-backdrop);

    --water-metal-light: var(--light-water-metal-light);
    --water-metal-mid: var(--light-water-metal-mid);
    --water-metal-dark: var(--light-water-metal-dark);
    --water-metal-edge: var(--light-water-metal-edge);
    --water-stream: var(--light-water-stream);
    --water-stream-core: var(--light-water-stream-core);
    --water-bar: var(--light-water-bar);
    --emblem-warm: var(--light-emblem-warm);

    --plan-wall: var(--light-plan-wall);
    --plan-room: var(--light-plan-room);
    --plan-room-hover: var(--light-plan-room-hover);
    --plan-glazing: var(--light-plan-glazing);
    --plan-door: var(--light-plan-door);
    --plan-furniture: var(--light-plan-furniture);
    --plan-furniture-line: var(--light-plan-furniture-line);
    --plan-roof: var(--light-plan-roof);
    --plan-lamp: var(--light-plan-lamp);
    --plan-lamp-on: var(--light-plan-lamp-on);
    --plan-lamp-glow: var(--light-plan-lamp-glow);
    --plan-sensor: var(--light-plan-sensor);
    --plan-sensor-field: var(--light-plan-sensor-field);
    --plan-device-selected: var(--light-plan-device-selected);
    --plan-label: var(--light-plan-label);
    --plan-label-fade: var(--light-plan-label-fade);

    --stale-brightness: var(--light-stale-brightness);
    --control-scheme: var(--light-control-scheme);
  }
}

/* Chosen explicitly. */
:root[data-theme='light'] {
  --surface-page: var(--light-surface-page);
  --surface-card: var(--light-surface-card);
  --surface-widget: var(--light-surface-widget);
  --surface-panel: var(--light-surface-panel);
  --surface-bar: var(--light-surface-bar);

  --border-card: var(--light-border-card);
  --border-control: var(--light-border-control);

  --text-primary: var(--light-text-primary);
  --text-label: var(--light-text-label);
  --text-muted: var(--light-text-muted);
  --text-panel: var(--light-text-panel);

  --icon-stroke: var(--light-icon-stroke);
  --soc-bar: var(--light-soc-bar);
  --solar-fill: var(--light-solar-fill);

  --pipe-casing: var(--light-pipe-casing);
  --pipe-bore: var(--light-pipe-bore);
  --socket-fill: var(--light-socket-fill);
  --socket-stroke: var(--light-socket-stroke);

  --flow-casing: var(--light-flow-casing);
  --flow-bore: var(--light-flow-bore);

  --flow-segment-even: var(--light-flow-segment-even);
  --flow-segment-odd: var(--light-flow-segment-odd);

  --text-hub-total: var(--light-text-hub-total);
  --text-reading-idle: var(--light-text-reading-idle);
  --text-reading-active: var(--light-text-reading-active);
  --text-reading-total: var(--light-text-reading-total);

  --histogram-surface: var(--light-histogram-surface);
  --histogram-border: var(--light-histogram-border);
  --histogram-import: var(--light-histogram-import);
  --histogram-export: var(--light-histogram-export);
  --histogram-soc: var(--light-histogram-soc);
  --histogram-day-line: var(--light-histogram-day-line);
  /* Was missing here while present in the follow-the-system block above,
     so an explicitly chosen light theme drew the scrubber in the dark
     theme's colour. */
  --scrub-line: var(--light-scrub-line);

  --forecast-wash: var(--light-forecast-wash);
  --forecast-wash-alpha: var(--light-forecast-wash-alpha);
  --forecast-boundary: var(--light-forecast-boundary);

  --failure-mark: var(--light-failure-mark);
  --failure-surface: var(--light-failure-surface);
  --failure-text: var(--light-failure-text);

  --sample-edge: var(--light-sample-edge);

  --aircon-mercury: var(--light-aircon-mercury);
  --aircon-over: var(--light-aircon-over);
  --aircon-under: var(--light-aircon-under);
  --aircon-ambience: var(--light-aircon-ambience);
  --aircon-flame-core: var(--light-aircon-flame-core);
  --aircon-flame-body: var(--light-aircon-flame-body);
  --aircon-flame-bright: var(--light-aircon-flame-bright);
  --aircon-draught-core: var(--light-aircon-draught-core);
  --aircon-text-halo: var(--light-aircon-text-halo);
  --aircon-muted-over-effect: var(--light-aircon-muted-over-effect);

  --gas-flame-glow: var(--light-gas-flame-glow);
  --gas-bar: var(--light-gas-bar);
  --gas-flame-backdrop: var(--light-gas-flame-backdrop);

  --water-metal-light: var(--light-water-metal-light);
  --water-metal-mid: var(--light-water-metal-mid);
  --water-metal-dark: var(--light-water-metal-dark);
  --water-metal-edge: var(--light-water-metal-edge);
  --water-stream: var(--light-water-stream);
  --water-stream-core: var(--light-water-stream-core);
  --water-bar: var(--light-water-bar);
  --emblem-warm: var(--light-emblem-warm);

  --plan-wall: var(--light-plan-wall);
  --plan-room: var(--light-plan-room);
  --plan-room-hover: var(--light-plan-room-hover);
  --plan-glazing: var(--light-plan-glazing);
  --plan-door: var(--light-plan-door);
  --plan-furniture: var(--light-plan-furniture);
  --plan-furniture-line: var(--light-plan-furniture-line);
  --plan-roof: var(--light-plan-roof);
  --plan-lamp: var(--light-plan-lamp);
  --plan-lamp-on: var(--light-plan-lamp-on);
  --plan-lamp-glow: var(--light-plan-lamp-glow);
  --plan-sensor: var(--light-plan-sensor);
  --plan-sensor-field: var(--light-plan-sensor-field);
  --plan-device-selected: var(--light-plan-device-selected);
  --plan-label: var(--light-plan-label);
  --plan-label-fade: var(--light-plan-label-fade);

  --stale-brightness: var(--light-stale-brightness);
  --control-scheme: var(--light-control-scheme);
}

/* --- High contrast: for direct sunlight. ---

   Never selected automatically (CF-THEME-005), so unlike the other two it
   has no media-query branch at all — only the explicit one. No OS signal
   means "I am outdoors in bright sun". `prefers-contrast: more` is a
   different question, a standing accessibility preference rather than a
   passing condition, and answering the second with the first would lock
   whoever set it out of the ordinary themes.

   Built on white, because outdoors the screen competes with the sun and
   the brightest thing available should be the background. Everything else
   goes to the ends of the scale: near-black type, black pipe outlines, a
   saturated blue for flow that survives being washed out.

   The quiet distinctions the other themes rely on are deliberately given
   up here. An idle reading is black and an active one is the flow blue,
   separated by hue and weight rather than by a grey step the sun would
   erase; and the segment pattern keeps real contrast rather than the
   whisper it is elsewhere, since in bright light a subtle pattern is no
   pattern at all. */
:root[data-theme='high-contrast'] {
  --surface-page: #fff;
  --surface-card: #fff;
  /* White like every other surface here: this theme separates by its black
     borders, and a grey widget would be its one low-contrast element. */
  --surface-widget: #fff;
  --surface-panel: #fff;
  /* No step at all. In this theme separation is carried by the borders,
     which are pure black; a grey band behind the bar would be the one
     low-contrast element on a page that exists to have none. */
  --surface-bar: #fff;

  --border-card: #000;
  --border-control: #000;

  --text-primary: #000;
  --text-label: #000;
  --text-muted: #1a1a1a;
  --text-panel: #000;

  --icon-stroke: #000;
  --soc-bar: #0047ab;
  --solar-fill: #8a5a00;

  --pipe-casing: #000;
  --pipe-bore: #fff;
  --socket-fill: #fff;
  --socket-stroke: #000;

  --flow-casing: #0047ab;
  --flow-bore: #cfe0f5;

  --flow-segment-even: #cfe0f5;
  --flow-segment-odd: #7aa8d8;

  /* The hub total takes the flow blue rather than black: it sits on the
     lit bore, inside the blue casing, and every other live figure on the
     picture is that blue. Black here made the one reading that sums all
     the others look like the quietest thing on the page. */
  --text-hub-total: #0047ab;
  --text-reading-idle: #000;
  --text-reading-active: #0047ab;
  --text-reading-total: #1a1a1a;

  /* The two directions have to separate in direct sun, where a pair of
     related blues would read as one. Import keeps the strong flow blue;
     export takes a dark slate against it, and the band is plain white so
     both sit at full contrast on it. */
  --histogram-surface: #fff;
  --histogram-border: #000;
  --histogram-import: #0047ab;
  --histogram-export: #006b3c;
  --histogram-soc: #8a5a00;
  --histogram-day-line: #000;
  --scrub-line: #000;

  /* Barely washed, for the same reason staleness is barely faded: in
     bright sun a pale graph is an unreadable one. The seam carries the
     distinction here instead, at full black like every other line in this
     theme — so what separates measurement from forecast is a mark rather
     than a subtle change of tone, which is the right way round on a
     screen being read at arm's length in daylight. */
  --forecast-wash: #fff;
  --forecast-wash-alpha: 0.3;
  --forecast-boundary: #000;

  /* Black text on white, like everything else in this theme; the amber is
     kept only for the border, which is what says at a glance that this box
     is not more of the panel. A tinted surface would lower the contrast
     this theme exists to raise. */
  --failure-mark: #8a5a00;
  --failure-surface: #fff;
  --failure-text: #000;

  /* The mock marker (CF-DATA-029). A deep green: in this theme the other
     two use the same green at ordinary saturation, which the sun erases.
     Dark enough to hold a 1px rule against white. */
  --sample-edge: #0a6b3d;

  /* The A/C thermometers, at full strength for direct sunlight. The three
     have to separate from each other at a glance where the sun has washed
     the screen out, so they take the ends of their hues rather than the
     comfortable middles the other themes use. */
  --aircon-mercury: #8a5a00;
  --aircon-over: #a3200a;
  --aircon-under: #0047ab;
  /* Faint: this theme is chosen for legibility, and anything moving behind
     the controls works against that. The moving edge still says it. */
  --aircon-ambience: 0.25;
  --aircon-flame-core: rgba(200, 40, 10, 0.9);
  --aircon-flame-body: rgba(163, 32, 10, 0.5);
  --aircon-flame-bright: #c8280a;
  --aircon-draught-core: rgba(0, 71, 171, 0.45);
  --aircon-text-halo: 0 0 2px #fff, 0 0 4px #fff;
  --aircon-muted-over-effect: var(--text-label);

  /* The Gas page in sunlight: no glow, which only greys the page here, and
     the bars at the dark end of the orange. */
  --gas-flame-glow: rgb(255 140 40 / 0);
  --gas-bar: #a33f00;
  --gas-flame-backdrop: #000;

  /* The Water page in sunlight: the metal outlined in black, the water and
     the bars at the dark end of the blue. */
  --water-metal-light: #f2f2f2;
  --water-metal-mid: #9a9a9a;
  --water-metal-dark: #444;
  --water-metal-edge: #000;
  --water-stream: #0069a8;
  --water-stream-core: #7cc8f0;
  --water-bar: #00547a;
  --emblem-warm: #8a5a00;

  /* The plans in high contrast: black line on white, which is what a plan
     printed on paper is, and the one theme where the furniture has to be
     outlined rather than filled — a pale fill that carries in the light
     theme is invisible against white at this contrast. */
  --plan-wall: #000;
  --plan-room: #fff;
  --plan-room-hover: #d8e4f0;
  --plan-glazing: #0047ab;
  --plan-door: #000;
  --plan-furniture: #fff;
  --plan-furniture-line: #000;
  --plan-roof: #e0e0e0;

  /* At this contrast a halo is nearly the whole signal a transparency
     would carry, so both are given much more alpha than elsewhere: a wash
     that reads as "slightly tinted" in the other themes reads as nothing
     here. The lamp itself goes black when off, since a grey symbol on white
     is exactly what this theme exists to avoid. */
  --plan-lamp: #000;
  --plan-lamp-on: #b36b00;
  --plan-lamp-glow: rgb(179 107 0 / 0.38);
  --plan-sensor: #0047ab;
  --plan-sensor-field: rgb(0 71 171 / 0.3);
  --plan-device-selected: #000;
  /* Full black: this theme trades subtlety for legibility throughout. */
  --plan-label: #000;
  /* **Barely faded, and deliberately louder than the other themes allow.**
     Subduing the label is a preference; this theme exists for people who
     cannot afford one. At the shared 0.55 it measured 2.1:1, which is a
     caption this theme's reader could not read at all. */
  --plan-label-fade: 0.9;

  /* Barely faded: in bright sun a washed-out card is an unreadable one,
     so staleness leans on the greyscale rather than on brightness. */
  --stale-brightness: 1.15;
  --control-scheme: light;
}
