/* thermii-skin.css — the 2026-08-25 UI skin, from Loz's reference screen.

   Loads LAST, after css/thermii-progress.css, so it can restyle anything without
   !important gymnastics. Everything is scoped under `body.thermii-skin`, which
   js/thermii-skin.js sets — so if that file fails to load the page falls back to
   the CURRENT design rather than to half of the new one.

   WHAT THE REFERENCE WAS AND WAS NOT. Loz: "mainly a reference for the overall
   container, header bar, progress bar design", plus a Thermii insight panel under
   the option tiles and purple Continue buttons. Explicitly NOT taken from it:
   the tile icon styling (the current icons stay) and its fonts (Poppins stays).
   Journey content and behaviour are untouched — this is a skin.

   The dark sidebar is HIDDEN, never deleted: it owns four ids and
   verify-parity.py holds index.html's id list to the frozen baseline. */

@media screen {

  /* ── The page and the container ──────────────────────────────────────────── */

  /* A light room around a white card, which is what gives the reference its calm.
     The aurora blobs behind the old layout fight it, so they go. */
  /* a fallback only: the aurora covers this once it has faded in */
  body.thermii-skin {
    background: #f4f5f9;

    /* THE STAGE DEPTH. Loz's figure, 2026-08-27: a flat depth rather than one
       that follows the window, and a FLOOR — `min-height`, so a screen with more
       content than this simply grows, which is what he asked for.

       1000px against a sweep of all 21 question steps at 1200 and 1400 wide: one
       screen overruns it, electric step 6 at 1264 — the only one, at both widths.
       That card therefore runs deeper than the rest and sticky holds its bar at
       the bottom of the view while you scroll it, which is the "longer if needed"
       Loz asked for. Every other screen sits at exactly the figure, so its bar
       lands in one place. On a window too short to show the whole card, every
       screen behaves that way regardless.

       Re-measure with the sweep in the transcript if the content changes. */
    --thermii-stage-depth: 1000px;

    /* .kb-wrapper's own radius, from css/thermii.css (byte-locked, so it cannot
       be read from there). Mirrored here for the bars that reach the card's
       bottom corners — see the note on those. */
    --thermii-card-radius: 22px;
  }

  /* THE AURORA STAYS — restored 2026-08-26 at Loz's request, having been hidden
     when the skin first landed.

     Nothing was ever lost: the whole thing lives in css/thermii.css (byte-locked)
     — .ab1-.ab5, the aurora-1..aurora-5 drift keyframes, the white top wash and
     the fractal-noise overlay — and hiding it here was the only reason it stopped
     appearing. The fix is to stop hiding it, not to re-add anything.

     It is `position:fixed; inset:0; z-index:-1`, so it paints above the body's
     background and below every element in the page: behind the whole container,
     which is exactly where it is wanted. The body colour below is now only a
     fallback for the moment before it fades in, and for print.

     `prefers-reduced-motion` already freezes the drift at thermii.css:125 —
     inherited for free by not overriding it. */

  /* ── THE WHITE TOP WASH GOES (Loz, 2026-09-07) ────────────────────────────
     "On the old version we made it paler at the top, but now the UI has
     changed we might as well have the full colour running across the whole
     animated background."

     THE WASH HAD A REASON AND IT NO LONGER HOLDS. `.thermii-aurora::before`
     (css/thermii.css:102) lays white over the top 32% of the VIEWPORT, and its
     own comment states why: "top 30% of viewport so logo + progress bar sit on
     clean white". Measured at 1600x1000 before touching it: the wash covers
     320px, `.kb-wrapper` starts at y=38 with `.kb-logo` INSIDE it on an opaque
     background, and the only things sitting on bare aurora in that band are
     the blobs themselves — no text, no control. The card does the job the wash
     was doing.

     SO WHAT IT ACHIEVED TODAY was desaturating the top third of the 44px side
     gutters and the 38px strip above the card — the paler top Loz is pointing
     at, for no remaining purpose.

     IT IS NOT A SUBTLE CHANGE, which is worth recording: the blobs it
     suppressed are `.ab4` (sky blue) at `top:-22%` and `.ab5` (mint) at
     `top:-20%`, so removing it brings blue and mint into the top corners.
     And the film-grain `::after` sits ABOVE the wash with
     `mix-blend-mode: overlay`, so the grain now reads on colour rather than on
     near-white and the top gains a little texture.

     `background: none` rather than `display: none`: the pseudo-element also
     carries `z-index: 1`, and leaving the box in place keeps the stacking
     order between the blobs and the grain exactly as thermii.css built it.
     No `!important` needed — (0,2,1) against thermii.css's (0,1,1), and this
     file loads later anyway. Inside this file's `@media screen`, so print is
     untouched. */
  body.thermii-skin .thermii-aurora::before {
    background: none;
  }

  /* The 6px brand gradient strip is position:fixed at the top of the viewport, so
     it cuts straight across the top of the rounded container. FLAGGED FOR LOZ:
     this is a brand element, not clutter — it is hidden here because the reference
     has no strip, and it is one line to bring back. */
  body.thermii-skin #thermiiTopBar {
    display: none;
  }

  /* WIDE ON A BIG DESKTOP, and shrinking with the viewport rather than stepping.
     `width: calc(100% - 48px)` keeps a 24px gutter either side at every size, so
     the max-width only bites once there is room for it — no media queries needed
     for the width itself.

     HEIGHT HUGS THE CONTENT. It shipped at min-height:960px (journey.css's
     100dvh), which held the card open to the full viewport however little was in
     it, leaving dead space under the Continue button. The min-heights that did
     that are cleared below. */
  body.thermii-skin .kb-wrapper {
    width: calc(100% - 48px);
    max-width: 1780px;
    min-height: 0;
    margin: 18px auto 16px;
    /* Loz, 2026-08-27: the body of the card is tinted; the header bar and the
       action bars stay white (they already carry their own #fff). The tiles and
       inputs are white cards, so they now read as cards. */
    background: #f7f8fc;
    border-radius: 22px;
    box-shadow: 0 1px 3px rgba(16, 24, 40, 0.06),
                0 12px 40px rgba(16, 24, 40, 0.07);
    /* `overflow: visible` EXPLICITLY, and it has to be explicit — components.css:13
       sets `overflow: hidden` on .kb-wrapper, and merely omitting the declaration
       here leaves that one in force. An ancestor with a non-visible overflow becomes
       the sticky containing block and never scrolls, which silently kills BOTH the
       sticky header and the sticky action bar. The rounded corners are kept by
       giving the header the top radius instead of clipping the whole card. */
    overflow: visible;
    padding: 0;
  }

  /* ── nothing props the container open ───────────────────────────────────── */

  /* These are the four that made it 960px tall regardless of content. They sized
     a layout that had a sidebar beside the shell and a fixed-height stage; with
     the sidebar gone and the card hugging its content they only add dead space.

     CLEARING min-height IS NOT ENOUGH ON ITS OWN — and that was the first
     attempt. Both .kb-wrapper and .thermii-app-grid are flex ITEMS with
     `flex: 1 0 auto`, so they GROW to fill whatever is available regardless of
     any min-height. The app-grid was 780px around 694px of content, and that 87px
     is the empty band under the Continue button. flex-grow has to go to zero as
     well, or the height is set by the viewport rather than the content. */
  body.thermii-skin .thermii-app-grid,
  body.thermii-skin .thermii-main-shell,
  body.thermii-skin .thermii-version-stage,
  body.thermii-skin .thermii-workspace {
    min-height: 0;
  }

  body.thermii-skin .kb-wrapper,
  body.thermii-skin .thermii-app-grid {
    flex: 0 0 auto;
  }

  /* THE BORDER INSIDE THE CONTAINER. .thermii-main-shell carries
     `1px solid #e4e7ef` and a 16px radius — it was a card in its own right when
     it sat next to the sidebar. Now that .kb-wrapper IS the card, it draws a
     second rounded box just inside the first, which is the stray border in the
     corner. */
  body.thermii-skin .thermii-main-shell {
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }

  /* ── THE SIDEBAR GOES ───────────────────────────────────────────────────────

     Hidden, not removed. It carries #thermiiProjectNext and #tav-g0/g1/g2, and
     the DOM contract in verify-parity.py compares index.html's id list against
     baseline/thermii.monolith.html for exact equality — so the nodes must stay in
     the document. The insight content it used to hold is not lost: the panel under
     the tiles is #eTip/#wTip, which is where the guidance text already lived. */
  body.thermii-skin .thermii-sidebar {
    display: none !important;
  }

  /* the grid was two columns for the sidebar; the question column takes it all */
  body.thermii-skin .thermii-app-grid {
    display: block;
    max-width: none;
    padding: 0;
  }

  /* ── The header bar ─────────────────────────────────────────────────────── */

  body.thermii-skin .kb-logo {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 14px 26px;
    margin: 0;
    /* the plain grey hairline is replaced by a 2px brand-gradient line — see
       the ::after below (Loz, 2026-09-21) */
    border-bottom: none;
    background: #fff;
    /* the wrapper cannot clip (sticky needs overflow:visible), so the white
       header must round its own top corners — invisible while the body was
       white too, square white corners over the rounded tint once it wasn't.
       Mirrors the bars' bottom corners; the var goes to 0 on mobile with them. */
    border-top-left-radius: var(--thermii-card-radius, 22px);
    border-top-right-radius: var(--thermii-card-radius, 22px);
    position: sticky;
    top: 0;
    z-index: 40;
    /* the wrapper no longer clips — see the note there */
    border-radius: 22px 22px 0 0;
  }

  /* the brand-gradient line under the header (Loz, 2026-09-21) — echoes the
     logo / CTA bar / selected-tile ring. A pseudo-element rather than a
     gradient border so it doesn't fight the header's rounded top corners; the
     header is sticky (a containing block), so this pins to its bottom edge on
     every screen. Never in the PDF — the header is not cloned. */
  body.thermii-skin .kb-logo::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--thermii-gradient);
    pointer-events: none;
  }

  /* logo LEFT, at a size that reads as chrome rather than as a banner */
  body.thermii-skin .kb-logo-center {
    order: 1;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    margin: 0;
    text-align: left;
  }

  /* the shop they came from, greyed so the Thermii mark stays the one that
     reads. Hidden until a shop sign-in; an email sign-in has no shop. The
     artwork is drawn for a dark header (white lettering), so greying it also
     has to darken it or the words disappear on this white bar. */
  body.thermii-skin .thermii-shop-mark {
    display: inline-flex;
    align-items: center;
    margin-left: 14px;
    padding-left: 14px;
    border-left: 1px solid #d7dbe3;
    height: 37px;
  }
  body.thermii-skin .thermii-shop-mark[hidden] { display: none; }
  body.thermii-skin .thermii-shop-mark img {
    height: 26px;
    width: auto;
    max-width: 148px;
    filter: grayscale(1) brightness(0.55);
  }

  body.thermii-skin .kb-logo-center .kb-logo-screen {
    /* 37px, up from 30 (Loz, 2026-08-27): at 30 the mark sat SHORTER than the
       42px controls beside it and read as one of them rather than the anchor of
       the bar. 37 puts it level-ish with the control row inside the same 79px
       header — nothing else moves. */
    height: 37px;
    width: auto;
    max-width: none;
  }

  /* the progress slot the JS creates, centred and taking the slack */
  body.thermii-skin .thermii-skin-progress-slot {
    order: 2;
    flex: 1 1 auto;
    display: flex;
    justify-content: center;
    min-width: 0;
  }

  body.thermii-skin .thermii-shell-actions {
    order: 3;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
  }

  /* the left .kb-logo-side is now empty but for the mobile logo */
  body.thermii-skin .kb-logo > .kb-logo-side:not(.thermii-shell-actions) {
    display: none;
  }

  /* one visual language for every header control */
  body.thermii-skin .thermii-shell-actions .thermii-shell-restart,
  body.thermii-skin .thermii-shell-actions .kb-return-btn,
  body.thermii-skin .thermii-skin-projects,
  body.thermii-skin .thermii-skin-insights,
  body.thermii-skin .thermii-skin-help {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 38px;
    padding: 0 13px;
    border: 1px solid transparent;
    border-radius: 10px;
    background: transparent;
    color: #3b4157;
    font-family: 'Poppins', sans-serif;
    font-size: 13.5px;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
  }

  /* Rollover is a COLOUR, not a chip (Loz, 2026-08-27, with a screenshot: the
     hover chip's box clipped into the separator lines either side). The label
     and every stroked icon follow via currentColor; #6c4bd8 is the Continue
     purple the rest of the skin already keys on. */
  body.thermii-skin .thermii-shell-actions .thermii-shell-restart:hover,
  body.thermii-skin .thermii-shell-actions .kb-return-btn:hover,
  body.thermii-skin .thermii-skin-projects:hover,
  body.thermii-skin .thermii-skin-insights:hover,
  body.thermii-skin .thermii-skin-help:hover {
    background: transparent;
    border-color: transparent;
    color: #6c4bd8;
    /* full strength: the engine fades exactly these two on hover — thermii.css
       .kb-return-btn:hover at 0.7 and components.css .thermii-shell-restart /
       .kb-return-btn at 0.66 — which washed their purple out next to Help and
       Projects (Loz). Restated here so all four land on the identical colour. */
    opacity: 1;
  }

  /* The Help mark is Loz's own artwork in an <img>, out of currentColor's
     reach, so the purple arrives as a filter. The chain was solved against the
     target, not eyeballed: painting the black source through it and sampling
     the canvas gives the Continue purple within a few RGB points. */
  /* LOZ'S OWN ROLLOVER ART, not a filter approximating it. The purple used to
     be reached with a solved filter chain because there was no purple asset —
     but assets/icons/help-icon-mouseover.svg was in the folder all along,
     invisible to git (see .gitignore's note) and so never noticed. His mark is
     #714dda where the filter landed on #6c4bd8, so the asset is also the more
     correct colour. Swapped by stacking the two images and cross-fading, which
     keeps the layout identical and needs no second <img> in the markup. */
  body.thermii-skin .thermii-skin-help img {
    transition: opacity 0.15s ease;
  }

  /* over the 19px mark (13px in from the edge), not the button's centre,
     now the button also holds a word */
  body.thermii-skin .thermii-skin-help::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 14px;
    width: 17px;
    height: 17px;
    transform: translateY(-50%);
    background: url('../assets/icons/help-icon-b.svg') center / contain
                no-repeat;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
  }

  body.thermii-skin .thermii-skin-help:hover img { opacity: 0; }
  body.thermii-skin .thermii-skin-help:hover::after { opacity: 1; }

  body.thermii-skin .thermii-shell-actions svg {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
  }

  /* The design's labels are heavier and darker than the first pass: semibold
     navy, not medium slate. */
  body.thermii-skin .thermii-shell-actions .thermii-shell-restart,
  body.thermii-skin .thermii-shell-actions .kb-return-btn,
  body.thermii-skin .thermii-skin-projects,
  body.thermii-skin .thermii-skin-help {
    font-weight: 600;
    color: #1b2140;
  }

  /* Projects and Help are PLACEHOLDERS — they must look like part of the
     furniture without pretending to be live, so they keep the hover but take
     the default cursor. */
  body.thermii-skin .thermii-skin-projects[aria-disabled="true"],
  body.thermii-skin .thermii-skin-help[aria-disabled="true"] {
    cursor: default;
  }

  /* HELP CARRIES ITS WORD on desktop (Loz, 2026-09-28), like every other
     control in the row, so it takes their 13px sides; the squarer 10px box it
     had as an icon-only control returns once the word is shed at 1170px, just
     before Insights' and Projects'. Loz's mark is a filled bubble, not a
     stroked outline, so it is an <img> and not a currentColor path. */

  /* INSIGHTS — the reachable switch for the tips panel (js/thermii-skin.js,
     buildHeader). Same weight as Projects; its state is the drawn switch, read
     off aria-pressed, which the button sets from `body.tips-off` — so the knob
     can only ever show what the page is doing. OFF is knob-left in the
     label's own grey; ON slides the knob right and takes the Continue purple
     the rest of the skin keys on. */
  body.thermii-skin .thermii-skin-insights {
    font-weight: 600;
    color: #1b2140;
  }

  /* the shared svg rule below sizes every mark in the bar to 17px; the switch
     is a 22x12 pill and says so at higher specificity */
  body.thermii-skin .thermii-skin-insights .thermii-skin-switch {
    width: 22px;
    height: 12px;
    margin-left: 2px;
  }

  body.thermii-skin .thermii-skin-insights .thermii-skin-switch-knob {
    transition: transform 0.15s ease, fill 0.15s ease;
  }

  body.thermii-skin .thermii-skin-insights[aria-pressed="true"] .thermii-skin-switch-knob {
    transform: translateX(10px);
    fill: #6c4bd8;
  }

  body.thermii-skin .thermii-skin-insights[aria-pressed="true"] .thermii-skin-switch-pill {
    stroke: #6c4bd8;
    fill: #efeaff;
  }

  body.thermii-skin .thermii-skin-help img {
    width: 19px;
    height: 19px;
    display: block;
  }

  /* The separators. One to the LEFT of every item but the first. Help, the
     first, lost its line on 2026-09-28 (Loz): with nothing on its left in the
     row it separated nothing and floated in the space before the group.

     Absolutely positioned rather than a border-left: the controls already carry
     a rounded hover chip, and a real border would read as an edge of THAT chip
     rather than as a rule between two items. Sitting at -3px it splits the
     row's 6px gap. */
  body.thermii-skin .thermii-skin-insights::before,
  body.thermii-skin .thermii-skin-projects::before,
  body.thermii-skin .thermii-shell-actions .thermii-shell-restart::before,
  body.thermii-skin .thermii-shell-actions .kb-return-btn::before,
  body.thermii-skin .thermii-skin-theme::before {
    content: '';
    position: absolute;
    left: -3px;
    top: 50%;
    width: 1px;
    height: 26px;
    transform: translateY(-50%);
    background: #e4e6ef;
    pointer-events: none;
  }

  /* THE ACCOUNT CONTROL (21 October 2026), last in the row: "Sign in" when
     signed out, the customer's first name when in, with a Trade badge when
     the shop said so. Same type and rollover as the controls beside it. */
  body.thermii-skin .thermii-skin-account {
    position: relative;
  }

  body.thermii-skin .thermii-skin-account::before {
    content: '';
    position: absolute;
    left: -3px;
    top: 50%;
    width: 1px;
    height: 26px;
    transform: translateY(-50%);
    background: #e4e6ef;
    pointer-events: none;
  }

  body.thermii-skin .thermii-skin-account-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 38px;
    padding: 0 13px;
    border: 1px solid transparent;
    border-radius: 10px;
    background: transparent;
    color: #202543;
    font-family: 'Poppins', sans-serif;
    font-size: 15px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    transition: opacity .15s ease;
  }

  body.thermii-skin .thermii-skin-account-btn:hover,
  body.thermii-skin .thermii-skin-account-btn[aria-expanded="true"] {
    color: #202543;
    opacity: .82;
  }

  /* signed in reads at a glance even where the name has been shed */
  body.thermii-skin .thermii-skin-account-btn { position: relative; }
  body.thermii-skin .thermii-skin-account.is-signed-in .thermii-skin-account-btn::after {
    content: '';
    position: absolute;
    top: 8px;
    left: 24px;
    width: 8px;
    height: 8px;
    border: 2px solid #fff;
    border-radius: 50%;
    background: #1fa463;
  }

  body.thermii-skin .thermii-skin-account-name {
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  body.thermii-skin .thermii-skin-account-trade {
    padding: 2px 7px;
    border-radius: 50px;
    background: #efeaff;
    color: #6c4bd8;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
  }

  body.thermii-skin .thermii-skin-account-trade[hidden],
  body.thermii-skin .thermii-account-menu[hidden] { display: none; }

  body.thermii-skin .thermii-account-menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 60;
    width: max-content;
    min-width: 268px;
    padding: 4px 22px;
    border: 0;
    border-radius: 14px;
    background: #fff;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .26);
    font-family: 'Poppins', sans-serif;
    text-align: left;
  }

  body.thermii-skin .thermii-account-how {
    margin: 0;
    padding: 14px 2px 6px;
    color: #202543;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
  }

  body.thermii-skin .thermii-account-item {
    display: block;
    width: 100%;
    margin: 0;
    padding: 14px 2px;
    border: 0;
    border-radius: 0;
    background: none;
    color: #202543;
    font: inherit;
    font-size: 15px;
    font-weight: 500;
    line-height: 1;
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
  }

  body.thermii-skin .thermii-account-shop { color: #FF5B00; }

  body.thermii-skin .thermii-account-item:hover { opacity: .82; }

  /* Wins over the 17px the actions row gives every other svg — this one is a
     caret, not an icon. */
  body.thermii-skin .thermii-shell-actions .thermii-skin-caret {
    width: 12px;
    height: 12px;
    opacity: 0.75;
    margin-left: -3px;
  }

  /* the save indicator — a caption under Save & Exit, absent until a save has
     happened. ABSOLUTE on purpose: it contributes no width, so it cannot nudge
     the row when "just now" becomes "12 min ago" (which it did as a sibling).
     The button already has position:relative for its separator. */
  body.thermii-skin .thermii-skin-saved {
    display: none;
    position: absolute;
    top: calc(100% - 3px);
    left: 50%;
    transform: translateX(-50%);
    align-items: center;
    gap: 5px;
    font-family: 'Poppins', sans-serif;
    font-size: 10.5px;
    font-weight: 500;
    /* THE DOT IS GREEN, THE WORDS ARE NOT (2026-08-28). This was the brand
       green — about 2:1 on white, at 10.5px, which is the least readable
       combination in the app. The green now lives entirely on the dot beside
       it, where shape carries the meaning and contrast does not have to. */
    color: #6b7391;
    white-space: nowrap;
    pointer-events: none;
  }

  body.thermii-skin .thermii-skin-saved.is-on {
    display: inline-flex;
  }

  body.thermii-skin .thermii-skin-saved::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #74b700;
    flex-shrink: 0;
  }

  /* the caption has nowhere to hang below the button once the header wraps */
  @media screen and (max-width: 900px) {
    body.thermii-skin .thermii-skin-saved {
      display: none !important;
    }
  }

  /* The light/dark switch. Loz's own artwork (assets/icons/light-toggle.svg and
     dark-toggle.svg, composited — see js/thermii-skin.js), animated here and
     still inert in function.

     The button is a bare frame: the pill, knob and glyphs are all inside the
     SVG, so no background, border or size of its own — that would draw a second
     pill around the drawn one. */
  body.thermii-skin .thermii-skin-theme {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* THE HIT AREA IS 38px TALL WHILE THE ARTWORK STAYS 22.4 (Loz,
       2026-09-03). The drawn pill is only 22.4px high, which is UNDER the
       24x24 CSS px that WCAG 2.2's Target Size (Minimum) asks for at AA — and
       16px shorter than the Home button sitting right beside it, which is
       38x41. Measured, not estimated.

       GROWN WITH min-height RATHER THAN padding, and that is forced by the
       cascade: the welcome-footer / confirm-footer / actionbar variant at
       :1888 sets `padding: 0`, so padding added here is discarded in exactly
       the placement the front door uses. min-height is not reset there, so
       one declaration covers both.

       The ARTWORK IS UNTOUCHED, deliberately. Loz asked whether the toggle
       should be bigger; visually it is fine — it is a wide control, so it does
       not read undersized — and scaling the pill up would give the header a
       chunky switch competing with the logo. This grows only what a finger
       has to find. `align-items: center` already held the art vertically
       centred, so it does not move: in the header the flex row centres it, and
       in the footer the box is centred by translate(-50%, -50%), so growing it
       grows symmetrically about the same point. Verified at both placements.

       It is STILL INERT, which is a separate matter and Loz's call to defer
       (2026-09-03): the click handler toggles only its own class and the
       aria-label says "coming soon". Do not read this size fix as the control
       having been wired up. */
    min-height: 38px;
    box-sizing: border-box;
    margin-left: 6px;
    padding: 0 0 0 10px;
    border: 0;
    background: none;
    cursor: pointer;
    flex-shrink: 0;
    line-height: 0;
  }

  /* 25% LARGER THAN IT SHIPPED (Loz, 2026-09-03, second pass). The first pass
     grew only the hit area to clear the WCAG minimum and left the drawing at
     44 x 22.4 — which was the accessibility fix but NOT what Loz asked for.
     He looked at it and said it still looked the same, correctly: nothing
     visible had changed.

     55 x 28 IS AN EXACT SCALE, not a rounded one. The artwork's viewBox is
     0 0 42.9 21.84, an aspect of 1.964286, and 55/28 is 1.964286 to six
     places — so the pill cannot go subtly oval. 66 x 33.6 (1.5x) is the next
     exact step and was judged too tall for the header, where it would stand
     nearly as tall as the whole 38px Home button beside it.

     SAFE TO SCALE BECAUSE THE KNOB TRAVEL IS IN USER UNITS, which is worth
     knowing before touching this: js/thermii-skin.js:142 sets
     --thermii-knob-travel to 21.06, measured out of the artwork's own
     coordinates, and a CSS length on an SVG child is user units — so the
     slide scales with the viewBox instead of drifting off the drawn knob.
     A px-derived travel would have broken here.

     These CSS lengths WIN over the width/height attributes the JS sets on the
     element (:137), so this is the one place the size lives. */
  body.thermii-skin .thermii-skin-theme svg {
    width: 55px;
    height: 28px;
    overflow: visible;
  }

  /* The slide is the gap between the two files' knob centres, measured out of
     the artwork by tests/build-toggle-art.py and set on the button by the JS.
     A CSS length on an SVG child is user units, so this lands the knob exactly
     where dark-toggle.svg draws it — and follows a re-upload that moves it. */
  body.thermii-skin .thermii-skin-theme .thermii-skin-theme-knob {
    transition: transform 0.24s cubic-bezier(0.4, 0.05, 0.2, 1);
  }

  body.thermii-skin .thermii-skin-theme.is-on .thermii-skin-theme-knob {
    transform: translateX(var(--thermii-knob-travel, 21.06px));
  }

  /* the glyphs cross-fade under the knob: sun in light, moon in dark */
  body.thermii-skin .thermii-skin-theme .thermii-skin-theme-sun,
  body.thermii-skin .thermii-skin-theme .thermii-skin-theme-moon {
    transition: opacity 0.2s ease;
  }

  body.thermii-skin .thermii-skin-theme .thermii-skin-theme-moon { opacity: 0; }
  body.thermii-skin .thermii-skin-theme.is-on .thermii-skin-theme-sun { opacity: 0; }
  body.thermii-skin .thermii-skin-theme.is-on .thermii-skin-theme-moon { opacity: 1; }

  /* the knob slide is the whole point of the control, but it is decoration:
     honour a reduced-motion preference and just swap the states. */
  @media (prefers-reduced-motion: reduce) {
    body.thermii-skin .thermii-skin-theme .thermii-skin-theme-knob,
    body.thermii-skin .thermii-skin-theme .thermii-skin-theme-sun,
    body.thermii-skin .thermii-skin-theme .thermii-skin-theme-moon {
      transition: none;
    }
  }

  /* ── Per-journey pills ────────────────────────────────────────────────────

     The electric journey never visits Heat Source, and its thermostat question
     sits mid-installation so the Controls orb never lights. Hidden while an
     electric screen is showing (navigation.js stamps body[data-thermii-screen]),
     so the visible-pill counter reads a clean 1..7 there and 1..9 on water.
     'electric-kit' and 'electric-summary' match the same prefix, keeping the
     rail steady to the end of the journey. */
  body[data-thermii-screen^="electric"] .thermii-step-heatsource,
  body[data-thermii-screen^="electric"] .thermii-step-floorlevel,
  body[data-thermii-screen^="electric"] .thermii-step-controls {
    display: none !important;
  }

  /* ── The stage header, as the reference's label + pills ──────────────────── */

  /* The engine's own stage header, restyled. #thermiiStageTitle is the step name
     and #thermiiStageKicker is "Step N of M", so the reference's
     "Heat source · Step 3 of 8" needs no new markup and no new state — see the
     note in js/thermii-skin.js. */

  body.thermii-skin .thermii-skin-progress-slot {
    order: 2;
    flex: 1 1 auto;
    display: flex;
    justify-content: center;
    min-width: 0;
  }

  body.thermii-skin .thermii-stage-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    /* capped so the pill row keeps the reference's proportions on a wide screen
       instead of stretching the full width of the header */
    width: 100%;
    max-width: 620px;
    gap: 12px;
    margin: 0;
    padding: 0;
    /* it ships with min-height:126px for the old stacked layout, which made the
       header three times taller than the logo beside it */
    min-height: 0;
    background: transparent;
    border: 0;
    box-shadow: none;
  }

  /* name and count on one line, as the reference has them */
  body.thermii-skin .thermii-stage-summary {
    display: flex;
    align-items: baseline;
    gap: 0;
    margin: 0;
    padding: 0;
    /* NEVER WIDER THAN THE SLOT (review, 2026-09-11). The row is nowrap text
       centred in a slot that shrinks to nothing between the logo and six
       actions (flex 1 1 auto, min-width 0); with no ceiling of its own it
       overflowed both ways and painted across the wordmark and the Home
       button — measured from 901px to ~1146px once Insights joined the row,
       901 to ~1000 before it. Clamped and clipped, the title ellipsises
       instead (the rules on its children below). */
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
  }

  /* DOM order in here is kicker, title, count. The kicker is hidden, so plain
     `row` renders "Rooms · Step 4 of 8" — the reference's order. It was
     row-reverse while the kicker was the visible count; leaving it that way once
     the count moved to the end put the number in front of the name. */
  body.thermii-skin .thermii-stage-summary > div:first-child {
    display: flex;
    align-items: baseline;
    flex-direction: row;
    gap: 7px;
    min-width: 0;
  }

  body.thermii-skin .thermii-stage-title {
    margin: 0;
    font-family: 'Poppins', sans-serif;
    font-size: 15px;
    font-weight: 600;
    color: #1b2140;
    white-space: nowrap;
    /* the title is the half that gives when the slot is short; the count
       stays whole, so a squeezed header reads "Measure… · Step 5 of 9" */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* hidden, not emptied: it counts journey steps where the pills count shell
     stages, so the two disagree. See the note in js/thermii-skin.js. */
  body.thermii-skin .thermii-stage-kicker {
    display: none;
  }

  /* the count derived from the stepper, so label and pills always agree */
  body.thermii-skin .thermii-skin-count {
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    font-weight: 400;
    color: #7b819a;
    white-space: nowrap;
  }

  body.thermii-skin .thermii-skin-count:not(:empty)::before {
    content: '· ';
    color: #c3c7d6;
  }

  /* the thin summary bar is redundant once the pills are the progress */
  body.thermii-skin .thermii-stage-progress {
    display: none;
  }

  /* THE VERTICAL LINE THROUGH THE DESIGN. .thermii-stage-summary::after is a
     1px x 96px rule that divided the summary column from the stepper back when the
     stage header was a two-column grid. Stacked and centred it has nothing left to
     divide, so it just draws a line down the middle of the header. */
  body.thermii-skin .thermii-stage-summary::after,
  body.thermii-skin .thermii-stage-summary::before {
    content: none !important;
    display: none !important;
  }

  /* ── the stepper becomes the pill row ───────────────────────────────────── */

  /* THREE THINGS IN THE BASE STYLING FOUGHT THIS AND ALL THREE HAD TO GO, which is
     why these rules are blunt rather than minimal:

     1. components.css:242 `.thermii-step:not(:last-child)::after` is the CONNECTOR
        LINE between orbs — absolutely positioned, 2px tall, at top:22px. The first
        attempt drew the tick on that same ::after, so it replaced the `content` and
        the colour but inherited the connector's box: a 2px dash under every pill,
        which is exactly the "underscores that are not needed". The connector is now
        switched off outright and the tick is drawn on ::before, which nothing else
        uses (the orb artwork is on .thermii-step-orb::before, a different element).

     2. components.css:447 `.thermii-stepper-wrap{overflow-x:auto}` was CROPPING THE
        TICKS. Per spec an overflow-x of auto forces the computed overflow-y to auto
        as well — `visible` cannot survive on one axis alone — so the wrap clipped
        anything below the pills and showed a scroll edge, which is the vertical
        line through the design. Both axes are now explicitly visible.

     3. components.css:231 / journey.css:168 put a min-width of 610-630px on the
        stepper, sized for eight orbs with labels. Overridden to 0 so the pills size
        themselves and cannot push the header wider than its centre column. */

  /* full width, or flex-grow on the pills has nothing to grow INTO: the stage
     header is a centred column, so the stepper was shrink-to-fit and every pill
     collapsed to its 22px minimum. */
  body.thermii-skin .thermii-stepper-wrap {
    width: 100%;
    margin: 0;
    padding: 0;
    overflow: visible;
    overflow-x: visible;
    overflow-y: visible;
  }

  body.thermii-skin .thermii-stepper {
    display: flex;
    align-items: center;
    /* the capped pills no longer fill the 600px track, so the row must centre
       itself under the centred title instead of hugging its left edge */
    justify-content: center;
    gap: 7px;
    margin: 0;
    padding: 0;
    min-width: 0;
    list-style: none;
  }

  /* EVERY PILL THE SAME WIDTH, WHATEVER ITS STATE. Completing a stage must change
     only the colour and add the tick — never the size.

     min-width and max-width are both explicitly neutralised, and that is the whole
     point of this rule rather than an accident of it. components.css:238 gives
     .thermii-step a min-width of 72px for an orb-and-label stepper; leave any floor
     or cap in place and a pill can be pinned to it while its neighbours take the
     slack, which is exactly how a completed pill ends up a third of the width of
     the one beside it. With `flex: 1 1 0`, no floor and no cap, the eight share the
     row equally and there is no state in which they can diverge. */
  /* EVERY PILL THE SAME WIDTH, WHATEVER ITS STATE. Completing a stage changes the
     colour and adds the tick — never the size.

     min-width and max-width are neutralised on purpose, not by accident.
     components.css:238 gives .thermii-step a min-width of 72px for an
     orb-and-label stepper; leave any floor or cap in place and a pill can be
     pinned to it while its neighbours absorb the slack, which is how one ends up a
     third the width of the next. With `flex: 1 1 0`, no floor and no cap, the eight
     always share the row equally.

     NO !important HERE, and there was for one commit. Two reports of broken
     completed pills were both a STALE STYLESHEET over file:// — the same trap
     build-fixtures.py content-hashes its assets to avoid — not a cascade conflict,
     so the armour was guarding against nothing and its comment claimed a cause
     that was not real. CLAUDE.md prefers avoiding !important here anyway. */
  body.thermii-skin .thermii-stepper .thermii-step {
    position: relative;
    display: block;
    /* 0% not 0. A unitless zero flex-basis in the shorthand is a long-standing
       Safari parsing bug — Safari can drop the whole declaration, leaving the item
       on `flex: 0 1 auto`, which sizes it from content. These <li> have every child
       hidden, so their content width is zero. Costs nothing to write it correctly. */
    flex: 1 1 0%;
    min-width: 0;
    /* Loz, 2026-08-27: with ten stages the pills were 54px each and he wanted
       them SLIMMER rather than the 7px gap closed. The cap only binds downward —
       on a narrow screen the zero flex-basis still lets them shrink to fit. */
    max-width: 44px;
    width: auto;
    height: 7px;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: #e3e6ef;
    text-align: left;
    color: transparent;
    transition: background 0.2s ease;
  }

  /* the orb artwork, its number badge and the per-step label all go: the name is
     carried once, in the line above, not eight times under eight orbs */
  body.thermii-skin .thermii-stepper .thermii-step-orb,
  body.thermii-skin .thermii-stepper .thermii-step-number,
  body.thermii-skin .thermii-stepper .thermii-step-label {
    display: none !important;
  }

  /* the connector line, off — see note 1 above */
  body.thermii-skin .thermii-stepper .thermii-step::after,
  body.thermii-skin .thermii-stepper .thermii-step:not(:last-child)::after,
  body.thermii-skin .thermii-stepper .thermii-step.is-complete:not(:last-child)::after {
    content: none !important;
    display: none !important;
  }

  /* navigation.js:144 maintains .is-complete and .is-active/aria-current, so the
     states need no JavaScript of their own */
  /* COLOUR ONLY. Nothing in a state rule may set width, min-width, max-width,
     flex, padding or transform, or the pills stop matching each other. */
  body.thermii-skin .thermii-stepper .thermii-step.is-complete {
    background: #74b700;
  }

  /* The tick, on ::before so the connector's box cannot leak into it. Drawn from
     two borders rather than set as a ✓ glyph, for the reason journey.css already
     gives at its own badge: at this size a glyph's weight and baseline shift with
     the font, while a drawn tick stays crisp. */
  body.thermii-skin .thermii-stepper .thermii-step.is-complete::before {
    content: '';
    position: absolute;
    top: 13px;
    left: 50%;
    width: 5px;
    height: 9px;
    border: solid #74b700;
    border-width: 0 2px 2px 0;
    transform: translateX(-50%) rotate(45deg);
  }

  body.thermii-skin .thermii-stepper .thermii-step.is-active,
  body.thermii-skin .thermii-stepper .thermii-step[aria-current="step"] {
    background: #5b3ce0;
  }

  /* complete AND current at once: done wins, so a finished stage never shows as
     in-progress. Ordered after both, so it does not depend on source order. */
  body.thermii-skin .thermii-stepper .thermii-step.is-complete.is-active,
  body.thermii-skin .thermii-stepper .thermii-step.is-complete[aria-current="step"] {
    background: #74b700;
  }

  /* the pills need room for the tick that now hangs below them */
  body.thermii-skin .thermii-stage-header {
    padding-bottom: 12px;
  }

  /* ── the old journey track ───────────────────────────────────────────────── */

  /* THE BAR STAYS, ONLY ITS TRACK GOES — and hiding the whole bar was a bug.
     #eqProgressBar / #wqProgressBar contain THREE things: the track (replaced by
     the header pills), a Restart button (duplicated in the header), and the
     JOURNEY'S BACK BUTTON. Hiding the bar wholesale took Back with it and left no
     way back through the journey.

     Hidden BY ID rather than by .eq-progress, because #kitNav and #wKitNav share
     that class and are kit navigation which must keep working. The bars stay in
     the DOM and stay where they are — wUpdateProgress writes their aria through
     `#waterPanel .eq-progress-track`, so relocating them breaks the engine. */
  /* Once js/thermii-skin.js has lifted Back into the step's action bar these
     bars hold nothing the skin shows, so they go back to hidden — but ONLY under
     `.thermii-skin-has-actionbar`, which the JS sets after Back has actually been
     relocated. If that ever fails, the bar stays visible with Back in it rather
     than the journey losing its only way back, which is the bug this replaced. */
  body.thermii-skin.thermii-skin-has-actionbar #eqProgressBar,
  body.thermii-skin.thermii-skin-has-actionbar #wqProgressBar {
    display: none !important;
  }

  body.thermii-skin #eqProgressBar,
  body.thermii-skin #wqProgressBar {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    max-width: 1280px;
    margin: 0 auto;
    padding: 16px 40px 0;
    background: transparent;
    border: 0;
    box-shadow: none;
  }

  /* the track is now the header pills, and Restart is in the header */
  body.thermii-skin #eqProgressBar .eq-progress-center,
  body.thermii-skin #wqProgressBar .eq-progress-center,
  body.thermii-skin #eqProgressBar .eq-restart-btn,
  body.thermii-skin #wqProgressBar .eq-restart-btn {
    display: none;
  }

  /* BACK, REDRAWN AS CONTINUE'S TWIN (Loz, 2026-08-28: too much air right of
     the word, and the design wanted improving).

     Three things were wrong at once. journey.css:317 gives the button
     min-width:116px while its content runs ~90px, and inline-flex packs the
     content to the start — so all the slack landed to the RIGHT of "Back",
     which is the lopsided gap in Loz's screenshot. The icon was the old
     engine's 32px filled navy disc, a heavier language than anything else in
     the skin (whose chevrons are all drawn strokes). And it stood 48px tall
     beside a 54px Continue, so the bar's two ends did not match.

     Now: content-sized (no min-width), Continue's 54px height and 13px
     radius, the disc hidden and a stroked chevron drawn in its place — the
     same drawing the carousel arrows and drawer caret use. The engine's SVG
     and span are untouched in the markup; this is presentation only.

     The chevron is a pseudo-element deliberately: thermii.css's compact mode
     hides the button's TEXT on small screens, and had the icon been the
     hidden svg too the button would have gone empty — the drawn chevron
     survives both. */
  body.thermii-skin .eq-back-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-width: 0;
    min-height: 54px;
    height: auto;
    padding: 0 24px 0 20px;
    border: 1.5px solid #dfe3ee;
    border-radius: 13px;
    background: #fff;
    color: var(--thermii-navy, #101735);
    font-family: 'Poppins', sans-serif;
    font-size: 15px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease,
                box-shadow 0.15s ease;
  }

  body.thermii-skin .eq-back-btn svg { display: none; }

  body.thermii-skin .eq-back-btn::before {
    content: '';
    width: 9px;
    height: 9px;
    flex: none;
    border-left: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    border-radius: 0.5px;
    transform: rotate(45deg);
    transition: transform 0.15s ease;
    opacity: 0.75;
  }

  body.thermii-skin .eq-back-btn:hover::before {
    transform: rotate(45deg) translate(2px, -2px);
    opacity: 1;
  }

  body.thermii-skin .eq-back-btn:hover {
    background: #f8faff;
    border-color: #b9aef2;
    box-shadow: 0 6px 16px rgba(27, 36, 74, 0.07);
    border-color: #d7dae7;
  }

  body.thermii-skin .eq-back-btn svg {
    width: 20px;
    height: 20px;
  }

  /* ── The question card ──────────────────────────────────────────────────── */

  /* Content widens with the container but stays a readable column rather than
     stretching to 1780px — the question headings would run half a metre wide. */
  body.thermii-skin .kb-card,
  body.thermii-skin .kb-card.filter-card {
    background: transparent;
    border: 0;
    box-shadow: none;
    border-radius: 0;
    padding: 34px 40px 40px;
    max-width: 1280px;
    min-height: 0;
    margin: 0 auto;
  }

  /* THE `margin: 0 auto` ABOVE LOSES on the journey panels and the System card:
     journey.css pins `#waterPanel > .filter-card` (and electric) with `margin: 0`
     and thermii-system.css pins #systemTypeCard, both behind ID selectors that
     out-rank a class rule. Below ~1440 viewport the 1280px cap never binds so it
     looked identical either way; on a wider window the card stopped growing,
     stayed LEFT-PINNED, and took the action bar's right edge with it — Loz saw
     the bar's line stop 426px short of the card edge at 2000px. The Version
     screen has no such cap, which is why it alone stayed edge to edge.

     Restated at ID strength. Centring rather than uncapping is deliberate: the
     cap is what keeps the reading column sane on a 1780px container, and a
     centred 1280 puts the question column at the same x the Version screen's
     centred body already uses, so the title sits in ONE place across every
     screen at every width. The bar still reaches both container edges because
     its bleed is measured from the wrapper, not from the card. */
  body.thermii-skin #waterPanel > .filter-card,
  body.thermii-skin #electricPanel > .filter-card,
  body.thermii-skin #unsurePanel > .filter-card,
  body.thermii-skin #systemTypeCard.kb-card {
    margin-left: auto;
    margin-right: auto;
  }

  /* ── ONE ALIGNMENT FOR EVERY QUESTION SCREEN ──────────────────────────────

     REWRITTEN 2026-08-27. The first version of this block centred every capped
     block independently — title, subtext, tile row, input row — by giving them
     all `margin: 0 auto`. That was wrong twice over, and both faults are the
     ones Loz reported.

     1. .eq-question-full is a FLEX ITEM (its parent .eq-section became a flex
        column so the action bar could take `margin-top: auto`). Auto side
        margins on a flex item make the item SHRINK TO FIT. So the column stopped
        being a column: its width became the max-content of whatever the widest
        row happened to be, and the title moved with it. Measured titles: 136 on
        pipe spacing, 251 on heat source, 272 on build year, 304 on rooms, 326 on
        floor level, 336 on install method. Every one a different screen position.

     2. The same shrink-to-fit starved the tile grids. `repeat(3, minmax(0, 1fr))`
        inside a shrink-to-fit parent sizes its tracks to CONTENT, not to the
        1040px cap css/thermii-system.css had already set for them — which is why
        the install-method tiles sat at 203px inside a row entitled to 1040, and
        the room tiles at 130px. The caps were right all along.

     The fix is the order: FILL first (`width: 100%`), then cap, then centre. And
     inside that column the authored left-range is restored, so the title, the
     rows and the number fields share one left edge on every screen — which is
     what fixes the floor-area and manifold fields Loz saw hanging off the text.

     1040px stays the canonical column: .eq-question-full, #systemTypeRow and
     --journey-content-max all already use it. */
  /* +20px because this box carries 10px of its own horizontal padding
     (components.css:293) where .eq-question-full carries none, and max-width
     caps the BORDER box. Capped at a flat 1040 its content measured 1020 and the
     Version headline sat 10px right of every other screen's. The padding stays —
     it is what keeps the cards off the edge below 900px, where the cap does not
     bind anyway. */
  body.thermii-skin .thermii-version-body {
    width: 100%;
    max-width: calc(1040px + 20px);
    margin-left: auto;
    margin-right: auto;
  }

  /* THE COLUMN. width:100% before max-width is the whole point — see fault 1.

     The four area steps are ID-scoped in BOTH journey.css (which centred a 680px
     column) and css/thermii-system.css:1143 (which left-ranged it, correct while
     the convention was left-ranged). Neither can be reached from a class, so they
     are named here: they take the shared 1040 column like everything else, and
     the 680 the comment there worries about is carried by .eq-input-row and
     .eq-input-wrap themselves — the fields stay 440px (--journey-field-max). */
  body.thermii-skin #wq-step-4b .eq-question-full,
  body.thermii-skin #wq-step-4bb .eq-question-full,
  body.thermii-skin #eq-q4 .eq-question-full,
  body.thermii-skin #eq-q5 .eq-question-full,
  body.thermii-skin .eq-question-full,
  body.thermii-skin #systemTypeCard > .kb-section-title,
  body.thermii-skin #systemTypeCard > .eq-subtext,
  body.thermii-skin #systemTypeRow {
    width: 100%;
    max-width: 1040px;
    margin-left: auto;
    margin-right: auto;
  }

  /* INSIDE the column, left-ranged — the convention the journey was authored
     with. Their own max-widths are untouched, so a 680px field stays 680px; it
     just starts where the headline starts instead of centring on its own. */
  body.thermii-skin .eq-title,
  body.thermii-skin .eq-question-full .eq-subtext,
  body.thermii-skin .electric-covering-row,
  body.thermii-skin .thermostat-row,
  body.thermii-skin .thermii-version-options,
  body.thermii-skin .eq-input-row,
  body.thermii-skin .eq-help-link,
  body.thermii-skin .eq-note,
  body.thermii-skin .wq-unheated-title {
    margin-left: 0;
    margin-right: auto;
  }

  /* thermii.css:991 centres every .eq-note; journey.css:1202 already re-ranges
     the two measurement screens' notes but nothing covered the insulation
     screen's, which also carried an inline nowrap (stripped — inline styles are
     outside the DOM contract) that held it centred across the full column. One
     rule for all question-column notes instead of a third per-screen patch. */
  body.thermii-skin .eq-question-full .eq-note {
    text-align: left;
  }

  /* ── The System screen keeps step 3's vertical rhythm ─────────────────────

     Loz, 2026-08-27: its subtext and tiles sat looser than every later screen.
     Measured against Heat Source (step 3): title-to-subtext 31px and
     subtext-to-tiles 32px there, 42px and 70px here — a fatter title margin
     plus 38px of top margin on the tile row. Both brought to the step-3
     figures; the subtext's own margins already match, so only these two
     numbers differed. */
  body.thermii-skin #systemTypeCard > .kb-section-title {
    margin-bottom: 20px;
  }

  body.thermii-skin #systemTypeRow {
    margin-top: 0;
  }

  /* ── TILE ROWS THAT FILL THE COLUMN ───────────────────────────────────────

     Loz's list, 2026-08-27, with the heat-source screen as the reference for
     "wide/square" (2 tiles in an 820px row = 397 each, deliberately capped
     there — see css/thermii-system.css:812 — and left alone).

     The System and build-year rows were laid out as content-sized tracks, so
     they kept their tiles at 236 and 220 no matter how much room the row had.
     Three even columns puts both at ~337, next to heat source's 397. Rooms and
     install method need nothing but the fix above: their grids fill now.

     The era row is matched by CLASS, not by step: the electric journey asks the
     same question at #eq-step-0 with the same .thermii-era-row, and it drifted
     to 310 for the same reason. Thermostat rows are deliberately NOT here —
     their widths are read back by wTstatCarouselScroll (legacy-core.js:3085),
     so #wq-step-4e and #eq-step-6 keep their own inset. */
  /* The "Before 1980" hint wraps as three lines against journey.css's 190px
     copy cap while its neighbours take two, and Loz wants all three tiles level.
     The string cannot carry a <br> — it is set via textContent and shared with
     the kit screen's pill — so the width is the lever. 220px fits
     "Solid or unfilled cavity walls," on the first line; measured against the
     middle tile too, whose "Filled cavity walls, double glazing" must NOT gain
     enough room to collapse onto one line. */
  body.thermii-skin .thermii-era-row .thermii-option-copy {
    max-width: 220px;
  }

  /* THE ERA ICONS ARE BIGGER, at Loz's request. His 2026-08-27 re-cut puts the
     era INSIDE the house — a 24-unit box where the digits are about 4 of those
     units, so at the 38px every .electric-covering-row tile gets
     (css/thermii.css:2065, byte-locked) "80-95" came out around 7px tall and
     unreadable. 88px puts it near 15px.

     Outside the desktop media block on purpose: the digits are no more readable
     at 7px on a phone, and the tiles are full-width there anyway. Both journeys,
     via the era class. */
  body.thermii-skin .thermii-era-row .fo-icon,
  body.thermii-skin .thermii-era-row .fo-icon img {
    width: 88px;
    height: 88px;
  }

  @media screen and (min-width: 901px) {
    body.thermii-skin #systemTypeRow,
    body.thermii-skin .thermii-era-row {
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    /* Pipe spacing's short form. Four 108px tiles in a flex row that centres
       them, so once the row was anchored to the column they huddled 280px in
       from the headline. Its own sibling screen (#wq-step-4ps) asks the same
       question with 248px tiles; four even columns brings them together. */
    body.thermii-skin #wq-step-2b .electric-covering-row {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    /* Floor level: five options on ONE line, as asked. Three-up left two of
       them alone on a second row. Five columns of the shared 1040 is 200 a
       tile against a 235px min-height, so they stay square-ish. Beats
       css/thermii-system.css:1866 on specificity and on source order. */
    body.thermii-skin #wq-step-4flr .electric-covering-row {
      grid-template-columns: repeat(5, minmax(0, 1fr));
    }
  }

  /* ── The thermostat carousel, on the tint ─────────────────────────────────

     Loz, 2026-08-27, two things. The "clipping white background" is the
     viewport's scroll-fade gradients (journey.css:1385): they fade to WHITE
     because they predate the tinted card body, so on #f7f8fc they render as
     white patches around the cards. Same trick, tint-coloured — the fades
     become invisible again, which was always their job.

     And the arrows: they were remote grey <img> icons in a borderless disc.
     Clearer, not relocated — dots were considered and rejected because the row
     is continuous snap-scroll, not pages, so dots would promise pagination it
     does not have. The chevron is DRAWN in the Continue purple (no remote
     asset, no filter), the disc gets a border and a deeper shadow, and hover
     inverts to a filled purple disc. The dimmed-at-the-ends behaviour is
     js/thermii-tstat-carousel.js's and is untouched. */
  body.thermii-skin #wTstatViewport.tstat-carousel-viewport,
  body.thermii-skin #electricPanel .tstat-carousel-viewport {
    background:
      linear-gradient(to right, #f7f8fc 30%, rgba(247, 248, 252, 0)) left center / 44px 100% no-repeat local,
      linear-gradient(to left, #f7f8fc 30%, rgba(247, 248, 252, 0)) right center / 44px 100% no-repeat local,
      linear-gradient(to right, rgba(16, 24, 40, 0.10), rgba(16, 24, 40, 0)) left center / 26px 100% no-repeat scroll,
      linear-gradient(to left, rgba(16, 24, 40, 0.10), rgba(16, 24, 40, 0)) right center / 26px 100% no-repeat scroll;
  }

  /* the Wireless badge sat top-right (thermii.css:1316, byte-locked), exactly
     under the selection ring and tick — selected wireless cards read
     "Wire[✓]s". Top-left, where nothing else lives (Loz, 2026-08-27). */
  body.thermii-skin .tstat-wireless-badge {
    right: auto;
    left: 8px;
  }

  body.thermii-skin .tstat-carousel-arrow {
    width: 48px;
    height: 48px;
    background: #fff;
    border: 1px solid #e4e6ef;
    box-shadow: 0 4px 14px rgba(16, 24, 40, 0.14);
  }

  body.thermii-skin .tstat-carousel-arrow img {
    display: none;
  }

  body.thermii-skin .tstat-carousel-arrow::before {
    content: '';
    display: block;
    width: 11px;
    height: 11px;
    border: solid #6c4bd8;
    border-width: 0 2.5px 2.5px 0;
  }

  body.thermii-skin .tstat-carousel-arrow-left::before {
    transform: rotate(135deg);
    margin-left: 5px;
  }

  body.thermii-skin .tstat-carousel-arrow-right::before {
    transform: rotate(-45deg);
    margin-right: 5px;
  }

  body.thermii-skin .tstat-carousel-arrow:hover {
    background: #6c4bd8;
    border-color: #6c4bd8;
  }

  body.thermii-skin .tstat-carousel-arrow:hover::before {
    border-color: #fff;
  }

  /* a dimmed arrow must not keep the filled hover look while fading out */
  body.thermii-skin .tstat-carousel-arrow:disabled,
  body.thermii-skin .tstat-carousel-arrow:disabled:hover {
    background: #fff;
    border-color: #e4e6ef;
  }

  body.thermii-skin .tstat-carousel-arrow:disabled:hover::before {
    border-color: #6c4bd8;
  }

  /* ── The thermostat screen's tail: Continue purple + a compact sensor card ──

     Loz, 2026-08-27, two asks. The "Next" after choosing a thermostat wears the
     BRAND gradient from thermii-system.css:948's nine-button restyle; every
     other advance is the flat Continue purple, so these two (water's
     #wNeoHubConfirm, electric's #eqTstatContinue — the wrapper-gated pair that
     cannot move into the action bar) take that purple here. Their labels are
     relabelled to "Continue ›" in js/thermii-skin.js; the engine never writes
     their text and the fixture runner reaches them by id, both checked. */
  body.thermii-skin #wNeoHubConfirm > button,
  body.thermii-skin #eqTstatContinue > button {
    background: linear-gradient(135deg, #7b4ee0 0%, #6c4bd8 55%, #8b5cf6 100%);
    box-shadow: 0 2px 10px rgba(108, 75, 216, 0.32);
    border-radius: 13px;
  }

  body.thermii-skin #wNeoHubConfirm > button:hover,
  body.thermii-skin #eqTstatContinue > button:hover {
    filter: brightness(1.06);
    box-shadow: 0 4px 16px rgba(108, 75, 216, 0.40);
  }

  /* The floor-sensor upsell was a tall centred stack — 160px image over stacked
     name / price / pill — pushing the insight panel down against the action bar.
     Compact horizontal row instead: image left, name and price beside it, the
     add pill on the right. Scoped to the floor-sensor extras so the electric
     journey's neoHub chooser cards keep their own layout. The wrapper's old
     inline margins live here now (index.html keeps only display:none, the one
     property the engine writes). */
  body.thermii-skin #wFloorSensorExtras {
    margin-top: 24px;
    padding-top: 22px;
    border-top: 1px solid #ecedf3;
    width: 100%;
  }

  /* SLIM, FULL-WIDTH ROWS (Loz, 2026-09-23). First pass shrank the tall 96x68
     image AND capped the card at 560px left-aligned — but a narrow box floating
     under the full-width thermostat tiles read as orphaned and crammed the
     neoHub name onto four lines. So the card keeps the compact thumbnail and
     tight padding (the height win Loz wanted) but spans the FULL width, aligned
     with the thermostat tiles above and giving the long name room. The base
     rule's 700px cap and auto-centring are both cleared.

     ALIGNED WITH THE THERMOSTAT CARDS (Loz, 2026-09-24: "too long"). The
     1120px first used here is thermii.css's viewport cap, but journey.css
     overrides the viewport to max-width 970px with 10px padding, so the cards
     themselves sit in a 950px centred band. The panels AND their question
     lines take that same band, so the left edge of "Would you like to add…"
     and of both panels lands on the first card's left edge. */
  body.thermii-skin #wFloorSensorExtras .neohub-card-wrap,
  body.thermii-skin .neohub-section .neohub-card-wrap,
  body.thermii-skin #wFloorSensorExtras .neohub-question,
  body.thermii-skin .neohub-section .neohub-question {
    width: calc(100% - 20px);       /* the viewport's own 10px inset, */
    max-width: 950px;               /* so it holds below 970px too    */
    margin-left: auto;
    margin-right: auto;
  }

  body.thermii-skin #wFloorSensorExtras .neohub-card,
  body.thermii-skin .neohub-section .neohub-card {
    flex-direction: row;
    align-items: center;
    gap: 14px;
    padding: 10px 14px;
    text-align: left;
  }

  body.thermii-skin #wFloorSensorExtras .neohub-card img,
  body.thermii-skin .neohub-section .neohub-card img {
    width: 64px;
    height: 46px;
  }

  body.thermii-skin #wFloorSensorExtras .neohub-card-body,
  body.thermii-skin .neohub-section .neohub-card-body {
    display: flex;
    align-items: center;
    gap: 16px;
    flex: 1 1 auto;
    text-align: left;
  }

  body.thermii-skin #wFloorSensorExtras .neohub-name,
  body.thermii-skin .neohub-section .neohub-name {
    margin-bottom: 0;
    /* the neoHub's name is long and the engine sets it nowrap — in a row it
       must wrap or it shoves the price and pill out of the card */
    white-space: normal;
    flex: 1 1 auto;
    /* smaller product title (Loz, 2026-09-23), down from the base 18px */
    font-size: 15px;
    /* ── LIGHTER, AND THE WEIGHT HE SAW WAS A STATE (Loz, 2026-09-09) ──────
       "Reduce the weight of the product titles on the Floor Sensor and NeoHub
       panels."

       THE BASE IS ALREADY 400 (css/thermii.css:1470); what he was looking at
       is `.neohub-card.is-added .neohub-name { font-weight: 600 }` (:1478) —
       both cards are "Added" in his screenshot, so both titles were bolded BY
       THE ADDED STATE. Reading the base rule alone would have said there was
       nothing to reduce.

       SO THE STATE BUMP IS WHAT GOES, and the title now reads 400 whether the
       card is added or not. The added state is not left unmarked: the card
       turns green, its border goes green and the button reads "Added ✓" — three
       signals without a fourth. That is also why 400 rather than 500: the bump
       existed to shout, and the shout is elsewhere.

       BOTH SELECTORS ARE NEEDED and both win. `#wFloorSensorExtras ...` is
       (1,2,0) against the locked rule's (0,3,0), so the id carries it; the
       `.neohub-section` half ties at (0,3,0) and wins on source order, this
       file loading after css/thermii.css. */
    font-weight: 400;
  }

  body.thermii-skin .neohub-section .neohub-price {
    white-space: nowrap;
  }

  body.thermii-skin .neohub-price {
    font-size: 17px;
    font-weight: 600;
    color: #af2318;
    margin: 0;
  }

  /* the pill anchors the row's right edge, where an action reads naturally.
     margin-top:0 clears the base rule's 8px (a leftover from the old vertical
     card) that was pushing the pill low — it now sits vertically centred in the
     row (Loz, 2026-09-23: "center the Add to my Kit pill"). */
  body.thermii-skin #wFloorSensorExtras .neohub-add-btn,
  body.thermii-skin .neohub-section .neohub-add-btn {
    margin-left: auto;
    margin-top: 0;
    flex: 0 0 auto;
  }

  /* Left-aligned, and EXACTLY the .thermostat-name size and weight (Loz,
     2026-09-23): var(--t-h4) / 500, matching the thermostat product titles.
     Was 20px centred; ranged left so it sits above the panel below. The base
     centres via flex, so both text-align and justify-content flip. */
  body.thermii-skin #wFloorSensorExtras .neohub-question,
  body.thermii-skin .neohub-section .neohub-question {
    margin-bottom: 14px;
    font-size: var(--t-h4);
    font-weight: 500;
    text-align: left;
    justify-content: flex-start;
  }

  /* ── ONE GREEN ON SELECTED TILES ──────────────────────────────────────────

     The vars cover most of the app, but thermii.css (byte-locked) hard-codes a
     DIFFERENT green, #70af21, on a selected tile's label, its stroke/fill icon
     parts, the recommended badge, and the pipe-spacing screen's persistent
     recommendation — plus an icon filter chain that lands near it. All
     restated at the brand green. The filter chain was SOLVED, not eyeballed:
     black source painted through it samples rgb(136,199,57) against the
     target's rgb(140,198,63). */
  body.thermii-skin .filter-option.is-selected .fo-label,
  body.thermii-skin .filter-option.is-recommended[data-group="wRoomPipeSpacing"] .fo-label {
    color: #74b700;
  }

  /* THE BADGE IS A CHIP NOW, NOT A GREEN WORD (2026-08-28). "RECOMMENDED" in
     brand green at 11px was the app's faintest piece of real information —
     roughly 2:1 on white, and unlike a tick it has no shape to fall back on.
     The green moves to the border and fill, where it still reads as the
     recommendation's colour, and the word itself takes navy ink. Same brand,
     same meaning, legible. */
  body.thermii-skin .fo-rec-badge {
    display: none;
    align-items: center;
    justify-content: center;
    align-self: center;
    /* GAP, because the tick is now a drawn ::before, not a text "✓ " (Loz,
       2026-09-18: "not centred in the pill"). It measured dead-centre in
       Chromium, so the off-centre he saw was Safari rendering the ✓ FONT glyph
       with its own side-bearing; a drawn tick has identical metrics in every
       browser, so the word now centres the same everywhere. */
    /* ROOMIER (Loz, 2026-09-18): more space between the tick and the word, and
       a deeper pill to sit it in — 8px gap (was 5), 6px/18px padding (was
       3/10). The pill hugs its content, so this extends both its height and its
       width to accommodate. */
    gap: 8px;
    padding: 6px 18px;
    border: 1px solid #74b700;
    border-radius: 999px;
    background: #f4fbe8;
    /* GREEN, not the navy this had (Loz, 2026-09-18: "the black is too heavy —
       maybe green text and green tick"). This restores what byte-locked
       thermii.css:618 always intended (#70af21); #3b6d11 is a darker leaf green
       so it clears AA on the pale-green pill, and the tick inherits it. */
    color: #3b6d11;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.04em;
  }

  /* The tick, drawn — a rotated two-sided border in the badge's own colour.
     No font glyph, so it cannot pick up a per-browser side-bearing, and it
     inherits the green from `color`. */
  body.thermii-skin .fo-rec-badge::before {
    content: "";
    flex: 0 0 auto;
    width: 5px;
    height: 9px;
    border: solid currentColor;
    border-width: 0 1.5px 1.5px 0;
    transform: translateY(-1px) rotate(45deg);
  }

  body.thermii-skin .filter-option.is-recommended .fo-rec-badge {
    display: inline-flex;
  }

  /* ── The remaining green words take ink, the green keeps the marks ────────

     Two more from the same audit, both in byte-locked css/thermii.css and so
     restated here. The phone button is the worse of the pair: a number
     someone is meant to read off the screen and dial, set in the brand green
     on white. Its border already carries the colour, so the text does not
     need to.

     SUPERSEDED 2026-09-02: the text was navy for the reason above; Loz asked
     for this button to take the popups' colours on the "help me choose" screen
     as well as in the Help dialog, so it is now purple ink on a purple border.
     The original finding still holds — the green text was the problem — this
     just answers it with the brand purple instead of navy. */
  body.thermii-skin .unsure-phone-btn {
    border-color: var(--thermii-purple, #7138ed);
    color: #6c4bd8;
  }

  /* "Added" beside the add-on toggle: the tick that appears next to it is the
     state, so the word can be read rather than decoded. */
  body.thermii-skin .neohub-card.is-added + .neohub-toggle #neohubLabel,
  body.thermii-skin .neohub-card.is-added + .neohub-toggle .neohub-label {
    color: var(--thermii-navy, #101735);
  }

  body.thermii-skin .filter-option.is-selected .fo-icon .stroke-icon { stroke: #74b700; }
  body.thermii-skin .filter-option.is-selected .fo-icon .fill-icon { fill: #74b700; }

  body.thermii-skin .filter-option.is-selected .fo-icon img,
  body.thermii-skin .filter-option.is-recommended[data-group="wRoomPipeSpacing"] .fo-icon img {
    filter: brightness(0) saturate(100%) invert(55%) sepia(65%) saturate(400%)
            hue-rotate(45deg) brightness(110%);
  }

  /* ── NO GRADIENT SQUARE ON THE ICON DURING THE CLICK FLASH ────────────────

     Loz, 2026-08-27, reproduced with a real pointer: clicking a tile flashed a
     square gradient patch over the icon, distinct from the whole-tile flash he
     wants kept. The patch is the HOVER rollover — thermii-system.css:93 paints
     the brand gradient across the icon's whole box (`inset: 0`) and relies on
     `mix-blend-mode: lighten` to show it only where the blackened icon has ink.
     On the tile's normal white that works; the instant the click adds
     `.fo-flash`, the confirm animation tints the tile and its transform starts
     a new stacking context, the blend composites against different backdrop,
     and the overlay renders as the raw square for the length of the flash.

     Suppressed for exactly the flash's duration, keyed on the engine's own
     class. Same specificity as the hover rule, later sheet, so it wins; hover
     comes straight back when fo-flash is removed on animationend. */
  body.thermii-skin .filter-option.fo-flash .fo-icon::after {
    content: none;
  }

  /* ── ONE TILE RADIUS ──────────────────────────────────────────────────────

     Authored as 17 / 16 / 14 / 14 across the four tile families, which is drift
     rather than intent. 14px is both the majority and what the newest screens
     use, so the older two come to it. Borders needed nothing: all four are already
     1px, and #e4e7ef against #dfe4ee is not a difference the eye can find. */
  body.thermii-skin .thermii-version-card,
  body.thermii-skin #systemTypeRow .system-option,
  body.thermii-skin .system-option {
    border-radius: 14px;
  }

  /* ── "Your project so far" strip ───────────────────────────────────────────

     Built by js/thermii-project-strip.js and shown ONLY once a room is banked
     — see that file's header for why. It sits inside the white header rail as
     its last row, so it reads as an extension of the header rather than a
     third band, and it takes the same centred 1040 column as everything else.
     The chip row scrolls horizontally on its own when a project runs to many
     rooms: the strip must never widen the card or wrap into a second line. */
  /* A PALE-LILAC TRAY (Loz, 2026-09-23). Was white-on-white under the white
     header rail, so it disappeared into it and read as an afterthought. A soft
     lilac ground (and lilac hairlines to match) gives it its own "this is your
     running project" band; the white chips now pop against it. */
  body.thermii-skin .thermii-project-strip {
    display: flex;
    align-items: center;
    gap: 14px;
    /* the rail's own 26px gutter plus the bar inset, so the chips start on
       the same left edge as every question title */
    padding: 9px 26px 10px;
    background: #f5f3fc;
    border-top: 1px solid #e7e4f3;
    border-bottom: 1px solid #e7e4f3;
  }

  body.thermii-skin .thermii-project-label {
    flex: 0 0 auto;
    /* the brand purple, tying the label to the lilac tint (was flat grey) */
    color: #6c4bd8;
    font-family: 'Poppins', sans-serif;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
  }

  /* A horizontal scroller CLIPS VERTICALLY TOO — overflow-x:auto forces the
     y-axis out of `visible` — so the chips' hover lift and drop shadow were
     sheared off at the box edge (Loz's screenshot). The padding buys the
     clipped box room for both, and the matching negative margins hand the
     space back so nothing on the strip moves. */
  body.thermii-skin .thermii-project-chips {
    display: flex;
    flex: 1 1 auto;
    gap: 8px;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 6px 4px 16px;
    margin: -6px -4px -16px;
  }

  body.thermii-skin .thermii-project-chips::-webkit-scrollbar {
    display: none;
  }

  body.thermii-skin .thermii-project-chip {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: baseline;
    gap: 6px;
    padding: 5px 12px;
    border: 1px solid #e4e6ef;
    border-radius: 999px;
    background: #fff;
    font-family: 'Poppins', sans-serif;
    font-size: 12.5px;
    white-space: nowrap;
  }

  /* Banked chips are BUTTONS (they re-open the room), so they need the button
     reset the span never did — and an affordance that says so without turning
     a quiet status strip into a row of controls: the lift and the purple edge
     arrive on hover, not at rest. */
  body.thermii-skin button.thermii-project-chip {
    font: inherit;
    line-height: inherit;
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease,
                transform 0.15s ease;
  }

  body.thermii-skin button.thermii-project-chip:hover {
    border-color: rgba(108, 75, 216, 0.45);
    box-shadow: 0 4px 12px rgba(16, 23, 53, 0.08);
    transform: translateY(-1px);
  }

  body.thermii-skin button.thermii-project-chip:active {
    transform: translateY(0);
  }

  body.thermii-skin button.thermii-project-chip:focus:not(:focus-visible) {
    outline: none;
  }

  body.thermii-skin button.thermii-project-chip:focus-visible {
    outline: 2px solid #7138ed;
    outline-offset: 2px;
  }

  body.thermii-skin .thermii-project-chip-name {
    color: var(--thermii-navy, #101735);
    /* a step down from the chip's 12.5px (Loz, 2026-08-28: the names read
       too large against the strip) — the weight keeps them the lead item */
    font-size: 11.5px;
    font-weight: 500;
  }

  body.thermii-skin .thermii-project-chip-sub {
    color: #8a92ad;
    font-size: 10.5px;
    font-weight: 400;
  }

  /* Banked rooms wear the brand green as a tick-in-a-dot, the same "done"
     language the stepper's completed pills use. */
  body.thermii-skin .thermii-project-chip.is-done .thermii-project-chip-name::before {
    content: '✓';
    margin-right: 5px;
    color: #74b700;
    font-size: 11px;
    font-weight: 700;
  }

  /* ── WHICH SYSTEM IS THIS ROOM? (Loz, 2026-09-01) ──────────────────────────

     First visible slice of mixed projects. The strip is the one surface that
     shows the whole project on every screen, so it is where "this job is part
     water, part electric" becomes legible — which means no screen has to learn
     a new identity to make mixed projects readable.

     SHAPE CARRIES THE MEANING, colour only reinforces it: a droplet and a bolt,
     tinted to the marks the system screen already uses (brand blue, and the
     bolt's amber). Hue alone would lose the distinction for a colour-blind
     customer on the one surface where it matters most.

     Masked rather than drawn as a background image, so each marker takes its
     colour from the rule below and there is no colour baked into a data URI to
     drift. -webkit- first, for Safari. */
  body.thermii-skin .thermii-project-chip-sys {
    flex: 0 0 auto;
    align-self: center;
    width: 11px;
    height: 11px;
    margin-right: 1px;
    background-color: currentColor;
  }

  body.thermii-skin .thermii-project-chip.is-water .thermii-project-chip-sys {
    color: #149de8;
    -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2012%2012%27%3E%3Cpath%20d%3D%27M6%20.9C6%20.9%202.2%205%202.2%207.5a3.8%203.8%200%200%200%207.6%200C9.8%205%206%20.9%206%20.9Z%27%20fill%3D%27%23000%27%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2012%2012%27%3E%3Cpath%20d%3D%27M6%20.9C6%20.9%202.2%205%202.2%207.5a3.8%203.8%200%200%200%207.6%200C9.8%205%206%20.9%206%20.9Z%27%20fill%3D%27%23000%27%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
  }

  body.thermii-skin .thermii-project-chip.is-electric .thermii-project-chip-sys {
    color: #e8a020;
    -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2012%2012%27%3E%3Cpath%20d%3D%27M7.1.7%202.3%206.8h2.9L4.7%2011.3%209.9%205.1H6.7Z%27%20fill%3D%27%23000%27%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2012%2012%27%3E%3Cpath%20d%3D%27M7.1.7%202.3%206.8h2.9L4.7%2011.3%209.9%205.1H6.7Z%27%20fill%3D%27%23000%27%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
  }

  /* A room from the journey NOT currently on show. Still counted and still
     legible — it is part of the project — but it is not a button, because
     re-opening it would need a panel switch that today also wipes the
     project. It WEARS THE SAME CHIP as the journey's own rooms (Loz,
     2026-09-24: the dashed pill "is not occurring on the water journey"): the
     droplet/bolt before its name already says which system it belongs to, so
     a second, dashed marker only made it look unfinished. Not a button, so
     no pointer. */
  body.thermii-skin .thermii-project-chip.is-other {
    cursor: default;
  }

  /* The room being added right now: Continue purple, so the strip answers
     "where am I in this loop?" at a glance. */
  body.thermii-skin .thermii-project-chip.is-current {
    border-color: rgba(108, 75, 216, 0.35);
    background: rgba(108, 75, 216, 0.06);
  }

  body.thermii-skin .thermii-project-chip.is-current .thermii-project-chip-name {
    color: #6c4bd8;
  }

  body.thermii-skin .thermii-project-chip.is-current .thermii-project-chip-sub {
    color: #7d6bc4;
  }

  body.thermii-skin .thermii-project-total {
    flex: 0 0 auto;
    color: var(--thermii-navy, #101735);
    font-family: 'Poppins', sans-serif;
    font-size: 12.5px;
    font-weight: 500;
  }

  @media screen and (max-width: 900px) {
    /* The label and the total are the first things to go: the chips carry
       both facts already, and horizontal room is the scarce thing here. */
    body.thermii-skin .thermii-project-label {
      display: none;
    }
    body.thermii-skin .thermii-project-strip {
      gap: 10px;
      padding: 9px 0 1px;
    }
  }

  @media screen and (max-width: 560px) {
    body.thermii-skin .thermii-project-total {
      display: none;
    }
  }

  /* ── The welcome screen ────────────────────────────────────────────────────

     Loz's design, 2026-08-28. Everything centred, three routes, no stepper.
     Built by js/thermii-welcome.js; shown by the body class, which is also
     what hides the System card and the pills behind it. */
  body.thermii-welcome-active #systemTypeCard,
  body.thermii-welcome-active #thermiiHowItWorksBtn,
  body.thermii-welcome-active .thermii-stepper-wrap,
  body.thermii-welcome-active .thermii-stage-summary {
    display: none !important;
  }

  /* THE WELCOME IS AN OVERLAY, AND UNTIL NOW IT ONLY COVERED THE JOURNEY
     (Loz, 2026-09-01: "it does return to the 1st screen - BUT - it brings in
     the question screen the user was on").

     The rule above names the System card and the pills because at BOOT that is
     all there is to hide. Press Home from inside a journey and the panel the
     customer was on is still displayed underneath — the welcome stage is only
     as tall as its own content, so the question screen simply scrolled into
     view below it, and its action bar brought a Back button along with it.

     Hiding by STRUCTURE rather than by name: .thermii-workspace holds exactly
     the Version stage, the System card, the how-it-works pill and the three
     journey panels, and everything the journey renders (summary, CTA, CAD
     card, kit) is nested inside those panels. So one rule covers all of it and
     keeps covering anything added to the workspace later.

     `display: none !important` beats the engine's own inline display, and
     because it is bounded by the body class it simply STOPS APPLYING on leave —
     the engine's inline value is untouched and the journey comes back exactly
     as it was. Same discipline as the kit-screen rules in thermii-system.css. */
  body.thermii-welcome-active .thermii-workspace > *:not(.thermii-welcome-stage) {
    display: none !important;
  }

  /* THE OLD "WELCOME BACK" BAND IS RETIRED (Loz, 2026-09-01: "this doesn't
     really match the overall styling of Thermii - I think it's coming in from
     the old version"). He was right on both counts: it was the last surface the
     skin had never reached — every style inline in index.html, a navy-to-black
     gradient (#0e2255 -> #06101e) that appears nowhere else in the palette,
     1410px wide against the 1200px tile row it introduced, and a primary action
     that was an <img> served off the WordPress site.

     Its job moved onto the Existing Projects tile instead of being restyled,
     because the band was also asking a second question over the top of this
     screen's own. See js/thermii-welcome.js.

     HIDDEN, NEVER REMOVED, and for two separate reasons: its buttons' inline
     onclick attributes are part of the DOM contract, and `wCheckSession` hangs
     the saved data off the element itself (`banner._savedData`) for
     `wRestoreSession` to read — so the node is the data carrier as well as the
     retired UI. `!important` because the engine sets `display: flex` inline. */
  body.thermii-skin #wSessionBanner {
    display: none !important;
  }

  body.thermii-skin .thermii-welcome-stage { display: none; }

  body.thermii-welcome-active .thermii-welcome-stage {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 1240px;
    margin: 0 auto;
    padding-top: 76px;
    min-height: var(--thermii-stage-depth, 1000px);
  }

  /* The same type as every question headline (journey.css:346) — token for
     token, not a lookalike. Loz: it was reading heavier than the rest. */
  body.thermii-skin .thermii-welcome-title {
    margin: 0;
    color: var(--thermii-navy, #101735);
    font-family: 'Poppins', sans-serif;
    font-size: clamp(30px, 3vw, 38px);
    font-weight: var(--thermii-font-weight-display);
    letter-spacing: var(--thermii-letter-spacing-question);
    line-height: 1.16;
    text-align: center;
  }

  body.thermii-skin .thermii-welcome-sub {
    margin: 22px auto 0;
    /* one line on a desktop, as designed — 780 broke it across two */
    max-width: 1000px;
    color: #596385;
    font-family: 'Poppins', sans-serif;
    font-size: 15px;
    font-weight: var(--thermii-font-weight-light, 300);
    line-height: 1.6;
    text-align: center;
  }

  /* WIDER THAN THE JOURNEY'S 1040 COLUMN, deliberately. This screen has no
     stepper and no question, and its card copy is authored to break in two
     lines — at 1040 the three cards are ~330px and every description runs to
     three. The column rule exists to line questions up with each other; there
     is no question here to line up with. */
  body.thermii-skin .thermii-welcome-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 26px;
    width: 100%;
    max-width: 1200px;
    margin: 40px auto 0;
  }

  /* The role question has two tiles, not three: same card, same gap, the
     row narrowed so each tile keeps the width of a three-tile row's. */
  body.thermii-skin .thermii-welcome-row.is-two {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 791px;
  }

  body.thermii-skin .thermii-welcome-switch {
    display: block;
    margin: 22px auto 0;
    padding: 4px 8px;
    border: 0;
    background: none;
    color: #596385;
    font-family: 'Poppins', sans-serif;
    font-size: 13.5px;
    font-weight: var(--thermii-font-weight-light, 300);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
  }
  body.thermii-skin .thermii-welcome-switch:hover { color: #101735; }

  /* KIT CHECK (21 October 2026): shown on the kit while the engine's quote
     is on its way, or when it could not be reached; the cart waits for it. */
  body.thermii-skin .thermii-quote-check {
    margin: 0 0 14px; padding: 10px 14px; border-radius: 10px;
    background: #f2f4f8; color: #28324b; font-size: 14px; line-height: 1.45;
  }
  body.thermii-skin .thermii-quote-check[hidden] { display: none; }
  body.thermii-skin .thermii-quote-check.is-failed { background: #fff1ea; color: #8a2f00; }
  body.thermii-skin .thermii-quote-check-retry {
    margin-left: 6px; padding: 0; border: 0; background: none;
    color: inherit; font: inherit; font-weight: 600; text-decoration: underline; cursor: pointer;
  }

  /* SIGN-IN STEP (21 October 2026): the email form opens under the two
     tiles when "Email me a sign-in link" is chosen; the notice carries a
     failed shop sign-in or an expired link back to the customer. */
  body.thermii-skin .thermii-welcome-email[hidden],
  body.thermii-skin .thermii-welcome-email-fields[hidden],
  body.thermii-skin .thermii-welcome-notice[hidden] { display: none; }

  body.thermii-skin .thermii-welcome-email {
    width: 100%;
    max-width: 560px;
    margin: 26px auto 0;
    font-family: 'Poppins', sans-serif;
    text-align: center;
  }

  body.thermii-skin .thermii-welcome-email-fields {
    display: flex;
    align-items: flex-end;
    gap: 10px;
  }

  body.thermii-skin .thermii-welcome-email-label {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
    color: #596385;
    font-size: 13px;
    text-align: left;
  }

  body.thermii-skin .thermii-welcome-email-label input {
    height: 48px;
    padding: 0 16px;
    border: 1.5px solid #d6d9e6;
    border-radius: 12px;
    background: #fff;
    color: #101735;
    font: inherit;
    font-size: 15px;
  }

  body.thermii-skin .thermii-welcome-email-label input:focus {
    outline: none;
    border-color: #6c4bd8;
    box-shadow: 0 0 0 3px rgba(108, 75, 216, 0.15);
  }

  body.thermii-skin .thermii-welcome-email-send {
    height: 48px;
    padding: 0 22px;
    border: 0;
    border-radius: 50px;
    background: #6c4bd8;
    color: #fff;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
  }

  body.thermii-skin .thermii-welcome-email-send:disabled { opacity: 0.6; cursor: default; }

  body.thermii-skin .thermii-welcome-email-status {
    min-height: 1.5em;
    margin: 12px 0 0;
    color: #596385;
    font-size: 14px;
    line-height: 1.6;
  }

  body.thermii-skin .thermii-welcome-email.is-sent .thermii-welcome-email-status b { color: #101735; }

  body.thermii-skin .thermii-welcome-email-again {
    margin-top: 6px;
    padding: 2px 6px;
    border: 0;
    background: none;
    color: #596385;
    font: inherit;
    font-size: 13.5px;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
  }

  body.thermii-skin .thermii-welcome-notice {
    max-width: 560px;
    margin: 22px auto 0;
    padding: 12px 16px;
    border-radius: 12px;
    background: #fff4e5;
    color: #7a4b00;
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    line-height: 1.5;
    text-align: center;
  }

  @media screen and (max-width: 560px) {
    body.thermii-skin .thermii-welcome-email-fields { flex-direction: column; align-items: stretch; }
  }

  body.thermii-skin .thermii-welcome-card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Loz: they read bottom-heavy. The content is a fixed stack, so the box is
       sized to it rather than padded out to an arbitrary height. */
    min-height: 0;
    /* .filter-option fixes tiles at 224px, which the two-line copy filled
       exactly. Priced copy runs to three or four lines, so the card grows
       instead, and the grid row keeps every card in it the same height. */
    height: auto;
    justify-content: flex-start;
    padding: 32px 26px 30px;
    border: 1.5px solid #e4e6ef;
    border-radius: 18px;
    background: #fff;
    color: var(--thermii-navy, #101735);
    font-family: 'Poppins', sans-serif;
    text-align: center;
    cursor: pointer;
    transition: border-color 0.16s ease, box-shadow 0.16s ease,
                transform 0.16s ease;
  }

  /* selected wears the brand gradient as its border, like every other
     selected card in the app */
  body.thermii-skin .thermii-welcome-card.is-selected {
    border-color: transparent;
    background:
      linear-gradient(#fff, #fff) padding-box,
      var(--thermii-gradient) border-box;
    box-shadow: 0 12px 28px rgba(100, 54, 229, 0.09);
    transform: none;
  }

  body.thermii-skin .thermii-welcome-card:focus:not(:focus-visible) {
    outline: none;
  }
  body.thermii-skin .thermii-welcome-card:focus-visible {
    outline: 2px solid #7138ed;
    outline-offset: 3px;
  }

  /* No bespoke tick here any more: the tiles wear .js-radio-tile, so the
     journey's own ::after badge draws it — same size, same ring, same purple,
     same transition as a question tile (Loz, 2026-08-28). */

  body.thermii-skin .thermii-welcome-art {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    height: 54px;
    margin-bottom: 22px;
    color: #101735;
    line-height: 0;
  }

  /* one height, each mark keeps its own width — see the note in
     js/thermii-welcome.js */
  body.thermii-skin .thermii-welcome-art img {
    height: 54px;
    width: auto;
    display: block;
  }

  body.thermii-skin .thermii-welcome-card-title {
    display: block;
    font-size: 19px;
    font-weight: 600;
    letter-spacing: -0.01em;
  }

  body.thermii-skin .thermii-welcome-card-copy {
    display: block;
    margin-top: 12px;
    color: #596385;
    font-size: 14px;
    font-weight: var(--thermii-font-weight-light, 300);
    line-height: 1.6;
  }

  /* THE NOT-YET-WIRED TILES ANSWER A CLICK BY STANDING DOWN (Loz,
     2026-08-28): the card greys out and says why, centred over itself. A pill
     tucked at the bottom edge in the muted palette was easy to miss on the
     exact interaction that needed explaining. */
  body.thermii-skin .thermii-welcome-soon {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%) scale(0.94);
    padding: 8px 18px;
    border-radius: 999px;
    background: #101735;
    color: #fff;
    font-size: 13.5px;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
    box-shadow: 0 10px 24px rgba(16, 23, 53, 0.22);
    opacity: 0;
    pointer-events: none;
    z-index: 3;
  }

  body.thermii-skin .thermii-welcome-card.is-nudging .thermii-welcome-soon {
    animation: thermii-welcome-soon 1.8s ease both;
  }

  /* everything the card is made of steps back while the hint is up — the
     badge included, or a bright empty ring floats over a dimmed card */
  body.thermii-skin .thermii-welcome-card.is-nudging .thermii-welcome-art,
  body.thermii-skin .thermii-welcome-card.is-nudging .thermii-welcome-card-title,
  body.thermii-skin .thermii-welcome-card.is-nudging .thermii-welcome-card-copy,
  body.thermii-skin .thermii-welcome-card.is-nudging::after {
    animation: thermii-welcome-dim 1.8s ease both;
  }

  body.thermii-skin .thermii-welcome-card.is-nudging {
    animation: thermii-welcome-grey 1.8s ease both;
  }

  @keyframes thermii-welcome-soon {
    0% { opacity: 0; transform: translate(-50%, -50%) scale(0.94); }
    14% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    80% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
  }

  @keyframes thermii-welcome-dim {
    0% { opacity: 1; }
    14% { opacity: 0.28; }
    80% { opacity: 0.28; }
    100% { opacity: 1; }
  }

  @keyframes thermii-welcome-grey {
    0% { background: #fff; }
    14% { background: #eef0f6; }
    80% { background: #eef0f6; }
    100% { background: #fff; }
  }

  @media (prefers-reduced-motion: reduce) {
    body.thermii-skin .thermii-welcome-card.is-nudging .thermii-welcome-soon {
      animation: none;
      opacity: 1;
    }
  }

  body.thermii-skin .thermii-welcome-how {
    display: flex;
    justify-content: center;
    margin-top: 40px;
  }

  /* MY PLAN uses this same front door (26 October 2026). The header stays,
     and the tiles are the welcome cards. A homeowner never sees a trade plan
     here; a shop trade account does, with buying still shut. */
  body.thermii-skin .thermii-plan { display: none; width: 100%; }
  body.thermii-plan-active .thermii-welcome-stage > .thermii-welcome-title,
  body.thermii-plan-active .thermii-welcome-stage > .thermii-welcome-sub,
  body.thermii-plan-active .thermii-welcome-stage > .thermii-welcome-row,
  body.thermii-plan-active .thermii-welcome-stage > .thermii-welcome-switch,
  body.thermii-plan-active .thermii-welcome-stage > .thermii-welcome-how,
  body.thermii-plan-active .thermii-welcome-stage > .thermii-welcome-email,
  body.thermii-plan-active .thermii-welcome-stage > .thermii-welcome-notice,
  body.thermii-plan-active .thermii-welcome-footer { display: none; }
  body.thermii-plan-active .thermii-plan {
    display: flex;
    flex-direction: column;
    width: 100%;
  }
  body.thermii-skin .thermii-plan-card { cursor: default; }
  body.thermii-skin .thermii-plan-card:hover { transform: none; box-shadow: none; }
  body.thermii-skin .thermii-plan-row.is-one {
    grid-template-columns: minmax(0, 380px);
    justify-content: center;
    max-width: none;
  }
  body.thermii-skin .thermii-plan-action {
    margin-top: 18px;
    height: 46px;
    padding: 0 22px;
    border: 0;
    border-radius: 50px;
    background: #6c4bd8;
    color: #fff;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
  }
  body.thermii-skin .thermii-plan-action:disabled { opacity: 0.6; cursor: default; }
  body.thermii-skin .thermii-plan-note {
    max-width: 720px;
    margin: 28px auto 0;
    color: #596385;
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    font-weight: var(--thermii-font-weight-light, 300);
    line-height: 1.6;
    text-align: center;
  }
  body.thermii-skin .thermii-plan .thermii-welcome-switch { display: block; }

  /* ── The "How Does Thermii™ Work?" pill lifts and fills on hover ────────────

     Loz, 2026-09-02. It had NO hover at all: css/components.css:380-391 is the
     pill's only chrome and declares no :hover, no transition and no transform,
     so the one control on the welcome screen that is not a tile gave no
     feedback whatsoever.

     THE LIFT IS THE JOURNEY'S OWN, VERBATIM — `translateY(-2px)` with
     `0 12px 28px rgba(66, 42, 139, .10)`, the identical pair already on
     .thermii-version-card:hover (components.css:338), .js-radio-tile:hover
     (journey.css:493) and #systemTypeRow .system-option:hover (journey.css:644).
     The transition list matches journey.css:485-490. Nothing here is invented.

     THE FILL IS THE PURPLE→MAGENTA PAIR, not the three-stop --thermii-gradient,
     and that is a decision. It is the same pair as .thermii-how-got
     (:3407) — the "Got it" button inside the popup THIS PILL OPENS, so the
     rollover previews where it is about to take you. The three-stop token starts
     at --thermii-blue, and white on that blue is about 3:1, which fails 4.5:1
     for a 13px label; purple→magenta clears it across the whole sweep. One line
     to switch if Loz wants the full brand sweep instead.

     `background-image`, not the `background` shorthand: the base rule sets no
     background at all, so there is nothing to reset, and the longhand cannot
     clobber a background-color added later.

     The "?" disc needs no rule of its own — components.css:397 draws it as
     `border: 1px solid currentColor`, so it goes white with the label.

     The fill is deliberately NOT in the transition list: no engine interpolates
     a gradient image, so it snaps while the lift, ink and shadow ease. That is
     what .thermii-continue:hover (components.css:424) and .thermii-how-got:hover
     (:3416) already do. */
  body.thermii-skin .thermii-how-button {
    transition:
      transform .2s ease,
      border-color .2s ease,
      box-shadow .2s ease,
      color .2s ease;
  }

  body.thermii-skin .thermii-how-button:hover {
    transform: translateY(-2px);
    border-color: transparent;
    background-image: linear-gradient(90deg, var(--thermii-purple, #7138ed),
                                             var(--thermii-magenta, #d414c4));
    color: #fff;
    box-shadow: 0 12px 28px rgba(66, 42, 139, .10);
  }

  /* the colour change carries the affordance on its own, so the movement is
     what goes — this file's established idiom (:1781, :2187, :2267, :2597) */
  @media (prefers-reduced-motion: reduce) {
    body.thermii-skin .thermii-how-button { transition: none; }
    body.thermii-skin .thermii-how-button:hover { transform: none; }
  }

  /* its own action bar, matching the journey's: toggle centred, Continue right */
  body.thermii-skin .thermii-welcome-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 16px;
    min-height: 76px;
    margin: auto calc(-1 * var(--thermii-bleed, 0px)) 0;
    padding: 18px var(--thermii-bar-inset, 35px);
    border-top: 1px solid #ecedf3;
    position: sticky;
    bottom: 0;
    background: #fff;
    z-index: 6;
    border-bottom-left-radius: var(--thermii-card-radius, 22px);
    border-bottom-right-radius: var(--thermii-card-radius, 22px);
  }

  /* THE TOGGLE, CENTRED IN WHICHEVER BAR IT IS IN (Loz, 2026-08-28). It is one
     node relocated per screen, so the centring has to come from the bar rather
     than from a fixed position: auto margins on both sides put it in the middle
     whatever sits either side of it. */
  /* TRULY CENTRED, not centred-if-the-ends-match. Auto margins split the slack
     between Back and Continue, which are different widths — so it sat left of
     centre (Loz spotted it). Absolute centring is independent of both.

     NO `position: relative` ON THE BARS: all three are already `position:
     sticky`, which positions them and so makes each the containing block this
     needs. Adding relative overrode sticky and dropped the welcome bar out of
     its pinned spot to the bottom of a 1000px stage, off screen. */

  body.thermii-skin .thermii-welcome-footer .thermii-skin-theme,
  body.thermii-skin #systemTypeCard .thermii-confirm-footer .thermii-skin-theme,
  body.thermii-skin .thermii-skin-actionbar .thermii-skin-theme {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    margin: 0;
    padding: 0;
  }

  /* the separator is header furniture — there are no neighbours to divide
     from down here */
  body.thermii-skin .thermii-welcome-footer .thermii-skin-theme::before,
  body.thermii-skin #systemTypeCard .thermii-confirm-footer .thermii-skin-theme::before,
  body.thermii-skin .thermii-skin-actionbar .thermii-skin-theme::before {
    content: none;
  }

  /* The 56px this used to set is GONE (2026-09-03). It predated the base rule
     being 55px wide and now differs from it by one pixel, which bought a
     pixel of letterboxing and a second place for the size to live. One size,
     in the base rule above. */

  /* the bar's own children keep their ends */
  body.thermii-skin .thermii-skin-actionbar .eq-back-btn { order: -1; }
  body.thermii-skin .thermii-skin-actionbar .thermii-continue,
  body.thermii-skin .thermii-skin-actionbar .thermii-step-continue,
  body.thermii-skin .thermii-welcome-footer .thermii-continue { order: 1; }

  /* The bulb too (Loz, 2026-09-14: "slightly larger to match the pixel height
     of the other icons near it"). Measured at 17px the stroked marks' ink runs
     12.2 (folder) to 13.2 (floppy) and the bulb 12.4 — level by the numbers,
     but a bulb's ink is a thin dome and a base, so it reads smaller beside the
     filled Help bubble. Loz then asked for 15px of ink (a 20.6px box — the
     path plus stroke spans 17.5 of 24 units) and then "slightly larger than it
     currently is": 22px, which draws 16.0px of ink, a touch over the house's
     15.5. The switch beside it keeps its own 22x12. */
  body.thermii-skin .thermii-shell-actions .thermii-skin-insights > svg:first-child {
    width: 22px;
    height: 22px;
    /* the drawing is bottom-heavy (dome top at 4.6, base at 20.4 of 24), so
       its ink centre sat 0.5px below the floppy's, the arrow's and the
       folder's, all of which land on the label's line centre exactly.
       Measured, then lifted by that half pixel. */
    transform: translateY(-0.5px);
  }

  /* The logo is the way home, so it must look pressable without turning the
     brand mark into a button: cursor and a small lift on hover, and the ring
     it needs as a real keyboard control. */
  body.thermii-skin .thermii-skin-logo-home {
    cursor: pointer;
    border-radius: 10px;
    transition: opacity 0.15s ease, transform 0.15s ease;
  }

  body.thermii-skin .thermii-skin-logo-home:hover {
    opacity: 0.82;
    transform: translateY(-1px);
  }

  body.thermii-skin .thermii-skin-logo-home:active { transform: none; }

  body.thermii-skin .thermii-skin-logo-home:focus:not(:focus-visible) {
    outline: none;
  }

  body.thermii-skin .thermii-skin-logo-home:focus-visible {
    outline: 2px solid #7138ed;
    outline-offset: 4px;
  }

  /* Help matches the other icons' height (Loz, 2026-08-28: reduce it) */
  body.thermii-skin .thermii-skin-help img { height: 17px; width: 17px; }

  @media screen and (max-width: 900px) {
    body.thermii-skin .thermii-welcome-title { font-size: 27px; }
    body.thermii-skin .thermii-welcome-sub { font-size: 13.5px; }
    body.thermii-skin .thermii-welcome-row,
    body.thermii-skin .thermii-welcome-row.is-two {
      grid-template-columns: minmax(0, 1fr);
      gap: 14px;
      margin-top: 28px;
    }
    body.thermii-skin .thermii-welcome-card {
      min-height: 0;
      padding: 26px 20px 24px;
    }
    body.thermii-welcome-active .thermii-welcome-stage { padding-top: 34px; }
    body.thermii-skin .thermii-welcome-footer {
      border-bottom-left-radius: 0;
      border-bottom-right-radius: 0;
    }
  }

  /* ── Version screen removed (Loz, 2026-08-28) ──────────────────────────────

     Paired with js/thermii-no-version.js — delete that script tag and this
     block and the front door is back. The stage is hidden rather than removed
     because ui.js (byte-locked) still owns it and still transitions out of it;
     the pill is hidden rather than renumbered because syncCount counts only
     visible pills, so System reads "Step 1 of 9" without touching a single
     data-shell-step or the navigation map. */
  body.thermii-no-version #thermiiVersionStage {
    display: none !important;
  }

  body.thermii-no-version .thermii-stepper .thermii-step[data-shell-step="1"] {
    display: none;
  }

  /* ── The project drawer ────────────────────────────────────────────────────

     Loz's thermii-step-responsive mockup: a navy panel that slides in from the
     right on desktop and up as a sheet on mobile, carrying the running spec.
     Navy is already the brand's "surface with weight" (the kit banner), so the
     drawer reads as a different plane from the white card rather than another
     card on top of it. */
  body.thermii-skin .thermii-drawer-scrim,
  .thermii-drawer-scrim {
    position: fixed;
    inset: 0;
    z-index: 210;
    background: rgba(11, 20, 55, 0.5);
    opacity: 0;
    transition: opacity 0.22s ease;
  }

  .thermii-drawer-scrim.is-open { opacity: 1; }

  /* THE DRAWER ITSELF moved to the "YOUR PROJECT DRAWER, v2" block near the
     end of this file (Loz's Claude Design handoff, 2026-09-25). */

  /* The Help dialog's CTAs are deliberately the unsure screen's buttons —
     but inside a dialog, their 6px engine radius sat next to the Save
     dialog's 13px like two different apps. Rounded to Continue's radius HERE
     ONLY; the unsure screen itself is untouched. */
  body.thermii-skin .thermii-skin-modal .unsure-quote-btn,
  body.thermii-skin .thermii-skin-modal .unsure-phone-btn {
    border-radius: 13px;
  }

  /* THE PHONE BUTTON'S COLOURS ARE NOW SET ONCE, GLOBALLY, at the
     `body.thermii-skin .unsure-phone-btn` rule far above this one.

     It arrived here first as a dialog-scoped rule, because Loz asked for the
     Help popup's phone button to take the popups' colours and
     `.unsure-phone-btn` is ALSO the "help me choose" screen's own button — so
     scoping kept a screen he had not mentioned out of it. He then asked for that
     screen to match too, which makes the scope pointless: one rule now covers
     both, and a dialog-only copy of the same two declarations would be a second
     place for them to drift.

     THE GREEN HOVER STAYS, at Loz's request ("keep the green on hover
     states"). css/thermii.css:1598 tints the button #f2faeb on hover and
     :1592 turns "Request a Quote" / "Email Us" fully green — both are left
     alone, so the resting state is purple and the green is what movement
     reveals. An earlier version of this rule replaced the tint with a pale
     purple; that is reverted deliberately, not lost.

     The BORDER WIDTH is untouched either way — 2px from thermii.css against the
     popup's 1.5px. Loz asked for the colours, and these buttons are 54px tall
     with 16px text where the popup's are 38px with 13px, so a thinner edge
     would read as thinner rather than as the same. */

  /* ── Reassurance line under the Version title ──────────────────────────────────────

     Commitment framing before the first question: quieter than the subtitle
     (it is scent, not instruction), one size down, with the dots faded so the
     three facts read as one soft line rather than a list. */
  body.thermii-skin .thermii-version-reassurance {
    margin: 10px 0 0;
    color: #8a92ad;
    font-size: 13px;
    font-weight: var(--thermii-font-weight-light, 300);
    letter-spacing: 0.01em;
  }
  body.thermii-skin .thermii-version-reassurance-dot {
    opacity: 0.55;
    margin: 0 6px;
  }
  body.thermii-skin .thermii-version-reassurance-item {
    white-space: nowrap;
  }

  /* ── ONE SELECTED STATE ───────────────────────────────────────────────────

     Three of the four families mark selection with the brand gradient as a border
     (journey.css:515, :706, :1377); the Version card alone uses a flat 2px #6326ff
     (components.css:339). Same technique adopted here so selection looks the same
     wherever it happens.

     FLAGGED: this changes the FIRST screen a customer sees. If the flat purple is
     the one to keep, the change to make is the opposite one — take the gradient
     off the other three — and this block is what to delete. */
  body.thermii-skin .thermii-version-stage .thermii-version-card.is-selected,
  body.thermii-skin .thermii-version-card.is-selected {
    border-color: transparent;
    background:
      linear-gradient(#fff, #fff) padding-box,
      var(--thermii-gradient) border-box;
    box-shadow: 0 12px 28px rgba(100, 54, 229, 0.09);
  }

  /* ── "Compare Install Methods" as the Version screen's pill ─────────────────

     Loz, 2026-08-27: same chrome as .thermii-how-button (components.css:380).
     Mirrored rather than sharing the class — the class cannot be added to the
     markup (id/on* lists are contract-frozen, class edits in index.html are
     allowed but this button's TEXT is rewritten by the engine at
     legacy-core.js:3068, so keeping all styling in one skin rule keeps the
     relationship obvious). thermii.css also styles it BY ID, so ID strength. */
  body.thermii-skin #wInstallCompareToggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-height: 46px;
    padding: 10px 28px;
    border: 1px solid #b89cfb;
    border-radius: 999px;
    background: none;
    color: #6230ef;
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
  }

  /* ── One tick colour ──────────────────────────────────────────────────────

     journey.css:545 confirms a RECOMMENDED tile in green while every other tile
     confirms in purple — green as "you took the recommendation". Under the skin
     that read as an inconsistency rather than a signal (Loz asked), so the tick
     is purple everywhere. The recommendation itself keeps its green identity:
     the is-recommended border and tint are untouched. */
  body.thermii-skin .filter-option.is-recommended.is-selected::after {
    border-color: var(--journey-selected);
    background: var(--journey-selected);
  }

  /* ── "How Does Thermii™ Work?" on the system screen ──────────────────────── */

  /* Dropped at Loz's request: the same offer already sits on the Version screen
     immediately before this one, as .thermii-how-button, so on the system choice
     it is the second ask in two screens. That one stays.

     THESE ARE TWO DIFFERENT ELEMENTS AND THEIR LABELS ARE NOW IDENTICAL, which
     makes hiding by id load-bearing rather than merely tidy. Until 2026-09-03
     the two read almost the same and could be told apart by eye — this one
     carried the trademark and the other did not; Loz then aligned all three
     wordings on the popup's title, so both are "How Does Thermii™ Work?" and
     TEXT NO LONGER DISTINGUISHES THEM AT ALL. The Version screen's is
     `.thermii-how-button`; this is `#thermiiHowItWorksBtn`. Never reach for
     either by its label.

     HIDDEN, NOT DELETED. The wrapper carries an id and its anchor carries
     onmouseover/onmouseout, all three of which are in the DOM contract
     verify-parity.py holds to the frozen baseline. js/ui.js is byte-locked and
     reads this element too; a CSS hide leaves that reading exactly what it did.

     No !important needed: the engine only ever sets this element's inline display
     to '' or 'none' (legacy-core.js:186, 771, 1623, 1904, 2061), and an empty
     inline value lets this rule through. It is shown ONLY on the system screen —
     by goBackToSystemType, restartKitBuilder and changeSystemSelection — so
     nothing else loses it. */
  body.thermii-skin #thermiiHowItWorksBtn {
    display: none;
  }

  /* ── ONE DEPTH, AND A BAR THAT DOES NOT MOVE ──────────────────────────────

     Measured across all 21 question steps, the content area ran from 490px to
     1118px — a 628px spread, which is why Continue jumped. Sizing every screen to
     the tallest would put ~600px of dead space under the tiles on the five
     shortest, which is worse than the dead space removed earlier today.

     So: a uniform depth at the 90th percentile, and a STICKY bar. Nineteen of the
     twenty-one screens are then exactly the same depth with the bar at the same
     height; the two taller ones (eq-step-6 at 1118, wq-step-4b at 949) grow past
     it and the bar sticks to the bottom of the view while their content scrolls.
     Continue is in one place either way, and no screen gains dead space it does
     not need.

     The section becomes a flex column purely so `margin-top: auto` on the bar can
     hold it at the bottom of that depth. */
  body.thermii-skin .eq-step .eq-section,
  body.thermii-skin .thermii-version-stage,
  body.thermii-skin #systemTypeCard {
    display: flex;
    flex-direction: column;
  }

  /* THE CARD REACHES THE BOTTOM OF THE VIEW, so the bar — held there by
     `margin-top: auto` — lands in the same place on every screen. A flat 880px did
     not do that: it was taller than the view on a 1000px-high window, putting the
     bar below the fold, and shorter on a tall one.

     142px is MEASURED, not guessed, and it is the chrome ABOVE the section only —
     the wrapper's top margin plus the header. Subtracting the chrome above AND
     below (218px) was the mistake in the first attempt: about 100px of it sits
     BELOW the section, so the section stopped ~100px short of the bottom of the
     view and the bar sat there, 118px high on short screens against 0 on tall
     ones. Measured from the top only, the section's bottom lands on the viewport
     bottom and the bar is in one place on every screen.

     The version line and the card's bottom edge then fall just below the fold on a
     short screen, which is a footnote moving rather than content being lost, and
     the small scroll it creates is what lets sticky hold the bar in exactly the
     same place there as on a long screen.

     `max()` puts a floor under it so a short window cannot crush the content; below
     that the page simply scrolls, and the bar sticks to the bottom of the view on
     the way down (see the sticky rule). This is deliberately the dead space removed
     earlier today, traded back for Continue never moving — Loz's call, 2026-08-26. */
  body.thermii-skin .eq-step .eq-section {
    min-height: var(--thermii-stage-depth);
  }

  /* NO JUMP ON SELECTION (Loz, 2026-08-27, measured at exactly 46px). Clicking
     a tile makes the engine mark the section `is-answered`, whose style is
     `padding: 6px 0` — sized for the old collapsed one-line summary — while
     thermii-gate.js holds the FULL question on screen (journey.css:419). The
     full layout on the collapsed padding is what yanked the title, subtext and
     tiles 46px up (52px top padding falling to 6). While the gate holds the
     screen open, the section keeps the padding the question was laid out with;
     the collapsed padding still applies wherever a section is answered WITHOUT
     the gate holding it (the genuine summary state). Bottom stays the depth
     pass's 0. */
  body.thermii-skin .eq-step .eq-section.is-answered.thermii-gate-open {
    padding: 52px 10px 0;
  }

  /* The pin must reproduce the UNANSWERED cascade at every width or it becomes
     a jump in the other direction. Below 700px that cascade is journey.css:1788's
     34px top — except thermii.css zeroes `.eq-section:first-child`'s top there,
     and every step's section IS its step's first child, so 0 is what actually
     lays the question out. Both mirrored. */
  @media screen and (max-width: 700px) {
    body.thermii-skin .eq-step .eq-section.is-answered.thermii-gate-open {
      padding: 34px 0 0;
    }

    body.thermii-skin .eq-step .eq-section.is-answered.thermii-gate-open:first-child {
      padding-top: 0;
    }
  }

  /* +24px, because the Version and System screens sit 24px HIGHER than a question
     step — a question step carries the progress bar's row above its section. They
     are therefore 24px deeper than Loz's figure on purpose: it is the bar's
     bottom edge that has to land in one place, and 24px of card depth is
     invisible where 24px of travel on Continue is not. */
  body.thermii-skin .thermii-version-stage,
  body.thermii-skin #systemTypeCard {
    min-height: calc(var(--thermii-stage-depth) + 24px);
  }

  body.thermii-skin .eq-step .eq-section,
  body.thermii-skin .thermii-version-stage,
  body.thermii-skin #systemTypeCard {
    /* The section's own 42px bottom padding was holding the bar 42px clear of the
       bottom of the view on screens short enough not to scroll, while the tall ones
       pinned at 0 — the last of the inconsistency. The bar carries its own padding,
       so the section does not need any below it. */
    padding-bottom: 0;
  }


  /* EDGE TO EDGE, like the header's rule. The bar sits inside a centred 1040px
     column nested in several padded ancestors, so the distance to the container
     edge is not a constant — it changes with the viewport. js/thermii-skin.js
     measures it and publishes it as --thermii-bleed; the negative margin opens the
     bar to the container's full width and the matching padding puts its contents
     back where they were. Falls back to 0, i.e. inset as before, if the JS has not
     run. */

  /* The version/system footer gets the same measured bleed. Its authored
     `margin: 0 -48px` was tuned for the old padding and survived only because the
     wrapper clipped it; with clipping gone (see .kb-wrapper) it overflowed the
     container by 27px. */
  body.thermii-skin .thermii-version-footer {
    margin-left: calc(-1 * var(--thermii-bleed, 0px));
    margin-right: calc(-1 * var(--thermii-bleed, 0px));
    /* Every bar now bleeds to the wrapper's edge, so this padding is an inset
       from the CONTAINER, not from the screen's own content — which is why the
       authored 36px put this Continue 24px left of every other one. The Version
       stage is the one screen not inside a .kb-card, so it adds that card's 10px
       itself and lands on the same x as the rest at every width. Its own content
       is centred, so there is no content edge here to align to instead. */
    padding: 18px var(--thermii-bar-inset, 35px);
  }

  /* The System screen keeps its own footer: the action bar is only built for
     .eq-step journeys, so #systemTypeCard never gets one. Without the same pin
     and bleed its Continue sat 226px above where every other screen puts it,
     with an inset border, which is exactly the jumping-about the whole depth
     pass was for. `margin-top: auto` eats the free space in the flex column;
     the negative side margins take the border edge to edge. */
  body.thermii-skin .thermii-version-footer,
  body.thermii-skin .thermii-confirm-footer:not(.thermii-skin-emptied) {
    margin-top: auto;
  }

  /* Sticky, exactly as the action bar is. It did not matter while the depth
     followed the window — the card ended AT the fold, so these two could never
     fall below it. With a flat 1110px they can, and on a 1000px-high window they
     did: the question steps pinned their bar at the bottom of the view while the
     Version and System screens left theirs at 1252, off screen. Same jump,
     different route. */
  body.thermii-skin .thermii-version-footer,
  body.thermii-skin .thermii-confirm-footer:not(.thermii-skin-emptied) {
    position: sticky;
    bottom: 0;
    background: #fff;
    z-index: 6;
  }

  body.thermii-skin .thermii-confirm-footer:not(.thermii-skin-emptied) {
    /* thermii-system.css caps this footer at --journey-content-max so its
       divider ended on the content's right edge. That was right for an inset
       divider; it is wrong for a full-width bar, and the cap is what held the
       border 267px short of the container. */
    max-width: none;
    margin-right: calc(-1 * var(--thermii-bleed, 0px));
    margin-bottom: 0;
    margin-left: calc(-1 * var(--thermii-bleed, 0px));
    /* Same numbers as the action bar: bleed out by the measured inset, pad back
       in by it. Border edge to edge, Continue on the content's right edge. */
    padding: 18px var(--thermii-bar-inset, 35px);
  }

  /* ── The Thermii insight panel ───────────────────────────────────────────── */

  /* This IS the old speech bubble (#eTip / #wTip), restyled. It already sits
     after the last step, so it renders under whichever step is showing — which is
     where the reference puts it. The bubble's little pointer arrow goes with the
     speech-bubble metaphor. */
  body.thermii-skin .thermii-tip {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 14px;
    /* 1040, not its old 980: the tip was the one block still on its own width,
       so it sat indented 30px right of the title (266 vs 236) and its edges
       aligned with nothing — which read as a different-sized panel on every
       screen even though it never actually changed. On the shared column its
       left edge IS the title's, everywhere. (Loz, 2026-08-27) */
    max-width: 1040px;
    width: 100%;
    /* 28px of air above it — at 4px it was touching the tiles — and 24px below,
       so on a full screen it sits up off the action bar's edge (Loz) */
    margin: 28px auto 24px;
    padding: 18px 46px 18px 20px;
    background: #f6f4ff;
    border: 1px solid #e4defb;
    border-radius: 16px;
    box-sizing: border-box;
  }

  /* the mascot stands on its own — the lilac chip it sat in went at Loz's
     request. Dropping the 6px padding takes the drawn mascot from 22px to the
     full 34, so it holds its weight without the box.

     AND IT FLOATS (Loz, 2026-08-27): a continuous bob, the one piece of the
     mascot's old sidebar liveliness that survives into the journey. Was 4s/4px;
     Loz called it "a little sleepy", so 2.8s — tempo woke it up better than
     distance would, which starts to read as bouncing next to text. transform
     only, so it never reflows the panel. */
  body.thermii-skin .thermii-tip-avatar {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    padding: 0;
    border-radius: 0;
    background: transparent;
    box-sizing: border-box;
    animation: thermii-tip-float 2.8s ease-in-out infinite;
  }

  @keyframes thermii-tip-float {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-4px); }
  }

  /* motion is decoration here — a vestibular-safe page matters more */
  @media (prefers-reduced-motion: reduce) {
    body.thermii-skin .thermii-tip-avatar {
      animation: none;
    }
  }

  body.thermii-skin .thermii-tip-bubble {
    background: transparent;
    border: 0;
    box-shadow: none;
    padding: 0;
    margin: 0;
    border-radius: 0;
    min-width: 0;
  }

  body.thermii-skin .thermii-tip-bubble::before {
    display: none;
  }

  body.thermii-skin .thermii-skin-insight-title {
    display: block;
    font-family: 'Poppins', sans-serif;
    font-size: 13.5px;
    font-weight: 600;
    color: #6c4bd8;
    margin-bottom: 3px;
  }

  body.thermii-skin .thermii-tip-text {
    font-size: 13.5px;
    line-height: 1.62;
    color: #333a57;
  }

  /* The Insights self-reference line (js/thermii-insights-hint.js) — bolder and
     in the Insights accent purple so it reads as a cue about the toggle rather
     than as more body copy. #6c4bd8 is the same purple the panel's title marks
     and the Continue button use; 6.0:1 on the tip's #f6f4ff ground, so it
     clears AA. Scoped under .thermii-tip-text at (0,3,0) so nothing out-specs
     it, and it is a <strong> so it stays bold even if the class rule is absent. */
  /* The off-switch nudge is a tinted callout chip — a soft purple-tint box so
     the eye lands on it while it stays in the Insights family (and keeps AA:
     #6c4bd8 on #efeafc is ~5.4:1). display:block turns the <strong> into the
     box; the emoji + text sit inside. */
  body.thermii-skin .thermii-tip-text .thermii-insights-hint {
    color: #6c4bd8;
    font-weight: 600;
    display: block;
    /* Loz, 2026-09-21: a WHITE card on the panel's lilac ground, rather than the
       old pale-purple tint — it lifts off the ground and reads crisper, and the
       purple text is 5.9:1 on white. The white edge separates it from the body
       copy, so the hairline that used to sit above it is gone; a 14px top margin
       gives the gap the separator used to. */
    background: #ffffff;
    border-radius: 10px;
    padding: 10px 12px;
    /* widen so it breaks out of the bubble's left indent and spans the panel —
       left back to the avatar's edge (avatar 34 + gap 14 = 48), right out past
       the tip's 46px right padding to a matching ~20px inset. The tip body copy
       above stays in its column. */
    margin: 14px -26px 0 -48px;
  }

  /* the header's bulb, inline before the text and centred on the first line */
  body.thermii-skin .thermii-tip-text .thermii-insights-bulb {
    width: 22px;
    height: 22px;
    vertical-align: -6px;
    margin-right: 7px;
  }

  /* The separator above the callout — a hairline in the panel's own border
     colour (#e4defb, from .thermii-tip above), so the nudge reads as set apart
     from the tip. Replaces the old <br><br> gap. */

  body.thermii-skin .thermii-skin-insight-chev {
    position: absolute;
    top: 14px;
    right: 14px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: #6f6a8c;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.18s ease;
  }

  body.thermii-skin .thermii-skin-insight-chev:hover {
    background: #ece6ff;
  }

  body.thermii-skin .thermii-tip.is-collapsed .thermii-skin-insight-chev {
    transform: rotate(180deg);
  }

  body.thermii-skin .thermii-tip.is-collapsed .thermii-tip-text {
    display: none;
  }

  /* ── The step action bar ─────────────────────────────────────────────────── */

  /* Back left, Continue right, on a rule that separates the actions from the
     question. Lives inside the step's .eq-section — see the note in
     js/thermii-skin.js on why Continue may not leave the step. */
  /* ONE BLOCK, and it has to be one. This was three separate rules for the same
     selector and the last of them used the `margin` SHORTHAND — `26px auto 0` —
     which reset margin-left/right to auto and beat the bleed margins declared
     above it. The bar centred itself at 116px wide instead of spanning the
     container. Shorthands and longhands for the same property in sibling rules is
     the trap; keeping every margin in one declaration removes it.

     margin-top:auto holds the bar at the bottom of the section's uniform depth.
     The negative left/right open it to the container's edges, and the matching
     padding puts its contents back on the content column. */
  /* THE VISIBLE STEP MUST NOT CLIP, or the sticky bar cannot stick. thermii.css
     :1232 gives every .eq-step `overflow: hidden` with `max-height: 0` — that pair
     is the progressive reveal, and the hidden overflow is what keeps a collapsed
     step's content out of sight. It also makes the step the bar's clipping
     ancestor, and a clipping ancestor is the sticky containing block, so the bar
     stayed put where it was rather than holding to the bottom of the view.

     Only the VISIBLE step is unclipped, so every collapsed step keeps its
     overflow:hidden and the reveal still works. */
  body.thermii-skin .eq-step.eq-visible {
    overflow: visible;
  }

  /* THE CARD'S BOTTOM CORNERS. The wrapper is rounded 22px but has to be
     `overflow: visible` for sticky to work at all (see .kb-wrapper), so a bar
     that bleeds to both edges paints its own square corners straight over the
     rounded ones — which is exactly what Loz spotted at the bottom left.

     Rounding the bar instead of clipping the card. It costs nothing while the bar
     is stuck mid-scroll either: what shows through the corners there is the white
     card behind it, not the gradient. */
  body.thermii-skin .thermii-skin-actionbar,
  body.thermii-skin .thermii-version-footer,
  body.thermii-skin .thermii-confirm-footer:not(.thermii-skin-emptied) {
    border-bottom-left-radius: var(--thermii-card-radius, 22px);
    border-bottom-right-radius: var(--thermii-card-radius, 22px);
  }

  body.thermii-skin .thermii-skin-actionbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin: auto calc(-1 * var(--thermii-bleed, 0px)) 0;
    padding: 18px var(--thermii-bar-inset, 35px);
    border-top: 1px solid #ecedf3;
    position: sticky;
    bottom: 0;
    background: #fff;
    z-index: 6;
  }

  /* THE BAR MUST NOT INHERIT THE OLD WRAPPER'S DIVIDER. thermii-system.css:1017
     dresses `div:has(> #wAreaNext)` (and the other five) as the mid-card divider
     those buttons used to sit above — width 100%, margin 34px 0 0, padding
     22px 0 0, border-top. With the buttons claimed into the action bar, the BAR
     is now the div that :has them, and the ID inside :has() out-ranks
     `body.thermii-skin .thermii-skin-actionbar` (1,0,1 vs 0,2,1) — which zeroed
     the bar's negative bleed margins and held its rule 45px off each edge on the
     four measurement screens. Loz spotted the line stopping short.

     Same :has selectors, so it cannot lose the same fight, and the skin loads
     last. Everything the offender sets is restated to the bar's own values —
     width included: 100% plus negative margins shifts the box instead of
     widening it, leaving the border 2x the bleed short on the right. */
  body.thermii-skin .thermii-skin-actionbar:has(> #wAreaNext),
  body.thermii-skin .thermii-skin-actionbar:has(> #wManifoldDistNext),
  body.thermii-skin .thermii-skin-actionbar:has(> #totalAreaNext),
  body.thermii-skin .thermii-skin-actionbar:has(> #heatedAreaNext),
  body.thermii-skin .thermii-skin-actionbar:has(> #wInstallConfirmBtn),
  body.thermii-skin .thermii-skin-actionbar:has(> #wSpacingConfirmBtn) {
    width: auto;
    align-self: auto;
    margin: auto calc(-1 * var(--thermii-bleed, 0px)) 0;
    padding: 18px var(--thermii-bar-inset, 35px);
    border-top: 1px solid #ecedf3;
  }

  /* Inside the bar they stop being standalone CTAs: `width: fit-content` with
     `margin-left: auto` pushed them to the right of their own row, which is the
     bar's job now (space-between). ID-scoped for the same specificity reason. */
  body.thermii-skin .thermii-skin-actionbar #wAreaNext,
  body.thermii-skin .thermii-skin-actionbar #wManifoldDistNext,
  body.thermii-skin .thermii-skin-actionbar #totalAreaNext,
  body.thermii-skin .thermii-skin-actionbar #heatedAreaNext,
  body.thermii-skin .thermii-skin-actionbar #wInstallConfirmBtn,
  body.thermii-skin .thermii-skin-actionbar #wSpacingConfirmBtn {
    width: auto;
    margin-left: 0;
  }

  /* And they follow the bar's rule: no Continue until you can use it. The four
     measurement buttons gate with `disabled` where the tile screens gate with
     the gate class, so this is the same behaviour keyed off the same truth
     rather than a dimmed button that cannot be pressed. thermii-system.css:988
     fades them to .45 for the mid-card life they no longer have. */
  /* DISABLED AND EXPLAINED, NOT HIDDEN (2026-08-28). These four used to
     vanish until the field validated. On a tile screen that works — the tile
     you just pressed is what summons the button — but here nothing has been
     pressed, so a control appearing from nowhere is easy to miss. It now sits
     there, visibly not ready, next to a line saying what it is waiting for. */
  body.thermii-skin .thermii-skin-actionbar #wAreaNext:disabled,
  body.thermii-skin .thermii-skin-actionbar #wRoomAreaContinue:disabled,
  body.thermii-skin .thermii-skin-actionbar #wManifoldDistNext:disabled,
  body.thermii-skin .thermii-skin-actionbar #totalAreaNext:disabled,
  body.thermii-skin .thermii-skin-actionbar #heatedAreaNext:disabled {
    background: #e9eaf1;
    color: #9aa1b7;
    box-shadow: none;
    cursor: not-allowed;
  }

  body.thermii-skin .thermii-skin-hint {
    display: none;
    margin-right: 12px;
    color: #8a92ad;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    font-weight: var(--thermii-font-weight-light, 300);
    order: 1;
  }

  body.thermii-skin .thermii-skin-hint.is-on { display: inline; }

  @media screen and (max-width: 700px) {
    /* the button is the message on a phone — the bar has no room for both */
    body.thermii-skin .thermii-skin-hint { display: none !important; }
  }

  /* ── "No thermostat" as a card in the row ──────────────────────────────────

     Same box as its neighbours (it inherits .thermostat-card). Restyled to
     Loz's design (2026-09-23): a plain white card with a soft lilac border and
     a gentle rest shadow, the grey circle-slash mark centred over a bold
     two-line "No Thermostat Required". The old dashed-grey tint and the
     "I already have one…" sub-line are gone. */
  body.thermii-skin .thermii-tstat-none {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 22px;
    padding: 24px 20px;
    border: 1px solid #dcd3f4;
    border-radius: 24px;
    background: #fff;
    box-shadow: 0 4px 20px rgba(74, 46, 139, 0.06);
    color: #5a6077;
    font-family: 'Poppins', sans-serif;
    text-align: center;
    cursor: pointer;
    transition: border-color 0.16s ease, background 0.16s ease,
                transform 0.16s ease, box-shadow 0.16s ease;
  }

  body.thermii-skin .thermii-tstat-none:hover {
    transform: translateY(-2px);
    border-color: #bba8fb;
    box-shadow: 0 12px 28px rgba(66, 42, 139, 0.12);
  }

  body.thermii-skin .thermii-tstat-none svg {
    width: 56px;
    height: 56px;
    color: #a0a6b8;
    flex-shrink: 0;
    opacity: 1;
  }

  body.thermii-skin .thermii-tstat-none-label {
    max-width: 220px;
    /* PURE BLACK, Loz's call (2026-09-23) — matching his mock exactly. The rest
       of the app's titles are var(--navy) (#101735, a near-black with a faint
       blue cast); he wanted this one true black, so it is the one #000 title. */
    color: #000;
    /* EXACTLY the sibling .thermostat-name titles' size and weight (Loz,
       2026-09-23). Those render at var(--t-h4) (16px) / 500 — thermii-system.css
       wins the size over journey's 17px — so the earlier 18px/400 never matched;
       this now does. Colour stays #000 (his mock); weight/size only. */
    font-size: var(--t-h4);
    font-weight: 500;
    line-height: 1.25;
  }

  /* ── Decision-critical text (2026-08-28) ───────────────────────────────────

     The thermostat descriptions were 11px — the smallest type on the page,
     and the only thing separating a 29.99 dial from a 74.99 smart stat. The
     insight panel, the one piece of expert guidance, sat at the same weight
     as body copy. Both were the wrong way round for a screen where someone is
     comparing. */
  body.thermii-skin .thermostat-desc {
    font-size: 13px;
    line-height: 1.5;
    color: #545b70;
  }

  body.thermii-skin .thermii-skin-insight-title {
    /* Loz, 2026-09-21: larger, and centred against the 34px avatar/mascot. The
       title is the first line of the bubble (a flex sibling of the avatar,
       top-aligned), so a line-height equal to the avatar's height makes the
       title text's centre sit on the avatar's centre. Applies to every
       Insight panel. The gap to the body copy closed 9px -> 3px (Loz,
       2026-09-28: "close the gap slightly"); the 34px line box, which is
       what centres the title on the mascot, is untouched. */
    font-size: 17px;
    line-height: 34px;
    letter-spacing: -0.005em;
    margin-bottom: 3px;
  }

  /* TEXT-LINK BUTTONS GET A 24px TAP TARGET (mobile sweep, 2026-09-25).
     "Not sure which to choose?", "Unsure?", "See an example of perimeter…" and
     "Need help calculating heated area?", "How is this calculated?" (15px),
     "Estimate your running costs" and "Show all details" measured 15-19px
     tall — under WCAG 2.2's
     24px minimum (2.5.8). A transparent ::after reaching 5px above and below
     widens what a finger can hit WITHOUT moving a pixel of layout: the links'
     spacing comes from several margin rules, which are left alone. */
  body.thermii-skin .thermii-how-more,
  body.thermii-skin .eq-unsure-link,
  body.thermii-skin .eq-help-link,
  body.thermii-skin .wkit-heat-calcbtn,
  body.thermii-skin .wkit-heat-runcost button,
  body.thermii-skin .thermii-review-all {
    position: relative;
  }
  body.thermii-skin .eq-unsure-link::after,
  body.thermii-skin .eq-help-link::after,
  body.thermii-skin .wkit-heat-calcbtn::after,
  body.thermii-skin .wkit-heat-runcost button::after,
  body.thermii-skin .thermii-review-all::after,
  body.thermii-skin .thermii-how-more::after {
    content: "";
    position: absolute;
    left: 0; right: 0; top: -5px; bottom: -5px;
  }

  /* RANGED LEFT ON "HELP ME CHOOSE" TOO (Loz, 2026-09-25). This panel sits
     inside .unsure-card, which css/thermii.css (byte-locked) centres —
     `.unsure-card { text-align: center }` — and the panel's title and body
     inherited it, the one Insights panel on the site set centred. The card's
     own copy stays centred; only the panel is put back on the left. */
  body.thermii-skin .unsure-card .thermii-tip {
    text-align: left;
  }

  body.thermii-skin .thermii-tip-text {
    font-size: 14.5px;
    line-height: 1.6;
    /* Loz, 2026-09-21: match the glossary dropdown's body copy — the SAME token
       (.eq-note uses var(--journey-muted)), so the two helper surfaces share one
       grey and cannot drift. #596584 is 4.95:1 on the panel's #f6f4ff — AA. */
    color: var(--journey-muted, #596584);
    /* match Thermii's other body copy (.eq-subtext/.eq-note are 300) — the tip
       inherited the body default 400 and so read slightly bolder. <strong> and
       the .thermii-insights-hint callout keep their own heavier weight. */
    font-weight: var(--thermii-font-weight-light);
  }

  /* CONTINUE IS HIDDEN UNTIL THE GATE ARMS, and the gate says so itself:
     setGate (thermii-gate.js:132) toggles `thermii-gate-open` on .eq-section,
     which is this bar's parent. So the button's visibility needs no JavaScript of
     its own and cannot drift from the gate's real state. */
  body.thermii-skin .thermii-skin-actionbar .thermii-step-continue {
    display: none;
  }

  body.thermii-skin .thermii-gate-open .thermii-skin-actionbar .thermii-step-continue,
  body.thermii-skin .eq-section.thermii-gate-open .thermii-skin-actionbar .thermii-step-continue {
    display: inline-flex;
  }

  /* Back sits left even before Continue exists. The System footer's Back is in
     the same list: that footer is justify-content flex-end from journey.css, so
     without this its Back would sit against Continue on the right. */
  body.thermii-skin .thermii-skin-actionbar .eq-back-btn,
  body.thermii-skin .thermii-confirm-footer .eq-back-btn {
    margin-right: auto;
  }

  /* Only the footer whose button we actually took — marked by the JS. Selecting
     it structurally guessed the wrong parent (the gate appends to
     .eq-question-full, not .eq-section) and left an empty footer holding space. */
  /* Not always a footer: the measurement buttons sit in a bare <div> that draws
     the mid-card divider above them (border-top, 34px margin, 22px padding), and
     that has to go with the button. The JS only marks a wrapper it actually
     emptied, so this cannot take a container that still holds something. */
  body.thermii-skin .thermii-skin-emptied {
    display: none !important;
  }

  /* ── The Save & Exit modal ────────────────────────────────────────────────

     Loz's design, 2026-08-27. Everything below the scrim is skin-built
     (js/thermii-skin.js wireSaveExitModal); the gradient button is the one
     place the BRAND gradient is used on an action, because the design shows it
     there — the journey's Continue stays the flat purple. */
  body.thermii-skin .thermii-skin-modal-scrim {
    position: fixed;
    inset: 0;
    z-index: 200;                 /* above the sticky header's 40 */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(15, 17, 35, 0.45);
  }

  body.thermii-skin .thermii-skin-modal {
    position: relative;
    width: 100%;
    max-width: 560px;
    padding: 44px 44px 26px;
    background: #fff;
    border-radius: 20px;
    box-shadow: 0 24px 70px rgba(16, 24, 40, 0.28);
    text-align: center;
    box-sizing: border-box;
  }

  body.thermii-skin .thermii-skin-modal-close {
    position: absolute;
    top: 16px;
    right: 16px;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 9px;
    background: transparent;
    color: #6f7387;
    cursor: pointer;
  }

  body.thermii-skin .thermii-skin-modal-close:hover {
    background: #f4f5f9;
  }

  /* NO UA FOCUS RING ON POINTER FOCUS (Loz, with screenshots: Safari boxed the
     X in blue on open and the Help icon on close). :focus-visible keeps a ring
     for keyboard users — the app's own quiet one from components.css:425 — and
     the dialog itself never shows one: it takes programmatic focus (tabindex -1)
     purely as the Escape/Tab starting point. */
  body.thermii-skin .thermii-skin-modal:focus,
  body.thermii-skin .thermii-skin-modal-close:focus:not(:focus-visible),
  body.thermii-skin .thermii-skin-help:focus:not(:focus-visible),
  body.thermii-skin .thermii-skin-projects:focus:not(:focus-visible),
  body.thermii-skin .thermii-skin-insights:focus:not(:focus-visible),
  body.thermii-skin .thermii-skin-theme:focus:not(:focus-visible),
  body.thermii-skin .thermii-skin-modal-save:focus:not(:focus-visible),
  body.thermii-skin .thermii-skin-modal-continue:focus:not(:focus-visible),
  body.thermii-skin .thermii-skin-modal-discard:focus:not(:focus-visible) {
    outline: none;
  }

  body.thermii-skin .thermii-skin-modal-close:focus-visible,
  body.thermii-skin .thermii-skin-help:focus-visible,
  body.thermii-skin .thermii-skin-projects:focus-visible,
  body.thermii-skin .thermii-skin-insights:focus-visible,
  body.thermii-skin .thermii-skin-theme:focus-visible,
  body.thermii-skin .thermii-skin-modal-save:focus-visible,
  body.thermii-skin .thermii-skin-modal-continue:focus-visible,
  body.thermii-skin .thermii-skin-modal-discard:focus-visible {
    outline: 2px solid #7138ed;
    outline-offset: 2px;
  }

  body.thermii-skin .thermii-skin-modal-icondisc {
    display: grid;
    place-items: center;
    width: 72px;
    height: 72px;
    margin: 0 auto 18px;
    border-radius: 50%;
    background: #f0ebff;
    color: #6c4bd8;
  }

  body.thermii-skin .thermii-skin-modal-title {
    margin: 0 0 10px;
    font-family: 'Sora', 'Poppins', sans-serif;
    font-size: 24px;
    font-weight: 700;
    color: #1b2140;
  }

  body.thermii-skin .thermii-skin-modal-sub {
    max-width: 360px;
    margin: 0 auto 24px;
    font-size: 15px;
    /* Loz, 2026-09-23: the light token, so every popup's body copy matches the
       journey's own body text (.eq-subtext is 300) instead of the browser's
       default 400. */
    font-weight: var(--thermii-font-weight-light, 300);
    line-height: 1.55;
    color: #5d6378;
  }

  /* THE REFERENCE FIELD (Loz, 2026-09-14). Left-ranged like the progress card
     beneath it, the card's own hairline and a 10px radius (the modal's note
     box and nav items use 10; only the card is 14). The hint is his wording,
     greyed: #8a90a6 is 3.6:1 on white — a placeholder is a hint, not the
     value, and it disappears the moment the value exists. Focus takes the
     Continue purple with the soft ring the skin's inputs already wear. */
  body.thermii-skin .thermii-skin-modal-field {
    /* last block before the buttons, so it takes the 24px the card used to;
       the card above it closes to 18 */
    margin: 0 0 24px;
    text-align: left;
  }

  body.thermii-skin .thermii-skin-modal-field-label {
    display: block;
  }

  body.thermii-skin .thermii-skin-modal-field-text {
    display: block;
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    font-weight: 600;
    color: #1b2140;
  }

  body.thermii-skin .thermii-skin-modal-field-input {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin-top: 8px;
    /* Loz, 2026-09-23: a touch deeper — 14px vertical, up from 11px */
    padding: 14px;
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    color: #1b2140;
    background: #fff;
    border: 1px solid #e4e6ef;
    border-radius: 10px;
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
  }

  /* 16px ON TOUCH SCREENS (mobile sweep, 2026-09-25): iOS Safari zooms the
     whole page into any field under 16px when it is focused, and this was the
     one input in Thermii at 14px. Desktop keeps the design's 14px. */
  @media (hover: none) and (pointer: coarse) {
    body.thermii-skin .thermii-skin-modal-field-input { font-size: 16px; }
  }

  body.thermii-skin .thermii-skin-modal-field-input::placeholder {
    color: #8a90a6;
    opacity: 1;
  }

  body.thermii-skin .thermii-skin-modal-field-input:focus {
    border-color: #6c4bd8;
    box-shadow: 0 0 0 3px rgba(108, 75, 216, 0.15);
  }

  body.thermii-skin .thermii-skin-modal-progress {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0 0 24px;
    padding: 18px 20px;
    border: 1px solid #e4e6ef;
    border-radius: 14px;
    text-align: left;
  }

  /* with the reference field beneath it, the card closes up to 18px */
  body.thermii-skin .thermii-skin-modal-progress:has(+ .thermii-skin-modal-field) {
    margin-bottom: 18px;
  }

  body.thermii-skin .thermii-skin-modal-progress-title {
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    font-weight: 600;
    color: #1b2140;
  }

  body.thermii-skin .thermii-skin-modal-progress-step,
  body.thermii-skin .thermii-skin-modal-progress-saved {
    font-size: 14px;
    color: #5d6378;
  }

  /* Flex, not inline + vertical-align: the disc sat visibly high of the text's
     middle (Loz, 2026-08-27) because -3px was tuned by eye against one font
     size. align-items centres the two boxes on the same axis at any size. */
  body.thermii-skin .thermii-skin-modal-progress-saved {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  /* the green confirmation disc, drawn — a tick glyph would ride on the line */
  body.thermii-skin .thermii-skin-modal-progress-saved::before {
    content: '\2713';
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #74b700;
    color: #fff;
    font-size: 10px;
    font-weight: 700;
  }

  /* not saved yet: the disc goes quiet grey rather than lying in green */
  body.thermii-skin .thermii-skin-modal-progress-saved:not(.is-saved)::before {
    content: '\2022';
    background: #c6cad9;
  }

  body.thermii-skin .thermii-skin-modal-actions {
    display: flex;
    gap: 14px;
  }

  /* the Help modal's CTAs are the "Help me choose" section's own 310px pills
     (thermii.css:1573) — two of those cannot sit side by side in a 560px card,
     so they stack, centred, exactly as wide as they are everywhere else */
  /* CENTRED, NOT STRETCHED. This class is shared with the Help dialog, whose
     buttons (.unsure-quote-btn / .unsure-phone-btn) carry their own width —
     so `stretch` did not widen them, it just stopped centring them and left
     them sitting off to one side (Loz spotted it). Centring works for both:
     the Save & Exit pair below asks for the full width explicitly, and a
     100%-wide child is centred by definition. */
  body.thermii-skin .thermii-skin-modal-actions-stacked {
    flex-direction: column;
    align-items: center;
    gap: 12px;
  }

  /* Loz, 2026-09-23: a bit more breathing room beneath the Call Us button in
     the Help popup. Scoped by the phone button, which only the Help modal's
     stacked actions carry (Save & Exit's stacked actions hold the gradient
     save/continue pair), so the Save & Exit dialog is untouched. */
  body.thermii-skin .thermii-skin-modal-actions-stacked > .unsure-phone-btn {
    margin-bottom: 12px;
  }

  /* full width when stacked — a centred pill in a column reads as adrift */
  body.thermii-skin .thermii-skin-modal-actions-stacked
    > .thermii-skin-modal-save,
  body.thermii-skin .thermii-skin-modal-actions-stacked
    > .thermii-skin-modal-continue {
    width: 100%;
    flex: 0 0 auto;
  }

  /* Continue's exact metrics (components.css:408 — 54px, 13px radius): the
     dialog buttons sat 2px shallower on a 12px radius, and Loz clocked it. */
  body.thermii-skin .thermii-skin-modal-save,
  body.thermii-skin .thermii-skin-modal-continue {
    flex: 1 1 0%;
    min-height: 54px;
    padding: 12px 18px;
    border-radius: 13px;
    font-family: 'Poppins', sans-serif;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
  }

  body.thermii-skin .thermii-skin-modal-save {
    border: 0;
    background: var(--thermii-gradient);
    color: #fff;
    box-shadow: 0 10px 22px rgba(113, 56, 237, 0.2);
  }

  body.thermii-skin .thermii-skin-modal-save:hover {
    filter: saturate(1.1) brightness(1.03);
  }

  body.thermii-skin .thermii-skin-modal-continue {
    border: 1px solid #d9dce8;
    background: #fff;
    color: #1b2140;
  }

  body.thermii-skin .thermii-skin-modal-continue:hover {
    background: #f4f5f9;
  }

  body.thermii-skin .thermii-skin-modal-discard {
    margin-top: 18px;
    padding: 4px 6px;
    border: 0;
    background: none;
    color: #6c4bd8;
    font-family: 'Poppins', sans-serif;
    font-size: 14px;
    font-weight: 500;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
  }

  /* ── "How Does Thermii™ Work?" — the tabbed popup ─────────────────────────

     Loz, 2026-09-02, with a design. Everything structural is INHERITED from
     .thermii-skin-modal above — scrim, card, shadow, radius, close button and
     its focus rules — so this section adds only what those three single-column
     modals do not have: a wider card, a left-aligned body and a tablist beside
     a panel. Same approach js/thermii-project-strip.js's confirm took. */
  body.thermii-skin .thermii-how-modal {
    max-width: 760px;
    padding: 30px 30px 22px;
    text-align: left;               /* the shared card centres; this one reads */
  }

  /* THE TITLE'S RULE IS THE DESIGN'S HORIZONTAL LINE (Loz, 2026-09-02: "we are
     missing the lines"). It has to span the whole card, so the gap for the
     close button is PADDING rather than the margin it used to be — a
     margin-right would have stopped the border 34px short of the right edge,
     which is exactly the half-width rule that reads as a mistake. */
  body.thermii-skin .thermii-how-title {
    margin: 0 0 18px;
    padding: 0 34px 14px 0;         /* clear of the close button */
    border-bottom: 1px solid var(--thermii-border, #e4e7ef);
    font-family: 'Sora', 'Poppins', sans-serif;
    font-size: 21px;
    font-weight: var(--thermii-font-weight-display, 600);
    color: #1b2140;
  }

  body.thermii-skin .thermii-how-body {
    display: grid;
    /* 193px, measured rather than guessed: "Need More Help?" needs 164px on one
       line at the ACTIVE weight (116px of text plus the icon, gap and padding),
       and the design has it on one line. 158px wrapped it.
       WAS 172px, AND THE RULE BROKE IT: adding the nav's 20px padding-right and
       1px border-right left the items only 151px and "Need More Help?" wrapped
       to two lines. The column has to carry the divider's own width on top of
       the text's — 172 + 20 + 1. Caught on screen, not by reading. */
    grid-template-columns: 193px minmax(0, 1fr);
    gap: 22px;
    align-items: stretch;           /* so the nav's rule runs the pane's depth */
  }

  /* AND THE NAV'S RIGHT EDGE IS THE DESIGN'S VERTICAL LINE. It is on the nav
     rather than a separate element so it needs no markup, and `align-items:
     stretch` above is what makes it run the full depth of the taller column
     instead of stopping at the last tab. Cleared on a phone, where the nav
     becomes a horizontal row. */
  body.thermii-skin .thermii-how-nav {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding-right: 20px;
    border-right: 1px solid var(--thermii-border, #e4e7ef);
  }

  body.thermii-skin .thermii-how-nav-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 11px;
    border: 0;
    border-radius: 10px;
    background: none;
    color: #5d6378;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    font-weight: 500;
    text-align: left;
    line-height: 1.3;
    cursor: pointer;
  }

  body.thermii-skin .thermii-how-nav-item > svg { flex: 0 0 auto; }

  body.thermii-skin .thermii-how-nav-item:hover {
    background: #f4f5f9;
    color: #1b2140;
  }

  /* the design's lilac pill — a tint of --thermii-purple, not a new colour */
  body.thermii-skin .thermii-how-nav-item.is-active,
  body.thermii-skin .thermii-how-nav-item.is-active:hover {
    background: rgba(113, 56, 237, 0.09);
    color: #6c4bd8;
    font-weight: 600;
  }

  body.thermii-skin .thermii-how-pane {
    min-height: 232px;
  }

  body.thermii-skin .thermii-how-pane:focus:not(:focus-visible) {
    outline: none;
  }

  /* Weights come from the tokens, never a hard-coded number — CLAUDE.md's
     typography rule. Loz asked to take the headers and subtext down
     (2026-09-02); the headers were 700 against the brand's 600 headline weight,
     so this also brings the popup back onto the supplied spec. */
  body.thermii-skin .thermii-how-pane-title {
    margin: 0 0 5px;
    font-family: 'Sora', 'Poppins', sans-serif;
    font-size: 17px;
    font-weight: var(--thermii-font-weight-display, 600);
    color: #1b2140;
  }

  body.thermii-skin .thermii-how-pane-sub {
    margin: 0 0 16px;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    /* the spec's subtext role, 300 — it was inheriting 400 */
    font-weight: var(--thermii-font-weight-light, 300);
    line-height: 1.55;
    color: #5d6378;
  }

  /* The numbered steps, with the design's connecting line. The line is drawn on
     the marker rather than the item so it cannot outrun the last step. */
  /* Loz's restyled Process screen (2026-09-23): the numbered circles are larger
     and nudged in from the pane's left edge. */
  body.thermii-skin .thermii-how-steps {
    margin: 0;
    padding: 0 0 0 12px;
    list-style: none;
    counter-reset: thermii-how-step;
  }

  body.thermii-skin .thermii-how-steps > li {
    position: relative;
    display: flex;
    align-items: center;
    gap: 15px;
    padding: 0 0 20px;
  }

  body.thermii-skin .thermii-how-steps > li:last-child { padding-bottom: 0; }

  body.thermii-skin .thermii-how-step-n {
    counter-increment: thermii-how-step;
    position: relative;
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--thermii-purple, #7138ed);
    color: #fff;
    font-family: 'Poppins', sans-serif;
    font-size: 18px;
    font-weight: 600;
    line-height: 1;
  }

  body.thermii-skin .thermii-how-step-n::before {
    content: counter(thermii-how-step);
  }

  /* THE DESIGN'S VERTICAL CONNECTOR. It existed before Loz said "we are missing
     the lines" — at 1.5px and 28% alpha it was simply too faint to see, which
     is the same thing as missing. The design draws it as a clear purple rail,
     so it is 2px at 55%. */
  body.thermii-skin .thermii-how-steps > li:not(:last-child)
    .thermii-how-step-n::after {
    content: '';
    position: absolute;
    top: 36px;
    left: 50%;
    width: 2px;
    height: 20px;
    transform: translateX(-50%);
    background: rgba(113, 56, 237, 0.55);
  }

  body.thermii-skin .thermii-how-step-t {
    font-family: 'Poppins', sans-serif;
    font-size: 16px;
    font-weight: 500;
    color: #1b2140;
    line-height: 1.4;
  }

  body.thermii-skin .thermii-how-bullets {
    margin: 0;
    padding: 0 0 0 17px;
    list-style: disc;
  }

  body.thermii-skin .thermii-how-bullets > li {
    margin: 0 0 8px;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    /* the light body-copy weight, matching the pane subtext and the journey */
    font-weight: var(--thermii-font-weight-light, 300);
    line-height: 1.55;
    color: #40465f;
  }

  body.thermii-skin .thermii-how-bullets > li::marker {
    color: rgba(113, 56, 237, 0.55);
  }

  body.thermii-skin .thermii-how-note {
    margin-top: 16px;
    padding: 11px 13px;
    border: 1px solid var(--thermii-border, #e4e7ef);
    border-radius: 10px;
    background: var(--thermii-surface-soft, #f8f9fc);
    font-family: 'Poppins', sans-serif;
    font-size: 12.5px;
    font-weight: var(--thermii-font-weight-light, 300);
    line-height: 1.55;
    color: #5d6378;
  }

  body.thermii-skin .thermii-how-contact {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 16px;
  }

  /* ROUNDED RECTANGLES, NOT PILLS (Loz, 2026-09-02). 10px is the popup's own
     rounded-rect radius, already on .thermii-how-note and .thermii-how-nav-item,
     so these two stop being the only pill-shaped things inside the card. The
     "Got it" pill keeps its shape deliberately: it is the primary action and the
     one control that should not look like the others. */
  body.thermii-skin .thermii-how-contact-btn {
    display: inline-flex;
    align-items: center;
    height: 38px;
    padding: 0 18px;
    border: 1.5px solid var(--thermii-purple, #7138ed);
    /* 8px, down from 10 (Loz, 2026-09-02: "reduce the corner radius slightly").
       The note box and the nav items stay at 10, so these two now read a touch
       crisper than the panels around them — which is the point. */
    border-radius: 8px;
    background: var(--thermii-purple, #7138ed);
    color: #fff;
    font-family: 'Poppins', sans-serif;
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
  }

  body.thermii-skin .thermii-how-contact-btn.is-secondary {
    background: #fff;
    color: #6c4bd8;
  }

  body.thermii-skin .thermii-how-foot {
    display: flex;
    align-items: center;
    /* flex-end plus an auto margin on the link, NOT space-between: the link is
       not rendered at all when no opener carries a usable href, and
       space-between would then push the lone "Got it" to the LEFT. One auto
       margin absorbs free space; it is not the `margin: 0 auto` PAIR that
       shrinks a flex item to fit, which is the trap recorded for the summary
       card in journey.css. */
    justify-content: flex-end;
    gap: 14px;
    margin-top: 22px;
  }

  body.thermii-skin .thermii-how-more {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-right: auto;
    color: #6c4bd8;
    font-family: 'Poppins', sans-serif;
    font-size: 13.5px;
    font-weight: 500;
    text-decoration: underline;
    text-underline-offset: 3px;
    white-space: nowrap;
  }

  body.thermii-skin .thermii-how-more:hover { color: #4d2fb0; }

  body.thermii-skin .thermii-how-more > svg { flex: 0 0 auto; }

  /* the accessible-only half of the link's name — same idiom as
     .thermii-guide-status in css/thermii-spark.css */
  body.thermii-skin .thermii-how-vh {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    border: 0;
    white-space: nowrap;
  }

  /* The design's purple-to-pink pill. Both stops are the brand's own tokens —
     --thermii-purple and --thermii-magenta, the middle and end of
     --thermii-gradient — rather than sampled from the mockup. */
  body.thermii-skin .thermii-how-got {
    min-width: 132px;
    height: 42px;
    padding: 0 26px;
    border: 0;
    border-radius: 50px;
    background: linear-gradient(90deg, var(--thermii-purple, #7138ed),
                                       var(--thermii-magenta, #d414c4));
    color: #fff;
    font-family: 'Poppins', sans-serif;
    font-size: 14.5px;
    font-weight: 600;
    cursor: pointer;
  }

  body.thermii-skin .thermii-how-got:hover { filter: brightness(1.06); }

  /* Narrow: the nav goes above the panel as a scrolling row, because a 172px
     column beside a panel does not fit a phone and the design has no landscape
     for one. */
  @media (max-width: 620px) {
    body.thermii-skin .thermii-how-modal {
      padding: 26px 20px 18px;
    }

    body.thermii-skin .thermii-how-body {
      grid-template-columns: minmax(0, 1fr);
      gap: 16px;
    }

    body.thermii-skin .thermii-how-nav {
      flex-direction: row;
      gap: 6px;
      overflow-x: auto;
      /* the rule belongs beside a column, not above a row */
      padding-right: 0;
      border-right: 0;
      border-bottom: 1px solid var(--thermii-border, #e4e7ef);
      padding-bottom: 8px;            /* was 4px, before the rule was under it */
      -webkit-overflow-scrolling: touch;
    }

    body.thermii-skin .thermii-how-nav-item {
      flex: 0 0 auto;
      padding: 8px 12px;
    }

    body.thermii-skin .thermii-how-pane { min-height: 0; }

    /* column-REVERSE so "Got it" stays the first thing a thumb reaches and the
       secondary link sits under it, rather than above the primary action */
    body.thermii-skin .thermii-how-foot {
      flex-direction: column-reverse;
      align-items: stretch;
      gap: 12px;
    }

    body.thermii-skin .thermii-how-got { width: 100%; }

    body.thermii-skin .thermii-how-more {
      justify-content: center;
      margin-right: 0;            /* the auto margin has no job in a column */
    }
  }


  /* ── The version line, now below the container ───────────────────────────── */

  /* js/thermii-skin.js moves this out of .kb-wrapper (see the note there — the
     wrapper's overflow:hidden makes it a node move rather than a margin). It now
     sits on the aurora, so it needs its own breathing room and a tone that reads
     against a light, shifting gradient rather than against white. */
  body.thermii-skin .kb-version {
    margin-top: 0;
    padding: 0 0 26px;
    font-size: 11px;
    color: #6a6f85;
    letter-spacing: 0.02em;
    text-align: center;
  }

  /* ── Purple Continue ────────────────────────────────────────────────────── */

  /* The six forward buttons are dressed as standalone primaries by
     css/thermii-system.css:948 — in the BRAND gradient (blue → purple → magenta)
     and ID-scoped, so a class rule cannot reach them. Named here so they take the
     same purple as every other advance, which is what Loz asked for. Measured
     against a real Continue first: background, shadow, width and margin were the
     only four properties that differed. */
  body.thermii-skin .thermii-continue,
  body.thermii-skin .thermii-step-continue,
  body.thermii-skin #wAreaNext,
  body.thermii-skin #wManifoldDistNext,
  body.thermii-skin #totalAreaNext,
  body.thermii-skin #heatedAreaNext,
  body.thermii-skin #wInstallConfirmBtn,
  body.thermii-skin #wSpacingConfirmBtn,
  body.thermii-skin #wOtherRoomNext {
    background: linear-gradient(135deg, #7b4ee0 0%, #6c4bd8 55%, #8b5cf6 100%);
    border: 0;
    color: #fff;
    box-shadow: 0 2px 10px rgba(108, 75, 216, 0.32);
  }

  body.thermii-skin .thermii-continue:hover,
  body.thermii-skin .thermii-step-continue:hover,
  body.thermii-skin #wAreaNext:hover,
  body.thermii-skin #wManifoldDistNext:hover,
  body.thermii-skin #totalAreaNext:hover,
  body.thermii-skin #heatedAreaNext:hover,
  body.thermii-skin #wInstallConfirmBtn:hover,
  body.thermii-skin #wSpacingConfirmBtn:hover,
  body.thermii-skin #wOtherRoomNext:hover {
    filter: brightness(1.06);
    box-shadow: 0 4px 16px rgba(108, 75, 216, 0.40);
  }
}

/* ── Below 1150px: the skin's labels go before the header does ─────────── */

/* Six actions with labels — Home, Help, Insights, Restart, Save & Exit,
   Projects — take 604px, and the progress slot between them and the logo is
   what gives: at 1024px it measured 78px with a 200px nowrap row inside it,
   painting across the wordmark and the Home button (review, 2026-09-11; iPad
   landscape is exactly this width, and Loz's own window is wide enough never
   to show it). Shedding the two skin labels here recovers ~130px, so the slot
   holds the longest row from ~1014px up; the clamp on .thermii-stage-summary
   covers the last hundred pixels down to the 900px wrap. Restart and Save &
   Exit keep their labels until the engine's own rule sheds them. */
/* HELP'S WORD GOES FIRST, at 1170px (2026-09-28). Measured with the longest
   stage titles ("Measurements", "Floor covering", "Install method" · Stage n of
   9): with Help labelled they need 205-209px and the slot is 201 at 1151, so
   they ellipsised between 1151 and ~1158. Shedding Help's word 20px before the
   other two keeps every title whole with a margin. Icon-only again, it takes
   back the squarer box it always had as one. */
@media screen and (max-width: 1170px) {
  body.thermii-skin .thermii-shell-actions .thermii-skin-help span { display: none; }
  body.thermii-skin .thermii-shell-actions .thermii-skin-help { padding: 0 10px; }
  body.thermii-skin .thermii-shell-actions .thermii-skin-help::after { left: 11px; }
}

@media screen and (max-width: 1150px) {
  body.thermii-skin .thermii-skin-projects span,
  body.thermii-skin .thermii-skin-insights span {
    display: none;
  }

  /* the account keeps its icon and Trade badge; the name goes with the
     other labels */
  body.thermii-skin .thermii-skin-account-name { display: none; }
  body.thermii-skin .thermii-skin-account-btn { padding: 0 10px; }

  /* and the row's 20px gaps close to 12 — "Stage 5 of 9" (2026-09-14) is
     ~10px wider than "Step 5 of 9" was, which took the longest title back to
     an ellipsis at exactly 1024px; 16px of slack puts it on one line again */
  body.thermii-skin .kb-logo {
    gap: 12px;
  }
}

/* ── Narrow screens ───────────────────────────────────────────────────────── */

@media screen and (max-width: 900px) {
  body.thermii-skin .kb-wrapper {
    width: 100%;
    margin: 0;
    border-radius: 0;
    box-shadow: none;
  }

  body.thermii-skin .kb-logo {
    flex-wrap: wrap;
    gap: 10px;
    padding: 12px 16px;
  }

  /* the pills would be hair-thin at eight segments squeezed beside the logo, so
     the progress drops below the logo row and takes the full width */
  body.thermii-skin .thermii-skin-progress-slot {
    order: 4;
    flex: 1 0 100%;
  }

  /* .thermii-skin-pill / -pillrow used to be targeted here. Those classes belonged
     to the invented pills that were deleted once the engine's own stepper took
     over, so the rules were dead and did nothing. */
  body.thermii-skin .thermii-stage-header {
    max-width: none;
  }

  body.thermii-skin .kb-card,
  body.thermii-skin .kb-card.filter-card {
    padding: 22px 16px 28px;
  }

  body.thermii-skin .thermii-tip {
    padding: 16px 42px 16px 16px;
  }

  /* the header's top corners go square with the card's (see the var note) */
  body.thermii-skin .kb-logo {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
  }

  /* Projects' and Insights' labels are already gone from 1150px down (the
     block above), so the row here is bare icons throughout once the engine's
     own rule takes Restart's and Save & Exit's. */

  /* A flat figure is a screen and a half of empty card on a phone, so the depth
     goes back to following the viewport where the card IS the device. The card
     also loses its radius at this width (.kb-wrapper above), so the bars have to
     lose theirs with it — otherwise they round two corners the card no longer
     has and the page shows through them. */
  body.thermii-skin {
    --thermii-stage-depth: max(490px, calc(100dvh - 142px));
    --thermii-card-radius: 0px;
  }
}

/* ── ONE-ROW HEADER ON A PHONE (Loz, 2026-09-15, prototype) ─────────────────
   Above 700px nothing here applies: the burger is hidden and the panel is
   empty, because thermii-skin.js keeps the four folded controls in the row.
   Below 700px Help, Restart, Save & Exit and Projects live in .thermii-skin-more,
   a dropdown hung off the sticky header, and the row is Home + Insights + the
   burger — which fits beside the wordmark, so the header loses its second band. */
body.thermii-skin .thermii-skin-burger {
  display: none;
  position: relative;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 38px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: #3b4157;
  cursor: pointer;
  transition: color 0.15s ease;
}
body.thermii-skin .thermii-skin-burger:hover { color: #6c4bd8; }
body.thermii-skin .thermii-skin-burger:focus:not(:focus-visible) { outline: none; }
body.thermii-skin .thermii-skin-burger:focus-visible { outline: 2px solid #7138ed; outline-offset: 2px; }
body.thermii-skin .thermii-skin-more { display: none; }
/* Help's label shows in the desktop row too since 2026-09-28 (Loz); it is shed
   from 1170px down, just before the other skin labels (the blocks above). */

@media screen and (max-width: 700px) {
  body.thermii-skin .thermii-skin-burger { display: inline-flex; }
  body.thermii-skin .thermii-skin-more:not([hidden]) {
    display: flex;
    flex-direction: column;
    gap: 2px;
    position: absolute;
    top: 100%;
    right: 12px;
    min-width: 210px;
    padding: 8px;
    background: #fff;
    border: 1px solid #ecedf3;
    border-radius: 12px;
    box-shadow: 0 12px 28px rgba(66, 42, 139, .12);
    z-index: 60;
  }
  /* each folded control becomes a full-width menu row, label showing */
  body.thermii-skin .thermii-skin-more > * {
    width: 100%;
    justify-content: flex-start;
    height: 42px;
    padding: 0 12px;
    /* one type size for the four rows: the skin-built Help and Projects wear
       13.5px/500 and the engine's Restart and Save & Exit their own 13px/600,
       which is invisible as icons in the row and obvious as words in a list */
    font-size: 14px;
    font-weight: 600;
  }
  body.thermii-skin .thermii-skin-more .thermii-skin-projects span,
  body.thermii-skin .thermii-skin-more .thermii-shell-restart span,
  body.thermii-skin .thermii-skin-more .kb-return-btn span,
  body.thermii-skin .thermii-skin-more .thermii-skin-help span {
    display: inline !important;
  }
  /* the row's left-hand separators have no meaning stacked in a menu */
  body.thermii-skin .thermii-skin-more .thermii-skin-help::before,
  body.thermii-skin .thermii-skin-more .thermii-skin-projects::before,
  body.thermii-skin .thermii-skin-more .thermii-shell-restart::before,
  body.thermii-skin .thermii-skin-more .kb-return-btn::before {
    display: none;
  }
  /* the menu row's 12px inset puts the mark 1px further left than the bar's */
  body.thermii-skin .thermii-skin-more .thermii-skin-help::after { left: 13px; }
}

/* ── THE TOGGLE LEAVES CONTINUE ALONE ON A PHONE (Loz, 2026-09-15) ──────────
   In the step action bar the theme toggle is absolutely centred (the rule at
   the welcome/confirm footers, above). At 390px Continue runs from Back to the
   right edge (x 88-376), so the centred toggle (x 168-223) sat ON it — on every
   screen that still gates (coverings, city, thermostat) and every input step.
   Below 700px, in the STEP bar only, the toggle goes back into the flex flow
   and packs RIGHT with Continue (Back's own margin-right:auto takes the slack):
   Back ... toggle | Continue. Auto margins on the toggle were tried first and
   floated it two-thirds across on Back-only screens (measured centre 271 in a
   390 bar); right-packed it sits in the same place on every phone screen. The welcome and confirm footers keep the
   absolute centring — they have no Continue to collide with.

   ...AND UP TO 1180px, NOT 700 (Loz, 2026-09-28): between phone and desktop
   the centred toggle sat on the input screens' hint instead — "Enter
   (toggle) ance to continue" at 800px. The right-hand group is the hint plus
   Continue, ~490px with the longest hint ("Enter the heated area to
   continue"), so the centred toggle clears it only above ~1130px; 1180 is the
   app's own breakpoint for this band. In flow, it packs right with them, the
   same place as on a phone, on every screen in the range. */
@media screen and (max-width: 1180px) {
  body.thermii-skin .thermii-skin-actionbar .thermii-skin-theme { position: static; transform: none; margin: 0; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE "YOUR PROJECT" DRAWER, v2 (Loz's Claude Design handoff, 2026-09-25)
   js/thermii-project-strip.js builds it, js/thermii-projects.js adds Saved
   projects. A column the height of the screen: a fixed header, a scrolling
   body and a fixed footer holding the one primary action. Every size, colour
   and gap is the handoff's own (README "Layout" and "Design tokens"); the
   prototype itself is not shipped. Screen only — the drawer is never printed.
   ═══════════════════════════════════════════════════════════════════════════ */
@media screen {
  .thermii-drawer {
    --tpd-text: #F5F2FA;
    --tpd-muted: #A79BBF;
    --tpd-faint: #7D7196;
    --tpd-accent: #7B4DFF;
    --tpd-accent-hover: #8A60FF;
    --tpd-bar: #8B5CFF;
    --tpd-accent-text: #B89CFF;
    --tpd-card: rgba(255, 255, 255, 0.05);
    --tpd-card-border: rgba(255, 255, 255, 0.07);
    --tpd-divider: rgba(255, 255, 255, 0.08);
    position: fixed;
    z-index: 220;
    left: 0;
    right: 0;
    bottom: 0;
    height: 92dvh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background-color: #1F1433;
    background-image: linear-gradient(180deg, #1F1433 0%, #251339 100%);
    color: var(--tpd-text);
    border-radius: 20px 20px 0 0;
    font-family: 'Sora', var(--thermii-font-sans, sans-serif);
    transform: translateY(100%);
    transition: transform 0.26s cubic-bezier(0.32, 0.72, 0, 1);
  }
  .thermii-drawer.is-open { transform: translateY(0); }
  body.thermii-drawer-locked { overflow: hidden; }
  /* the kit screen's sticky total bar (css/journey.css, below 1500px) sat over
     the open drawer and covered its footer — it steps aside while the drawer
     is open, and the page behind is locked anyway */
  body.thermii-drawer-locked .thermii-kit-bar { display: none !important; }
  .thermii-drawer button { font-family: inherit; }

  .thermii-drawer-grab {
    flex: none; width: 38px; height: 4px; margin: 8px auto 0;
    border-radius: 99px; background: rgba(255, 255, 255, 0.25);
  }
  @media (min-width: 760px) {
    .thermii-drawer {
      top: 0; left: auto; right: 0; bottom: 0;
      width: 400px; height: auto;
      border-radius: 0;
      transform: translateX(100%);
    }
    .thermii-drawer.is-open { transform: translateX(0); }
    .thermii-drawer-grab { display: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    .thermii-drawer, .thermii-drawer-scrim { transition: none; }
  }

  /* ── header ─────────────────────────────────────────────────────────────── */
  .tpd-head {
    flex: none; display: flex; align-items: center; justify-content: space-between;
    padding: 22px 20px 16px;
  }
  .tpd-title { margin: 0; font-size: 24px; font-weight: 600; letter-spacing: -0.01em; line-height: 40px; }
  .tpd-close {
    flex: none; display: grid; place-items: center; width: 40px; height: 40px;
    border: 0; border-radius: 50%; background: rgba(255, 255, 255, 0.08);
    color: var(--tpd-text); cursor: pointer; transition: background 0.15s ease;
  }
  .tpd-close:hover { background: rgba(255, 255, 255, 0.14); }
  .tpd-close svg { width: 14px; height: 14px; }

  /* ── body ───────────────────────────────────────────────────────────────── */
  .tpd-body {
    flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    display: flex; flex-direction: column; gap: 28px;
    padding: 4px 20px 28px;
  }
  .tpd-card {
    flex: none; overflow: hidden;
    background: var(--tpd-card); border: 1px solid var(--tpd-card-border); border-radius: 16px;
  }

  /* the estimate */
  .tpd-est { border-bottom: 1px solid var(--tpd-divider); }
  .tpd-price-row {
    display: flex; align-items: flex-end; justify-content: space-between; gap: 12px;
    padding: 16px 16px 12px;
  }
  .tpd-price-lbl { display: block; font-size: 12px; color: var(--tpd-muted); }
  .tpd-price {
    display: block; margin-top: 4px; font-size: 30px; font-weight: 600;
    letter-spacing: -0.02em; line-height: 1; font-variant-numeric: tabular-nums;
  }
  .tpd-price-side { font-size: 13px; line-height: 1.4; color: var(--tpd-muted); text-align: right; }
  .tpd-status {
    display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
    padding: 10px 16px; border: 0; border-top: 1px dashed var(--tpd-divider);
    background: none; color: var(--tpd-muted); font-size: 12px; text-align: left; cursor: pointer;
  }
  .tpd-status-l { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
  .tpd-dot { flex: none; width: 6px; height: 6px; border-radius: 50%; background: #4ADE80; }
  .tpd-status-r {
    flex: none; display: inline-flex; align-items: center; gap: 6px;
    font-weight: 500; color: var(--tpd-accent-text);
  }
  .tpd-chev { flex: none; width: 12px; height: 12px; transition: transform 0.2s ease; }
  .tpd-status[aria-expanded="true"] .tpd-chev { transform: rotate(180deg); }
  .tpd-bd { display: flex; flex-direction: column; gap: 8px; padding: 4px 16px 16px; font-size: 14px; }
  .tpd-bd[hidden] { display: none; }
  .tpd-bd-row { display: flex; justify-content: space-between; gap: 12px; }
  .tpd-bd-row > span:first-child { color: var(--tpd-muted); display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
  .tpd-bd-row > span:last-child { font-weight: 500; white-space: nowrap; font-variant-numeric: tabular-nums; }
  .tpd-bd-rule { height: 1px; margin: 4px 0; background: var(--tpd-divider); }
  .tpd-bd-total { font-size: 15px; }
  .tpd-bd-total > span:first-child { color: var(--tpd-text); font-weight: 600; }
  .tpd-bd-total > span:last-child { font-weight: 600; }
  .tpd-bd-note { margin: 4px 0 0; font-size: 12px; color: var(--tpd-faint); }

  /* the system strip */
  .tpd-strip { display: grid; grid-auto-columns: minmax(0, 1fr); grid-auto-flow: column; padding: 14px 0; }
  .tpd-cell { padding: 0 12px; min-width: 0; }
  .tpd-cell + .tpd-cell { border-left: 1px solid var(--tpd-divider); }
  .tpd-cell-l { display: block; font-size: 12px; color: var(--tpd-muted); }
  .tpd-cell-v {
    display: flex; align-items: center; gap: 7px; margin-top: 4px;
    font-size: 14px; font-weight: 500; white-space: nowrap;
  }
  .tpd-cell-v.is-pending { color: var(--tpd-muted); font-weight: 400; }
  /* the System value carries the system's own mark — the droplet / bolt every
     other surface uses (.thermii-drawer-sys below), not a bare dot (Loz,
     2026-09-28: "it should be the water icon") */
  .thermii-drawer .tpd-cell-v .thermii-drawer-sys { width: 14px; height: 14px; }  /* (0,3,0): the shared 16px rule below is (0,2,0) and later */

  /* ── sections ───────────────────────────────────────────────────────────── */
  .tpd-sec { display: flex; flex-direction: column; gap: 12px; }
  .tpd-sec-h { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
  .tpd-sec-t {
    margin: 0; font-size: 13px; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.1em; color: var(--tpd-accent-text);
  }
  .tpd-add {
    flex: none; display: inline-flex; align-items: center; gap: 6px;
    height: 32px; padding: 0 12px; border: 1px solid rgba(255, 255, 255, 0.14); border-radius: 16px;
    background: none; color: var(--tpd-text); font-size: 14px; font-weight: 500; cursor: pointer;
    position: relative;
  }
  /* coloured by the system the room will join (the kit page's two add-room
     buttons: green water, magenta electric). The magenta is lightened for this
     dark ground: the kit's #ba39b5 is 3.5:1 on #251339, #e070dc (same hue) is
     6.1:1; the green #74b700 is 6.9:1 as it stands. */
  .tpd-add.is-water { border-color: #74b700; color: #74b700; }
  .tpd-add.is-water:hover { background: rgba(116, 183, 0, 0.12); }
  .tpd-add.is-electric { border-color: #e070dc; color: #e070dc; }
  .tpd-add.is-electric:hover { background: rgba(224, 112, 220, 0.12); }
  .tpd-add::after { content: ""; position: absolute; left: 0; right: 0; top: -6px; bottom: -6px; }
  .tpd-add:hover { background: rgba(255, 255, 255, 0.06); }
  .tpd-add svg { width: 14px; height: 14px; }
  .tpd-rooms { display: flex; flex-direction: column; gap: 8px; }

  /* room cards */
  .tpd-room {
    overflow: hidden; background: var(--tpd-card);
    border: 1px solid var(--tpd-card-border); border-radius: 16px;
  }
  .tpd-room-h {
    display: grid; grid-template-columns: 40px minmax(0, 1fr) auto 20px; align-items: center; gap: 12px;
    width: 100%; padding: 14px; border: 0; background: none; color: inherit; text-align: left; cursor: pointer;
  }
  .tpd-room.is-current .tpd-room-h { cursor: default; grid-template-columns: 40px minmax(0, 1fr) auto; }
  .tpd-ico {
    display: grid; place-items: center; width: 40px; height: 40px;
    border-radius: 12px; background: rgba(255, 255, 255, 0.08); color: var(--tpd-text);
  }
  .tpd-ico svg { width: 20px; height: 20px; display: block; }
  .tpd-room-txt { display: flex; flex-direction: column; min-width: 0; }
  .tpd-room-name { display: flex; align-items: center; gap: 7px; font-size: 17px; font-weight: 600; }
  .tpd-room-name .thermii-drawer-sys { flex: none; width: 12px; height: 12px; background-color: currentColor; }
  .tpd-room-sub {
    margin-top: 2px; font-size: 14px; color: var(--tpd-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .tpd-room-area { text-align: right; line-height: 1.25; }
  .tpd-room-area b { display: block; font-size: 16px; font-weight: 500; white-space: nowrap; }
  .tpd-room-area span { display: block; font-size: 12px; color: var(--tpd-muted); }
  .tpd-room-h .tpd-chev { width: 16px; height: 16px; color: var(--tpd-muted); justify-self: center; }
  .tpd-room.is-open .tpd-room-h .tpd-chev { transform: rotate(180deg); }
  .tpd-room-b { display: flex; flex-direction: column; gap: 18px; padding: 2px 14px 14px; }

  .tpd-area { padding: 12px; border-radius: 12px; background: rgba(0, 0, 0, 0.18); }
  .tpd-bar { height: 6px; border-radius: 3px; background: rgba(255, 255, 255, 0.12); overflow: hidden; }
  .tpd-bar > span { display: block; height: 100%; border-radius: 3px; background: var(--tpd-bar); }
  .tpd-area-l {
    display: flex; justify-content: space-between; gap: 8px; margin-top: 10px;
    font-size: 12px; color: var(--tpd-muted); white-space: nowrap;
  }
  .tpd-area-l b { color: var(--tpd-text); font-weight: 500; }
  .tpd-area-l .tpd-key { display: inline-block; width: 8px; height: 8px; margin-right: 6px; border-radius: 2px; background: var(--tpd-bar); }

  .tpd-grp { display: flex; flex-direction: column; gap: 10px; }
  .tpd-grp-t {
    margin: 0; font-size: 11px; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.1em; color: var(--tpd-faint);
  }
  .tpd-row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; font-size: 15px; }
  .tpd-row > span:first-child { flex: none; color: var(--tpd-muted); white-space: nowrap; }
  .tpd-row > span:last-child { font-weight: 500; text-align: right; }
  .tpd-edit {
    height: 44px; width: 100%; border: 1px solid rgba(255, 255, 255, 0.16); border-radius: 12px;
    background: rgba(255, 255, 255, 0.04); color: var(--tpd-text); font-size: 15px; font-weight: 600; cursor: pointer;
  }
  .tpd-edit:hover { background: rgba(255, 255, 255, 0.08); }
  .tpd-room-note { margin: 0; font-size: 13px; color: var(--tpd-muted); }

  /* ── footer ─────────────────────────────────────────────────────────────── */
  .tpd-foot {
    flex: none; padding: 14px 20px calc(24px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--tpd-divider); background: #231338;
  }
  .tpd-save {
    width: 100%; height: 52px; border: 0; border-radius: 14px;
    background: var(--tpd-accent); color: #fff; font-size: 16px; font-weight: 600; cursor: pointer;
    transition: background 0.15s ease;
  }
  .tpd-save:hover { background: var(--tpd-accent-hover); }

  /* focus, for every control in the drawer */
  .thermii-drawer button:focus:not(:focus-visible) { outline: none; }
  .thermii-drawer button:focus-visible { outline: 2px solid var(--tpd-accent-text); outline-offset: 2px; }

  /* ── saved projects (js/thermii-projects.js) ────────────────────────────── */
  .tpd-saved { padding-top: 20px; border-top: 1px solid var(--tpd-divider); }
  .tpd-saved-h {
    display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px; padding: 0;
    border: 0; background: none; color: inherit; cursor: pointer; text-align: left;
  }
  .tpd-saved-h .tpd-chev { margin-left: auto; width: 16px; height: 16px; color: var(--tpd-muted); }
  .tpd-saved-h[aria-expanded="true"] .tpd-chev { transform: rotate(180deg); }
  .tpd-count {
    padding: 2px 8px; border-radius: 10px; background: rgba(255, 255, 255, 0.1);
    font-size: 12px; font-weight: 600; color: var(--tpd-text);
  }
  .tpd-saved-list { display: flex; flex-direction: column; gap: 8px; }
  .tpd-saved-list[hidden] { display: none; }
  .tpd-srow {
    position: relative; display: grid; grid-template-columns: minmax(0, 1fr) 40px; align-items: center;
    background: var(--tpd-card); border: 1px solid var(--tpd-card-border); border-radius: 14px;
  }
  .tpd-srow-main {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; row-gap: 4px;
    padding: 14px 4px 14px 16px; border: 0; background: none; color: inherit; text-align: left; cursor: pointer;
    border-radius: 14px 0 0 14px;
  }
  .tpd-srow-main:hover .tpd-resume { text-decoration: underline; }
  .tpd-srow-name { font-size: 16px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .tpd-srow-price { font-size: 16px; font-weight: 500; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
  .tpd-srow-meta { font-size: 13px; color: var(--tpd-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .tpd-resume { font-size: 13px; font-weight: 600; color: var(--tpd-accent-text); text-align: right; white-space: nowrap; }
  .tpd-more {
    display: grid; place-items: center; width: 36px; height: 44px; padding: 0;
    border: 0; border-radius: 10px; background: none; color: var(--tpd-muted); cursor: pointer;
  }
  .tpd-more:hover, .tpd-more[aria-expanded="true"] { background: rgba(255, 255, 255, 0.08); color: var(--tpd-text); }
  .tpd-more svg { width: 18px; height: 18px; }
  .tpd-more svg path { stroke-width: 3.2; }
  .tpd-menu {
    position: absolute; z-index: 3; right: 6px; top: calc(100% - 6px); min-width: 170px;
    padding: 6px; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 12px;
    background: #35264F; box-shadow: 0 12px 30px rgba(0, 0, 0, 0.4);
  }
  .tpd-menu[hidden] { display: none; }
  .tpd-menu button {
    display: block; width: 100%; min-height: 44px; padding: 10px 12px; border: 0; border-radius: 8px;
    background: none; color: var(--tpd-text); font-size: 15px; text-align: left; cursor: pointer;
  }
  .tpd-menu button:hover { background: rgba(255, 255, 255, 0.08); }
  .tpd-menu .tpd-menu-del { color: #FF8A9A; }
  .tpd-confirm {
    grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    padding: 12px 16px; border-top: 1px solid var(--tpd-divider); font-size: 14px;
  }
  .tpd-confirm-q { flex: 1 1 100%; color: var(--tpd-text); }
  .tpd-confirm button {
    min-height: 40px; padding: 0 16px; border-radius: 10px; font-size: 14px; font-weight: 600; cursor: pointer;
  }
  .tpd-confirm-no { border: 1px solid rgba(255, 255, 255, 0.16); background: none; color: var(--tpd-text); }
  .tpd-confirm-yes { border: 0; background: #d23d52; color: #fff; }
  .tpd-empty { padding: 14px 16px; border-radius: 14px; background: var(--tpd-card); font-size: 14px; color: var(--tpd-muted); }
  .tpd-empty b { display: block; margin-bottom: 4px; color: var(--tpd-text); font-size: 15px; }
  .tpd-toast {
    margin: 0; padding: 9px 12px; border-radius: 9px; font-size: 13px;
    color: #cfe8a8; background: rgba(116, 183, 0, 0.16);
  }
  .tpd-toast[hidden] { display: none; }
}

/* the droplet and bolt, shared with every other screen that marks a system */
.thermii-drawer .thermii-drawer-sys { flex: 0 0 auto; width: 16px; height: 16px; background-color: currentColor; }
.thermii-po .thermii-drawer-sys.is-water,
.thermii-pr-on .thermii-drawer-sys.is-water,
.thermii-review-rooms .thermii-drawer-sys.is-water,
.thermii-project-sum .thermii-drawer-sys.is-water,
.thermii-rc-split .thermii-drawer-sys.is-water,
.thermii-rc-group .thermii-drawer-sys.is-water,
.thermii-rc-room .thermii-drawer-sys.is-water,
.thermii-drawer .thermii-drawer-sys.is-water {
  color: #149de8;
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2012%2012%27%3E%3Cpath%20d%3D%27M6%20.9C6%20.9%202.2%205%202.2%207.5a3.8%203.8%200%200%200%207.6%200C9.8%205%206%20.9%206%20.9Z%27%20fill%3D%27%23000%27%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2012%2012%27%3E%3Cpath%20d%3D%27M6%20.9C6%20.9%202.2%205%202.2%207.5a3.8%203.8%200%200%200%207.6%200C9.8%205%206%20.9%206%20.9Z%27%20fill%3D%27%23000%27%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
}
.thermii-po .thermii-drawer-sys.is-electric,
.thermii-pr-on .thermii-drawer-sys.is-electric,
.thermii-review-rooms .thermii-drawer-sys.is-electric,
.thermii-project-sum .thermii-drawer-sys.is-electric,
.thermii-rc-split .thermii-drawer-sys.is-electric,
.thermii-rc-group .thermii-drawer-sys.is-electric,
.thermii-rc-room .thermii-drawer-sys.is-electric,
.thermii-drawer .thermii-drawer-sys.is-electric {
  color: #e8a020;
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2012%2012%27%3E%3Cpath%20d%3D%27M7.1.7%202.3%206.8h2.9L4.7%2011.3%209.9%205.1H6.7Z%27%20fill%3D%27%23000%27%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2012%2012%27%3E%3Cpath%20d%3D%27M7.1.7%202.3%206.8h2.9L4.7%2011.3%209.9%205.1H6.7Z%27%20fill%3D%27%23000%27%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
}



/* ── the running-costs popup (Loz, 2026-09-24) ───────────────────────────────
   js/thermii-running-costs.js. The shell — scrim, card, shadow, radius, close
   button — is the shared .thermii-skin-modal block; this adds only the wider
   card and its contents, in the How-it-works popup's palette. Screen only by
   construction: the opener is hidden in print and the popup lives on <body>. */
body.thermii-skin .thermii-rc-modal {
  max-width: 760px;
  max-height: calc(100vh - 32px);
  overflow: auto;
  padding: 0;
  text-align: left;
}
body.thermii-skin .thermii-rc-modal .thermii-skin-modal-close { font-size: 22px; line-height: 1; }
.thermii-rc-head { padding: 28px 60px 18px 32px; border-bottom: 1px solid var(--thermii-border, #e4e6ef); }
.thermii-rc-title { margin: 0 0 6px; font-size: 24px; font-weight: var(--thermii-font-weight-display, 600); color: #1f2a44; }
.thermii-rc-sub { margin: 0; font-size: 14px; font-weight: var(--thermii-font-weight-light, 300); color: #6b7280; }
.thermii-rc-body { padding: 20px 32px 6px; }
.thermii-rc-eyebrow {
  margin: 0 0 10px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #9aa0b4;
}
.thermii-rc-given { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-bottom: 22px; }
.thermii-rc-given-i { padding: 12px 14px; border: 1px solid #e4defb; border-radius: 12px; background: #f6f4ff; }
.thermii-rc-given-i b { display: block; font-size: 16px; font-weight: 600; color: #1f2a44; }
.thermii-rc-given-i small { display: block; margin-top: 2px; font-size: 12px; color: #6b7280; }

.thermii-rc-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.thermii-rc-field { display: block; }
.thermii-rc-field-l { display: block; margin-bottom: 6px; font-size: 13px; font-weight: 600; color: #1f2a44; }
/* THE MEASUREMENT FIELDS' FRAME (Loz, 2026-09-28: "so they are more obvious as
   inputs"). The same three states and the same colours as Room Size / Width /
   Length (css/journey.css, `#wq-step-4b .eq-input-wrap`): the soft brand
   gradient at rest, stronger under the pointer, the full gradient with a faint
   halo while typing — which is the focus indicator, so the input's own
   outline is gone below. 52px and a 13px corner rather than those fields'
   72/16: the popup holds several side by side. */
.thermii-rc-field-in {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 52px;
  padding: 0 14px;
  border: 1.5px solid transparent;
  border-radius: 13px;
  background:
    linear-gradient(#fff, #fff) padding-box,
    linear-gradient(115deg, rgba(20, 157, 232, .48), rgba(113, 56, 237, .46) 55%, rgba(212, 20, 196, .38)) border-box;
  box-shadow: 0 8px 20px rgba(16, 23, 53, .06), 0 2px 5px rgba(16, 23, 53, .04);
  transition: background .2s ease, box-shadow .2s ease;
  cursor: text;
}
.thermii-rc-field-in:hover {
  background:
    linear-gradient(#fff, #fff) padding-box,
    linear-gradient(115deg, rgba(20, 157, 232, .75), rgba(113, 56, 237, .68) 55%, rgba(212, 20, 196, .58)) border-box;
  box-shadow: 0 10px 24px rgba(75, 44, 165, .10), 0 2px 6px rgba(16, 23, 53, .04);
}
.thermii-rc-field-in:focus-within {
  background:
    linear-gradient(#fff, #fff) padding-box,
    var(--thermii-gradient) border-box;
  box-shadow: 0 0 0 4px rgba(113, 56, 237, .10), 0 12px 28px rgba(77, 45, 166, .14);
}
/* the browser's own up/down arrows go: system furniture beside a styled frame,
   and Safari draws them differently again. Typing and the number pad remain. */
.thermii-rc-field-in input { -moz-appearance: textfield; appearance: textfield; }
.thermii-rc-field-in input::-webkit-outer-spin-button,
.thermii-rc-field-in input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.thermii-rc-field-in input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  outline: 0;
  background: none;
  font: inherit;
  font-size: 16px;
  color: #1f2a44;
}
.thermii-rc-field-u { font-size: 13px; color: #6b7280; white-space: nowrap; }
.thermii-rc-field-h { display: block; margin-top: 5px; font-size: 12px; line-height: 1.4; color: #6b7280; }
.thermii-rc-dated { margin: 8px 0 22px; font-size: 12px; color: #6b7280; }

.thermii-rc-results { display: grid; grid-template-columns: 1.3fr 1fr 1fr; gap: 10px; margin-bottom: 14px; }
.thermii-rc-res { display: block; padding: 16px 18px; border: 1px solid #e4e6ef; border-radius: 14px; }
.thermii-rc-res.is-hero { border-color: transparent; background: linear-gradient(135deg, #7138ed, #ba39b5); color: #fff; }
.thermii-rc-res-l { display: block; font-size: 12px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: #6b7280; }
.thermii-rc-res.is-hero .thermii-rc-res-l { color: rgba(255, 255, 255, .85); }
.thermii-rc-res-v {
  display: block;
  margin: 6px 0 2px;
  font-size: 24px;
  font-weight: 700;
  color: #1f2a44;
  font-variant-numeric: tabular-nums;
}
.thermii-rc-res.is-hero .thermii-rc-res-v { font-size: 30px; color: #fff; }
.thermii-rc-res-s { display: block; font-size: 12px; color: #6b7280; }
.thermii-rc-res.is-hero .thermii-rc-res-s { color: rgba(255, 255, 255, .9); }

.thermii-rc-rooms { margin-bottom: 14px; padding: 4px 18px; border: 1px solid #e4e6ef; border-radius: 14px; }
.thermii-rc-room {
  display: grid;
  grid-template-columns: minmax(90px, 150px) minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  padding: 11px 0;
  font-size: 14px;
  color: #1f2a44;
}
.thermii-rc-room + .thermii-rc-room { border-top: 1px solid #e4e6ef; }
.thermii-rc-room-n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thermii-rc-room .thermii-drawer-sys {
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-right: 6px;
  vertical-align: -1px;
  background-color: currentColor;
}
.thermii-rc-bar { display: block; height: 10px; overflow: hidden; border-radius: 999px; background: #efeaff; }
.thermii-rc-bar i { display: block; height: 100%; border-radius: 999px; background: #7138ed; }
.thermii-rc-room-c { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* A MIXED PROJECT (Loz, 2026-09-25): the year split by system under the
   headline, and the room list grouped water-then-electric under the same
   headings Your Selections and the kit screen use. Empty on one system. */
.thermii-rc-split:empty { display: none; }
.thermii-rc-split { display: flex; flex-wrap: wrap; gap: 10px; margin: -4px 0 14px; }
.thermii-rc-split-i {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 14px; border-radius: 999px; font-size: 13.5px; color: #1f2a44;
}
.thermii-rc-split-i.is-water { background: #f1f8fe; }
.thermii-rc-split-i.is-electric { background: #fef7ea; }
.thermii-rc-split-v { font-weight: 600; font-variant-numeric: tabular-nums; }
.thermii-rc-split .thermii-drawer-sys,
.thermii-rc-group .thermii-drawer-sys {
  display: inline-block; flex: 0 0 13px; width: 13px; height: 13px; background-color: currentColor;
}
.thermii-rc-group {
  display: flex; align-items: center; gap: 8px; margin: 0; padding: 12px 0 4px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: #8b93a4;
}
.thermii-rc-room + .thermii-rc-group { margin-top: 4px; border-top: 1px solid #e4e6ef; }

.thermii-rc-insight {
  display: flex;
  gap: 14px;                       /* the Insights panel's own gap and inset */
  margin-bottom: 18px;
  padding: 18px 20px;
  border: 1px solid #e4defb;
  border-radius: 16px;
  background: #f6f4ff;
}
/* the Insights panels' own body copy (Loz, 2026-09-24: "is the body text the
   same as the others?" — it was 13.5px #333a57 against their 14.5px muted) */
.thermii-rc-insight p {
  margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--journey-muted, #596584);
  /* and the same LIGHT weight (Loz, 2026-09-25): the journey Insight's body
     takes --thermii-font-weight-light; without it this inherited 400 and read
     bolder beside it */
  font-weight: var(--thermii-font-weight-light, 300);
}

.thermii-rc-foot {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 32px 22px;
  border-top: 1px solid #e4e6ef;
}
/* the small print stops well short of the button (Loz, 2026-09-24) */
.thermii-rc-foot { justify-content: space-between; }
.thermii-rc-foot p { flex: 0 1 auto; max-width: 480px; margin: 0; font-size: 11.5px; line-height: 1.5; color: #6b7280; }
.thermii-rc-got {
  flex: 0 0 auto;
  padding: 12px 26px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, #7138ed, #ba39b5);
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.thermii-rc-got:focus-visible { outline: 2px solid #7138ed; outline-offset: 2px; }
/* a field's focus ring is its frame's full gradient + halo (above), for mouse
   and keyboard alike, so the input carries no second ring inside it */
.thermii-rc-field-in input:focus-visible { outline: 0; }

@media (max-width: 700px) {
  .thermii-rc-head { padding: 24px 56px 16px 20px; }
  .thermii-rc-body { padding: 18px 20px 4px; }
  .thermii-rc-foot { flex-direction: column; align-items: stretch; padding: 14px 20px 20px; }
  .thermii-rc-foot p { max-width: none; }
  .thermii-rc-given, .thermii-rc-fields, .thermii-rc-results { grid-template-columns: minmax(0, 1fr); }
  .thermii-rc-room { grid-template-columns: minmax(70px, 110px) minmax(0, 1fr) auto; gap: 10px; }
}


/* ── THE FOCUS RING IS VISIBLE (2026-09-24) ─────────────────────────────────
   The header controls, the logo, the welcome cards, the project chips and the
   modal buttons all drew their keyboard ring in rgba(20,157,232,.35) — about
   1.45:1 on white, under the 3:1 WCAG 2.2 asks of a focus indicator (1.4.11,
   2.4.13). Now the brand purple, #7138ed: 6.2:1 on white, 5.4:1 on the lilac
   chip ground — the same ring the era boxes already use. 2px, not 3, because a
   solid ring needs less width than a translucent one to read.
   components.css:425-428 gives Restart and Save & Exit the same faint ring and
   is APPEND-ONLY, so they — and every Continue button, which shares that rule — are restated here at the skin's specificity. */
body.thermii-skin .thermii-continue:focus-visible,
body.thermii-skin .thermii-shell-restart:focus-visible,
body.thermii-skin .kb-return-btn:focus-visible {
  outline: 2px solid #7138ed;
  outline-offset: 3px;
}

/* ── PHONE TIDY (Loz, 2026-09-28) ─────────────────────────────────────────────
   Four changes at 700px and under, agreed from a two-round mockup
   (tests/phone-frame.html?prop=1 draws the same thing). Desktop and the PDF
   are untouched: every rule sits in this screen-only phone block, and each one
   ties or out-weighs the rule it replaces and comes later in the last-loaded
   stylesheet, so none needs !important.

   1. THE INSIGHTS PANEL. Its body was 14.5px, larger than the question's own
      14px subtext, and it sat in a 254px column beside the mascot, so the
      heat-source Insight ran to 337px, about 40% of a 390px screen. On a phone
      the body is 13.5px (footnote size in Apple's own scale, well above its
      11pt floor) and runs the full width under the mascot/title row. The bubble
      goes `display: contents` so its title and text become grid items in their
      own right. The "These are Insights" callout no longer needs to break out of
      an indent, so its negative margins go.
   2. BACK AND CONTINUE AT 48px. Back was 57x54 for one chevron and the bar 91px
      tall on every question. 48 clears Apple's 44x44 minimum with room to spare.
   3. EVERY CONTROL UNDER 44x44 GETS A BIGGER, INVISIBLE TAP AREA via ::after.
      The drawing does not move or grow. Measured before: the Insight collapse
      arrow 28x28, the Edit buttons 68x25, Home 37 tall, the Insights switch,
      menu and theme toggle 38 tall. The Edit areas are 44 tall, exactly the
      review rows' pitch, so a tap cannot land on the row above or below. None
      of these elements used ::after already (checked).
   4. THE FOOTER. The version sat ~7px under the content with a 26px gap below
      it, and the copyright ended 10px from the page foot, under an iPhone's
      home bar. Now 24px above, 8px between, 24px + the safe-area inset below. */
@media screen and (max-width: 700px) {
  /* 1. Insights */
  body.thermii-skin .thermii-tip {
    display: grid;
    grid-template-columns: 34px minmax(0, 1fr);
    column-gap: 12px;
    row-gap: 4px;
    align-items: center;
    padding: 14px 16px 16px;
  }
  body.thermii-skin .thermii-tip-bubble { display: contents; }
  body.thermii-skin .thermii-tip-avatar { grid-column: 1; grid-row: 1; }
  body.thermii-skin .thermii-skin-insight-title {
    grid-column: 2;
    grid-row: 1;
    font-size: 15px;
    line-height: 34px;
    padding-right: 30px; /* clears the collapse arrow, which is absolute */
  }
  body.thermii-skin .thermii-tip-text {
    grid-column: 1 / -1;
    grid-row: 2;
    font-size: 13.5px;
    line-height: 1.55;
  }
  body.thermii-skin .thermii-tip-text .thermii-insights-hint {
    font-size: 13px;
    line-height: 1.5;
    margin: 14px 0 0;
  }
  /* the two panels dressed as Insights — the kit screen's "How is this
     calculated?" explanation and the "Not sure which to choose?" glossary card —
     cross-read the tip text's size on desktop, so they follow it down here too */
  body.thermii-skin .wkit-heat-calc-line,
  body.thermii-skin .eq-unsure-info .eq-note { font-size: 13.5px; line-height: 1.55; }

  /* 2. the action bar */
  body.thermii-skin .thermii-skin-actionbar { padding: 12px 14px; }
  body.thermii-skin .thermii-skin-actionbar .eq-back-btn {
    width: 48px;
    min-width: 48px;
    height: 48px;
    min-height: 48px;
    padding: 0;
    justify-content: center;
  }
  body.thermii-skin .thermii-skin-actionbar .thermii-continue { min-height: 48px; height: 48px; }

  /* 3. tap areas — each host needs a containing block for its ::after. The
     collapse arrow is already absolute. The theme toggle is absolute (its own
     containing block) everywhere except the step bar, where the phone rule puts
     it back in the flow, so there it goes relative with the centring offsets
     neutralised, or it would jump half its width. */
  body.thermii-skin .eq-ans-edit,
  body.thermii-skin .kb-logo-center { position: relative; }
  body.thermii-skin .thermii-skin-actionbar .thermii-skin-theme { position: relative; left: auto; top: auto; }
  body.thermii-skin .thermii-skin-insight-chev::after,
  body.thermii-skin .eq-ans-edit::after,
  body.thermii-skin .thermii-skin-theme::after,
  body.thermii-skin .thermii-skin-insights::after,
  body.thermii-skin .thermii-skin-burger::after,
  body.thermii-skin .kb-logo-center::after {
    content: '';
    position: absolute;
  }
  body.thermii-skin .thermii-skin-insight-chev::after { inset: -8px; }          /* 28 -> 44 */
  body.thermii-skin .eq-ans-edit::after { top: -9.5px; bottom: -9.5px; left: 0; right: 0; } /* 25 -> 44 */
  body.thermii-skin .thermii-skin-theme::after,
  body.thermii-skin .thermii-skin-insights::after,
  body.thermii-skin .thermii-skin-burger::after { top: -3px; bottom: -3px; left: 0; right: 0; } /* 38 -> 44 */
  body.thermii-skin .kb-logo-center::after { top: -4px; bottom: -4px; left: 0; right: 0; }    /* 37 -> 45 */

  /* 5. the header's stepper (Loz's mockup, same day, measured at 2x): smaller
     wording (15/14 -> 13/12px) and ticks (9 -> 7px), the wording moved clear of
     the logo row (13 -> ~30px of air), the pills closer under it and more air
     between the ticks and the gradient line. The pills themselves are unchanged. */
  body.thermii-skin .thermii-skin-progress-slot { margin-top: 17px; }
  body.thermii-skin .thermii-stage-header { gap: 6px; }
  body.thermii-skin .thermii-stage-title { font-size: 13px; }
  body.thermii-skin .thermii-skin-count { font-size: 12px; }
  body.thermii-skin .thermii-stepper .thermii-step.is-complete::before {
    top: 10px;
    width: 4px;
    height: 7px;
  }

  /* 4. the footer */
  body.thermii-skin .kb-version { padding-top: 24px; padding-bottom: 8px; }
  body.thermii-skin .kb-copyright { padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px)); }
}

/* ── PHONE: CHOICE BARS, CLOSED INSIGHTS, DARK MODE IN THE MENU (Loz, 2026-09-28)
   Round 3 of the phone tidy, agreed from a mockup over the live app
   (tests/phone-frame.html). Phone only; desktop keeps tiles, open Insights and
   the toggle in the action bar.

   BARS ON THE SHORT OPTION SCREENS ONLY: heat source, both pipe-spacing
   screens, floor level, subfloor and install method on water; subfloor,
   insulation and self-levelling on electric. Each is 2 to 5 options, and a
   full-width bar reads top to bottom with a proper line for any description.
   Rooms (10), floor coverings (7) and the thermostat carousel keep their grids:
   there the icon does the work, and as bars Rooms alone would scroll ~700px.
   Listed by step id rather than by a class so a new screen opts in
   deliberately. Property age keeps its own full-width row, whose 88px icons
   carry the era digits and would be unreadable at a bar's 32px.

   Layout: the icon, bare in a 48px column | name (and description or the
   Recommended badge under it) | the radio, centred on the right. The radio is
   the tile's own ::after, only re-centred. The badge was absolutely placed and
   on a phone tile it sat over the word "Screed" (measured, live); in a bar it
   joins the flow under the name. */
@media screen and (max-width: 700px) {
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .electric-covering-row {
    display: grid;
    /* !important because journey.css's own phone rule pins heat source,
       install method and pipe spacing to two columns with !important */
    grid-template-columns: minmax(0, 1fr) !important;
    gap: 10px;
  }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option {
    display: grid;
    grid-template-columns: 48px minmax(0, 1fr) 26px;
    grid-template-rows: auto auto;
    column-gap: 14px;
    row-gap: 1px;
    align-items: center;
    text-align: left;
    width: 100%;
    height: auto;
    min-height: 72px;
    padding: 12px 16px;
  }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option .fo-icon {
    grid-column: 1;
    grid-row: 1 / 3;
    width: 48px;
    height: 48px;
    margin: 0;
    /* no grey square behind the icon (Loz, same day): desktop tiles draw their
       icons bare, so the bars do too, a little larger to hold the column */
    display: grid;
    place-items: center;
  }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option .fo-icon img { width: 40px; height: 40px; max-width: none; }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option .fo-label {
    grid-column: 2;
    grid-row: 1 / 3;
    align-self: center;
    margin: 0;
    font-size: 16px;
    text-align: left;
  }
  /* a second line under the name: the label rises to make room for it */
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option:has(.thermii-option-copy) .fo-label { grid-row: 1; align-self: end; }
  /* a name-only bar is one row, so the name centres on the icon */
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option:not(:has(.thermii-option-copy)) :is(.fo-icon, .fo-label) { grid-row: 1; }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option .thermii-option-copy {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
    margin: 0;
    max-width: none;
    font-size: 13.5px;
    line-height: 1.45;
    text-align: left;
  }
  /* THE RECOMMENDED PILL SITS ON THE NAME'S LINE, and smaller (Loz, same
     day): "Screed  ✓ RECOMMENDED", 20px tall in place of 29, so the
     recommended bar is the same height as its neighbours and says so with its
     green border, tint and a label rather than with bulk. The recommended bar
     gets two extra tracks, name then pill, both sized to their content; a long
     name wraps inside its own track rather than pushing the pill out. Only
     install method and pipe spacing carry the pill, and every name there is
     short. */
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option.is-recommended {
    grid-template-columns: 48px minmax(0, max-content) max-content minmax(0, 1fr) 26px;
  }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option.is-recommended .fo-label { grid-column: 2; grid-row: 1; align-self: center; }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option .fo-rec-badge {
    position: static;
    transform: none;
    grid-column: 3;
    grid-row: 1;
    justify-self: start;
    align-self: center;
    margin: 0 0 0 10px;
    gap: 5px;
    padding: 3px 9px;
    font-size: 10px;
    line-height: 1.2;
    white-space: nowrap;
  }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option .fo-rec-badge::before { width: 4px; height: 7px; }
  body.thermii-skin :is(#wq-step-2, #wq-step-2b, #wq-step-4flr, #wq-step-4c, #wq-step-4d, #wq-step-4ps, #eq-step-2, #eq-step-7, #eq-step-8) .filter-option::after { top: 50%; right: 16px; transform: translateY(-50%); }
}

/* The phone menu's Dark Mode row (js/thermii-skin.js, 2026-09-28): the menu's
   last row, under a grey rule that runs the panel's full width — the panel's
   8px padding is escaped on both sides. The toggle keeps its own drawing. */
@media screen and (max-width: 700px) {
  body.thermii-skin .thermii-skin-more .thermii-skin-dark-row {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 11px;
    color: #1b2140;
    cursor: pointer;
  }
  body.thermii-skin .thermii-skin-more .thermii-skin-dark-row::before {
    content: '';
    position: absolute;
    top: -7px;
    left: -8px;
    right: -8px;
    border-top: 1px solid #e6e8f0;
  }
  body.thermii-skin .thermii-skin-more .thermii-skin-dark-row .thermii-skin-theme { margin: 0; }
  /* the header's left-hand separator means nothing inside a menu row */
  body.thermii-skin .thermii-skin-more .thermii-skin-dark-row .thermii-skin-theme::before { display: none; }
}

/* Insight headlines (js/thermii-insight-heads.js, 2026-09-28). The title
   carries two wordings: the brand everywhere but a phone, the headline on a
   phone, where the panel starts closed and the headline is what earns the tap.
   The closed panel is one bar: tighter padding, and a headline that may wrap
   to a second line sits on a normal line-height rather than the 34px one that
   centres a single line on the mascot. */
body.thermii-skin .thermii-insight-head { display: none; }
@media screen and (max-width: 700px) {
  body.thermii-skin .thermii-tip .thermii-insight-brand { display: none; }
  body.thermii-skin .thermii-tip .thermii-insight-head { display: inline; }
  body.thermii-skin .thermii-tip .thermii-skin-insight-title { cursor: pointer; }
  body.thermii-skin .thermii-tip.is-collapsed { padding: 12px 16px; }
  body.thermii-skin .thermii-tip.is-collapsed .thermii-skin-insight-title { line-height: 1.35; }
  body.thermii-skin .thermii-tip.is-collapsed .thermii-skin-insight-chev { top: 15px; }
  /* with the theme toggle in the menu, Continue takes the bar's width */
  body.thermii-skin .thermii-skin-actionbar .thermii-continue { flex: 1 1 auto; margin-left: 12px; }
}

/* THE SYSTEM SCREEN AS BARS, and with no Continue (Loz, 2026-09-28). It now
   auto-advances (js/thermii-confirm.js), and on a phone its three stacked
   266px tiles become the same bars as the other short option screens, so the
   whole choice fits on one screen: icon, name and description, radio right.
   The footer is kept for Back and the desktop theme toggle; on a phone it
   holds neither (no Version stage, toggle in the menu), so an empty one is
   hidden rather than left as a blank bar. */
@media screen and (max-width: 700px) {
  body.thermii-skin #systemTypeRow {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
  }
  body.thermii-skin #systemTypeRow .system-option {
    display: grid;
    grid-template-columns: 48px minmax(0, 1fr) 26px;
    grid-template-rows: auto auto;
    column-gap: 14px;
    row-gap: 1px;
    align-items: center;
    text-align: left;
    width: 100%;
    height: auto;
    min-height: 72px;
    padding: 12px 16px;
  }
  /* the icon here is the tile's ::before background (journey.css hides the
     <img> outright), so the pseudo-element takes the bar's icon column, the
     drawing contained in its middle 40px, bare as on desktop */
  body.thermii-skin #systemTypeRow .system-option::before {
    grid-column: 1;
    grid-row: 1 / 3;
    width: 48px;
    height: 48px;
    flex: none;
    box-sizing: border-box;
    padding: 4px;
    background-origin: content-box;
    background-size: contain;
  }
  body.thermii-skin #systemTypeRow .system-option .so-label {
    grid-column: 2;
    grid-row: 1;
    align-self: end;
    margin: 0;
    font-size: 16px;
    text-align: left;
  }
  body.thermii-skin #systemTypeRow .system-option .thermii-option-copy {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
    margin: 0;
    max-width: none;
    font-size: 13.5px;
    line-height: 1.45;
    text-align: left;
  }
  body.thermii-skin #systemTypeRow .system-option::after { top: 50%; right: 16px; transform: translateY(-50%); }
  body.thermii-skin #systemTypeCard .thermii-confirm-footer:not(:has(> *)) { display: none; }
  /* the welcome screen's footer only ever held the theme toggle, which lives
     in the menu on a phone — V.1.48 left it as an empty 76px sticky bar */
  body.thermii-skin .thermii-welcome-footer:not(:has(> *)) { display: none; }
}
