/* ══════════════════════════════════════════════════════════════════════════
   halo9.css — "Constellation: Colour" (b228)

   The second of two shipped looks for the dashboard. Profile → Constellation
   chooses between Simple (the frosted glass this app has always drawn) and
   Colour (a per-list tint, hairline, glyph, label and halo). Simple is the
   default and a permanently supported state, NOT a fallback.

   EVERY selector in this file is rooted at `body.halo9`. Nothing here can
   reach a screen, or a state, that has not opted in — and there is no
   `body:not(.halo9)` rule anywhere, because the Simple look needs no rules at
   all: the extra SVG circles ship with a `visibility="hidden"` PRESENTATION
   attribute, which any stylesheet rule outranks. Turn the class off and the
   attribute is all that is left.

   WHY TWO CIRCLES PER NODE. A <radialGradient> resolves `var()` where it is
   DECLARED, not where it is used (design-v2-app.css:118-127), so a gradient
   fill cannot follow a theme token. And setTheme() only flips
   documentElement[data-theme] — it does not repaint the constellation. So
   app.js emits BOTH themes' gradients and BOTH circles, and the three rules
   below choose. Flipping Light/Dark therefore needs no re-render and nothing
   can go stale.

   Scope. Outer constellation nodes and the dashboard activity cards, and
   nothing else. The HUB is deliberately untouched: it keeps its frosted
   `--dv2-c-dial-bg` / `-bd` and its rainbow `.dv2-const-halo`. It is the hero
   and takes no section colour, so no rule here mentions `.fhc-hub`.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Which theme's layer is on show ──────────────────────────────────────── */
/* Light is the resting state; dark overrides both halves. The <head> FOUC
   guard always sets html[data-theme], so exactly one of the two is visible. */
body.halo9 .h9-l { visibility: visible; }
html[data-theme="dark"] body.halo9 .h9-l { visibility: hidden; }
html[data-theme="dark"] body.halo9 .h9-d { visibility: visible; }

/* ── Constellation nodes ─────────────────────────────────────────────────── */
/* The tile gradient replaces the glass FILL; the shipped circle stays in place
   as the hairline, the focus ring and — the part that must not regress — the
   hit area for `data-open` / role=button / tabindex=0. */
body.halo9 .fhc-node[data-h9] .fhc-node-bg {
  fill: none;
  /* NOT optional. SVG's default is `visiblePainted`, so an unfilled circle
     stops being hittable across its whole interior — dropping `fill` alone
     would leave the coloured nodes tappable only on their 1.5px rim and their
     glyph strokes, which is a silent, look-only-looking break of every
     `data-open` on the ring. `all` restores the disc as the target regardless
     of what is painted, so the hit area is byte-for-byte the Simple one. */
  pointer-events: all;
  stroke: var(--h9-c2-l);
  stroke-width: 1.5;
}
html[data-theme="dark"] body.halo9 .fhc-node[data-h9] .fhc-node-bg {
  stroke: var(--h9-c2-d);
}
/* design-v2-app.css draws the focus ring at the same specificity this file
   overrides the hairline at, and this file loads later — so restate it, or a
   keyboard user loses the ring on exactly the nine coloured nodes. */
body.halo9 .fhc-node[data-h9]:focus-visible .fhc-node-bg {
  stroke: var(--dv2-link);
  stroke-width: 4;
}

/* The glyph. `.fhc-node` never matches the hub group, so `.fhc-hub
   .fhc-node-ic` is out of reach here by construction. */
body.halo9 .fhc-node[data-h9] .fhc-node-ic { stroke: var(--h9-mk-l); }
html[data-theme="dark"] body.halo9 .fhc-node[data-h9] .fhc-node-ic { stroke: var(--h9-mk-d); }

/* Labels live in their own top layer, out of reach of any selector rooted at
   the node — so they carry their own `--h9-ik-*` pair. */
body.halo9 .fhc-label[data-h9] { fill: var(--h9-ik-l); }
html[data-theme="dark"] body.halo9 .fhc-label[data-h9] { fill: var(--h9-ik-d); }

/* ── Activity cards ──────────────────────────────────────────────────────── */
/* HTML, not SVG, so a plain radial-gradient is enough — the custom properties
   are read where they are used and follow the theme without help. Geometry
   matches the SVG tile: 42% / 34%, hi → c0 at 40% → c1. */
body.halo9 .dv2-actcard[data-h9] .dv2-actcard-ic {
  background: radial-gradient(circle at 42% 34%,
    var(--h9-hi-l) 0%, var(--h9-c0-l) 40%, var(--h9-c1-l) 100%);
  border-color: var(--h9-c2-l);
}
html[data-theme="dark"] body.halo9 .dv2-actcard[data-h9] .dv2-actcard-ic {
  background: radial-gradient(circle at 42% 34%,
    var(--h9-hi-d) 0%, var(--h9-c0-d) 40%, var(--h9-c1-d) 100%);
  border-color: var(--h9-c2-d);
}
body.halo9 .dv2-actcard[data-h9] .dv2-actcard-lineic { stroke: var(--h9-mk-l); }
html[data-theme="dark"] body.halo9 .dv2-actcard[data-h9] .dv2-actcard-lineic { stroke: var(--h9-mk-d); }

/* b228.1 — the accent bar runs mark -> hairline, not body -> hairline.
   c1 and c2 are both near-white by day (health: #FFE7E8 -> #FFD2D4), and the
   card behind them is rgba(255,255,255,.65) glass, so a c1->c2 bar measured
   about 1.15:1 against its own card — present in the DOM and invisible on the
   screen. Starting at the mark colour gives the bar the section's identity at
   full strength, which is what a 3px accent is for. */
body.halo9 .dv2-actcard[data-h9] .dv2-actcard-accent {
  background: linear-gradient(180deg, var(--h9-mk-l), var(--h9-c2-l));
}
html[data-theme="dark"] body.halo9 .dv2-actcard[data-h9] .dv2-actcard-accent {
  background: linear-gradient(180deg, var(--h9-mk-d), var(--h9-c2-d));
}

/* The Profile control itself is NOT styled here. It has to render identically
   in both states, so it cannot hang off `body.halo9` — it reuses
   `.theme-seg-btn` from style.css, which is the component the Theme picker
   already uses and the one this control is meant to read as a sibling of. */


/* ══════════════════════════════════════════════════════════════════════════
   b229.2 — the ramps, regenerated. Two changes from b229a:

   1. A NEW lightest step, `room`. Ritesh: "the back ground is too dark, has to
      be lighter". `bg` stays put for anything sitting ON the ground; `room` is
      the ground itself and is a further step up — near-white with the hue only
      just present.

   2. Every rule now matches BOTH `body.halo9[data-h9]` (the element itself) and
      `body.halo9 [data-h9]` (a descendant). The ground has to be painted on
      <body>, because <body>'s own wallpaper is what shows through, and a token
      hosted only on a descendant cannot travel up to it.

   DO NOT hand-edit. Regenerate the whole set so it stays perceptually even.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── light ─────────────────────────────────────────────────── */
body.halo9[data-h9="health"], body.halo9 [data-h9="health"] { --h9-room:#FFFCFC; --h9-bg:#FFF8F8; --h9-card:#FFEEEE; --h9-band:#FFD8DA; --h9-edge:#F9B9BC; --h9-mark:#B3505B; --h9-ink:#793940; }
body.halo9[data-h9="grocery"], body.halo9 [data-h9="grocery"] { --h9-room:#FFFCFB; --h9-bg:#FFF9F5; --h9-card:#FFEFE5; --h9-band:#FFDBC4; --h9-edge:#F3C09E; --h9-mark:#AD5C15; --h9-ink:#754118; }
body.halo9[data-h9="maintenance"], body.halo9 [data-h9="maintenance"] { --h9-room:#FFFDF8; --h9-bg:#FDFAEE; --h9-card:#F9F3DB; --h9-band:#EFE3B8; --h9-edge:#DBCC94; --h9-mark:#8A7300; --h9-ink:#5F4F00; }
body.halo9[data-h9="home"], body.halo9 [data-h9="home"] { --h9-room:#FBFEF9; --h9-bg:#F6FDF2; --h9-card:#E9F8E2; --h9-band:#D3ECC6; --h9-edge:#B7D8A7; --h9-mark:#51852F; --h9-ink:#395A25; }
body.halo9[data-h9="shopping"], body.halo9 [data-h9="shopping"] { --h9-room:#F8FFFD; --h9-bg:#F0FEF9; --h9-card:#DDFAF1; --h9-band:#BBF0E1; --h9-edge:#97DDC9; --h9-mark:#008871; --h9-ink:#005E4D; }
body.halo9[data-h9="trips"], body.halo9 [data-h9="trips"] { --h9-room:#FAFEFF; --h9-bg:#F2FCFF; --h9-card:#DDF8FF; --h9-band:#B7EEFB; --h9-edge:#92D9EB; --h9-mark:#008399; --h9-ink:#025A69; }
body.halo9[data-h9="car"], body.halo9 [data-h9="car"] { --h9-room:#FCFDFF; --h9-bg:#F7FAFF; --h9-card:#EBF3FF; --h9-band:#D1E5FF; --h9-edge:#ACCFFD; --h9-mark:#3A75BF; --h9-ink:#2B5180; }
body.halo9[data-h9="school"], body.halo9 [data-h9="school"] { --h9-room:#FDFDFF; --h9-bg:#FAF9FF; --h9-card:#F3F0FF; --h9-band:#E4DEFF; --h9-edge:#CFC3F9; --h9-mark:#7B62B8; --h9-ink:#54457C; }
body.halo9[data-h9="pets"], body.halo9 [data-h9="pets"] { --h9-room:#FFFCFE; --h9-bg:#FFF8FD; --h9-card:#FFECFA; --h9-band:#FCD5F2; --h9-edge:#ECBAE0; --h9-mark:#A25492; --h9-ink:#6D3B63; }

/* ── dark ─────────────────────────────────────────────────── */
html[data-theme="dark"] body.halo9[data-h9="health"], html[data-theme="dark"] body.halo9 [data-h9="health"] { --h9-room:#0F0506; --h9-bg:#1B0B0C; --h9-card:#2D1719; --h9-band:#412325; --h9-edge:#593538; --h9-mark:#F78E97; --h9-ink:#FBCDD0; }
html[data-theme="dark"] body.halo9[data-h9="grocery"], html[data-theme="dark"] body.halo9 [data-h9="grocery"] { --h9-room:#0E0602; --h9-bg:#1A0D05; --h9-card:#2B190D; --h9-band:#3E2615; --h9-edge:#573925; --h9-mark:#EF9A5D; --h9-ink:#F7D2BB; }
html[data-theme="dark"] body.halo9[data-h9="maintenance"], html[data-theme="dark"] body.halo9 [data-h9="maintenance"] { --h9-room:#0A0802; --h9-bg:#141003; --h9-card:#231E08; --h9-band:#342C0F; --h9-edge:#4A411F; --h9-mark:#CBB045; --h9-ink:#E5DBB5; }
html[data-theme="dark"] body.halo9[data-h9="home"], html[data-theme="dark"] body.halo9 [data-h9="home"] { --h9-room:#050903; --h9-bg:#0B1307; --h9-card:#172210; --h9-band:#22321A; --h9-edge:#35472B; --h9-mark:#8DC36E; --h9-ink:#CCE3C1; }
html[data-theme="dark"] body.halo9[data-h9="shopping"], html[data-theme="dark"] body.halo9 [data-h9="shopping"] { --h9-room:#020A07; --h9-bg:#031410; --h9-card:#08241D; --h9-band:#0E342B; --h9-edge:#1F4A3F; --h9-mark:#3CCBAC; --h9-ink:#B8E7D9; }
html[data-theme="dark"] body.halo9[data-h9="trips"], html[data-theme="dark"] body.halo9 [data-h9="trips"] { --h9-room:#010A0D; --h9-bg:#021318; --h9-card:#052229; --h9-band:#09323B; --h9-edge:#1A4852; --h9-mark:#25C5E4; --h9-ink:#B4E4F0; }
html[data-theme="dark"] body.halo9[data-h9="car"], html[data-theme="dark"] body.halo9 [data-h9="car"] { --h9-room:#040810; --h9-bg:#08111D; --h9-card:#121F2F; --h9-band:#1C2D43; --h9-edge:#2E425C; --h9-mark:#79B4FF; --h9-ink:#C4DDFD; }
html[data-theme="dark"] body.halo9[data-h9="school"], html[data-theme="dark"] body.halo9 [data-h9="school"] { --h9-room:#08060F; --h9-bg:#110E1B; --h9-card:#1F1B2D; --h9-band:#2E2841; --h9-edge:#433B5A; --h9-mark:#B7A0FA; --h9-ink:#DDD5FA; }
html[data-theme="dark"] body.halo9[data-h9="pets"], html[data-theme="dark"] body.halo9 [data-h9="pets"] { --h9-room:#0D050B; --h9-bg:#180C15; --h9-card:#291725; --h9-band:#3B2436; --h9-edge:#52364C; --h9-mark:#E391D1; --h9-ink:#F1CEE9; }


/* ══════════════════════════════════════════════════════════════════════════
   b229a — COLOUR ON THE LIST SCREEN

   One room, one hue. `#view-list` carries `data-h9="<key>"` (set in
   renderShop) whenever the list resolves to one of the nine, so the token
   block above lands on the view and everything below reads it by inheritance.
   A list outside the nine — Renewals today — gets NO attribute, matches none
   of these rules, and renders as Simple. That is deliberate.

   EVERY selector here starts `body.halo9 #view-list[data-h9]`. With Simple
   chosen the body class is absent and not one declaration below can apply, so
   the list screen is byte-for-byte what it is today.

   ONE HUE PER ROOM. `sectionColours[section]` still writes `--hue` onto each
   `<section>` and Simple still honours it — but nothing below reads `--hue`,
   so a per-group colour cannot reach a `--h9-*` token. The two places it used
   to show through under Colour (the section head's band and the head's
   progress ring) are repainted from the room's own `--h9-band` / `--h9-mark`.
   The feature and its storage are untouched; they just stop being visible
   here, which is the ruling.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · The ground ──────────────────────────────────────────────────────── */
/* The room is painted on <body>, and only on <body>.

   b229a tried a viewport-filling fixed layer inside the view. It does not
   work: `.view` carries a transform whenever the nav slide runs
   (body[data-nav-dir], set in show()), and a transformed ancestor makes
   `position: fixed` resolve against that ancestor instead of the viewport. So
   the layer stopped at the view's box and the app's wallpaper showed down both
   edges — which is what Ritesh photographed.

   `#view-list` is also a normal block inside <body>'s 20px side padding, and
   its box ends at the last section, so a background on the view alone leaves a
   gutter down each side and under the fold either way.
   design-v2-grocery.css:625-638 hit this same trap and solved it the same way.

   So the tokens now match `body.halo9[data-h9]` as well as a descendant, and
   <body> hosts them itself. `!important` is required — the LIQUID GLASS block
   sets body's four-layer wallpaper at style.css:6464. renderShop() puts the
   attribute on <body>; show() takes it off on the way out, so the room cannot
   outlive the list. */
body.halo9[data-h9] { background: var(--h9-room) !important; }
body.halo9 #view-list[data-h9] { background: transparent; }

/* ── 2 · The topbar ──────────────────────────────────────────────────────── */
/* style.css:6512 paints this with a hue gradient (and :6517 the dark twin);
   design-v2-grocery.css:90 replaces both on a Grocery list. This is (1,3,0)
   and lands after all three. The gradient is opaque, so the backdrop-filter
   underneath simply has nothing to show — that is the point of a room. */
body.halo9 #view-list[data-h9] .topbar {
  background: linear-gradient(180deg, var(--h9-band), var(--h9-edge));
  border-bottom: .75px solid var(--h9-edge);
}
body.halo9 #view-list[data-h9] .lp-name { color: var(--h9-ink); }

/* ── 3 · The tool pill ───────────────────────────────────────────────────── */
/* The translucent ground stays as it is; only the keyline and the glyphs move.
   By night the glyphs take `mark` rather than `ink` — ink is the text tone and
   a 22px stroked glyph needs the brighter one to hold at that weight. */
body.halo9 #view-list[data-h9] .lp-tools { border-color: var(--h9-edge); }
body.halo9 #view-list[data-h9] .lp-tool { color: var(--h9-ink); }
html[data-theme="dark"] body.halo9 #view-list[data-h9] .lp-tool { color: var(--h9-mark); }

/* ── 4 · The section head ────────────────────────────────────────────────── */
/* `.list .section` is already transparent-with-!important (style.css:8025) and
   its colour spine is `display:none`, so the head is the only band left on the
   section — and it is the one surface `sectionColours` used to reach. */
body.halo9 #view-list[data-h9] .list .section-head {
  background: var(--h9-band);
  /* A no-op on every list but Grocery, whose head is drawn as a bordered glass
     card (design-v2-grocery.css:309) — without this the white keyline stays. */
  border-color: var(--h9-edge);
}
body.halo9 #view-list[data-h9] .list .section-head h2,
body.halo9 #view-list[data-h9] .list .section-head .count { color: var(--h9-ink); }
/* The head's completion ring and its finished tick — the second and last place
   a per-group hue was visible. `.ring .fill` reads `--sec`, which is derived
   from `--hue`; `.section.done .tick` was the app purple (style.css:9394). */
body.halo9 #view-list[data-h9] .list .section-head .ring .fill { stroke: var(--h9-mark); }
body.halo9 #view-list[data-h9] .list .section.done .tick { background: var(--h9-mark); }

/* ── 5 · The row cards ───────────────────────────────────────────────────── */
/* Near-white by day is already `--surface` (#fff), so day needs no rule at all
   — writing one would only be a chance to get it wrong. Night swaps the app's
   #1c1c1e for the room's own card tone. `:not(.fresh):not(:active)` keeps the
   new-item highlight and the press state, both of which are lower
   specificity than this and would otherwise be swallowed. */
html[data-theme="dark"] body.halo9 #view-list[data-h9] .list .row-swipe,
html[data-theme="dark"] body.halo9 #view-list[data-h9] .list .row:not(.fresh):not(:active):not(.wanted) {
  background: var(--h9-card);
}
/* The hairline. A ring shadow rather than a border: `.list .row-swipe` is
   `overflow:hidden` with a 14px radius and a border would move the swipe
   panel's clip by a pixel on every row. */
body.halo9 #view-list[data-h9] .list .row-swipe {
  box-shadow: 0 0 0 .75px var(--h9-edge), 0 1px 2px rgba(0,0,0,.06);
  /* Grocery's card carries a real border (design-v2-grocery.css:393); every
     other list has none, where this is inert. */
  border-color: var(--h9-edge);
}
html[data-theme="dark"] body.halo9 #view-list[data-h9] .list .row-swipe {
  box-shadow: 0 0 0 .75px var(--h9-edge);
}

/* ── 6 · The progress fill ───────────────────────────────────────────────── */
/* style.css:6759 (the LIQUID GLASS block) paints this `--accent` → #8b7dff.
   NOTE it is always 0% wide on a tasks list — that is app.js's business and
   is deliberately left alone here. */
body.halo9 #view-list[data-h9] .overall .bar > span { background: var(--h9-mark); }

/* ══ The four purples ══════════════════════════════════════════════════════
   The app accent, shared by every list. Simple keeps all four exactly as they
   are; under Colour each takes the room's own colour. */

/* The FAB. style.css:6748 fills `.fab, .fab-add` with the indigo gradient and
   an indigo drop shadow using `!important`, which is why it is purple on every
   list whatever the hue — so this needs `!important` too. Scoped to
   `#btn-shop-add` inside a keyed `#view-list`, so no other `.fab` anywhere in
   the app is reachable from here. The glyph stays white (style.css:1888). */
body.halo9 #view-list[data-h9] #btn-shop-add {
  background: linear-gradient(180deg, var(--h9-mark), var(--h9-ink)) !important;
  box-shadow:
    0 20px 34px -12px color-mix(in oklab, var(--h9-mark) 55%, transparent),
    inset 0 1px 0 rgba(255,255,255,.32) !important;
}

/* The History pill (style.css:9355). */
body.halo9 #view-list[data-h9] .tc-hist {
  color: var(--h9-mark);
  border-color: var(--h9-edge);
}

/* The repeat chip (style.css:9295). */
body.halo9 #view-list[data-h9] .tc-rep {
  background: var(--h9-band);
  border-color: var(--h9-edge);
  color: var(--h9-ink);
}

/* The completed tick (style.css:9392), and the ring that pulses out of it on
   the moment of completion (style.css:9407) — one gesture, one colour. */
body.halo9 #view-list[data-h9] .row.on .box,
body.halo9 #view-list[data-h9] .row.just-done .box {
  background: var(--h9-mark);
  border-color: var(--h9-mark);
}
body.halo9 #view-list[data-h9] .row.just-done .box::after { border-color: var(--h9-mark); }

/* ══════════════════════════════════════════════════════════════════════════
   b229.1 — two hues that escaped the sweep.

   Both are cases where the ROOM is one colour but something inside it is
   still wearing the app's generic accent. That is the exact fault the whole
   "one colour per room" decision was made to remove, so they belong here and
   not on a list of things to do later.
   ══════════════════════════════════════════════════════════════════════════ */

/* 1 · The row label. style.css:1625 tints item text with the list's OWN hue
   (`hsl(var(--hue) 60% 38%)`). `body.lp-clean` neutralises it for Grocery and
   for every task list, which is most of them — but a plain shopping list
   (Shop) is neither, so on that one screen the labels kept the old 210 blue
   while everything around them turned teal. One hue per room means this one
   too. `--h9-ink` is the token designed for text on card: 7.0-7.6 by day. */
body.halo9 #view-list[data-h9] .section .row-swipe .label { color: var(--h9-ink); }

/* 2 · The "done" chip — the confirmation that appears for about two seconds
   after a tick, at style.css:9423. Short-lived, but it appears at the exact
   moment the user is looking at the row, and it is a lilac pill with a purple
   dot in the middle of a coloured room. */
body.halo9 #view-list[data-h9] .tc-done-chip {
  background: var(--h9-band);
  border-color: var(--h9-edge);
  color: var(--h9-ink);
}
body.halo9 #view-list[data-h9] .tc-done-chip .tcd { background: var(--h9-mark); }


/* ══════════════════════════════════════════════════════════════════════════
   b229b — COLOUR ON THE SIX HUBS

   b229a coloured `#view-list`. That was one screen, and it was not the screen
   Ritesh was looking at: loadShop() (app.js) dispatches SIX of the nine fixed
   tiles away from the list view entirely — Pets, School, Shop, Home, Garage
   and Health each open their own hub — so only Grocery, Maintenance and
   Renewals ever reached the rules above. Turning Colour on and opening a list
   therefore changed nothing six times out of nine. This block is the other six.

   HOW THE ATTRIBUTE GETS HERE. show() carries VIEW_H9, which names the room
   each hub view is in, and writes `data-h9` onto <body> AND onto the view root
   on the way in and clears it on the way out — one place, so the room cannot
   flash off mid-navigation and cannot outlive the screen it belongs to.

   SPECIFICITY, AND WHY IT IS SPELLED OUT WITH SIX IDs. `:is()` takes the
   specificity of its most specific argument, so every selector below is
   (1,2,1) or more. That is not decoration:

     · `body.hv-on #view-health { background: var(--hv-ground) }` is (1,2,1)
       and would otherwise tie — this file loads last, but a tie is not a
       margin, and Health also paints a fixed `::before` under everything.
     · the six `*-c.css` token blocks each exist THREE times — bare,
       `html[data-theme="dark"] body.xx-on` and
       `@media (prefers-color-scheme: dark) html:not([data-theme="light"])
       body.xx-on` — and the last two are (0,2,2). A (0,2,1) override would be
       right by day and silently wrong by night, which is the b212 bug this
       codebase has now hit three times.

   SIMPLE IS UNTOUCHED. Every selector starts `body.halo9`; none can match
   without the class the Profile control adds.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · The ground reaches the bottom of the screen ─────────────────────── */
/* style.css:132 paints `html` as well as `body`, so <body>'s background does
   NOT propagate to the canvas — it stops at the body box, and on a short hub
   (one pet, no vehicles, an empty Shop) the app's grey showed in the strip
   underneath. pets-c.css:148 and school-c.css:159 both hit this and both
   answered it with min-height; the room needs the same answer, and needs it on
   the four hubs that never had it (Garage, Home, Health, Shop) as well as on
   the list. Applies only where a room is actually being painted. */
body.halo9[data-h9] { min-height: 100dvh; }

/* Health is the one hub that paints its own opaque ground, and it paints it
   twice: on the view, and as a fixed full-viewport `::before` at
   health-c.css:161 for exactly the short-screen strip the rule above now
   covers. The view stands down; the ::before is repainted rather than removed,
   so if a browser ever disagrees about `100dvh` the room is still what shows.
   The declaration is inert on every other hub — no other `body::before` in the
   app sets `content`, so no box is generated to paint. */
body.halo9 #view-health[data-h9] { background: transparent; }
body.halo9[data-h9]::before { background: var(--h9-room); }

/* ── 2 · The topbar ──────────────────────────────────────────────────────── */
/* Same band → edge gradient the list screen wears, so a hub and a list read as
   the same room. It lands over style.css:6504 (`.topbar.glass`) and over the
   four `body.xx-on .topbar.glass` restatements in the section files. The
   gradient is opaque, so the backdrop-filter under it has nothing left to show.

   `.back-btn` is deliberately NOT recoloured. style.css:6543 forces every back
   chip in the app to solid navy with `!important`, twice fixed, because a glass
   chevron vanished on light headers — the list screen keeps that chip under
   Colour too, so the hubs match it rather than inventing a seventh answer. */
/* b230.2 — `band -> edge`, REVERTED from the `card -> band` b230.1 tried.

   b230.1 changed this ramp on the theory that the header sat too dark against
   the constellation tile and had drifted off the tile's hue. Measured in OKLCH
   afterwards, that theory is wrong on both counts. Every surface involved is
   the SAME hue — 254.8 to 258.4 degrees — and the header is not darker: tile
   body 94.8% L / 0.025 C against header top 96.2% L / 0.018 C. The colours were
   never mismatched.

   What differs is CHROMA, and in the opposite direction to the assumption. The
   constellation tile sits on a halo at chroma 0.112, about 4.5x the tile's own,
   and that halo is what the eye actually reads as "Garage's colour" on the
   dashboard. `card -> band` is 0.018 -> 0.042 — under half the halo's weight.
   So b230.1 HALVED the header's colour at the moment Ritesh was saying the
   screen did not look coloured enough. `band -> edge` is 0.042 -> 0.075, much
   nearer the halo, and it is what shipped before b230.1.

   The light ground above is NOT part of this revert. That was approved on its
   own and is independent of the header ramp. */
body.halo9 :is(#view-pets, #view-school, #view-shop, #view-property,
               #view-car, #view-health, #view-trips)[data-h9] .topbar {
  background: linear-gradient(180deg, var(--h9-band), var(--h9-edge));
  border-bottom: .75px solid var(--h9-edge);
}
body.halo9 :is(#view-pets, #view-school, #view-shop, #view-property,
               #view-car, #view-health, #view-trips)[data-h9] .lp-name {
  color: var(--h9-ink);
}

/* ── 3 · The identity accents ────────────────────────────────────────────── */
/* Each hub hard-codes one colour that means "this section". Under Colour that
   colour is the room's, and these are the only hard-coded hues below touched.
   The `*-c.css` files themselves are NOT edited — they are Simple. */

/* Pets — the count on a header tool. A saturated badge, so `mark`; `--pv-badge-tx`
   is already #fff by day and #14121F by night, which is the right way round for
   `mark` in both themes. */
body.halo9 #view-pets[data-h9] { --pv-badge-bg: var(--h9-mark); }

/* Health — `--hv-rose` is the section's own colour (hue 350) and is worn by the
   avatar initial, the appointment rail, the year knot, the chosen radio and
   every rose pill. `-sf` is its soft fill, `--hv-band` the hero's ground, and
   `--hv-trend-was` the muted earlier bar — a 30% rose, so it stays a fraction
   of the mark rather than becoming a fourth flat tone. */
body.halo9 #view-health[data-h9] {
  --hv-rose: var(--h9-mark);
  --hv-rose-sf: var(--h9-band);
  --hv-trend-was: color-mix(in oklab, var(--h9-mark) 32%, transparent);
  --hv-band: linear-gradient(145deg, var(--h9-band), var(--h9-edge));
}

/* Shop — `.sh-band` is the fold control over the rows, and hue 25 (amber) is
   the only identity Shop has. Three values, the Diary recipe: fill → band,
   edge → edge, ink → ink.

   `:not(.sh-band-q)` IS LOAD-BEARING. The archive band is `.sh-band.sh-band-q`
   and is deliberately quiet — grey glass, because it is a record and not a call
   to act (shop-c.css:139). Its own rule is (0,2,1); this one is (1,3,2), so
   without the exclusion the archive band would be repainted in the section's
   colour and the two bands would stop meaning different things. */
body.halo9 #view-shop[data-h9] .sh-band:not(.sh-band-q) {
  background: var(--h9-band);
  border-color: var(--h9-edge);
  color: var(--h9-ink);
}

/* Garage — the fold chip, tinted with hue 220 because that is the number
   RENEWAL_SECTIONS gives Garage. It is a fold chip, but it is the section's OWN
   colour rather than a category tint, which is the one case the rollout brief
   says to move. Same two values in both themes, so one rule covers both. */
body.halo9 #view-car[data-h9] .gv-st-ic {
  background: var(--h9-band);
  color: var(--h9-ink);
}

/* School and Home get NO accent rule, and that is a finding rather than a gap.
   · School's only hard-coded hue is `--sv-badge-bg`, and school-c.css:84 says
     what it is for in as many words: "Red because it is a date that is close,
     not a notification; the same red the ribbon uses for a closure." It reports
     a state, so it stays red — the same reasoning that keeps `--hv-high-ink`
     out of the Health block above. Everything else in School is a `--sv-t-*`
     category tint or a `--sv-rib-*` status ribbon.
   · Home DECLARES an identity triple — `--hm-fill` / `--hm-edge` / `--hm-ink`,
     home-c.css:48-50, the Diary recipe for hue 100 — but nothing in the app
     reads any of the three. They are declared in all three theme blocks and
     used in zero rules, in any stylesheet or template. Repointing them at the
     room's tokens would have looked like work and changed nothing on screen,
     so they are left as they are and written down here instead.

   The app accent, `--dv2-link`, is also left alone on all six. It is the one
   remaining purple inside a coloured room (Garage 16 uses, Pets 13, Home 7,
   Health 1) — but it is worn as much by the SHEETS those hubs open, and a sheet
   is a sibling of the view, not a descendant, so a rule scoped to
   `#view-x[data-h9]` would recolour half of each section and leave the other
   half indigo. Moving it properly means deciding what a Save button, a focus
   outline and a `.tc-hist` pill are — a change with its own verification. */


/* ══════════════════════════════════════════════════════════════════════════
   b230 — THE DIARY, AND THE ONE LIST THAT IS NINE COLOURS AT ONCE

   Renewals is now "The Diary", and it is a CONTAINER, not a section — the same
   ruling the Vault got. It takes no hue of its own: `h9Key('renewals')` returns
   '' and that stays true, so `#view-list` gets NO `data-h9`, no room is
   painted, its topbar and its tile stay neutral, and every rule in the b229a
   block above is out of reach on this screen. That is deliberate. Do not give
   the Diary a tenth colour.

   What DOES carry colour is each GROUP, because a group is one section's
   renewals. b230 groups the rows by the section that owns each row's source
   document (server-derived, `/api/renewals/index`) and sorts by date inside
   each group. renderShop() puts `data-h9="<key>"` on the `<section>` itself, so
   the token block at the top of this file lands on the group and each header
   reads its own room's tokens. Nine colours can therefore appear on one screen
   — which is exactly what "one hue per room" forbids for a room, and exactly
   what a container is for.

   A group the index could not attribute — a reminder whose document was
   deleted, a job somebody typed in by hand, the always-present Adhoc — gets no
   attribute and no colour. It still appears. An unattributed row wearing Home's
   green would be a claim we cannot stand behind.

   SIMPLE. The grouping is structure, not colour, so it happens in both states;
   the name changed in both states too. Nothing else on this screen moves under
   Simple: the header keeps the list's own hue and each row keeps the 3.5px rail
   style.css has drawn since b211.

   SPECIFICITY. Every selector below is (1,5,1) or more, which it needs to be:
   `.section.done .section-head` (style.css:1604) is (0,3,0), `.section.done
   .section-head h2` (style.css:9396) is (0,3,1) with a (0,4,1) dark twin, and
   `body.lp-clean .section .count` (style.css:9531) is (0,3,0) with a (0,4,0)
   dark twin. Every one of those is beaten in BOTH themes by one rule, which is
   why there is no `html[data-theme="dark"]` restatement here — the tokens
   already carry the theme.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · The group header ────────────────────────────────────────────────── */
/* Same band → ink relationship the list screen's own `.section-head` wears, so
   a Diary group and a coloured list read as the same material. */
body.halo9 #view-list .list .section[data-h9] .section-head {
  background: var(--h9-band);
  border-color: var(--h9-edge);
}
body.halo9 #view-list .list .section[data-h9] .section-head h2,
body.halo9 #view-list .list .section[data-h9] .section-head .count {
  color: var(--h9-ink);
}
/* The completion ring, whose `.fill` reads `--sec` (derived from `--hue`), and
   the finished tick, which is the app purple at style.css:9394. */
body.halo9 #view-list .list .section[data-h9] .section-head .ring .fill {
  stroke: var(--h9-mark);
}
body.halo9 #view-list .list .section[data-h9].done .section-head .tick {
  background: var(--h9-mark);
}

/* ── 2 · The row rail ────────────────────────────────────────────────────── */
/* The rail is Simple's answer and it stays exactly as it is there. Under Colour
   it takes the group's own `mark` instead of the hsl() number style.css:9906
   computes, so the rail and the header above it cannot be two different reds.
   The rail is still drawn by style.css — geometry, position and z-index are
   untouched; only the paint moves. */
body.halo9 #view-list .list .section[data-h9] .row-swipe[data-rnsec]::before {
  background: var(--h9-mark);
}

/* ── Travel ──────────────────────────────────────────────────────────────
   Trips is the ninth tile and the only one that is not a Shop row — its own
   feature, its own view, its own stylesheet — which is how it stayed grey
   while the other eight were coloured. It also does not share the hubs'
   chrome: the header is `.sub-head` with a bare <h1>, not `.topbar` with
   `.lp-name`, so the group rule above cannot reach it and it needs its own
   pair. Same two tones as every other header, so it matches its tile.

   The ground needs no rule: `body.tv-on #view-trips` is already transparent
   (trips-c.css:63), and `body.tv-on`'s own aurora loses to the `!important`
   on the room. */
/* b230.2 — `band -> edge` here too, for the same reason and by the same
   measurement as the hub topbar above: the ramp is a CHROMA question, not a hue
   or a lightness one, and `card -> band` was under half the halo's weight. */
body.halo9 #view-trips[data-h9] .sub-head {
  background: linear-gradient(180deg, var(--h9-band), var(--h9-edge));
  border-bottom: .75px solid var(--h9-edge);
}
body.halo9 #view-trips[data-h9] .sub-head h1 { color: var(--h9-ink); }


/* ══════════════════════════════════════════════════════════════════════════
   b230.2 — THE DIARY'S OWN CHROME IS NEUTRAL, NOT SHOP'S AMBER

   The block above is right that the Diary takes no `data-h9`: it is a
   container, its groups wear their own rooms' colours and it has none of its
   own. What that block did not follow through is what the screen then looks
   like. `data-h9` absent means EVERY rule in the b229a list block misses this
   view — so the topbar, the tool pill and the group heads went on painting
   themselves from `--hue`, which renderShop() sets from `shop.hue`, which on
   this list is 25. Under Colour the Diary's header was AMBER, and amber is
   Shop's. That is Simple's hue showing through a hole in Colour, not a
   decision.

   "No colour of its own" has to mean the app's own neutral chrome. So the
   rules below only ever SUBTRACT: every one replaces an `hsl(var(--hue) …)`
   with the neutral token the same surface wears everywhere outside a list
   (`--lg-mat-light`, `--lg-hair-ink`, `--text`, `--text-2`, `--row-bg`), all of
   which already carry the theme, so there is no dark twin to keep in step.

   `data-h9-container="diary"`, NOT a tenth `data-h9` key. A key would open
   every selector in the b229a block — `body.halo9 #view-list[data-h9] …` — and
   paint a room, which is the one thing a container must not have. This
   attribute matches nothing else in the app.

   SIMPLE IS UNTOUCHED. Every selector starts `body.halo9`, so with Colour off
   the Diary keeps the amber header, the amber tool pill and the amber group
   heads it has today, byte for byte.

   SPECIFICITY. `#view-list .topbar` (style.css:6510) is (1,1,0) and its dark
   twin (1,2,1); `.lp-tools` (5737) is (0,1,0) and its dark twin (0,2,1);
   `.section-head` (1591) is (0,1,0), `.list .section-head` (8039) (0,2,0),
   `.section.done .section-head` (1604) (0,3,0). Every rule below is (1,3,0) or
   more and beats all of them in both themes.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · The topbar ──────────────────────────────────────────────────────── */
/* Back to the plain frosted panel `.topbar` wears on every view that is not a
   list (style.css:6504) — the blur and the saturate are inherited from there,
   only the hue gradient is replaced. */
body.halo9 #view-list[data-h9-container="diary"] .topbar {
  background: var(--lg-mat-light);
  border-bottom: .75px solid var(--lg-hair-ink);
}
body.halo9 #view-list[data-h9-container="diary"] .lp-name { color: var(--text); }

/* ── 2 · The tool pill ───────────────────────────────────────────────────── */
body.halo9 #view-list[data-h9-container="diary"] .lp-tools {
  background: var(--lg-mat-light);
  border-color: var(--lg-hair-ink);
  box-shadow: var(--lg-lift-1);
}
body.halo9 #view-list[data-h9-container="diary"] .lp-tool { color: var(--text-2); }
/* The three hue-tinted states of a tool button. Included because leaving them
   would put one amber flash back on a screen the rest of this block just made
   neutral — `:active` fires on a phone even though `:hover` does not. */
body.halo9 #view-list[data-h9-container="diary"] .lp-tool:hover,
body.halo9 #view-list[data-h9-container="diary"] .lp-tool:active {
  background: var(--row-bg);
}
body.halo9 #view-list[data-h9-container="diary"] .lp-tool[aria-pressed="true"] {
  background: var(--row-bg);
  color: var(--text);
}

/* ── 3 · A group with no section ─────────────────────────────────────────── */
/* "Not filed" — and Adhoc, and any group left over from the index — carries no
   `data-h9`, so §1 of the b230 block above cannot reach it and `.section-head`
   fell back to `hsl(var(--hue) 65% 88%)`: pale amber. A group whose whole point
   is that we cannot attribute it must not be wearing a colour, least of all
   another section's. Neutral band, neutral ink, and the completion ring and
   the finished tick with it.

   `:not([data-h9])` is what keeps this off the nine coloured groups; the
   container attribute is what keeps it off every other list in the app. */
body.halo9 #view-list[data-h9-container="diary"] .list .section:not([data-h9]) .section-head {
  background: var(--lg-mat-light);
  border-color: var(--lg-hair-ink);
}
body.halo9 #view-list[data-h9-container="diary"] .list .section:not([data-h9]) .section-head h2,
body.halo9 #view-list[data-h9-container="diary"] .list .section:not([data-h9]) .section-head .count {
  color: var(--text-2);
}
body.halo9 #view-list[data-h9-container="diary"] .list .section:not([data-h9]) .section-head .ring .fill {
  stroke: var(--text-3);
}
body.halo9 #view-list[data-h9-container="diary"] .list .section:not([data-h9]).done .section-head .tick {
  background: var(--text-3);
}

/* NOT HERE: the progress fill. style.css:1535 paints `.bar > span` from
   `--accent`, never from `--hue`, so it is the app purple on the Diary in BOTH
   states already and there is nothing to neutralise. The b230.2 brief asked for
   it; a rule would have been a no-op with a comment claiming otherwise. Same
   for the FAB: style.css:6748 fills `#btn-shop-add` with the indigo gradient
   using `!important`, so it is purple here too. */

/* ══════════════════════════════════════════════════════════════════════════
   b232 · THE (i) SHEET WEARS THE LIST'S ROOM
   ══════════════════════════════════════════════════════════════════════════
   openWelcome() puts `data-h9="<key>"` on the hero itself and REMOVES the
   inline `--c` / `--c-deep` pair when Colour is on, so these two rules are
   what paints it. The attribute goes on the hero rather than relying on
   <body>'s because the sheet is a sibling of `#view-list`, opened from the
   toolbar ⓘ and from the burger, and must not depend on which.

   Two pairs, not one, and the reason is the white text. `.welcome-hero` is
   `color:#fff` with a white <h2> on it (style.css:2689), so BOTH stops have to
   stay dark whichever theme is on. By day `--h9-mark` → `--h9-ink` is the
   room's darkest pair. By night `--h9-mark` is the BRIGHT stroke colour
   (#F78E97 on Health) and white would vanish on it, so night takes the two
   dark surface tones instead.

   `body.halo9 [data-h9="<key>"]` (halo9.css:127) hosts the tokens on any
   element carrying the attribute, so the hero self-hosts and nothing has to
   inherit down through the sheet. */
body.halo9 #welcome-hero[data-h9] {
  --c: var(--h9-mark);
  --c-deep: var(--h9-ink);
}
html[data-theme="dark"] body.halo9 #welcome-hero[data-h9] {
  --c: var(--h9-edge);
  --c-deep: var(--h9-card);
}

/* ══════════════════════════════════════════════════════════════════════════
   b232 · THE LIST COLOUR PICKER HAS NOTHING TO PICK UNDER COLOUR
   ══════════════════════════════════════════════════════════════════════════
   `#panel-hues` writes `shop.hue`, and under Colour a list's hue comes from
   its IDENTITY — `dv2NodeIconKey()` → `h9Key()` → the room's `--h9-*` tokens —
   not from `--hue`. So the swatches under Colour are a control that changes
   nothing you can see: it was already ruled that a list's colour is not the
   user's to set once Colour is on.

   The LABEL goes with the FIELD. Hiding only the swatches leaves the heading
   "Section colour — soft pastel" standing over nothing, which is the exact
   bug index.html:1836 records for the a2a-clean pair. Both, or neither.

   Simple is untouched: the picker is the whole point there, and this rule
   cannot reach it. */
body.halo9 #panel-hue-lbl,
body.halo9 #panel-hue-field { display: none; }
