/* Icons ship with the app. This was a CDN @import: it blocked first paint on all 112 screens,
   and offline (or behind any CDN block) every glyph — tab bar, back arrows, everything — was
   tofu with no fallback. Regenerate after adding icons: python3 assets/icons/build-subset.py */
@import url('assets/icons/tabler-icons.css');

/* THE HIDDEN ATTRIBUTE MEANS HIDDEN — everywhere (Sep 24; Tito row 37). `hidden` is only the UA
   stylesheet's display:none, so ANY author rule that sets display on the element (.cta{display:flex},
   .today-bar{display:flex}) silently beats it and the element paints anyway. Seven pages carried
   this line locally after row 37; the rest did not, and spending-review.html was painting "Head
   over to Goals" on a month in the red — the exact thing the founder asked on Sep 16 not to show
   ("don't mention goals"), with the code already saying hidden. One rule here closes the class. */
[hidden]{ display:none !important; }

/* A DISABLED BUTTON MUST LOOK DISABLED (Sep 24). The .btn entrance animation (wbRise, fill-mode both)
   ends at opacity:1, and an animation outranks any normal declaration — so every page's
   `.btn.is-off{opacity:.4}` was silently undone: WePromise's trial button looked live while it
   ignored taps. !important is the one thing an animation does not outrank. */
.btn.is-off{ opacity:.4 !important; pointer-events:none; }

/* ═══ Cross-document view transitions — 120 documents behaving as one app ═══
   Every navigation is a full document load, so it lands as a hard cut. wbRise already masks the
   ARRIVAL; nothing masked the departure. Because app.css is shared, both the outgoing and the
   incoming document opt in from this one rule. WebKit ships this on iOS 18+, which the Capacitor
   target clears; older engines ignore it silently, so no guard is needed.

   ::view-transition-new(root){animation:none} is the LOAD-BEARING line. Left at its default the
   new snapshot cross-fades, which double-fades against the wbRise screen entrance and makes
   content appear to arrive twice. Off, the outgoing screen dissolves while the incoming one
   assembles top-down under the entrance that already exists. */
@view-transition{ navigation:auto; }
::view-transition-old(root){ animation:wbVTOut var(--d-2) var(--ease-out) both; }
::view-transition-new(root){ animation:none; }
@keyframes wbVTOut{ to{ opacity:0; transform:scale(.985); } }
@media (prefers-reduced-motion: reduce){
  ::view-transition-old(root), ::view-transition-new(root){ animation:none; }
}

/* ═══ Money world TOP nav (moneytabs.js) — Spending · Investments · Goals ═══ */
.mtabs{ display:flex; gap:6px; width:100%; box-sizing:border-box; margin-top:12px; padding:4px; border-radius:13px; background:var(--channel-fill); box-shadow:var(--channel-bevel); border:none; }
.mtab{ flex:1; background:none; border:none; color:var(--tx-m1); font-size:14px; font-weight:800; padding:9px; border-radius:9px; cursor:pointer; font-family:inherit; }
.mtab.on{ background:var(--chart); color:var(--ink-on-accent); }

/* ═══ per-world bottom tab bar (worldtabs.js) — the unbundled-world nav ═══ */
.wtabs{ position:absolute; left:0; right:0; bottom:0; z-index:45; display:flex; align-items:flex-end; justify-content:space-around;
  /* The one component on every world screen, so it is the highest-frequency premium cue there is:
     frames are where objects announce they are objects. Opaque machined hull, top bevel only.
     backdrop-filter DELETED — metal is opaque (that is the physics), and dropping it is also a
     free win on a permanently-composited fixed element. Glass gets backdrop-filter; steel never
     does, and holding that line is what keeps the two materials legible against each other. */
  padding:7px 6px calc(9px + env(safe-area-inset-bottom,0));
  background:linear-gradient(180deg,#1B222B,#0E1319); border-top:none;
  box-shadow: inset 0 1px 0 rgba(200,214,230,.14), inset 0 2px 0 rgba(0,0,0,.5),
              0 -8px 24px rgba(2,5,10,.5); }
.wtab{ flex:1; display:flex; flex-direction:column; align-items:center; gap:3px; background:none; border:none; cursor:pointer; font-family:inherit; color:var(--tx-m4); padding:4px 2px; }
.wtab i{ font-size:21px; line-height:1; }
.wtab span{ font-size:10px; font-weight:700; letter-spacing:.02em; }
.wtab.on{ color:var(--chart); }
/* the WE home button — a house with WE in it, inside the green circle (Sep 24; was WE+) */
.wtab.wthome{ flex:0 0 auto; }
.wthome .wth{ width:46px; height:46px; border-radius:50%; background:var(--chart); color:var(--ink-on-accent); display:flex; align-items:center; justify-content:center;
  box-shadow:0 5px 16px rgba(var(--chart-rgb),.32); margin-bottom:2px; }
.wthome .wth-ic{ width:30px; height:28px; display:block; overflow:visible; }
/* The bar grows by the home-indicator inset on an iPhone (padding-bottom above), so the room left
   for it must grow too. It did not: at full scroll the last ~34pt of every barred screen stayed under
   the bar — on the ownership statement that was "+ Add new" (founder, Sep 25: "it doesnt scroll to add
   something its cutoff"). The preview has no inset, which is why it never showed there. */
.screen.has-wtabs{ padding-bottom:calc(92px + env(safe-area-inset-bottom,0px)); }

:root{
  --blue:#2680C4; --chart:#DCE85C; --ink:#13324d; --ink2:#1a3a52;
  --w70:rgba(255,255,255,0.70); --w85:rgba(255,255,255,0.85); --w16:rgba(255,255,255,0.16);
  /* ── PREMIUM-DARK canvas: dark navy + ambient glow (keeps WeBetter blue DNA + the "glow" narrative) ── */
  --canvas:
    radial-gradient(ellipse 75% 40% at 80% 2%, rgba(var(--chart-rgb),.10), transparent 55%),
    radial-gradient(ellipse 85% 50% at 10% 20%, rgba(38,128,196,.20), transparent 55%),
    radial-gradient(ellipse 95% 55% at 50% 106%, rgba(38,128,196,.12), transparent 60%),
    linear-gradient(180deg,#0a1726,#070f1a 55%,#050a12);
  --line:rgba(255,255,255,.10); --line2:rgba(255,255,255,.16); --mut:rgba(255,255,255,.62);
  /* ── MOTION TOKENS (design panel, Aug 13). One vocabulary instead of 22 accidental durations. ── */
  --d-1:120ms; --d-2:180ms; --d-3:240ms; --d-4:320ms;
  --ease-out:cubic-bezier(.2,.8,.2,1); --ease-in-out:cubic-bezier(.4,0,.2,1); --ease-spring:cubic-bezier(.2,.9,.3,1.05);
  --ink-on-accent:#20260a;
  /* --d-5 is for OBJECT motion only: flips, morphs, shared-element transitions.
     UI state changes never exceed --d-4. */
  --d-5:480ms;

  /* ═══ STEEL — the secondary MATERIAL (not a hue). Cool, near-neutral: ~214deg, S <= 22%.
     The navy it replaces is HSL(217, 57%, 18%) — a SATURATED blue, 76% as chromatic as the
     accent and near-complementary to it, so today the two fight and green wins only on area.
     At 22% saturation chartreuse becomes ~3.4x the chroma of anything else on screen: the same
     green pixel gets measurably louder because everything around it stopped competing. That is
     the whole reason steel beats "another blue". ═══ */
  --st-900:#0F1319;   /* falloff, channel floor */
  --st-800:#151A22;
  --st-700:#1C232C;   /* plate body, the workhorse */
  --st-600:#232B36;   /* lit end of the ramp */
  --st-500:#2E3846;   /* bevel */
  --st-400:#3C4652;   /* specular peak — ALL contrast is measured against THIS, not the body */
  --st-spec:#C8D6E6;  /* the light */

  /* Text on steel. The two greys used app-wide pass on navy and FAIL against the specular band:
     #9fb0c8 = 4.36:1 and #8fa2b8 = 3.67:1. Swap to these on any plated element. */
  /* --icon-1 is the canonical GLYPH colour — icons only, never body text. It was hard-coded as
     #9FB0C2 in 177 places. The near-identical #9fb0c8 sitting alongside it in ~98 places is a
     DIFFERENT thing (secondary text: .bkt-desc, .cc-tag, .conn) and is deliberately NOT folded in
     here; merging one byte of difference would have quietly flattened icon colour into text
     colour everywhere. Two tokens, two jobs. */
  --icon-1:#9FB0C2;
  --on-plate-1:#EAF1FB;  /* 8.4:1  */
  --on-plate-2:#B8C2CC;  /* 5.33:1 — the drop-in for both failing greys */
  --on-plate-3:#A9B4C0;  /* 4.6:1  — engraved eyebrow labels */

  /* ONE light angle for the entire app, never per-component. The app was ALREADY lit from the
     upper left and nobody wrote it down: splash sets dl.position(-1.35,0.35,1.1) and spacebg
     paints its brightest nebula at (0.08w, 0.19h). Formalised, every future component is
     correct by construction. Specular and grain run at --lit; body ramps run 158deg; light
     catches border-top and border-left; shadows fall down and slightly right. */
  --lit:104deg;
  --rake:50%;         /* driven by scroll in Stage 5; static default is a correct still frame */

  /* ═══ THE MATERIALS, AS TOKENS — the single source of truth for both recipes ═══
     Why tokens and not just classes. The steel system reached the PRIMITIVES (buttons, money
     tiles, tabs, input wells, toggles) and stopped before the CONTENT CARDS, which were left on
     the pre-system flat wash rgba(255,255,255,.05) — no gradient, no bevel, no shadow, so they
     read as HOLES CUT IN THE BACKGROUND rather than as objects sitting on it. That was 26 rules
     here and ~397 more written inline inside the pages.

     A .plate CLASS cannot reach those 397, because reaching them would mean editing markup on
     60 screens. A custom property can: a page-level rule swaps one value and inherits the
     recipe. So the recipe lives here, .plate consumes it, and so does every card rule in every
     page. Change the material once and 400 surfaces follow.

     THE SORT RULE, three seconds per element:
       Does it HOUSE an instrument — a measured number, a track, a steel chip, a control?
         -> STEEL. It is hull.
       Does it CARRY prose you read through, or does it repeat down the page as a list row?
         -> GLASS. It is a window. Six plates in a vertical run is wallpaper, not a material.
       Is it cut INTO a surface — an input, a nested row, a track?
         -> CHANNEL. Inverted light: dark top lip, light bottom lip.
       Is it the one thing the user can act on right now?
         -> LIT. Chartreuse, and nothing else on the screen.

     ONE LIGHT DIRECTION. Both ramps run 158deg, the plate radial sits at 10%/-14%, grain and
     specular run at --lit, and the channel is the deliberate inversion. Nothing here is lit
     from anywhere else. Inconsistent light is what makes a screen feel cheap even when every
     element on it is individually fine.

     TRAP: these are IMAGE lists. `background:var(--plate-fill)` is a clean swap for a rule whose
     only background was the flat wash, because it resets background-color to transparent at the
     same time. Where a background-COLOR has to survive, or where veining is layered on top,
     use `background-image:` instead — the shorthand erases layered gradients, which is how the
     monolith veining was lost once already. */

  /* STEEL — machined hull. Structure that HOLDS things. */
  --plate-fill:
    radial-gradient(130% 90% at 10% -14%, rgba(122,150,182,.13), transparent 58%),
    linear-gradient(158deg, var(--st-600) 0%, var(--st-700) 42%, var(--st-800) 74%, var(--st-900) 100%);
  /* Four ASYMMETRIC insets are a chamfer, not a stroke: light catches top and left, dark falls
     bottom and right, agreeing with --lit. A uniform 1px ring is the biggest "CSS card" tell. */
  --plate-bevel:
    inset 0 1px 0 rgba(200,214,230,.16),
    inset 1px 0 0 rgba(200,214,230,.06),
    inset 0 -1px 0 rgba(0,0,0,.55),
    inset -1px 0 0 rgba(0,0,0,.35);
  --plate-lift:4px 12px 30px rgba(2,5,10,.52);      /* a full-width card standing off the hull */
  --plate-lift-sm:0 6px 18px rgba(2,5,10,.34);      /* a row, or a plate nested inside another */
  --plate-line:1px solid rgba(255,255,255,.10);
  /* Tooling grain, MASKED to the lit band below — real brushed steel only shows tooling where
     light rakes it, and the mask conveniently keeps 11-12px type off the texture. */
  --plate-grain:repeating-linear-gradient(var(--lit),
    rgba(228,240,255,.055) 0 1px, rgba(0,0,0,.055) 1px 2.5px);
  /* Specular: a PRE-PAINTED layer that only ever TRANSLATES, never recomputes its stops.
     Translate composites; recomputing a gradient repaints. That is the whole 60fps question. */
  --plate-spec:linear-gradient(var(--lit),
    transparent 0%, rgba(200,214,230,.05) 22%, rgba(226,238,250,.115) 36%,
    rgba(200,214,230,.04) 48%, transparent 68%);
  /* Small icon medallion. Deliberately NO grain: a 2.5px period under a <=24px glyph moires at
     3x and reads as dirt, which is why .chip-steel has no ::before. */
  --chip-fill:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a);
  --chip-bevel:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55),
               0 2px 6px rgba(0,0,0,.35);
  /* The same chamfer with NO outer shadow. Ten sites had hand-copied the two insets without
     the 0 2px 6px — some deliberately (they sit flush, or they add their own longer throw),
     and folding them onto --chip-bevel would have quietly grown a shadow on each one. Dark
     mode has to come back byte-identical, so the short form gets its own token rather than
     being rounded up to the long one. */
  --chip-bevel-flush:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55);
  /* COLD steel — machined but not yet powered. Sits FLUSH (no outer lift) rather than proud,
     which is what makes "locked" read as awaiting activation instead of as a disabled div. */
  --plate-cold-fill:linear-gradient(158deg,#2a323b,#171d24 58%,#0e1318);
  --plate-cold-bevel:inset 0 1px 0 rgba(255,255,255,.12), inset 0 -1px 0 rgba(0,0,0,.55);

  /* GLASS — content you look THROUGH at the cosmos. Same 158deg axis as the plate, so the two
     materials agree about where the lamp is. The `inset 0 1px 0` top light and the long soft
     shadow are the whole difference between a window and a hole: premium dark is made of edge
     light, not texture. No backdrop-filter here on purpose — blur is expensive in WKWebView and
     it is already carried by the .surface tier below; the gradient, the top light and the
     shadow do 95% of the work at none of the cost. */
  --glass-fill:linear-gradient(158deg, rgba(255,255,255,.075), rgba(255,255,255,.023));
  --glass-line:1px solid rgba(255,255,255,.12);
  --glass-shadow:0 10px 30px rgba(3,7,14,.46), inset 0 1px 0 rgba(255,255,255,.15);
  --glass-shadow-sm:0 6px 18px rgba(3,7,14,.34), inset 0 1px 0 rgba(255,255,255,.13);

  /* CHANNEL — a groove milled INTO the hull. NOTE THE INVERSION: dark at the top lip, light on
     the LOWER lip. Getting this backwards is the number one way a recessed control reads as
     raised, and it is the reason a nested row must never reuse the plate. */
  --well-fill:linear-gradient(180deg, rgba(0,0,0,.28), rgba(255,255,255,.035));
  --well-bevel:inset 0 2px 4px rgba(0,0,0,.35), inset 0 -1px 0 rgba(214,230,250,.14);
  --channel-fill:linear-gradient(180deg, var(--st-900), #12171E);
  --channel-bevel:inset 0 1px 2px rgba(0,0,0,.75), inset 0 -1px 0 rgba(200,214,230,.10);

  /* ═══ TYPE SCALE. app.css carried 35 distinct sizes, most of them on HALF-PIXELS
     (10.5/11.5/12.5/13.5/14.5/15.5) — the single most reliable amateur tell in a UI, and the
     reason Copilot and Monzo read as more considered at a glance. Half-pixels are gone; these
     nine steps are the target for new work, and for collapsing the remaining whole-pixel sizes
     when there is time to check 120 screens for reflow.
     Tracking tightens as size grows — large type needs less air, small type needs more. ═══ */
  --t-1:11px; --t-2:12px; --t-3:13px; --t-4:14px; --t-5:16px;
  --t-6:19px; --t-7:23px; --t-8:28px; --t-9:34px;
  --tr-1:.01em; --tr-2:0em; --tr-3:-.005em; --tr-4:-.01em; --tr-5:-.015em;
  --tr-6:-.018em; --tr-7:-.02em; --tr-8:-.022em; --tr-9:-.025em;

  /* ═══ TEXT TOKENS — the nine colour LITERALS that carried every word in the app ═══
     Before the theme system these were hex, written 1,690 times across 134 files: #fff 475x,
     #eaf1fb 171x, #9fb6cf 164x, #20260a 149x and so on. A literal cannot have a light twin, so
     every one of those 1,690 sites was a screen that could never follow a theme — and the only
     alternatives were a light-mode stylesheet per screen (60+ files, the way a design system
     dies) or a blanket inversion that would have eaten the accent along with the text.
     Tokenised once, mechanically, in `color:` position only. Backgrounds keep their literals:
     a background is a MATERIAL, and materials are the --plate, --glass and --chip recipes.
     Dark values are the originals, so this block changed nothing about how dark mode renders.
     TWO literals were consolidated (both under 4/255, listed at the point of merge):
       #EAF1F8 -> --tx-2 (#EAF1FB)      #C7D2E0 -> --tx-3 (#C7D5E4)  */
  --tx-1:#FFFFFF;    /* brightest — headings, the figure on a card            (was #fff)      */
  --tx-2:#EAF1FB;    /* standard body on a plate                              (was #eaf1fb)   */
  --tx-2a:#E8EEF4;   /* topbar title + a few chrome labels                    (was #e8eef4)   */
  --tx-3:#C7D5E4;    /* secondary prose                                       (was #c7d5e4)   */
  --tx-3a:#CFE0F2;   /* secondary prose, the cooler variant                   (was #cfe0f2)   */
  --tx-m1:#9FB6CF;   /* muted meta                                            (was #9fb6cf)   */
  --tx-m2:#8FA2B8;   /* muted meta, dimmer                                    (was #8fa2b8)   */
  --tx-m3:#9FB0C8;   /* muted meta, the near-twin of --icon-1 kept separate   (was #9fb0c8)   */
  --tx-m4:#7F92A8;   /* eyebrow / caption                                     (was #7f92a8)   */
  --tx-m5:#93A4BB;   /* placeholder / ghost text                              (was #93a4bb)   */
  /* An OFF state — present but not active. The literal it replaces (#6b7d95, one site: the
     day-dot on wellness.html) measured 2.65:1 in DARK, on a wash that was itself invisible in
     light. Both halves are fixed together: the dot became a milled groove instead of a white
     wash, and the ink was lifted until the pair clears 4.5:1. THE ONE DELIBERATE DARK-MODE
     COLOUR CHANGE in this pass — everything else returns byte-identical. It is made because
     the value it replaces was failing, not because light mode wanted it. */
  --tx-m6:#8A9AB0;

  /* ON MEDIA — the one text tier that must NOT follow the theme. A caption sitting on a
     PHOTOGRAPH under a dark scrim has a fixed background: the picture does not get lighter
     because the app did. The news flip-card front is the case that proved it — tokenising its
     headline to --tx-1 turned white-on-photo into near-black-on-photo at 1.23:1. Identical in
     both token sets by design; if a value here ever differs between them, it is wrong.
     --media-panel is the housing those cards sit IN, which does follow the theme. */
  --on-media-1:#FFFFFF; --on-media-2:#C7D5E4; --on-media-3:#A9B4C0;
  --media-panel:#0B1A29;
  --media-scrim:rgba(255,255,255,.25);   /* a dot/rule drawn ON media, not on the theme */

  /* THE FOUR STATE COLOURS. Also literals until now (#e6b877 24x, #a6d95a 12x, #e0746a 7x), and
     they are the ones a light backdrop punishes hardest: a pastel-on-pastel warning is not a
     warning. Same discipline as the accent — the hue is kept, the lightness is what moves.
     None of them is allowed an outward glow in either mode: chartreuse emits, nothing else does. */
  --ok-1:#A6D95A;    /* done / healthy                                        (was #a6d95a)   */
  --warn-1:#E6B877;  /* needs attention — deliberately NOT the accent         (was #e6b877)   */
  --info-1:#8FB2D6;  /* live / syncing                                        (was #8fb2d6)   */
  --danger-1:#E0746A;/* destructive                                           (was #e0746a)   */

  /* THE ACCENT, AS A PAIR. --chart is the accent SURFACE, --ink-on-accent is what is written on
     it. In dark the surface is the lit chartreuse and the writing is near-black. In light the
     two SWAP ROLES (see the light block at the foot of this file): the surface becomes a deep
     chartreuse plate and the writing becomes the lit #DCE85C. Because both are tokens and every
     accent site in the app pairs them, that inversion needs no per-site edits at all. */
  --accent-fill:linear-gradient(180deg,#E9F383,#DCE85C 52%,#C5D14B);   /* .btn-primary ramp */
  --accent-fill-press:linear-gradient(180deg,#D3DF57,#C8D451 52%,#B7C344);
  --accent-glow:0 8px 22px rgba(var(--chart-rgb),.16);   /* chartreuse EMITS; steel never does */
  --accent-glow-sm:0 5px 14px rgba(120,140,20,.26);
  /* The accent as a lit ORB — a selected chip, a filled radio, a checked box. Written out as a
     literal radial in a dozen places, which pinned every one of them to the bright chartreuse
     and left --ink-on-accent (which DOES invert) sitting on top of it, unreadable in light. */
  --accent-orb:radial-gradient(circle at 38% 32%,#EEF6A8,#DCE85C 72%);
  /* EDGES. A hairline is a non-text indicator and owes 3:1 like any other. 389 borders across
     57 files were written as rgba(255,255,255,a) — correct on a dark hull, invisible on a pale
     one, and the case that makes it a defect rather than a blemish is the UNCHECKED checkbox:
     `border:2px solid rgba(255,255,255,.28)` with no fill is the entire affordance, so on light
     it stops being a control and becomes a gap. Swept in BORDER declarations only — the same
     literal in a background or a box-shadow is a highlight or a scrim, a different job with a
     different answer, and folding those in would have flipped every inset light to dark. */
  --edge-rgb:255,255,255;
  /* The accent as an rgb TRIPLE, so the 320 translucent accent washes and hairlines written
     as rgba(220,232,92,a) across the app move with the theme instead of staying lit-green on
     a pale field. Swept mechanically in the same pass as the text tokens; the dark value is
     the original triple, so nothing about dark mode moved.
     TRAP, and it cost a real regression before it was caught: a CANVAS fillStyle and an SVG
     PRESENTATION ATTRIBUTE (fill="…" / stroke="…" / stop-color="…") cannot resolve a CSS
     custom property — the value parses as invalid and the paint silently disappears. Canvas
     keeps literals (see spacebg.js); SVG that must follow the theme moves the paint into an
     inline style="fill:…", which IS real CSS. */
  --chart-rgb:220,232,92;
  /* Text written ON an accent WASH (a translucent chartreuse panel, not a solid accent fill).
     It is a third case and it needs its own token: --ink-on-accent is for the solid fill and
     is far too dark against a 15%-alpha wash, while --tx-1 has no accent character at all. */
  --on-accent-wash:#F2F7CF;
}
/* iOS picks the display optical size above 20px, which is what makes large type look drawn
   rather than scaled. Costs nothing on other platforms — the name simply does not resolve. */
h1, h2, .big, .nw-hero .big, .qr-grade b, .rc-grade b, .wl-greet, .rc-badge-name{
  font-family:'SF Pro Display', -apple-system, 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
html{ background:#03060d; }                 /* white-flash guard: dark before ANY paint, on every screen */
:root{ color-scheme:dark; }                 /* native form controls, scrollbars + keyboard render dark */

/* ── WAVE 1 · THE FEEL PASS ─────────────────────────────────────────────────
   Global craft floor. One block, all 120 screens. Nothing here is per-screen. */

/* 8 · Focus ring. :where() keeps specificity 0 so it never fights a component.
   Chartreuse reads as brand, not as compliance.

   THAT ZERO SPECIFICITY IS ALSO HOW IT DIED. Seven component rules — .field, .field-at input,
   .wb-inputbar input, .fb-note, .qa-search, .qa-specific input, .gen-row input — each declared
   `outline:none` at specificity 0,1,0, and each is declared AFTER this block. So the ring lost on
   both counts and there was no visible keyboard focus on ANY text field in the app. Those seven
   declarations are removed: the rule below already suppresses the browser default for pointer
   focus, which is the only thing they were there for. Do not re-add `outline:none` to a component
   — if a component needs a different ring, override `outline-color` or `outline-offset` instead. */
:where(a,button,input,select,textarea,[tabindex],[role="button"]):focus-visible{
  outline:2px solid var(--chart); outline-offset:2px; border-radius:inherit;
}
:where(a,button,input,select,textarea):focus:not(:focus-visible){ outline:none; }

/* 9 · Press feedback. 1,966 onclick handlers previously shared 56 :active rules, so most
   taps acknowledged nothing until the next page loaded.
   This list and WB_TAP_SEL in app.js must stay in sync. They had drifted, and the gap caught the
   wrong controls: `.cta` was in NEITHER, so in circle.html the three most consequential buttons in
   the app — Add to circle, Save birthday, Save rename — gave no visual and no tactile response. */
.btn,.glance,.qact,.sub-act,.pth-row,.c-orb,.wtab,.mtab,.opt,.hrow,.tapc,.plan,.door2,.ucard,.rtile,
.tile,.prow,.tool,.srow,.conn,.act-tile,.msq,.cc-row,.pi-opt,.mc-card,.crow,.codecard .cc-btn,
.cta,.h-go,.c-invite,.composer button,.wpath-cta,.bd-go,.addmem,.tl-arrow,.orbit-cyc{
  -webkit-tap-highlight-color:transparent; transition:transform var(--d-1) var(--ease-out);
}
.btn:active,.glance:active,.qact:active,.sub-act:active,.pth-row:active,.c-orb:active,.wtab:active,
.mtab:active,.opt:active,.hrow:active,.tapc:active,.plan:active,.door2:active,.ucard:active,
.rtile:active,.tile:active,.prow:active,.tool:active,.srow:active,.conn:active,.act-tile:active,
.msq:active,.cc-row:active,.pi-opt:active,.mc-card:active,.crow:active,
.cta:active,.h-go:active,.c-invite:active,.composer button:active,.wpath-cta:active,
.bd-go:active,.addmem:active,.tl-arrow:active,.orbit-cyc:active{ transform:scale(.97); }

/* 9b · Press feedback, THE FLOOR (M14). The list above names the 40 classes it knows about;
   everything else — the sidebar (72 handlers), the topbar icons (47), the bell (32), the back
   chevrons (18) — went down with no response at all. The floor is the attribute itself: if an
   element carries an onclick it is a control, so it dims on press. That one rule closes the gap
   for every handler in the app at once, including the 77 bare <button>s and the 83 bare icons
   that no class-based list would ever have caught.

   Excluded, deliberately: overlay scrims and sheets (`.ov`, `.sheet`, `.sb-panel`, `.pm-sheet`)
   carry an onclick only to close on backdrop tap — dimming the whole panel while a finger rests
   on it reads as the app breaking, not as a press. Form fields never dim.

   NO `transition` on the attribute rule. Several of these elements already declare
   `transition:transform` above, and a shorthand at this specificity would replace it outright and
   silently kill the scale on every .btn in the app. Opacity snaps on and snaps off. */
[onclick]{ -webkit-tap-highlight-color:transparent; }
/* THE GENERIC DIM IS GONE (Sep 28, founder: "there is a bug where touching/holding the screen makes it
   transparent fix that app-wide"). `[onclick]:active{ opacity:.62 }` dimmed ANY clickable element while a
   finger rested on it — and on a large clickable (a hero card, a plate, a whole row of squares) holding
   anywhere turned the section see-through, which reads as the app breaking. Press feedback now comes only
   from the designed states — the 0.97 depress on the named controls above and below, and the plates'
   inset press (§ plates). Nothing in the app changes opacity because it is being touched. */
/* The named high-traffic controls get the house treatment — depress, not just dim. Same 0.97 as
   the list above, so a control that gained feedback here feels identical to one that already had it.

   `.gcirc` is deliberately ABSENT from this transition group and present in the :active group
   below. wellness-workouts.html:114 already declares `transition:border-color var(--d-1),transform
   var(--d-1)` on it, and restating the shorthand here would delete the border-colour transition on
   the gym circles on any tie this file happened to win. It no longer wins that tie — app.css is a
   <link> in <head> and every page's own <style> comes after it, so a page's equal-specificity rule
   now beats this file by order (that is the whole reason this block was folded out of the injected
   wb-agency.css) — but the omission stays: it is correct independently of load order, and it is the
   only thing protecting a page that declares its transition somewhere app.css still outranks.
   Any class added to this group must first be checked for an existing `transition` declaration. */
.sb-item,.tb-ic,.bell,.b-back,.chip,.qzc-tog,.qzc-pm,.t-btn,.t-alt,.addex,.ds-btn,
.wrow,.act-row,.seg,.mtab-i,.ask-row{
  -webkit-tap-highlight-color:transparent; transition:transform var(--d-1) var(--ease-out);
}
.sb-item:active,.tb-ic:active,.bell:active,.b-back:active,.chip:active,.qzc-tog:active,
.qzc-pm:active,.t-btn:active,.t-alt:active,.addex:active,.ds-btn:active,.wrow:active,
.act-row:active,.gcirc:active,.seg:active,.mtab-i:active,.ask-row:active{
  transform:scale(.97);
}

/* 11 · 44px tap targets on topbar chrome. Negative margin grows the hit area without moving the glyph. */
.tb-ic,.bell{ display:inline-flex; align-items:center; justify-content:center;
  min-width:44px; min-height:44px; margin:-11px; }

/* 12 · Screen entrance. Every screen used to appear fully formed in a single frame, which is the
   main reason navigation felt like page loads rather than an app. Content rises a few pixels as it
   fades in, staggered over the first handful of blocks so the screen assembles top-down.

   Constraints this respects:
   · .topbar is excluded — navigation chrome should be present instantly, not animate in.
   · opacity + transform only, both compositor-driven; nothing here triggers layout.
   · `to { transform:none }` so no containing block survives the animation — a lingering transform
     on these would re-parent any absolutely-positioned descendant.
   · Gated on `no-preference`, not merely shortened under `reduce`: that way reduced-motion users
     get no animation and therefore no fill-mode, so content can never be held at opacity 0. */
@media (prefers-reduced-motion: no-preference){
  /* .no-rise opts a screen out — for art-directed sequences (splash) that choreograph their own
     elements and would otherwise be fighting a generic entrance for the same properties. */
  /* LONGHANDS, not the `animation` shorthand. The shorthand resets animation-delay to 0, and at
     specificity (0,4,2) it outranked the (0,2,0) delay rules below, so the 25ms stagger never ran
     on any screen: children 3 through 6 all computed animation-delay:0s. The screens still rose,
     they just rose all at once. Longhands leave delay alone. */

  /* EVERYTHING is wrapped in :where() so this whole block computes to specificity (0,0,0).
     That is the load-bearing part, not cosmetics. Written plainly, the `:not()` chain scored
     (0,6,0) — six classes — because :not() contributes the specificity of its argument. A
     generic default therefore outranked every page's own `.cb-title{animation:cbUp ...}`, and
     five screens silently lost the entrance choreography they were authored with: the staged
     reveals on celebrate and mywhy-report, .skip on splash, .glass on welcome, .on in
     wellness-mind. All of them computed animation-name:wbRise instead. At zero specificity a
     single class beats this, so page-authored motion always wins and this is only the default
     for screens that never asked for anything. */
  :where(.screen:not(.no-rise)) > :where(:not(.topbar):not(style):not(script):not(.ov)){
    animation-name:wbRise; animation-duration:var(--d-3);
    animation-timing-function:var(--ease-out); animation-fill-mode:both;
  }
  /* same guard on the delays, or a .no-rise screen gets delays on elements that never animate.
     :nth-child is inside :where() too — left bare it would re-introduce (0,1,0) and tie with a
     page's own single-class animation rule. */
  :where(.screen:not(.no-rise)) > :where(:not(.topbar):not(style):not(script):not(.ov)):where(:nth-child(2)){ animation-delay:25ms; }
  :where(.screen:not(.no-rise)) > :where(:not(.topbar):not(style):not(script):not(.ov)):where(:nth-child(3)){ animation-delay:50ms; }
  :where(.screen:not(.no-rise)) > :where(:not(.topbar):not(style):not(script):not(.ov)):where(:nth-child(4)){ animation-delay:75ms; }
  :where(.screen:not(.no-rise)) > :where(:not(.topbar):not(style):not(script):not(.ov)):where(:nth-child(5)){ animation-delay:100ms; }
  :where(.screen:not(.no-rise)) > :where(:not(.topbar):not(style):not(script):not(.ov)):where(:nth-child(6)){ animation-delay:125ms; }
  /* past the 6th block we are below the fold — no further delay, so nothing lags into view */
}
@keyframes wbRise{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }

/* 12b · Entrance, ONE LEVEL DOWN (M14). §12 rises the top-level blocks of every screen. This is
   the same motion for lists and card rows that a page rebuilds in place (the quiz options, a set
   of results) where no navigation happened and so nothing on the screen moved at all.

   `animation-fill-mode:backwards`, NOT `both`. `both` holds the final keyframe forever, and the
   final keyframe here is `transform:none` — which would then outrank `.qz-opt.sel{transform:
   translateY(-3px)}` for the life of the page and flatten every selected card. `backwards` fills
   only during the delay, which is the half a stagger actually needs, and releases the property
   the moment the animation ends.

   LONGHANDS, not the `animation` shorthand — same reason recorded at §12 above: the shorthand
   resets animation-delay, and the delay classes below would stop meaning anything. */
@media (prefers-reduced-motion: no-preference){
  @keyframes wbIn{ from{ opacity:0; transform:translateY(10px); } to{ opacity:1; transform:none; } }
  .wb-in{
    animation-name:wbIn; animation-duration:var(--d-3);
    animation-timing-function:var(--ease-out); animation-fill-mode:backwards;
    /* Explicit 0, or the screen-entrance delays above (25/50/75/100ms by nth-child) leak in
       through the cascade and the first item of a stagger starts AFTER the second. Measured: the
       quiz question inherited 75ms and landed behind its own first card. */
    animation-delay:0ms;
  }
  /* 55ms apart. Close enough to read as one gesture, far enough apart to read as an order —
     three cards land in 350ms total, which is under the threshold where a person starts waiting. */
  .wb-in.s2{ animation-delay:55ms; }
  .wb-in.s3{ animation-delay:110ms; }
  .wb-in.s4{ animation-delay:165ms; }
  .wb-in.s5{ animation-delay:220ms; }
  .wb-in.s6{ animation-delay:275ms; }
  /* past six the row is off-screen; no further delay, so nothing lags in behind the fold */
}

/* 12c · THE SUCCESS MOMENT (M14). One treatment, applied everywhere a person finishes something:
   a haptic (native only), one beat of motion, and the number counts rather than blinks.
   wbSuccess() in app.js is the only caller — see the comment there for the full contract.

   The ring is chartreuse because a completion IS the user's own act, which is the one thing the
   colour is reserved for. It expands and dissolves in 420ms and leaves nothing behind: no
   permanent glow, no state on the element. box-shadow, so it cannot participate in layout and
   cannot push a sibling. */
@media (prefers-reduced-motion: no-preference){
  /* LINEAR, and three stops. The first cut was two stops on --ease-out, and measuring it in the
     browser at 38% progress showed a 16px ring already down to 0.047 alpha — the easing spends the
     ring's whole life in the first fifth of its duration, so what shipped was a flicker nobody
     would consciously register. A ring is an expanding wavefront; it travels at a constant speed.
     Holding the alpha to 70% and collapsing it only at the end is what makes it read as one pulse. */
  @keyframes wbConfirm{
    0%  { box-shadow:0 0 0 0    rgba(var(--chart-rgb),.50); }
    70% { box-shadow:0 0 0 13px rgba(var(--chart-rgb),.24); }
    100%{ box-shadow:0 0 0 20px rgba(var(--chart-rgb),0); }
  }
  .wb-confirm{ animation:wbConfirm 480ms linear 1; }

  /* the settle — a completed thing takes its place rather than teleporting into it */
  @keyframes wbSettle{ from{ transform:translateY(5px); opacity:.5; } to{ transform:none; opacity:1; } }
  .wb-settle{ animation:wbSettle var(--d-3) var(--ease-out) 1; }
}

/* 13 · Reduced motion. Previously guarded 3 selectors on 3 screens; now global. */
@media (prefers-reduced-motion: reduce){
  :root{ --d-1:1ms; --d-2:1ms; --d-3:1ms; --d-4:1ms; --d-5:1ms; }
  *,*::before,*::after{ animation-duration:1ms !important; animation-iteration-count:1 !important;
    transition-duration:1ms !important; scroll-behavior:auto !important; }
}
*{ box-sizing:border-box; -webkit-font-smoothing:antialiased; }
body{
  margin:0; min-height:100vh; display:flex; align-items:center; justify-content:center;
  background:#0b1f33; padding:24px;
  font-family:-apple-system,'Helvetica Neue',Helvetica,Arial,sans-serif;
}
/* THE PHONE MOCK. `height` was a flat 852px, and body adds 24px of padding on each side — so on any
   viewport shorter than ~900px the mock overflowed, the DOCUMENT scrolled, and everything pinned to
   the phone's bottom edge scrolled away with it. The bottom tab bar is absolute/bottom:0 inside
   .phone, so that is exactly what it did: it rolled up the page instead of sitting at the foot.
   It looked page-specific and was not — it did it identically on home, wellness and wealth.

   Capping at the viewport fixes it everywhere at once and changes nothing on a screen tall enough to
   hold 852px, which includes the device the app actually ships to. `.screen` is inset:0 of this box,
   so it inherits the cap and keeps its own scroll. dvh (not vh) so a mobile browser's collapsing
   toolbar does not leave the bar cut off. */
.phone{
  width:393px; height:852px; max-height:calc(100dvh - 48px);
  background:var(--canvas); border-radius:54px;
  position:relative; overflow:hidden; border:11px solid #0a0a0a;
  box-shadow:0 24px 70px rgba(0,0,0,.55);
}
.island{ position:absolute; top:13px; left:50%; transform:translateX(-50%);
  width:122px; height:30px; background:#000; border-radius:20px; z-index:60; }
/* overscroll-behavior: .screen is a nested scroller inside an overflow:hidden .phone, so without
   this a rubber-band at either end chains to the document. That chaining is the classic
   "this is a web page, not an app" tell on iOS. */
.screen{ position:absolute; inset:0; padding:64px 26px 52px; overflow-y:auto;
  overscroll-behavior-y:contain; display:flex; flex-direction:column; }
.screen::-webkit-scrollbar{ display:none; }
.src-panel, .qa-panel, .sb-panel, .sheet{ overscroll-behavior:contain; }

/* ── PREMIUM-DARK shared utilities (glass surface + animated light-sheen) ── */
.glass{ position:relative; overflow:hidden; flex-shrink:0; border:1px solid var(--line);
  background:rgba(255,255,255,.045); backdrop-filter:blur(12px); border-radius:18px; }
/* Sheen. Two problems fixed at once: it animated `left` (a LAYOUT property) on a 5s infinite
   loop across every element carrying .sheen, and light-on-a-timer reads as a skeleton loader —
   years of shimmer placeholders have trained people to see it as "not loaded yet".
   Now: transform-only (compositor), and it runs ONCE when something actually happens.
   Add .sweep in JS at the moment that matters (a value updating, a card completing, a reveal). */
.sheen::before{ content:""; position:absolute; top:0; left:0; width:55%; height:100%;
  background:linear-gradient(115deg,transparent,rgba(255,255,255,.10),transparent);
  transform:translate3d(-110%,0,0); pointer-events:none; }
.sheen.sweep::before{ animation:wbsheen var(--d-4) var(--ease-out) 1; }
.sheen.d2.sweep::before{ animation-delay:90ms; } .sheen.d3.sweep::before{ animation-delay:180ms; }
@keyframes wbsheen{ from{ transform:translate3d(-110%,0,0); } to{ transform:translate3d(320%,0,0); } }

/* ── SKELETON — a held space, not a jump (M14) ──
   The news hero used to print a sentence ("Getting your 5-minute brief…") into a box sized for a
   card, and then swap in a card of a different height. Two layout shifts and a paragraph of
   apology. A skeleton holds the exact geometry the content will occupy, so the arrival is a
   crossfade rather than a jolt.

   The shimmer is the ONE place in this app where light-on-a-timer is correct. The .sheen note
   directly above records why the decorative sheen was killed — years of shimmer placeholders have
   trained people to see it as not-loaded-yet. That training is the asset here: this genuinely is
   not loaded yet.

   NEVER put .wb-skel on a .plate or a .glass. It sets `background`, and the shorthand erases the
   veining and the ramp underneath it. Skeletons are their own throwaway elements — which is also
   why this sits AFTER .glass rather than before it. */
.wb-skel{
  position:relative; overflow:hidden; border-radius:10px;
  background:linear-gradient(180deg, rgba(200,214,230,.075), rgba(200,214,230,.035));
  box-shadow:inset 0 1px 0 rgba(200,214,230,.06);
}
.wb-skel.line{ height:12px; }
.wb-skel.title{ height:19px; }
.wb-skel.block{ height:100%; border-radius:14px; }
.wb-skel.w40{ width:40%; } .wb-skel.w60{ width:60%; } .wb-skel.w85{ width:85%; }
.wb-skel + .wb-skel{ margin-top:9px; }
.wb-skels{ display:flex; flex-direction:column; justify-content:center; height:100%; padding:14px 2px; }
/* The news hero specifically. Both hosts (.wbn-stage 206px, .mkh 200px) are fixed-height boxes
   whose content is absolutely positioned, so the skeleton fills them the same way the story will:
   kicker, two lines of headline, a source line, all bottom-aligned where the real card puts them.
   Sizes match the type it stands in for — a skeleton that is not the shape of the content is just
   a grey box, and the whole point is that nothing moves when the words arrive. */
.wb-newsskel{
  position:absolute; inset:0; border-radius:16px; overflow:hidden;
  display:flex; flex-direction:column; justify-content:flex-end; padding:16px;
}
.wb-newsskel .kick{ width:32%; height:10px; }
.wb-newsskel .l1{ width:94%; height:16px; }
.wb-newsskel .l2{ width:62%; height:16px; }
.wb-newsskel .meta{ width:44%; height:10px; margin-top:12px; }
@media (prefers-reduced-motion: no-preference){
  .wb-skel::after{
    content:''; position:absolute; inset:0; pointer-events:none;
    background:linear-gradient(115deg, transparent 18%, rgba(200,214,230,.11) 50%, transparent 82%);
    transform:translate3d(-100%,0,0);
    animation:wbSkelSweep 1250ms linear infinite;
  }
  @keyframes wbSkelSweep{ to{ transform:translate3d(100%,0,0); } }
}

/* ── PULL TO REFRESH (M14; app.js mounts it, opt-in per screen via data-ptr) ──
   Mounted into .phone, not into .screen: .screen is the scroller, and an absolutely-positioned
   child of a scroller is laid out against the top of its CONTENT, so the indicator would scroll
   away the moment the list moved. .phone is position:relative and never scrolls.

   The disc is steel and reflects; it does not light up until the pull passes the threshold and a
   release would actually refresh something. That is the whole colour law in one control: dark
   while nothing will happen, chartreuse the instant the user's act would land. */
.wb-ptr{
  position:absolute; top:0; left:0; right:0; z-index:48; height:0;
  display:flex; align-items:flex-start; justify-content:center;
  pointer-events:none;
}
.wb-ptr-d{
  /* 56px clears the dynamic island (the mock draws it 13px down and 30px tall) and, in the native
     build, the status bar — .screen already reserves 64px of top padding for exactly this. Measured
     at 8px the armed disc sat BEHIND the island and the whole gesture had no visible indicator. */
  margin-top:56px; width:32px; height:32px; border-radius:50%;
  display:grid; place-items:center; font-size:16px; color:var(--icon-1);
  background:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a);
  border:1px solid rgba(var(--edge-rgb),.11);
  box-shadow:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55),
             0 4px 14px rgba(2,5,10,.5);
  opacity:0; transform:translate3d(0,-46px,0);
}
/* armed = past the threshold. The arrow has already turned to point up (JS rotates it with the
   pull), so the colour is confirming a state the geometry has stated. */
.wb-ptr.armed .wb-ptr-d{ color:var(--chart); border-color:rgba(var(--chart-rgb),.40); }
.wb-ptr.spin .wb-ptr-d{ color:var(--chart); }
@media (prefers-reduced-motion: no-preference){
  .wb-ptr.spin .wb-ptr-d i{ animation:wbPtrSpin 700ms linear infinite; }
  @keyframes wbPtrSpin{ from{ transform:rotate(0deg); } to{ transform:rotate(360deg); } }
}

/* ── LIVE (user-facing) mode: strip the prototype phone-frame + dev nav; full-bleed real page.
   Applied (via app.js) on the live domain; localhost keeps the framed prototype + dev tools. ── */
body.wb-live{ display:block; background:#070f1a; padding:0; }
/* max-width (C14): unbounded 100vw made desktop a stretched phone — 1228px-wide cards with 12px
   type and a 1200px CTA. 480px caps the column and centres it; on any actual phone 100vw is under
   the cap, so the shipped app is untouched. One rule, all 120 screens. */
body.wb-live .phone{ width:100vw; max-width:480px; margin-inline:auto; height:100dvh; min-height:100dvh; border:none; border-radius:0; box-shadow:none; }
body.wb-live .island{ display:none; }
body.wb-live #demonav{ display:none; }

/* ?shot=1 — CAPTURE MODE: crop-clean framed-phone screenshots.
   Backdrop matches the landing canvas so the corner slivers outside the phone's
   radius blend invisibly when the image sits on the landing; no shadow, no dev chrome. */
body.wb-shot{ background:#06101b; padding:0; }
body.wb-shot #demonav{ display:none; }
body.wb-shot .phone{ box-shadow:none; }
/* dev-only controls never show to real users or in captures */
body.wb-live .tc-cycle, body.wb-shot .tc-cycle{ display:none; }

.topbar{ display:flex; align-items:center; justify-content:space-between; }
/* Topbar chrome is NEUTRAL. This used to tint the back arrow, screen title and menu with the
   brand accent, and it was the single loudest wrong note in the app: no premium consumer app
   (Apple, Revolut, Oura, Copilot, Monzo) colours its chrome, because chrome that competes with
   the primary action caps perceived quality no matter what else is done. Accent is for the one
   thing you can act on; navigation is furniture. */
.topbar .tb-title{ color:var(--tx-2a); font-weight:800; }
.topbar .tb-ic, .topbar .tb-ic i{ color:var(--icon-1); }
/* The topbar band reads as the lit top edge of the hull. The highlight sits OFF-CENTRE (38%)
   so it reads as a light source rather than a border — a centred hairline always reads as a rule. */
.topbar{ position:relative; }
/* The topbar's right-hand pair — MyVault (home) and Notifications (bell). It replaced the hamburger
   Sep 1: the sidebar that opened listed the three worlds plus MyVault, and the bottom bar now carries
   the worlds on every screen while the home icon carries MyVault, so it was a third copy of a nav
   that already existed twice. Grouped in one span so `justify-content:space-between` still reads as
   [back] [title] [actions] rather than spreading three items across the bar. */
.tb-right{ display:flex; align-items:center; gap:10px; flex:0 0 auto; }
.topbar::after{
  content:''; position:absolute; left:-26px; right:-26px; bottom:-10px; height:1px; pointer-events:none;
  background:linear-gradient(100deg, rgba(255,255,255,.03), rgba(255,255,255,.26) 38%, rgba(255,255,255,.06));
}
/* persistent in-app back arrow (injected by app.js on header-less screens) */
.appback{ align-self:flex-start; width:34px; height:34px; border-radius:50%; background:var(--w16);
  color:var(--tx-1); border:none; cursor:pointer; display:inline-flex; align-items:center; justify-content:center;
  font-size:20px; margin-bottom:10px; flex:0 0 auto; }
/* landing → home forward arrow (returning users) */
.welcome-fwd{ position:absolute; top:58px; right:22px; z-index:30; width:34px; height:34px; border-radius:50%;
  background:var(--w16); color:var(--tx-1); display:inline-flex; align-items:center; justify-content:center;
  font-size:20px; cursor:pointer; text-decoration:none; }
.wordmark{ color:var(--chart); font-size:13px; font-weight:800; letter-spacing:1px; }
.bell{ color:var(--tx-1); font-size:21px; }

.h1{ color:var(--tx-1); font-size:26px; font-weight:800; line-height:1.12; }
.h2{ color:var(--tx-1); font-size:22px; font-weight:600; line-height:1.2; }
.sub{ color:var(--w85); font-size:16px; line-height:1.45; }
.small{ color:var(--w85); font-size:14px; line-height:1.4; }
.fine{ color:var(--w70); font-size:12px; line-height:1.45; }
.center{ text-align:center; }
.mt8{margin-top:8px;} .mt12{margin-top:12px;} .mt16{margin-top:16px;} .mt20{margin-top:20px;} .mt28{margin-top:28px;}
.spacer{ flex:1; }

.btn{ display:block; width:100%; border:none; border-radius:999px; padding:15px;
  font-size:15px; font-weight:600; text-align:center; cursor:pointer; text-decoration:none; }
/* A flat fill read as a coloured rectangle rather than a key you press. Same chartreuse, but
   lit: a top highlight, a shaded bottom edge, a soft chartreuse bloom so it appears to emit, and
   a real drop shadow so it sits ABOVE the plate instead of being painted onto it. The pressed
   state inverts the lighting — the highlight goes, an inner shadow arrives, the bloom dies — so
   the button physically depresses rather than just shrinking. */
.btn-primary{
  background:var(--accent-fill);
  color:var(--ink2);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.50),
              inset 0 -1.5px 0 rgba(0,0,0,.16),
              var(--accent-glow),
              0 2px 6px rgba(0,0,0,.40);
}
.btn-primary:active{
  background:var(--accent-fill-press);
  box-shadow: inset 0 2px 5px rgba(0,0,0,.26), 0 1px 2px rgba(0,0,0,.40);
}
.btn-white{ background:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a); border:1px solid rgba(var(--edge-rgb),.10); box-shadow:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55); color:var(--tx-2a); letter-spacing:.5px; }
.btn-ghost{ background:transparent; color:var(--tx-1); border:1px solid var(--chart); }
.btn-locked{ background:var(--w16); color:rgba(255,255,255,.6); cursor:not-allowed; }
.link{ color:var(--w85); font-size:13px; text-decoration:none; }
.linkc{ color:var(--chart); text-decoration:none; }

/* 9b · Overlays. Every screen declared its own `.ov{display:none}` / `.ov.on{display:block}`, so
   every modal in the app snapped in and out — and the 35 slide transforms already written for
   .sb-panel / .sheet / .gsheet / .add-sheet never played once, because a transition cannot run on
   an element emerging from display:none. Each screen now keeps its display value on `.ov` itself
   and hides via opacity, so those transforms finally animate.
   visibility is delayed on close (--d-4 = 320ms) so the child's slide-out — measured at ~257ms for
   a full-height sheet — finishes before the overlay leaves the a11y tree. pointer-events drops
   immediately either way, so nothing stays clickable during the fade. */
.ov{ opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity var(--d-2) var(--ease-out), visibility 0s linear var(--d-4); }
.ov.on{ opacity:1; visibility:visible; pointer-events:auto;
  transition:opacity var(--d-2) var(--ease-out), visibility 0s; }

/* Bottom sheets slide up. Only 4 of 19 screens had written this, so most sheets appeared by
   fading in place. Declared as a child selector so every sheet gets it without touching 19 files;
   the screens that already define their own transform still win on the cascade. */
.ov > .sheet, .ov > .pm-sheet{ transform:translateY(100%); transition:transform var(--d-3) var(--ease-out); }
.ov.on > .sheet, .ov.on > .pm-sheet{ transform:translateY(0); }

/* 10 · Dark inputs. `.field` was background:#fff across 93 uses, so a dark app flashed white
   slabs the moment anyone typed. Dark glass matches the treatment the tool screens already use. */
/* Input wells are CUT INTO the hull. Note the light edge moves to the BOTTOM — a recessed
   surface catches light on its lower lip, the inverse of a raised plate. Raised plates and
   recessed wells sharing one light source is the strongest available signal that a UI is a
   physical object rather than a stylesheet, and it costs four lines. */
.field{ width:100%; border-radius:12px; padding:14px; font-size:15px; color:var(--tx-1);
  background:linear-gradient(180deg, rgba(0,0,0,.28), rgba(255,255,255,.035));
  border:1px solid rgba(var(--edge-rgb),.08); border-bottom-color:rgba(214,230,250,.14);
  box-shadow:inset 0 2px 4px rgba(0,0,0,.35); }
.field::placeholder{ color:rgba(255,255,255,.42); }
.field:focus{ border-color:rgba(var(--chart-rgb),.5); }
.field-at{ display:flex; align-items:center; background:var(--well-fill); border:1px solid rgba(var(--edge-rgb),.08);
  border-bottom-color:rgba(214,230,250,.14); box-shadow:var(--well-bevel); border-radius:12px; padding:0 12px; }
.field-at span{ color:var(--blue); font-size:16px; font-weight:600; }
/* --ink is #13324d, a dark navy for light surfaces. On this dark card it renders typed text at
   roughly 1.3:1 — effectively invisible — and this is the @handle field on the fourth screen of
   onboarding, where someone is typing the name everyone will see them by. */
.field-at input{ border:none; background:transparent; padding:13px 8px; font-size:15px; width:100%; color:var(--tx-1); }
.code-field{ text-align:center; font-size:18px; font-weight:600; letter-spacing:3px; }

.check{ display:flex; align-items:flex-start; gap:10px; color:var(--tx-1); font-size:14px; line-height:1.4; }
.check input{ width:18px; height:18px; margin-top:2px; flex:0 0 auto; }

.card{ background:var(--chart); border-radius:20px; padding:22px; display:flex; flex-direction:column; align-items:center; gap:13px; }
.icon-lg{ font-size:58px; color:var(--ink2); }
.codebox{ background:linear-gradient(160deg, rgba(21,42,66,.85), rgba(9,20,33,.92)); border:1px solid rgba(var(--edge-rgb),.10); border-radius:12px; padding:14px; text-align:center; }
.codebox .lbl{ color:#888780; font-size:11px; letter-spacing:.5px; }
.codebox .val{ color:var(--ink); font-size:23px; font-weight:600; letter-spacing:3px; }
/* Was a flat chartreuse disc with a dark glyph — the one element on these screens that looked
   like clip art rather than part of the object. The system's rule is "hull is metal, only
   instruments are lit", so the disc becomes machined steel and the GLYPH is what lights up. */
.disc-circle{ width:72px; height:72px; border-radius:50%; margin:0 auto;
  display:flex; align-items:center; justify-content:center; color:var(--chart);
  background:linear-gradient(158deg,#3a4550,#1e252e 58%,#11161c);
  border:1px solid rgba(var(--edge-rgb),.12);
  box-shadow: inset 0 1.5px 0 rgba(210,224,240,.26),
              inset 0 -2px 0 rgba(0,0,0,.60),
              0 10px 28px rgba(0,0,0,.50); }

/* The brand mark inside the medallion. A generic sparkle glyph said nothing and read as clip art;
   WE is the actual mark and it is the one thing on the screen allowed to be lit. Optical sizing,
   not nominal — two heavy caps need slightly negative tracking or they read as W E. */
.disc-we{ font-size:29px; font-weight:900; letter-spacing:-.5px; line-height:1;
  color:var(--chart); font-family:inherit; }

.chips{ display:flex; gap:8px; flex-wrap:wrap; }
.chip{ font-size:12px; border-radius:999px; padding:6px 12px; }
.chip-on{ background:var(--chart); color:var(--ink2); font-weight:600; }
.chip-off{ background:var(--w16); color:var(--tx-1); }

.tog{ display:flex; background:var(--channel-fill); box-shadow:var(--channel-bevel); border-radius:999px; padding:3px; margin:14px auto 0; width:fit-content; }
.tog button{ border:none; background:transparent; font-size:13px; padding:6px 22px; border-radius:999px; color:var(--tx-1); cursor:pointer; font-family:inherit; }
.tog .on{ background:var(--chart); color:var(--ink2); font-weight:600; }

.orb{ position:relative; width:300px; height:300px; margin:8px auto 0; flex:0 0 auto; }
.mec{ position:absolute; left:115px; top:115px; width:70px; height:70px; border-radius:50%;
  background:radial-gradient(circle at 38% 30%, #2b3540, #141a21 72%); color:var(--chart);
  border:1px solid rgba(var(--edge-rgb),.12); box-shadow:inset 0 1px 0 rgba(200,214,230,.18), 0 4px 14px rgba(0,0,0,.45);
  display:flex; flex-direction:column; align-items:center; justify-content:center; }
.sat{ position:absolute; width:74px; text-align:center; }
.satc{ width:54px; height:54px; border-radius:50%; background:var(--chart);
  display:flex; align-items:center; justify-content:center; margin:0 auto; color:var(--ink2); font-size:24px; }
.satl{ color:var(--tx-1); font-size:11px; margin-top:4px; line-height:1.15; }
.hidden{ display:none; }

.tour-tab{ position:absolute; bottom:18px; right:18px; z-index:40;
  background:var(--chart); color:var(--ink2); border:none; border-radius:999px;
  padding:9px 14px; font-size:13px; font-weight:600; cursor:pointer; display:flex; align-items:center; gap:6px; font-family:inherit; }
.tour-box{ position:absolute; bottom:18px; right:18px; z-index:41; width:256px;
  background:linear-gradient(160deg, rgba(21,42,66,.85), rgba(9,20,33,.92)); border:1px solid rgba(var(--edge-rgb),.10); border-radius:14px; padding:14px; box-shadow:0 10px 30px rgba(0,0,0,.45); }
/* time-aware Today card (persistent under the orbit, both toggles) */
.today-card{ position:relative; background:var(--plate-fill); border:var(--plate-line);
  border-radius:18px; padding:13px 14px; margin:14px 2px 0; box-shadow:var(--plate-bevel), var(--plate-lift); }
.tc-cycle{ position:absolute; top:10px; right:10px; z-index:6; background:var(--chart); border:none;
  color:var(--ink2); font-size:11px; font-weight:800; border-radius:999px; padding:5px 12px; cursor:pointer; font-family:inherit; box-shadow:0 2px 8px rgba(0,0,0,.3); }
.today-card .tc-title{ padding-right:84px; }
.tc-title{ color:var(--tx-1); font-size:15px; font-weight:700; }
.tc-slides{ position:relative; margin-top:10px; min-height:86px; cursor:pointer; }
.tc-slide{ display:none; }
.tc-slide.active{ display:block; }
.tc-dots{ display:flex; gap:6px; justify-content:center; align-items:center; margin-top:11px; }
.tcd{ width:6px; height:6px; border-radius:50%; background:var(--w16); }
.tcd.on{ background:var(--chart); }
.tc-hint{ color:var(--w70); font-size:11px; margin-left:6px; }
.tc-reveal{ display:flex; align-items:center; gap:9px; background:var(--w16); border-radius:10px; padding:8px 10px; margin-top:9px; }
.tc-reveal i{ color:var(--chart); font-size:17px; flex:0 0 auto; }
.tc-reveal .rt{ color:var(--tx-1); font-size:12px; line-height:1.3; }
.tc-reveal b{ color:var(--chart); }
.tc-block{ margin-top:9px; border-top:1px solid var(--w16); padding-top:9px; }
.tc-tag{ color:var(--chart); font-size:10px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; }
.tc-quote-text{ color:var(--tx-1); font-size:14px; line-height:1.45; font-style:italic; margin-top:5px; }
.tc-by{ color:var(--w70); font-size:12px; margin-top:4px; }
.tc-ql{ color:var(--tx-1); font-size:14px; line-height:1.4; }
.tc-mrow{ display:flex; gap:8px; margin-top:9px; }
.tc-mini{ flex:1; padding:9px; border-radius:10px; font-size:13px; font-weight:600; text-align:center; cursor:pointer; font-family:inherit; }
.tc-mini.solid{ background:var(--chart); color:var(--ink2); border:none; }
.tc-mini.ghost{ background:transparent; border:1px solid var(--w70); color:var(--tx-1); }
.tc-cta{ display:block; width:100%; background:var(--chart); color:var(--ink2); border:none; border-radius:999px;
  padding:11px; font-size:14px; font-weight:700; margin-top:11px; cursor:pointer; font-family:inherit; text-align:center; text-decoration:none; }
.tc-note{ color:var(--w70); font-size:12px; text-align:center; margin-top:10px; }
.tc-prog{ color:var(--tx-1); font-size:13px; margin-top:11px; }

.tour-row{ display:flex; align-items:center; gap:9px; font-size:14px; margin-top:11px; }
.tour-done{ color:#9a9a94; text-decoration:line-through; }
.tour-todo{ color:var(--ink); }
.dock-left{ left:18px; right:auto; }

/* WeBot launcher (bottom-right) */
.webot-tab{ position:absolute; bottom:18px; right:18px; z-index:40; width:52px; height:52px;
  border-radius:50%; background:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a);  box-shadow:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55); color:var(--chart); border:1px solid rgba(var(--edge-rgb),.10); cursor:pointer;
  display:flex; align-items:center; justify-content:center; font-size:26px; box-shadow:0 8px 22px rgba(0,0,0,.28); }

/* 3-point home tour box (under the orbit) */
.hometour{ background:linear-gradient(160deg, rgba(21,42,66,.85), rgba(9,20,33,.92)); border:1px solid rgba(var(--edge-rgb),.10); border-radius:18px; padding:18px 18px 16px; margin:8px 2px 0;
  box-shadow:0 12px 34px rgba(0,0,0,.22); }
.hometour h4{ margin:0; color:var(--tx-2a); font-size:16px; font-weight:800; }
.ht-row{ display:flex; gap:10px; margin-top:12px; }
.ht-n{ width:20px; height:20px; border-radius:50%; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2);
  font-size:11px; font-weight:800; display:flex; align-items:center; justify-content:center; flex:0 0 auto; margin-top:1px; }
.ht-row span{ color:var(--tx-3); font-size:14px; line-height:1.4; }
.ht-rem{ color:var(--icon-1); font-size:13px; line-height:1.45; margin-top:14px; border-top:1px solid rgba(var(--edge-rgb),.10); padding-top:12px; }
.ht-rem b{ color:var(--tx-2a); }
.ht-body{ color:var(--tx-3); font-size:14px; line-height:1.5; margin-top:8px; }
#ht-action{ background:transparent; color:var(--blue); border:1.5px solid var(--blue); }
.ht-step{ color:#8a8f93; font-size:11px; font-weight:800; letter-spacing:.6px; }
/* guided-tour satellite highlight */
.satc{ transition:transform var(--d-2), box-shadow var(--d-2); }
.orb.touring .sat{ opacity:.32; transition:opacity var(--d-2); }
.orb.touring .sat.hl{ opacity:1; }
.sat.hl .satc{ transform:scale(1.16); box-shadow:0 0 0 4px rgba(255,255,255,.55), 0 0 22px rgba(var(--chart-rgb),.95); }
.orb.touring .mec.hl{ transform:scale(1.12); box-shadow:0 0 0 4px rgba(255,255,255,.55), 0 0 22px rgba(var(--chart-rgb),.95); transition:transform var(--d-2), box-shadow var(--d-2); }

/* MyCommunities rows */
.ccard{ display:flex; align-items:center; gap:12px; background:var(--w16); border-radius:14px; padding:14px; margin-top:10px; }
.ccard .ci{ width:42px; height:42px; border-radius:12px; background:var(--chart); color:var(--ink2);
  display:flex; align-items:center; justify-content:center; font-size:22px; flex:0 0 auto; }
.ccard .cn{ color:var(--tx-1); font-size:15px; font-weight:600; }
.ccard .cm{ color:var(--w70); font-size:13px; margin-top:2px; }

/* WeBot chat */
/* ── Wellthii chat ──────────────────────────────────────────────────────────────────────────────
   Steel for what Wellthii says, chartreuse for what you say. The old version was two flat rounded
   rectangles in a column: nothing carried the material the rest of the app is built from, so the
   one surface where the product literally speaks looked cheaper than every screen around it. */
.chat{ flex:1; display:flex; flex-direction:column; gap:14px; overflow-y:auto; padding:10px 0 6px;
  scrollbar-width:none; }
.chat::-webkit-scrollbar{ display:none; }

.bub{ max-width:82%; padding:12px 15px; font-size:14.5px; line-height:1.5;
  animation:bubIn .28s cubic-bezier(.2,.8,.2,1) both; }
@keyframes bubIn{ from{ opacity:0; transform:translateY(7px) } to{ opacity:1; transform:none } }

/* Wellthii speaks from a steel plate, with her mark in the gutter beside it. */
.bub-bot{ align-self:flex-start; position:relative; margin-left:38px; color:var(--tx-2);
  border-radius:16px 16px 16px 6px;
  background:linear-gradient(158deg,#2f3841,#1e262e 58%,#151b21);
  border:1px solid rgba(var(--edge-rgb),.10);
  box-shadow:inset 0 1px 0 rgba(200,214,230,.16), inset 0 -1px 0 rgba(0,0,0,.5), 0 6px 18px rgba(0,0,0,.34); }
.bub-bot::before{ content:''; position:absolute; left:-38px; bottom:1px; width:28px; height:28px; border-radius:50%;
  background:linear-gradient(158deg,#39424c,#232b34 58%,#171d23);
  border:1px solid rgba(var(--edge-rgb),.12);
  box-shadow:inset 0 1px 0 rgba(200,214,230,.18), 0 3px 10px rgba(0,0,0,.45); }
.bub-bot::after{ content:''; position:absolute; left:-28px; bottom:11px; width:8px; height:8px; border-radius:50%;
  background:radial-gradient(circle at 38% 32%, #f8ffcf, #dce85c 55%, #a6b636);
  box-shadow:0 0 8px rgba(var(--chart-rgb),.55);
  animation:wlPulse 2.6s ease-in-out infinite; }
@keyframes wlPulse{ 0%,100%{ opacity:1 } 50%{ opacity:.55 } }
.bub-bot + .bub-bot::after{ display:none; }
/* One mark per run of Wellthii bubbles, so a three-part answer is one voice, not three speakers. */
.bub-bot + .bub-bot::before{ display:none; }
.bub-bot + .bub-bot{ border-radius:6px 16px 16px 6px; margin-top:-6px; }

.bub-user{ align-self:flex-end; color:var(--ink-on-accent); font-weight:600;
  border-radius:16px 16px 6px 16px;
  background:var(--accent-fill);
  border:1px solid rgba(var(--edge-rgb),.22);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.42), 0 6px 18px rgba(120,140,20,.20); }

/* Three dots that actually breathe, instead of a literal "…" in a bubble. */
.bub-typing{ display:flex; gap:5px; align-items:center; padding:15px; }
.bub-typing span{ width:6px; height:6px; border-radius:50%; background:var(--chart);
  opacity:.35; animation:bubDot 1.25s ease-in-out infinite; }
.bub-typing span:nth-child(2){ animation-delay:.16s }
.bub-typing span:nth-child(3){ animation-delay:.32s }
@keyframes bubDot{ 0%,60%,100%{ opacity:.28; transform:translateY(0) } 30%{ opacity:1; transform:translateY(-3px) } }

.crisis-act{ display:flex; gap:8px; flex-wrap:wrap; max-width:100%; }
/* Wellthii's "jump into the tool she named" row. Quiet chips, not a second CTA stack. */
.tool-act{ display:flex; gap:8px; flex-wrap:wrap; max-width:100%; background:none; border:none; padding:0; }
.tool-act a{ display:inline-flex; align-items:center; min-height:44px; padding:0 14px; border-radius:999px;
  background:rgba(var(--chart-rgb),.13); border:1px solid rgba(var(--chart-rgb),.34); color:var(--chart);
  font-size:13px; font-weight:800; cursor:pointer; text-decoration:none; }

.crisis-act a{ flex:1; min-width:96px; text-align:center; padding:12px 10px; border-radius:12px;
  font-weight:800; font-size:13.5px; text-decoration:none; background:var(--chart); color:var(--ink2);  min-height:44px; display:flex; align-items:center; justify-content:center;}
.crisis-act a[href^="tel:911"]{ background:transparent; border:1px solid var(--chart); color:var(--chart); }

/* Openers are prompts, not a menu of four equal buttons stacked down the page. */
.wb-sugg{ display:flex; gap:8px; margin-top:2px; margin-left:38px; overflow-x:auto;
  scrollbar-width:none; padding-bottom:2px; }
.wb-sugg::-webkit-scrollbar{ display:none; }
.wb-sugg button{ flex:0 0 auto; font-family:inherit; text-align:left; cursor:pointer;
  font-size:12.5px; font-weight:650; color:#cfdcea; padding:9px 14px; border-radius:999px;
  background:linear-gradient(158deg,#2b333c,#1b222a 60%,#141a20);
  border:1px solid rgba(var(--edge-rgb),.11);
  box-shadow:inset 0 1px 0 rgba(200,214,230,.12); }
.wb-sugg button:active{ color:var(--tx-1); border-color:rgba(var(--chart-rgb),.45); }

.wb-inputbar{ display:flex; gap:9px; align-items:center; flex:0 0 auto;
  padding:11px 0 4px; margin-top:2px; border-top:1px solid rgba(var(--edge-rgb),.07); }
.wb-inputbar input{ flex:1; min-width:0; font-family:inherit; color:var(--tx-1);
  border-radius:999px; padding:13px 17px; font-size:14.5px;
  background:linear-gradient(180deg, rgba(0,0,0,.30), rgba(255,255,255,.035));
  border:1px solid rgba(var(--edge-rgb),.09); border-bottom-color:rgba(214,230,250,.15);
  box-shadow:inset 0 2px 5px rgba(0,0,0,.38); transition:border-color var(--d-1); }
.wb-inputbar input:focus{ border-color:rgba(var(--chart-rgb),.55); }
.wb-inputbar input::placeholder{ color:rgba(255,255,255,.42); }
.wb-send{ flex:0 0 auto; width:44px; height:44px; border-radius:50%; border:0; cursor:pointer;
  display:flex; align-items:center; justify-content:center; color:var(--ink-on-accent); font-size:19px;
  background:var(--accent-fill);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.42), var(--accent-glow-sm);
  transition:opacity var(--d-1), transform var(--d-1); }
.wb-send:active{ transform:scale(.94) }
.wb-send:disabled{ opacity:.3; cursor:default; box-shadow:none; }

/* dev nav — VERTICAL, outside the phone on the right (never over the screens) */
#demonav{ position:fixed; top:50%; left:calc(50% + 195px); transform:translateY(-50%); z-index:999;
  display:flex; flex-direction:column; gap:10px; background:rgba(0,0,0,.6); padding:12px 8px; border-radius:999px; }
/* narrow panels: pin to the viewport edge so it never clips off-screen */
@media (max-width:560px){ #demonav{ left:auto; right:6px; } }
#demonav button{ background:transparent; border:none; color:var(--tx-1); font-size:18px; cursor:pointer; opacity:.85; }
#demonav button:hover{ opacity:1; }
body.present #demonav{ display:none; }
#toast{ position:fixed; bottom:64px; left:50%; transform:translateX(-50%); z-index:999;
  background:#0a0a0a; color:var(--tx-1); font-size:13px; padding:10px 16px; border-radius:999px; opacity:0; transition:opacity var(--d-3); pointer-events:none; }
#toast.show{ opacity:.95; }

/* ---- MyKMBA assessment ---- */
.kdots{ display:flex; gap:6px; margin-top:14px; }
.kdots i{ width:7px; height:7px; border-radius:50%; background:var(--w16); }
.kdots i.on{ background:var(--chart); }
.kdots i.done{ background:var(--w70); }
.prompt{ color:var(--tx-1); font-size:23px; font-weight:700; line-height:1.18; margin-top:14px; }
.helper{ color:var(--w70); font-size:14px; line-height:1.4; margin-top:8px; }

.opts{ display:flex; flex-wrap:wrap; gap:9px; margin-top:18px; }
.opt{ position:relative; display:flex; align-items:center; gap:7px; border:1.5px solid transparent;
  background:var(--w16); color:var(--tx-1); border-radius:999px; padding:11px 15px; font-size:14px;
  font-family:inherit; cursor:pointer; line-height:1.1; transition:background var(--d-1),color var(--d-1),border-color var(--d-1); }
.opt .rb{ display:none; }
.opt[data-rank] .rb{ display:flex; align-items:center; justify-content:center;
  width:18px; height:18px; border-radius:50%; font-size:11px; font-weight:800;
  background:var(--chart); color:var(--ink2); }
.opt[data-rank]{ background:transparent; color:var(--chart); border-color:var(--chart); font-weight:600; }
.opt[data-rank="1"]{ background:var(--chart); color:var(--ink2); font-weight:600; }
.opt[data-rank="1"] .rb{ background:var(--ink2); color:var(--chart); }
.opt[data-rank="2"]{ background:rgba(var(--chart-rgb),.62); color:var(--ink2); font-weight:600; }
.opt[data-rank="2"] .rb{ background:var(--ink2); color:var(--tx-1); }
.opt[data-rank="3"]{ background:transparent; color:var(--chart); border-color:var(--chart); font-weight:600; }
.opt[data-rank="3"] .rb{ background:var(--chart); color:var(--ink2); }
.opt.sel{ background:var(--chart); color:var(--ink2); font-weight:600; }
.menu-group{ margin-top:18px; }
.menu-group-label{ color:var(--chart); font-size:11px; font-weight:800; letter-spacing:.8px; text-transform:uppercase; }
.menu-group .opts{ margin-top:9px; }
.plan-empty{ display:flex; flex-direction:column; align-items:center; text-align:center; gap:14px; }
.plan-empty .pe-ico{ width:72px; height:72px; border-radius:50%; background:var(--chart); color:var(--ink2);
  display:flex; align-items:center; justify-content:center; font-size:34px; }
/* Me hub — profile header */
.me-head{ display:flex; align-items:center; gap:14px; }
.me-av{ width:60px; height:60px; border-radius:50%; background:var(--chart); color:var(--ink2);
  display:flex; align-items:center; justify-content:center; font-size:30px; flex:0 0 auto; }
.me-id{ flex:1; min-width:0; }
.me-name{ color:var(--tx-1); font-size:19px; font-weight:800; }
.me-handle{ color:var(--w70); font-size:14px; margin-top:2px; }
.me-edit{ width:38px; height:38px; border-radius:50%; background:var(--w16); border:none; color:var(--tx-1);
  font-size:17px; cursor:pointer; flex:0 0 auto; display:flex; align-items:center; justify-content:center; }
.me-status{ display:flex; align-items:center; gap:7px; background:var(--w16); border-radius:12px;
  padding:11px 13px; margin-top:14px; color:var(--w85); font-size:13px; }
.me-status i{ color:var(--chart); flex:0 0 auto; }
.me-status-link{ margin-left:auto; color:var(--chart); font-weight:700; font-size:13px; cursor:pointer; flex:0 0 auto; }
/* MyCheckIn setup */
.ci-field{ margin-top:16px; }
.ci-q{ color:var(--tx-1); font-size:15px; font-weight:600; display:flex; align-items:center; gap:8px; line-height:1.35; }
.ci-sub{ color:var(--chart); font-size:12px; font-weight:700; }
.ci-stepper{ display:flex; align-items:center; gap:14px; margin-top:12px; }
.ci-step{ width:44px; height:44px; border-radius:50%; background:var(--w16); border:none; color:var(--tx-1); font-size:24px; font-weight:700; cursor:pointer; flex:0 0 auto; line-height:1; }
.ci-step:disabled{ opacity:.3; cursor:default; }
.ci-count{ flex:1; text-align:center; color:var(--chart); font-weight:800; }
.ci-count #ci-n{ font-size:34px; }
.ci-unit{ font-size:15px; color:var(--w70); margin-left:3px; }
.ci-rec{ color:var(--w70); font-size:12px; text-align:center; margin-top:8px; }
.ci-chips{ display:flex; flex-wrap:wrap; gap:8px; margin-top:12px; }
.ci-chip{ background:var(--w16); border:1px solid transparent; color:var(--w85); border-radius:999px; padding:9px 14px; font-size:13px; font-family:inherit; cursor:pointer; }
.ci-chip.on{ background:var(--chart); color:var(--ink2); font-weight:700; }
.ci-floor{ display:flex; align-items:center; gap:6px; color:var(--w70); font-size:12px; margin-top:12px; }
.ci-floor i{ color:var(--chart); }
.ci-card{ background:var(--plate-fill); border:var(--plate-line); border-radius:18px; padding:16px; margin-top:20px;
  box-shadow:var(--plate-bevel), var(--plate-lift); }
.ci-min{ display:flex; align-items:center; gap:12px; background:var(--w16); border-radius:14px; padding:13px; margin-top:20px; }
.ci-min.hidden{ display:none; }
.ci-min-i{ width:38px; height:38px; border-radius:10px; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2); display:flex; align-items:center; justify-content:center; font-size:18px; flex:0 0 auto; }
.ci-min-tx{ flex:1; min-width:0; }
.ci-min-t{ color:var(--tx-1); font-weight:700; font-size:14px; }
.ci-min-s{ color:var(--w70); font-size:12px; margin-top:2px; }
.ci-adjust{ background:var(--chart); color:var(--ink2); border:none; border-radius:999px; padding:8px 16px; font-size:13px; font-weight:700; font-family:inherit; cursor:pointer; flex:0 0 auto; }
.ts-card{ display:flex; align-items:center; gap:12px; background:var(--glass-fill); border:var(--glass-line); border-radius:14px; padding:13px; cursor:pointer;
  box-shadow:var(--glass-shadow-sm); }
.sys-link{ display:flex; align-items:center; gap:6px; color:var(--chart); font-size:13px; margin-top:8px; }
.sys-link.hidden{ display:none; }
/* Momentum menu card (home — the persistent "act" card) */
.mo-card{ background:var(--plate-fill); border:var(--plate-line); border-radius:18px; padding:16px; margin-top:14px;
  box-shadow:var(--plate-bevel), var(--plate-lift); }
.mo-head{ color:var(--tx-1); font-weight:800; font-size:15px; line-height:1.3; }
.mo-addsub{ color:var(--w70); font-size:13px; text-align:center; margin-top:12px; }
.mo-recs{ margin-top:10px; display:flex; flex-direction:column; gap:8px; }
.mo-rec{ display:flex; align-items:center; gap:10px; background:var(--w16); border:none; border-radius:12px; padding:11px 12px; cursor:pointer; font-family:inherit; text-align:left; }
.mo-rec .mo-ck{ color:var(--chart); font-size:20px; flex:0 0 auto; }
.mo-rec .mo-lbl{ flex:1; color:var(--tx-1); font-size:14px; }
.mo-rec.done .mo-lbl{ text-decoration:line-through; color:var(--w70); }
.mo-rec .dtag{ flex:0 0 auto; }
.mo-add{ width:100%; margin-top:8px; background:transparent; border:1.5px dashed var(--chart); color:var(--chart); border-radius:12px; padding:11px; font-size:14px; font-weight:700; font-family:inherit; cursor:pointer; }
.mo-rec.mo-added{ animation:moin .35s ease; }
@keyframes moin{ 0%{ transform:translateY(-6px) scale(.96); opacity:0; } 100%{ transform:none; opacity:1; } }
/* live feedback card */
.fb-card{ background:var(--plate-fill); border:var(--plate-line); border-radius:18px; padding:16px; margin-top:14px;
  box-shadow:var(--plate-bevel), var(--plate-lift); animation:moin .35s ease; }
.fb-top{ display:flex; align-items:center; justify-content:space-between; }
.fb-tag{ color:var(--chart); font-size:11px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; }
.fb-q{ color:var(--tx-1); font-size:15px; font-weight:700; margin-top:8px; line-height:1.3; }
.fb-chips{ display:flex; flex-wrap:wrap; gap:8px; margin-top:12px; }
.fb-schip{ background:var(--w16); border:1px solid transparent; color:var(--w85); border-radius:999px; padding:8px 13px; font-size:13px; font-family:inherit; cursor:pointer; }
.fb-schip.on{ background:var(--chart); color:var(--ink2); font-weight:700; }
.fb-note{ width:100%; border:none; background:linear-gradient(180deg, rgba(0,0,0,.28), rgba(255,255,255,.035)); border:1px solid rgba(var(--edge-rgb),.08); border-bottom-color:rgba(214,230,250,.14); box-shadow:inset 0 2px 4px rgba(0,0,0,.35); color:var(--tx-1); border-radius:12px; padding:11px 13px; font-size:14px; margin-top:12px; }
.fb-note::placeholder{ color:var(--w70); }
/* Quick-add library sheet */
.qa-sheet{ position:absolute; inset:0; z-index:60; }
.qa-backdrop{ position:absolute; inset:0; background:rgba(7,20,33,0.62); }
.qa-panel{ position:absolute; left:0; right:0; bottom:0; background:#0e2942; border-top-left-radius:22px; border-top-right-radius:22px; padding:18px 18px 22px; max-height:80%; overflow-y:auto; }
.qa-top{ display:flex; justify-content:space-between; align-items:center; color:var(--tx-1); font-weight:800; font-size:17px; }
.qa-hint{ color:var(--w70); font-size:13px; margin-top:4px; }
.qa-search{ width:100%; border:none; background:linear-gradient(180deg, rgba(0,0,0,.28), rgba(255,255,255,.035)); border:1px solid rgba(var(--edge-rgb),.08); border-bottom-color:rgba(214,230,250,.14); box-shadow:inset 0 2px 4px rgba(0,0,0,.35); color:var(--tx-1); border-radius:12px; padding:11px 13px; font-size:14px; margin-top:12px; }
.qa-search::placeholder{ color:var(--w70); }
.qa-specific{ margin-top:18px; }
.qa-specific input{ width:100%; border:none; background:var(--w16); color:var(--tx-1); border-radius:12px; padding:11px 13px; font-size:14px; }
.qa-specific input::placeholder{ color:var(--w70); }
.qa-pet{ display:flex; align-items:flex-start; gap:6px; color:var(--chart); font-size:12px; margin-top:8px; line-height:1.35; }
.qa-pet i{ flex:0 0 auto; margin-top:1px; }
.qa-panel .btn{ margin-top:16px; }
/* Me hub — connection rows */
.conn{ display:flex; align-items:center; gap:12px; background:var(--w16); border-radius:14px; padding:13px; margin-top:10px; }
.conn-i{ width:42px; height:42px; border-radius:12px; color:var(--icon-1);
  background:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a);
  box-shadow:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55);
  display:flex; align-items:center; justify-content:center; font-size:21px; flex:0 0 auto; }
.conn-tx{ flex:1; min-width:0; }
.conn-n{ color:var(--tx-1); font-size:15px; font-weight:600; }
.conn-s{ color:var(--w70); font-size:12px; margin-top:2px; }
.conn-btn{ background:var(--chart); color:var(--ink2); border:none; border-radius:999px; padding:8px 16px;
  font-size:13px; font-weight:700; font-family:inherit; cursor:pointer; flex:0 0 auto; }
.conn-status{ color:var(--chart); font-size:13px; font-weight:700; display:inline-flex; align-items:center; gap:5px; flex:0 0 auto; }
.conn-soon{ color:var(--w70); font-size:12px; font-weight:700; flex:0 0 auto; }
.mec{ cursor:pointer; }

/* Paywall / trial-confirm */
.pay-card{ width:100%; background:var(--w16); border-radius:16px; padding:16px; margin-top:0; }
.pay-row{ display:flex; align-items:center; justify-content:space-between; color:var(--tx-1); font-size:15px; padding:5px 0; }
.pay-row b{ color:var(--chart); font-weight:800; }
.pay-note{ color:var(--w70); font-size:12px; line-height:1.4; margin-top:9px; border-top:1px solid var(--w16); padding-top:9px; }

/* MyPlans — the recoverable WeBetter Report card */
.rep-card{ background:var(--plate-fill); border:var(--plate-line); border-radius:18px;
  padding:15px 16px; margin-top:16px; cursor:pointer; box-shadow:var(--plate-bevel), var(--plate-lift); }
.rep-card .rc-eyebrow{ color:var(--chart); font-size:11px; font-weight:800; letter-spacing:.6px; text-transform:uppercase; }
.rep-card .rc-row{ display:flex; align-items:center; gap:12px; margin-top:10px; }
.rep-card .rc-ico{ width:44px; height:44px; border-radius:50%; background:var(--chart); color:var(--ink2);
  display:flex; align-items:center; justify-content:center; font-size:22px; flex:0 0 auto; }
.rep-card .rc-name{ color:var(--chart); font-size:17px; font-weight:800; }
.rep-card .rc-line{ color:var(--tx-1); font-size:13px; line-height:1.4; margin-top:2px; }
.rep-card .rc-view{ display:flex; align-items:center; justify-content:flex-end; gap:5px; color:var(--chart);
  font-size:13px; font-weight:700; margin-top:12px; }

/* populated MyPlans */
.qrow{ display:flex; gap:10px; margin-top:14px; }
.qbtn{ flex:1; display:flex; align-items:center; justify-content:center; gap:7px; background:var(--w16); color:var(--tx-1);
  border:none; border-radius:12px; padding:12px; font-size:14px; font-weight:600; font-family:inherit; cursor:pointer; }
.qbtn i{ color:var(--chart); font-size:17px; }
.psec{ margin-top:20px; }
.psec-label{ color:var(--chart); font-size:11px; font-weight:800; letter-spacing:.8px; text-transform:uppercase; }
.pcard{ background:var(--w16); border-radius:14px; padding:14px; margin-top:10px; cursor:pointer; }
.pcard-top{ display:flex; align-items:flex-start; justify-content:space-between; gap:10px; }
.pcard .nm{ color:var(--tx-1); font-size:15px; font-weight:600; }
.pcard .tg{ color:var(--w70); font-size:12px; margin-top:3px; }
.pstat{ font-size:11px; font-weight:800; border-radius:999px; padding:4px 10px; white-space:nowrap; flex:0 0 auto; }
.pstat.act{ background:var(--chart); color:var(--ink2); }
.pstat.done{ background:var(--w16); color:var(--w85); border:1px solid var(--w70); }
.pstat.draft{ background:transparent; color:var(--chart); border:1px solid var(--chart); }
.pbar{ height:5px; background:var(--channel-fill); box-shadow:var(--channel-bevel); border-radius:999px; margin-top:11px; }
.pbar > i{ display:block; height:100%; background:var(--chart); border-radius:999px; box-shadow:0 0 0 1px rgba(6,9,14,.85), inset 0 1px 0 rgba(255,255,255,.28), 0 2px 10px rgba(var(--chart-rgb),.22); }

/* WeShare — scoped feed */
.post{ background:var(--w16); border-radius:14px; padding:14px; margin-top:11px; }
.post-head{ display:flex; align-items:center; gap:10px; }
.post-av{ width:38px; height:38px; border-radius:50%; background:var(--chart); color:var(--ink2);
  display:flex; align-items:center; justify-content:center; font-size:18px; flex:0 0 auto; }
.post-who{ flex:1; }
.post-name{ color:var(--tx-1); font-size:14px; font-weight:600; }
.post-src{ color:var(--chart); font-size:12px; margin-top:1px; }
.post-badge{ flex:0 0 auto; width:26px; height:26px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-weight:800; font-size:15px; }
.post-badge.share{ background:var(--chart); color:var(--ink2); }
.post-badge.ask{ background:transparent; border:1.5px solid var(--chart); color:var(--chart); }
.post-body{ color:var(--tx-1); font-size:14px; line-height:1.45; margin-top:11px; }
.post-foot{ display:flex; gap:16px; margin-top:11px; color:var(--w70); font-size:13px; }
.post-foot span{ display:flex; align-items:center; gap:5px; cursor:pointer; }
.fab-col{ position:absolute; bottom:18px; right:18px; display:flex; flex-direction:column; gap:10px; z-index:40; }
.fab{ width:52px; height:52px; border-radius:50%; border:none; cursor:pointer; font-size:25px; font-weight:800;
  display:flex; align-items:center; justify-content:center; box-shadow:0 8px 22px rgba(0,0,0,.28); }
.fab.ask{ background:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a); box-shadow:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55); color:var(--chart); border:1px solid rgba(var(--edge-rgb),.10); }
.fab.share{ background:var(--chart); color:var(--ink2); }

/* MyNews — swipe card */
.news-card{ background:linear-gradient(160deg, rgba(21,42,66,.85), rgba(9,20,33,.92)); border:1px solid rgba(var(--edge-rgb),.10); border-radius:18px; overflow:hidden; margin-top:16px; box-shadow:0 12px 30px rgba(0,0,0,.25); }
.news-img{ height:118px; display:flex; align-items:center; justify-content:center; font-size:46px; color:var(--ink2); background:var(--chart); }
.news-pad{ padding:16px; }
.news-cat{ color:var(--blue); font-size:11px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; }
.news-head{ color:var(--ink); font-size:18px; font-weight:800; line-height:1.25; margin-top:7px; }
.news-snip{ color:#566; font-size:14px; line-height:1.45; margin-top:8px; }
.news-source{ color:#889; font-size:12px; margin-top:10px; }
.news-actions{ display:flex; gap:10px; margin-top:14px; }
.news-actions .btn{ flex:1; margin-top:0; }
.news-deck{ text-align:center; color:var(--w70); font-size:12px; margin-top:14px; }
.news-hint{ text-align:center; color:var(--w70); font-size:12px; margin-top:6px; }
.coming{ background:var(--w16); border:1px dashed var(--w70); border-radius:14px; padding:14px; margin-top:16px;
  color:var(--w85); font-size:13px; text-align:center; }
.coming b{ color:var(--chart); }

/* MyReferrals — cash home */
.earn-card{  border:1px solid var(--w16); border-radius:18px;
  padding:18px; text-align:center; margin-top:14px; box-shadow:0 8px 22px rgba(0,0,0,.2); }
.earn-card .ec-lbl{ color:var(--w70); font-size:11px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; }
.earn-card .ec-amt{ color:var(--chart); font-size:40px; font-weight:800; line-height:1; margin-top:8px; }
.earn-card .ec-sub{ color:var(--w85); font-size:13px; margin-top:8px; }
.earn-card .ec-btn{ display:inline-block; background:var(--chart); color:var(--ink2); border:none; border-radius:999px;
  padding:11px 22px; font-size:14px; font-weight:700; margin-top:14px; cursor:pointer; font-family:inherit; }
.share-link{ display:flex; align-items:center; gap:8px; background:var(--w16); border-radius:12px; padding:11px 13px; margin-top:11px; }
.share-link .sl-code{ flex:1; color:var(--tx-1); font-size:14px; font-family:ui-monospace,monospace; letter-spacing:.3px; }
.share-link .sl-copy{ color:var(--chart); font-weight:700; font-size:13px; cursor:pointer; flex:0 0 auto; }
/* stays white for scannability — the bezel makes it read as a screen in a housing */
.qr-box{ width:140px; height:140px; background:#fff; border-radius:16px; margin:12px auto 0;
  box-shadow:0 0 0 6px #1C232C, 0 0 0 7px rgba(200,214,230,.18), 0 8px 22px rgba(0,0,0,.5);
  display:flex; align-items:center; justify-content:center; }
.qr-box i{ font-size:104px; color:var(--ink2); }
.rate-note{ color:var(--w70); font-size:12px; text-align:center; margin-top:12px; line-height:1.4; }
.rate-note b{ color:var(--chart); }

/* MyTrophies — achievements (no point score) */
.badge-grid{ display:flex; flex-wrap:wrap; gap:10px; margin-top:11px; }
.badge{ width:calc(33.333% - 7px); text-align:center; }
.badge .bmedal{ width:62px; height:62px; border-radius:50%; margin:0 auto; display:flex; align-items:center; justify-content:center;
  font-size:28px; background:var(--chart); color:var(--ink2); box-shadow:0 6px 16px rgba(var(--chart-rgb),.25); }
.badge .bnm{ color:var(--tx-1); font-size:12px; font-weight:600; margin-top:8px; line-height:1.2; }
.badge .bsub{ color:var(--w70); font-size:10px; margin-top:2px; }
.badge.locked .bmedal{ background:var(--w16); color:var(--w70); box-shadow:none; }
.badge.locked .bnm{ color:var(--w70); }

/* MyTools — systems-check assessment */
.sys-row{ background:var(--w16); border-radius:14px; padding:13px; margin-top:10px; }
.sys-top{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
.sys-label{ color:var(--tx-1); font-size:15px; font-weight:600; }
.yn{ display:flex; gap:6px; flex:0 0 auto; }
.yn button{ border:1px solid var(--w70); background:transparent; color:var(--w85); border-radius:999px;
  padding:6px 15px; font-size:13px; font-family:inherit; cursor:pointer; }
.yn button.on{ background:var(--chart); color:var(--ink2); border-color:var(--chart); font-weight:700; }
.sys-pick{ margin-top:11px; }
/* Was background:#fff with a dark-navy chevron — it overrode the dark .field and put a white
   slab in a dark app, with the caret invisible once darkened. Chevron stroke lightened to match. */
select.field{ width:100%; appearance:none; -webkit-appearance:none; box-shadow:inset 0 2px 4px rgba(0,0,0,.35); background:linear-gradient(180deg,rgba(0,0,0,.28),rgba(255,255,255,.035)), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3'><path d='M6 9l6 6 6-6'/></svg>") no-repeat right 14px center;
  border:1px solid var(--line); border-radius:12px; padding:11px 36px 11px 14px; font-size:14px; color:var(--tx-1); font-family:inherit; cursor:pointer; }

/* MyTools — toolkit launcher */
.tool-assess{ display:flex; align-items:center; gap:12px; background:var(--plate-fill); border:var(--plate-line);
  border-radius:16px; padding:14px; margin-top:16px; cursor:pointer; box-shadow:var(--plate-bevel), var(--plate-lift-sm); }
.tool-assess .ta-i{ width:42px; height:42px; border-radius:12px; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2);
  display:flex; align-items:center; justify-content:center; font-size:22px; flex:0 0 auto; }
.tool-assess .ta-t{ color:var(--tx-1); font-size:15px; font-weight:600; }
.tool-assess .ta-s{ color:var(--w70); font-size:12px; margin-top:2px; }
.tool-assess .ta-arrow{ margin-left:auto; color:var(--chart); }
.tool-grid{ display:flex; flex-wrap:wrap; gap:10px; margin-top:11px; }
.tile{ width:calc(33.333% - 7px); background:var(--w16); border-radius:14px; padding:13px 6px 11px; text-align:center; cursor:pointer; }
.tool-grid.tg-2 .tile{ width:calc(50% - 5px); }   /* 2×2 grid (WeBetter tools) */
.tile .tic{ width:46px; height:46px; border-radius:13px; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2);
  display:flex; align-items:center; justify-content:center; font-size:23px; margin:0 auto; }
.tile .tnm{ color:var(--tx-1); font-size:12px; font-weight:600; margin-top:8px; line-height:1.2; }
.tile .tst{ color:var(--w70); font-size:10px; margin-top:3px; }
.tile.covered{ opacity:.55; }
.tile.covered .tst{ color:var(--w85); }
.tile.add{ background:transparent; border:1.5px dashed var(--chart); }
.tile.add .tst{ color:var(--chart); font-weight:700; }
/* MyTools — Projects */
.proj-card{ display:flex; align-items:center; gap:12px; background:var(--glass-fill); border:var(--glass-line); border-radius:14px; padding:14px; margin-top:10px;
  box-shadow:var(--glass-shadow-sm); }
.proj-tx{ flex:1; min-width:0; }
.proj-n{ color:var(--tx-1); font-size:15px; font-weight:700; }
.proj-c{ color:var(--w70); font-size:12px; margin-top:2px; }
.proj-actions{ display:flex; gap:8px; flex:0 0 auto; }
.proj-btn{ background:var(--w16); color:var(--tx-1); border:none; border-radius:999px; padding:7px 13px; font-size:12px; font-weight:700; font-family:inherit; cursor:pointer; }
.proj-btn.up{ background:var(--chart); color:var(--ink2); }
.proj-pop{ position:absolute; inset:0; z-index:70; display:flex; align-items:center; justify-content:center; }
.proj-pop.hidden{ display:none; }
.proj-pop-bg{ position:absolute; inset:0; background:rgba(7,20,33,0.62); }
.proj-pop-card{ position:relative; width:80%; background:#0e2942; border:1px solid var(--w16); border-radius:18px; padding:22px; text-align:center; }
.proj-pop-t{ color:var(--tx-1); font-size:17px; font-weight:800; }
/* Trophies tab — sort toggle + count chip + motivator */
.tr-head{ display:flex; align-items:center; justify-content:space-between; }
.tr-sort{ display:flex; gap:4px; background:var(--channel-fill); box-shadow:var(--channel-bevel); border-radius:999px; padding:3px; }
.tr-sort button{ border:none; background:transparent; color:var(--w85); font-size:11px; padding:4px 11px; border-radius:999px; font-family:inherit; cursor:pointer; }
.tr-sort button.on{ background:var(--chart); color:var(--ink2); font-weight:700; }
.tr-motiv{ display:flex; align-items:center; gap:7px; color:var(--w85); font-size:13px; margin-top:8px; background:var(--w16); border-radius:12px; padding:11px 13px; }
.tr-motiv i{ color:var(--chart); }
.tr-motiv b{ color:var(--chart); }
.badge{ position:relative; }
.b-count{ position:absolute; top:6px; right:8px; background:var(--chart); color:var(--ink2); font-size:11px; font-weight:800; border-radius:999px; padding:1px 7px; }
/* flex card — mystery → trophy reveal */
.tc-rv{ text-align:center; padding:2px 0; }
.tc-rv-medal{ width:62px; height:62px; border-radius:50%; background:var(--chart); color:var(--ink2); display:flex; align-items:center; justify-content:center; margin:0 auto; position:relative; font-size:29px; }
.tc-rv-medal.mystery i{ opacity:.22; }
.tc-rv-medal .rv-q{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-size:32px; font-weight:800; color:var(--ink2); }
.tc-rv-medal.revealed{ animation:rvpop .5s ease; }
@keyframes rvpop{ 0%{ transform:scale(.6) rotate(-12deg); opacity:.4; } 60%{ transform:scale(1.18) rotate(6deg); } 100%{ transform:scale(1) rotate(0); opacity:1; } }
.tc-rv-title{ color:var(--tx-1); font-weight:800; font-size:15px; margin-top:9px; }
.tc-rv-line{ color:var(--w70); font-size:13px; margin-top:3px; }
.tc-rv-btn{ background:var(--chart); color:var(--ink2); border:none; border-radius:999px; padding:8px 16px; font-size:13px; font-weight:800; font-family:inherit; cursor:pointer; margin-top:11px; }
/* flex card — QOTD vote */
.qotd-vote{ display:flex; align-items:center; gap:8px; margin-top:11px; }
.qv{ width:34px; height:34px; border-radius:50%; background:var(--w16); border:none; color:var(--tx-1); font-size:15px; cursor:pointer; }
.qv-hint{ color:var(--w70); font-size:11px; margin-left:2px; }

/* MyInsights — link + manage */
.ins-hero{ text-align:center; margin-top:18px; }
.ins-hero .ih-ico{ width:64px; height:64px; border-radius:50%; background:var(--chart); color:var(--ink2);
  display:flex; align-items:center; justify-content:center; font-size:30px; margin:0 auto; }
.ins-hero h3{ color:var(--tx-1); font-size:21px; font-weight:800; margin:14px 0 0; }
.ins-hero p{ color:var(--w85); font-size:14px; line-height:1.45; margin:8px 0 0; }
.locked-insight{ position:relative; background:var(--plate-cold-fill); border:1px solid rgba(var(--edge-rgb),.08);
  border-radius:14px; padding:14px; margin-top:18px; box-shadow:var(--plate-cold-bevel); }
.locked-insight .li-tag{ color:var(--chart); font-size:10px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; }
.locked-insight .li-text{ color:var(--tx-1); font-size:14px; line-height:1.4; margin-top:6px; filter:blur(3px); opacity:.85; }
.locked-insight .li-lock{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center; gap:7px;
  color:var(--chart); font-size:13px; font-weight:700; }
.trust-line{ display:flex; align-items:center; justify-content:center; gap:6px; color:var(--w70); font-size:12px; margin-top:16px; }
.link-card{ display:flex; align-items:center; gap:13px; background:var(--w16); border-radius:14px; padding:15px; margin-top:11px; cursor:pointer; }
.link-card .lc-i{ width:44px; height:44px; border-radius:12px; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2);
  display:flex; align-items:center; justify-content:center; font-size:23px; flex:0 0 auto; }
.link-card .lc-t{ color:var(--tx-1); font-size:15px; font-weight:600; }
.link-card .lc-s{ color:var(--w70); font-size:13px; margin-top:2px; }
.link-card .lc-arrow{ margin-left:auto; color:var(--w70); }
.acct{ display:flex; align-items:center; gap:12px; background:var(--w16); border-radius:14px; padding:13px; margin-top:10px; }
.acct .ac-i{ width:40px; height:40px; border-radius:10px; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2);
  display:flex; align-items:center; justify-content:center; font-size:20px; flex:0 0 auto; }
.acct .ac-n{ color:var(--tx-1); font-size:15px; font-weight:600; }
.acct .ac-m{ color:var(--w70); font-size:12px; margin-top:2px; }
.acct .ac-rm{ margin-left:auto; color:var(--w70); font-size:20px; cursor:pointer; flex:0 0 auto; }
.ins-priv{ display:flex; align-items:center; gap:10px; background:var(--w16); border-radius:12px; padding:13px; margin-top:10px; }
.ins-priv i{ color:var(--chart); font-size:19px; }
.ins-priv .ip-t{ color:var(--tx-1); font-size:14px; }
.ins-priv .ip-v{ margin-left:auto; color:var(--chart); font-size:13px; font-weight:700; cursor:pointer; }
/* MyInsights — priority 2 (insight cards) + priority 3 (reports) */
.itabs{ margin-top:14px; }
.icard{ background:var(--w16); border-radius:14px; padding:14px; margin-top:11px; }
.icard.hero{ background:var(--plate-fill); border:var(--plate-line); box-shadow:var(--plate-bevel), var(--plate-lift-sm); }
.icard.bench{ background:transparent; border:1px dashed var(--w70); }
.ic-tag{ color:var(--chart); font-size:10px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; }
.icard.hero .ic-tag{ display:inline-flex; align-items:center; gap:5px; }
.ic-find{ color:var(--tx-1); font-size:14px; line-height:1.45; margin-top:6px; }
.ic-find b{ color:var(--chart); }
.ic-viz{ height:6px; background:var(--channel-fill); box-shadow:var(--channel-bevel); border-radius:999px; margin-top:11px; }
.ic-viz > i{ display:block; height:100%; background:var(--chart); border-radius:999px; box-shadow:0 0 0 1px rgba(6,9,14,.85), inset 0 1px 0 rgba(255,255,255,.28), 0 2px 10px rgba(var(--chart-rgb),.22); }
.ic-act{ display:inline-flex; align-items:center; gap:5px; color:var(--chart); font-size:13px; font-weight:700; margin-top:11px; cursor:pointer; }
.gen-row{ display:flex; gap:8px; align-items:center; margin-top:10px; }
.gen-row input{ flex:1; border:1px solid var(--line); background:linear-gradient(180deg, rgba(0,0,0,.28), rgba(255,255,255,.035)); border:1px solid rgba(var(--edge-rgb),.08); border-bottom-color:rgba(214,230,250,.14); box-shadow:inset 0 2px 4px rgba(0,0,0,.35); border-radius:999px; padding:11px 14px; font-size:14px; color:var(--tx-1); }
.gen-row input::placeholder{ color:rgba(255,255,255,.45); }
.gen-send{ width:42px; height:42px; border-radius:50%; background:var(--chart); color:var(--ink2); border:none; cursor:pointer; font-size:18px; display:flex; align-items:center; justify-content:center; flex:0 0 auto; }
.rep-row{ display:flex; align-items:center; gap:11px; background:var(--w16); border-radius:13px; padding:13px; margin-top:10px; cursor:pointer; }
.rep-row .rr-i{ width:38px; height:38px; border-radius:10px; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2); display:flex; align-items:center; justify-content:center; font-size:19px; flex:0 0 auto; }
.rep-row .rr-n{ color:var(--tx-1); font-size:14px; font-weight:600; }
.rep-row .rr-m{ color:var(--w70); font-size:12px; margin-top:2px; }
.rep-row .rr-share{ margin-left:auto; color:var(--w70); font-size:18px; }

/* MyActions */
.stat-strip{ display:flex; gap:10px; margin-top:14px; }
.stat{ flex:1; background:var(--w16); border-radius:14px; padding:14px; }
.stat .lbl{ color:var(--w70); font-size:11px; font-weight:800; letter-spacing:.4px; text-transform:uppercase; }
.stat .big{ color:var(--chart); font-size:28px; font-weight:800; line-height:1; margin-top:8px; }
.stat .sub2{ color:var(--w85); font-size:12px; line-height:1.35; margin-top:7px; }
.mdots{ display:flex; gap:5px; margin-top:9px; }
.md{ width:11px; height:11px; border-radius:50%; background:transparent; border:1.5px solid var(--w70); }
.md.on{ background:var(--chart); border-color:var(--chart); }
.xhook{ display:flex; align-items:center; gap:12px; background:var(--plate-fill); border:var(--plate-line);
  border-radius:16px; padding:14px; margin-top:16px; cursor:pointer; box-shadow:var(--plate-bevel), var(--plate-lift-sm); }
.xhook .xi{ color:var(--chart); font-size:22px; flex:0 0 auto; }
.xhook .xt{ color:var(--tx-1); font-size:13px; line-height:1.4; flex:1; }
.xhook .xt b{ color:var(--chart); }
.xhook .xt span{ color:var(--chart); font-weight:700; }
.xhook .xarrow{ color:var(--chart); flex:0 0 auto; }
.act-sec{ margin-top:20px; }
.act-cap{ color:var(--w70); font-size:12px; margin-top:3px; }
.act-row{ display:flex; align-items:center; gap:12px; padding:12px 2px; border-bottom:1px solid var(--w16); }
.act-check{ font-size:24px; color:var(--w70); cursor:pointer; flex:0 0 auto; line-height:1; }
.act-row.done .act-check{ color:var(--chart); }
.act-body{ flex:1; }
.act-name{ color:var(--tx-1); font-size:15px; }
.act-row.done .act-name{ color:var(--w70); text-decoration:line-through; }
.act-meta{ display:flex; align-items:center; gap:8px; margin-top:4px; }
.dtag{ font-size:11px; color:var(--w85); background:var(--w16); border-radius:999px; padding:2px 8px; }
.act-prog{ color:var(--w70); font-size:12px; }
.opt-add{ border:1.5px dashed var(--w70); color:var(--w85); background:transparent; }
.add-field{ width:100%; margin-top:10px; }

.fu{ margin-top:22px; border-top:1px solid var(--w16); padding-top:18px; }
.fu-head{ color:var(--chart); font-size:12px; font-weight:800; letter-spacing:.6px; text-transform:uppercase; }
.fu-item{ margin-top:14px; }
.fu-q{ color:var(--tx-1); font-size:15px; line-height:1.3; margin-bottom:7px; display:flex; align-items:center; gap:7px; }
.fu-q .qn{ width:18px; height:18px; border-radius:50%; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2);
  font-size:11px; font-weight:800; display:flex; align-items:center; justify-content:center; flex:0 0 auto; }
.fu-item .field{ font-size:14px; padding:11px 12px; }
.fu-toggle{ width:100%; background:transparent; border:none; padding:0; margin-bottom:0;
  font-family:inherit; cursor:pointer; text-align:left; }
.fu-qt{ flex:1; }
.fu-chev{ color:var(--w70); transition:transform var(--d-2); flex:0 0 auto; }
.fu-item.open .fu-chev{ transform:rotate(180deg); }
.fu-input{ margin-top:10px; }

/* ---- KMBA artifact (the mirror card) ---- */
/* One of the THREE veined objects in the app. background-image, never the shorthand: the
   shorthand erases the layered gradients and takes the veining with them. */
.acard{ width:100%; background:var(--plate-fill); border:var(--plate-line);
  border-radius:24px; padding:26px 22px; text-align:center; box-shadow:var(--plate-bevel), 0 14px 40px rgba(2,5,10,.5); }
.acard .eb{ color:var(--chart); font-size:11px; font-weight:800; letter-spacing:1.6px; }
.acard .sym{ width:64px; height:64px; border-radius:50%; background:var(--chart); color:var(--ink2);
  display:flex; align-items:center; justify-content:center; margin:16px auto 0; font-size:32px; }
.acard .type{ color:var(--chart); font-size:30px; font-weight:800; letter-spacing:.3px; margin-top:14px; }
.acard .line{ color:var(--tx-1); font-size:16px; line-height:1.5; margin-top:12px; }
.acard .achips{ display:flex; gap:7px; justify-content:center; flex-wrap:wrap; margin-top:18px; }
.acard .achip{ font-size:12px; font-weight:600; background:var(--w16); color:var(--tx-1); border-radius:999px; padding:6px 13px; }
.acard .quote{ margin-top:20px; border-top:1px solid var(--w16); padding-top:16px;
  color:var(--w85); font-size:15px; font-style:italic; line-height:1.5; }
.acard .quote b{ display:block; color:var(--chart); font-style:normal; font-weight:800;
  font-size:11px; letter-spacing:.7px; text-transform:uppercase; margin-bottom:6px; }
.acard-foot{ color:var(--w70); font-size:11px; margin-top:14px; display:flex; align-items:center; justify-content:center; gap:5px; }
.arow{ display:flex; gap:10px; margin-top:18px; }
.arow .btn{ flex:1; }
/* ---- WeBetter Report — synthesized sections ---- */
.r-headline{ color:var(--chart); font-size:15px; font-weight:700; font-style:italic; line-height:1.4; margin-top:9px; }
.r-toggle{ width:100%; background:transparent; border:1px solid var(--w16); color:var(--tx-1); border-radius:999px;
  padding:12px; font-size:14px; font-weight:600; font-family:inherit; cursor:pointer; margin-top:16px;
  display:flex; align-items:center; justify-content:center; gap:7px; }
.r-toggle i{ color:var(--chart); }
.r-sec{ margin-top:22px; }
.r-eyebrow{ color:var(--w70); font-size:11px; font-weight:800; letter-spacing:.7px; text-transform:uppercase; }
.r-read{ color:var(--tx-1); font-size:16px; line-height:1.55; margin-top:9px; }
.r-read b{ color:var(--chart); }
.r-vote{ margin-top:22px; }
.r-vote-q{ color:var(--w85); font-size:14px; text-align:center; margin-bottom:11px; }
.r-facet{ display:flex; justify-content:space-between; align-items:baseline; gap:14px; padding:11px 0; border-bottom:1px solid var(--w16); }
.r-facet:last-child{ border-bottom:none; }
.rf-k{ color:var(--w70); font-size:13px; flex:0 0 auto; }
.rf-v{ color:var(--tx-1); font-size:14px; font-weight:600; text-align:right; }
.r-connect{ background:var(--glass-fill); border:var(--glass-line); border-radius:16px;
  padding:16px; margin-top:22px; box-shadow:var(--glass-shadow); }
.r-ctext{ color:var(--tx-1); font-size:15px; line-height:1.5; margin-top:7px; }
.r-ctext b, .r-move-text b{ color:var(--chart); }
.r-quote{ color:var(--tx-1); font-size:15px; font-style:italic; line-height:1.5; margin-top:9px; padding-left:14px; border-left:2px solid var(--chart); }
.r-quote-cap{ color:var(--w70); font-size:12px; margin-top:7px; padding-left:14px; }
.r-move{ background:transparent; border:1.5px dashed var(--chart); border-radius:16px; padding:16px; margin-top:22px; }
.r-move-text{ color:var(--tx-1); font-size:15px; line-height:1.5; margin-top:7px; }
.r-baseline{ color:var(--w70); font-size:13px; line-height:1.45; text-align:center; margin-top:22px; }

/* ---- KMBA "go deeper" consolidated screen ---- */
.dpicks{ margin-top:18px; }
.dpick{ width:100%; text-align:left; display:block; background:var(--w16); border:1.5px solid transparent;
  border-radius:14px; padding:13px 15px; margin-top:10px; cursor:pointer; font-family:inherit; transition:border-color var(--d-1), background var(--d-1); }
.dpick .dp-cat{ color:var(--chart); font-size:11px; font-weight:800; letter-spacing:.6px; text-transform:uppercase; }
.dpick .dp-label{ color:var(--tx-1); font-size:16px; font-weight:600; margin-top:3px; }
.dpick.sel{ border-color:var(--chart); background:rgba(var(--chart-rgb),.14); }

/* ---- formative identity card deck ---- */
.iddeck{ position:relative; margin-top:20px; }
.idcard{ position:relative; background:var(--plate-fill); border:var(--plate-line);
  border-radius:24px; padding:32px 22px 22px; text-align:center; min-height:316px;
  display:flex; flex-direction:column; align-items:center; box-shadow:0 14px 40px rgba(0,0,0,.28);
  transition:border-color var(--d-1), box-shadow var(--d-1); }
.idcard.picked{ border-color:var(--chart); box-shadow:0 0 0 2px var(--chart), 0 14px 40px rgba(0,0,0,.28); }
.id-check{ position:absolute; top:15px; right:15px; width:30px; height:30px; border-radius:50%;
  background:var(--chart); color:var(--ink2); display:none; align-items:center; justify-content:center; font-size:18px; }
.idcard.picked .id-check{ display:flex; }
.id-sym{ width:86px; height:86px; border-radius:50%; background:var(--chart); color:var(--ink2);
  display:flex; align-items:center; justify-content:center; font-size:43px; }
.id-label{ color:var(--tx-1); font-size:23px; font-weight:700; line-height:1.25; margin-top:22px; padding:0 30px; }
.id-add{ margin-top:18px; }
.id-pick{ margin-top:auto; }
.idcard.picked .id-pick{ background:transparent; color:var(--chart); border:1.5px solid var(--chart); }
.id-nav{ position:absolute; top:50%; transform:translateY(-50%); z-index:5;
  width:38px; height:38px; border-radius:50%; background:rgba(255,255,255,.94); color:var(--blue);
  border:none; cursor:pointer; display:flex; align-items:center; justify-content:center; font-size:22px;
  box-shadow:0 4px 14px rgba(0,0,0,.3); }
.id-prev{ left:8px; }
.id-next{ right:8px; }
.id-nav:disabled{ opacity:.28; cursor:default; }
.id-dots{ display:flex; gap:6px; justify-content:center; flex-wrap:wrap; margin-top:16px; }
.idd{ width:6px; height:6px; border-radius:50%; background:var(--w16); transition:width var(--d-1), background var(--d-1); }
.idd.on{ background:var(--chart); width:18px; border-radius:999px; }
.id-counter{ text-align:center; color:var(--w70); font-size:12px; margin-top:9px; }

/* ---- agenda (S2) deliverable list ---- */
.deliv{ display:flex; gap:15px; align-items:flex-start; margin-top:26px; }
.deliv .dn{ width:50px; height:50px; border-radius:50%; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); color:var(--on-plate-2);
  display:flex; align-items:center; justify-content:center; font-size:24px; font-weight:800; flex:0 0 auto; line-height:1; margin-top:2px; }
.deliv .dt{ color:var(--tx-1); font-size:21px; font-weight:700; line-height:1.2; }
.deliv .ds{ color:var(--w85); font-size:18px; line-height:1.45; margin-top:6px; text-wrap:balance; }
.agenda-bar{ background:var(--w16); color:var(--tx-1); border-radius:12px; padding:12px 14px; text-align:center; font-size:15px; line-height:1.4; }
.agenda-bar.stay{ background:var(--chart); color:var(--ink2); font-weight:800; }
.closer-card{ background:rgba(255,255,255,.05); border:1px solid rgba(var(--edge-rgb),.10); border:1px solid var(--w16); border-radius:16px;
  padding:16px; text-align:center; color:var(--tx-1); font-size:14px; line-height:1.5; }

/* ═══════════════ HI-FI SPACE STANDARD (app-wide) — locked from the Home pilot ═══════════════
   Frosted-glass floating panels over the living cosmos (spacebg.js). Applied globally to the
   recurring dark-navy surface classes so every world inherits the elevated feel at once.
   Chartreuse (.card), white (.field), and the momentum accent (.mom) are intentionally left alone.
   `.surface` / `.surface-solid` / `.inset` are the named primitives — prefer those on new work
   rather than extending these legacy class lists. 770 distinct class names in this app paint the
   same rounded rectangle; every one added to a list here is one that never gets deduplicated. */
.surface, .tile, .prow, .tool, .glance, .srow, .glass, .gs-card, .ins-card, .wl-ask, .closer-card{
  background:linear-gradient(158deg, rgba(255,255,255,.075), rgba(255,255,255,.023)) !important;
  -webkit-backdrop-filter:blur(16px) saturate(1.22); backdrop-filter:blur(16px) saturate(1.22);
  border:1px solid rgba(var(--edge-rgb),.12) !important;
  box-shadow:0 10px 30px rgba(3,7,14,.46), inset 0 1px 0 rgba(255,255,255,.15) !important;
}
/* Modals a touch more opaque so copy stays crisp through the blur */
.surface-solid, .sheet, .sb-panel{
  background:linear-gradient(160deg, rgba(21,42,66,.85), rgba(9,20,33,.92)) !important;
  -webkit-backdrop-filter:blur(22px) saturate(1.2); backdrop-filter:blur(22px) saturate(1.2);
  box-shadow:0 -12px 44px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.12) !important;
}
/* Nested rows/items stay FLAT — spacing over material, no glass-in-glass */
.inset, .ask-row, .sb-item, .gs-row, .ask-menu, .pth-row{
  background:transparent !important; box-shadow:none !important;
  -webkit-backdrop-filter:none !important; backdrop-filter:none !important;
}
/* A nested row is cut INTO its parent, so it takes the CHANNEL inversion (dark top lip, light
   bottom lip) rather than the plate. Reusing the plate here is the number one way a recessed
   element reads as raised, and the flat wash it replaces read as neither. */
.inset, .ask-menu, .pth-row{ background:var(--well-fill) !important;
  border:1px solid rgba(var(--edge-rgb),.08) !important; border-bottom-color:rgba(214,230,250,.14) !important;
  box-shadow:var(--well-bevel) !important; }

/* ════════════════════════ STEEL — the machined-hull primitives ════════════════════════
   Declared AFTER the HI-FI SPACE STANDARD block above, which force-overrides its class list
   with !important. Anything plated must sit below that block or it is silently eaten.

   The material rule these encode:
     THE HULL IS METAL. THE WINDOWS ARE GLASS. ONLY THE INSTRUMENTS ARE LIT.
     steel = structure that HOLDS things   ·   glass = content you look THROUGH at the cosmos
     chartreuse = power (the one action, the one live thing, the one current selection)
   Corollary, absolute: steel REFLECTS, chartreuse EMITS. Nothing steel ever glows.
   Hard cap: 6 plated elements per screen. At ~15% of surfaces this is a material; at 80% it is
   wallpaper and you have traded a blue app for a grey one. ════════════════════════════════ */

/* ── .plate — machined hull. Structure only, never content, never glass. ── */
.money-card, .earn-card, .nw-hero, .stat, .sp-card, .qr-grade, .rc-grade, .ph, .plate{
  /* flex-shrink:0 is load-bearing, not tidiness. .screen is a column flex container, so its
     children shrink by default; before plating, content simply overflowed the squashed box and
     still looked right. Adding overflow:hidden turned that latent bug into a clipped card.
     .glass carries the same guard for the same reason. */
  position:relative; overflow:hidden; border:none; flex-shrink:0;
  background:var(--plate-fill);
  box-shadow:var(--plate-bevel), var(--plate-lift);
  /* The grain and the specular below are z-index:-1 INSIDE this stacking context — between the
     hull and whatever is printed on it. Without the isolation they painted over the type: in the
     light theme the .80 white band of --plate-spec washed a $67,569 to a ghost (founder, Sep 16:
     "make these legible"). Light rakes the metal, never the ink. */
  isolation:isolate;
}
/* ── The same hull, as a ROW: identical material, shorter shadow throw. A full 30px lift under
   every item in a vertical list stacks into a grey smear; the object still has to stand off the
   background, just not as far. Used wherever the element is a housing that repeats. ── */
.plate-row{
  position:relative; border:none; flex-shrink:0;
  background:var(--plate-fill);
  box-shadow:var(--plate-bevel), var(--plate-lift-sm);
}
/* ── .glasscard — a WINDOW, not a hull. The tier every content card that carries prose falls
   through to. It is what the flat rgba(255,255,255,.05) wash was reaching for and missing: the
   wash had no gradient, no top light and no shadow, so it read as a hole punched in the
   starfield. Same 158deg light axis as the plate — one lamp, two materials. ── */
.glasscard{
  background:var(--glass-fill); border:var(--glass-line);
  box-shadow:var(--glass-shadow);
}
.glasscard-sm{
  background:var(--glass-fill); border:var(--glass-line);
  box-shadow:var(--glass-shadow-sm);
}
/* ── .well — a surface cut INTO the hull. Inverted light, so it reads as recessed. ── */
.well{
  background:var(--well-fill); border:1px solid rgba(var(--edge-rgb),.08);
  border-bottom-color:rgba(214,230,250,.14); box-shadow:var(--well-bevel);
}
/* tooling grain, MASKED to the lit band — real brushed steel only shows tooling where light
   rakes it, and the mask conveniently keeps 11-12px type off the texture. */
.money-card::before, .earn-card::before, .nw-hero::before, .stat::before, .sp-card::before, .qr-grade::before, .rc-grade::before, .ph::before, .plate::before{
  content:''; position:absolute; inset:0; border-radius:inherit; pointer-events:none; z-index:-1;
  background:var(--plate-grain);
  -webkit-mask-image:linear-gradient(var(--lit), transparent 6%, #000 26%, #000 54%, transparent 76%);
          mask-image:linear-gradient(var(--lit), transparent 6%, #000 26%, #000 54%, transparent 76%);
}
/* specular — a PRE-PAINTED layer that only ever TRANSLATES, never recomputes its stops.
   That distinction is the entire 60fps question: translate = composite, recompute = repaint.
   inset:0 -30% gives it room to travel without exposing a bare edge. */
.money-card::after, .earn-card::after, .nw-hero::after, .stat::after, .sp-card::after, .qr-grade::after, .rc-grade::after, .ph::after, .plate::after{
  content:''; position:absolute; inset:0 -30%; border-radius:inherit; pointer-events:none; z-index:-1;
  background:var(--plate-spec);
  transform:translate3d(calc((var(--rake) - 50%) * 1.4), 0, 0);
}
/* Plates DEPRESS, they do not shrink. Metal set into a hull does not get smaller when pressed. */
.money-card:active, .earn-card:active, .nw-hero:active, .stat:active, .sp-card:active, .qr-grade:active, .rc-grade:active, .ph:active, .plate:active{
  box-shadow: inset 0 2px 5px rgba(0,0,0,.75), inset 0 -1px 0 rgba(200,214,230,.06),
              2px 3px 8px rgba(2,5,10,.5);
  filter:brightness(.93); transform:none;
  transition:box-shadow var(--d-1) var(--ease-out), filter var(--d-1) var(--ease-out);
}

/* ── .channel — a milled groove. NOTE THE INVERSION: dark at the top lip, light on the LOWER
   lip. Getting this backwards is the #1 way a recessed control reads as raised. ── */
.channel{
  background:var(--channel-fill); border:none; box-shadow:var(--channel-bevel);
}
/* the chartreuse fill/thumb becomes an INLAY pressed into the groove. The near-black gasket
   restores local edge contrast against the slightly-brighter plate. */
.inlay{
  box-shadow: 0 0 0 1px rgba(6,9,14,.85),
              inset 0 1px 0 rgba(255,255,255,.28),
              0 2px 10px rgba(var(--chart-rgb),.22);
}

/* ── .chip-steel — small icon medallion. Deliberately NO grain: a 2.5px period under a <=24px
   glyph moires at 3x and reads as dirt. Ramp + bevel only. ── */
.chip-steel{
  background:var(--chip-fill); border:var(--plate-line);
  box-shadow:var(--chip-bevel); color:var(--on-plate-2);
}
/* cold steel — machined but not yet powered. "Locked" should read as awaiting activation,
   not as a disabled div. Sits flush (no outer shadow) rather than proud. */
.chip-steel.cold{ box-shadow:var(--plate-cold-bevel); color:#6E7C89; }

@media (prefers-reduced-motion: reduce){
  .plate::after{ transform:none; }
}

/* ════════════ MONEY IS SOLID — the one place transparency is a DEFECT ════════════
   Founder, Aug 27, looking at the running app:
     "all money cards need the steel upgrade — transparent and difficult to read on something
      such as money is an instant turn off — needs to be solid — ie solid information that they
      can stand/rely on."

   This is a product argument, not a taste one, and it OUTRANKS the glass/steel balance wherever
   the two conflict. The reasoning, kept here because it is the part that gets forgotten first:
   a translucent card reads as PROVISIONAL. On a wellness surface that is fine, because a mood
   note IS provisional. On money it is a claim about the reliability of the number — the user is
   deciding about their rent, their debt and their retirement against a panel they can see the
   starfield through, and it reads as a draft, a placeholder, something still loading. The
   instinct that produces is "I'll go check my real bank app", and once a money product has
   produced that instinct it is over.

   The number may be an estimate. The SURFACE may never look like one. Uncertainty belongs in
   WORDS — "about", "not enough to say", "an estimate, not a quote" — never in the opacity of the
   panel. Those are two different channels and this app already does the first one well.

   So on a money screen the "is this genuinely a window?" judgment is not applied: the answer is
   always no. One body hook reaches every glass surface on all 13 money screens, which is why
   this is a rule rather than thirteen files of overrides. !important is required because the
   HI-FI SPACE STANDARD block above force-glasses this exact class list.

   backdrop-filter is explicitly killed, not merely overpainted: it is the literal see-through,
   and it is also the expensive part. Deleting it is both the fix and the optimisation. */
body.wb-money .surface, body.wb-money .tile, body.wb-money .prow, body.wb-money .tool,
body.wb-money .glance, body.wb-money .srow, body.wb-money .glass, body.wb-money .gs-card,
body.wb-money .ins-card, body.wb-money .closer-card{
  background:var(--plate-fill) !important;
  border:var(--plate-line) !important;
  box-shadow:var(--plate-bevel), var(--plate-lift-sm) !important;
  -webkit-backdrop-filter:none !important; backdrop-filter:none !important;
}
/* The two greys used app-wide FAIL against the plate's specular band — #9fb0c8 at 4.36:1 and
   #8fa2b8 at 3.67:1 — and they are exactly the colours on the small labels under a figure.
   "Difficult to read" was the second half of the complaint, so this is the other half of the fix.
   Measured at the specular peak #3C4652, because you must measure a lit surface where it is
   BRIGHTEST or you have measured the case that does not fail. */
body.wb-money .mc-sub, body.wb-money .mc-lab, body.wb-money .bkt-desc, body.wb-money .nw-sub,
body.wb-money .wi-s, body.wb-money .tc-s, body.wb-money .qc-s, body.wb-money .conn,
body.wb-money .cc-tag, body.wb-money .empty-note, body.wb-money .doc-s, body.wb-money .tx-s{
  color:var(--on-plate-2);
}

/* ═══ C16 · MONEY SHEETS ARE SOLID — the last translucent money surface ═══
   Founder, standing: "transparent and difficult to read on something such as money is an instant
   turn off — needs to be solid — ie solid information that they can stand/rely on."

   DESIGN-DIRECTION adjudication #3 exempted sheet BODIES from the steel pass and kept them glass,
   on the argument that the cosmos-glass-accent depth stack is the identity. That exemption is now
   OVERRULED FOR MONEY SHEETS ONLY, and the spec has been updated to match (see the C16 note under
   adjudication #3 and the "do not touch" table). The reasoning is the same one that already made
   the money CARDS plates directly above: a bottom sheet is where the money is EDITED and CONFIRMED
   — the cushion ladder's $500-$20,000, the add/edit transaction amount, the goal target, the asset
   value. Reading the page you are about to change THROUGH the number you are changing it to is the
   literal failure the founder described. Everywhere else, sheets stay glass; the exemption stands.

   This is deliberately a rule and not four files of overrides, because four of the six money sheets
   live in files held by other lanes. One body hook reaches all of them, and it survives whatever
   those lanes do to their local `.sheet` rules.

   !important is required TWICE over: the HI-FI SPACE STANDARD block force-glasses `.sheet` and
   `.sb-panel` with !important, and `#shOv .sh-sheet` in wealth-plan.html carries an ID.

   backdrop-filter is killed, not overpainted — it is the literal see-through, and the sheet bodies
   are the transform-animated elements where it was also the most expensive (adjudication #3's own
   finding). Deleting it is the fix and the optimisation at once.

   `background:var(--plate-fill)` is the safe shorthand here: every one of these rules had a flat
   wash and nothing layered on top, so resetting background-color to transparent loses nothing, and
   --plate-fill's bottom layer is a full-coverage linear-gradient of opaque --st-* hex. No veining
   to erase. Do not add a background-COLOR alongside it later without switching to background-image. */
body.wb-money .sheet, body.wb-money .gsheet, body.wb-money .sh-sheet,
body.wb-money .add-sheet, body.wb-money .lo-sheet, body.wb-money .pm-sheet,
body.wb-money .surface-solid{
  background:var(--plate-fill) !important;
  border:var(--plate-line) !important;
  box-shadow:var(--plate-bevel), 0 -12px 44px rgba(2,5,10,.55) !important;
  -webkit-backdrop-filter:none !important; backdrop-filter:none !important;
}
/* The metal LIP is what a glass sheet needed to announce itself as an object. A sheet whose whole
   body is the plate does not need a 48px band of the same plate painted over its top on a shorter
   gradient — that reads as a seam, not a lip. Suppress it where the body is already hull. */
body.wb-money .sheet::before{ display:none; }
/* The grip sits on metal now, so it takes the milled treatment the spec already defines for
   .sh-grip rather than a white wash that reads as a smudge on steel. */
body.wb-money .grip, body.wb-money .gs-grip, body.wb-money .as-grip, body.wb-money .sh-grab{
  background:linear-gradient(180deg,#8f9aa6,#4c545d);
  box-shadow:inset 0 -1px 0 rgba(0,0,0,.6);
}

/* ── Machined hardware: the controls physically SHAPED like hardware (round/squircle, icon-only,
   edge-mounted). .tl-arrow was a translucent white wash that read as a disabled chip rather than
   a control. Milled key + chartreuse glyph; on press the insets INVERT so the key visibly seats
   into the plate. ── */
.tl-arrow, .orbit-cyc, .nf-nav, .id-nav, .ci-step, .me-edit, .appback{
  background:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a);
  border:1px solid rgba(var(--edge-rgb),.10); color:var(--chart);
  box-shadow: inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55),
              0 2px 6px rgba(0,0,0,.35);
}
.tl-arrow i, .orbit-cyc i, .nf-nav i, .id-nav i, .ci-step i, .me-edit i, .appback i{ color:var(--chart); }
.tl-arrow:active, .orbit-cyc:active, .nf-nav:active, .id-nav:active,
.ci-step:active, .me-edit:active, .appback:active{
  box-shadow: inset 0 1px 0 rgba(0,0,0,.5), inset 0 -1px 0 rgba(255,255,255,.12);
  transform:none;
}

/* ── Locked / not-yet states. These were flat var(--w16) and read as a disabled div. Cold steel
   says "machined but not yet powered" — a component awaiting activation, which is on-brand for
   sovereignty and turns unbuilt payoffs from apologies into anticipation. Also removes an accent
   fill from every screen that has an unbuilt feature. ── */
.btn-locked, .qa-soon, .tile.covered, .tcd, .idd, .badge.locked .bmedal{
  background:linear-gradient(158deg,#2a323b,#171d24 58%,#0e1318);
  border:1px solid rgba(var(--edge-rgb),.08);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.12), inset 0 -1px 0 rgba(0,0,0,.55);
  color:#6E7C89;
}
.btn-locked i, .qa-soon i, .badge.locked .bmedal i{ color:#6E7C89; }
/* the COMING SOON badge stops being a chartreuse fill and becomes a machined tag */
.soon{ background:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a) !important;
  color:var(--icon-1) !important; box-shadow:inset 0 1px 0 rgba(200,214,230,.16), inset 0 -1px 0 rgba(0,0,0,.5); }

/* ── Sheet lips. 19 sheets already slide up at --d-3 via the shared rule, so a metal lip arriving
   at the top of a rising panel lands 19x for one selector. The lip is also the part that stops
   moving first and stays under your thumb, so the texture is at rest exactly when the eye lands.
   The sheet BODY stays glass — marbling the whole sheet would delete the cosmos-glass-accent
   depth stack that is the identity. ── */
.sheet{ position:relative; }
.sheet::before{
  content:''; position:absolute; top:0; left:0; right:0; height:48px; pointer-events:none;
  border-radius:20px 20px 0 0; z-index:0;
  background:var(--plate-fill);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.2);
  -webkit-mask-image:linear-gradient(#000 60%, transparent);
          mask-image:linear-gradient(#000 60%, transparent);
}
.sheet > *{ position:relative; z-index:1; }
.sh-grip{
  background:linear-gradient(180deg,#8f9aa6,#4c545d);
  box-shadow:inset 0 -1px 0 rgba(0,0,0,.6);
}

/* ── Hull seams. Section labels stop being text and become structure. home.html is twelve panels
   in one undifferentiated vertical run, so the eye has nothing to chunk on; a seam gives the
   screen readable zones for about six lines of CSS. Add .live to the ONE section holding the
   next action — an 8px tick buys you a per-screen "you are here" instead of a whole card border. */
.sec-lab, .mv-lbl, .psec-label{ display:flex; align-items:center; }
.sec-lab::after, .mv-lbl::after, .psec-label::after{
  content:''; flex:1; height:1px; margin-left:10px; min-width:12px;
  background:linear-gradient(90deg, rgba(190,210,230,.24), rgba(190,210,230,0));
}
.sec-lab.live::before{
  content:''; flex:0 0 auto; width:2px; height:10px; margin-right:8px; border-radius:1px;
  background:var(--chart);
}

/* ── Tabular numerals. Present in ONE file out of 120 today, which is why any value that changes
   jitters its container. Copilot and Monzo are recognisable at a glance largely because of
   numeral discipline. Required before count-up, or the count visibly shakes as it runs. ── */
.mc-val, .ec-amt, .stat .big, .qr-grade b, .rc-grade b, .nw-hero .big, .money-card .mc-val,
.wi-v, .g-amt, .tx-amt, .bal, .amt, .num, .mp-dom .v, .mvw-v, [data-countup]{
  font-variant-numeric:tabular-nums; font-feature-settings:'tnum' 1;
}

/* ════════════ THE MONOLITH — veined stone. EXACTLY THREE IN THE APP. ════════════
   The trophy surface, and the one place with enough area for a vein to read as intentional
   rather than as a compression artefact. Used once per world it is a monument; used everywhere
   it is a granite countertop, which is why the cap is three and why nothing else may carry it.

   .rc-badge earns it hardest: the Report Card literally asks users to "Screenshot & share your
   superlative", and that badge was styled identically to plain settings rows. The single most
   shared asset in the product looked like a list item.

   The veining is a BAKED data-URI, never a runtime filter:. WKWebView rasterises SVG filters on
   the CPU, so a live feTurbulence on a scrolling element is the most expensive thing available
   in the target runtime. This rasterises once and caches forever.
   The ANISOTROPIC baseFrequency — .012 horizontal against .045 vertical — is the whole recipe.
   Equal frequencies give you clouds; the 4:1 ratio is what stretches them into veins.
   Static forever: moving stone is liquid, and it would pull the eye off the card's one CTA. */
.monolith{
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='v'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.012 .045' numOctaves='4' seed='7'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 .74 0 0 0 0 .80 0 0 0 0 .88 0 0 0 -.58 .26'/%3E%3C/filter%3E%3Crect width='256' height='256' filter='url(%23v)'/%3E%3C/svg%3E"),
    var(--plate-fill);
  /* background-IMAGE, never the shorthand: `background:` erases the layered gradients and takes
     the veining with them. --plate-fill contributes TWO layers, so the three-value size and
     blend lists below stay correct. */
  background-size:cover, auto, auto;
  background-blend-mode:soft-light, normal, normal;
}

/* (Sep 26 — founder: "why is continue with google still not showing".) A rule here hid every Google
   button in the native app, from when Google refused OAuth inside the webview. auth.js wbGoogleSignIn
   has since opened Supabase's Google URL in the SYSTEM browser (@capacitor/browser, linked) and comes
   back through the /auth-callback.html universal link (in webetter.app's AASA), which app.js finishes
   and closes — so the rule was hiding a working door. Removed; the button shows on the phone. */

/* ═══ Expired bank connection banner (plaid.js injects it) ═══
   Amber, not chartreuse: chartreuse is the system's affirmative/CTA colour and this is a state
   the user has to repair, not an invitation. The action button inside it IS chartreuse, because
   that is the one thing here we want tapped. Sits on the steel plate ramp like every other card
   so it reads as part of the surface rather than an alert bolted on top. */
.wb-reauth{
  width:100%; box-sizing:border-box; flex-shrink:0; margin-top:12px;
  display:flex; align-items:center; gap:12px; padding:13px 15px; border-radius:14px;
  background:linear-gradient(158deg,#2a2419,#1d1a14 58%,#14120e);
  border:1px solid rgba(255,178,122,.34);
  box-shadow:inset 0 1px 0 rgba(255,210,170,.14), inset 0 -1px 0 rgba(0,0,0,.55);
}
.wb-reauth i.lead{ color:#ffb27a; font-size:20px; flex:0 0 auto; }
.wb-reauth .ra-x{ flex:1; min-width:0; }
.wb-reauth .ra-t{ color:var(--tx-1); font-size:13.5px; font-weight:700; }
.wb-reauth .ra-s{ color:#c6b6a4; font-size:11.5px; margin-top:2px; line-height:1.35; }
.wb-reauth button{
  flex:0 0 auto; background:var(--chart); color:var(--ink-on-accent); border:none; border-radius:20px;
  padding:8px 14px; font-family:inherit; font-size:12.5px; font-weight:800; cursor:pointer;
}
.wb-reauth button:active{ transform:scale(.96); }
.wb-reauth button[disabled]{ opacity:.55; }

/* ═══ Paywall tier chooser ═══
   Steel plate per tier, chartreuse reserved for the SELECTED one and the CTA — the accent marks
   the choice, it does not decorate three options at once. Per-month is the large number because
   that is what people compare; the billed total is the smaller line, because that is what they
   brace against. Apple only ever shows the total, which is why we compute the other one. */
.tier{
  width:100%; box-sizing:border-box; display:flex; align-items:center; gap:12px;
  padding:13px 15px; margin-top:9px; border-radius:15px; cursor:pointer; text-align:left;
  background:linear-gradient(158deg,#333d47,#1b222a 58%,#10151a);
  border:1px solid rgba(var(--edge-rgb),.10);
  box-shadow:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55);
  transition:border-color var(--d-2) var(--ease-out), transform var(--d-1);
}
.tier:active{ transform:scale(.99); }
.tier.on{ border-color:var(--chart); box-shadow:inset 0 1px 0 rgba(200,214,230,.20), 0 0 0 1px var(--chart); }
.tier-rad{ width:19px; height:19px; border-radius:50%; flex:0 0 auto; border:1.5px solid rgba(var(--edge-rgb),.30);
  display:flex; align-items:center; justify-content:center; }
.tier.on .tier-rad{ border-color:var(--chart); }
.tier.on .tier-rad::after{ content:''; width:10px; height:10px; border-radius:50%; background:var(--chart); }
/* These are <span>s inside a <button>, so they inline by default and the label ran straight into
   the billed line — "6 months$49.99 billed every 6 months". Block is load-bearing, not tidiness. */
.tier-x{ flex:1; min-width:0; display:block; }
.tier-n{ display:block; color:var(--tx-1); font-size:14.5px; font-weight:800; }
.tier-s{ display:block; color:var(--on-plate-2); font-size:11.5px; margin-top:2px; line-height:1.35; }
.tier-r{ text-align:right; flex:0 0 auto; display:block; }
.tier-pm{ display:block; color:var(--tx-1); font-size:15px; font-weight:900; letter-spacing:-.3px; white-space:nowrap; }
.tier-pm span{ font-size:10.5px; font-weight:700; color:var(--on-plate-2); }
.tier-save{ display:inline-block; margin-top:3px; font-size:10px; font-weight:900; letter-spacing:.4px;
  text-transform:uppercase; color:var(--chart); }


/* ── THE REPORT CARD ─────────────────────────────────────────────────────────
   Shared by welcome.html (with the email gate) and report-card.html (without it).
   These lived inside welcome.html, so the in-app card rendered the same markup with none
   of the styling — one renderer needs one stylesheet. */
.rc-eyb{text-align:center;font-size:11px;font-weight:800;letter-spacing:1.6px;text-transform:uppercase;color:var(--on-plate-3);}
.rc-badge{text-align:center;margin-top:12px;padding:17px 12px;border-radius:14px;}
.rc-badge-tag{color:#eaf1f7;font-size:14px;font-style:italic;margin-top:5px;line-height:1.3;}
.rc-guess{margin-top:12px;padding:13px 14px;border-radius:14px;border:1px solid var(--d-line2);background:rgba(255,255,255,.05);}
.rc-guess-q{color:var(--tx-1);font-size:14.5px;font-weight:600;line-height:1.35;}
.rc-guess-q b{color:var(--chart);font-weight:800;}
.rc-guess-btns{display:flex;gap:8px;margin-top:10px;}
.rc-gbtn{flex:1;padding:9px 6px;border-radius:10px;border:1px solid var(--d-line2);background:transparent;color:var(--tx-1);font-size:13px;font-weight:700;font-family:inherit;cursor:pointer;}
.rc-gbtn.sel{border-color:var(--chart);background:rgba(var(--chart-rgb),.14);color:var(--chart);}
.rc-guess-react{margin-top:9px;font-size:13.5px;font-weight:700;color:var(--chart);text-align:center;}
.rc-gh{margin-top:16px;margin-bottom:2px;font-size:11px;font-weight:800;letter-spacing:1.4px;text-transform:uppercase;color:var(--d-mut2);}
.rc-lockwrap{position:relative;margin-top:6px;}
.rc-locked{filter:blur(5px);opacity:.5;pointer-events:none;user-select:none;}
.rc-consider{margin-top:8px;padding:12px 13px;border-radius:12px;background:var(--well-fill);box-shadow:var(--well-bevel);}
.rc-lbl{font-size:11px;font-weight:800;letter-spacing:1px;text-transform:uppercase;color:var(--on-plate-3);}
.rc-consider p{color:#eaf1f7;font-size:14px;line-height:1.4;margin:5px 0 0;}
.rc-quote{margin-top:10px;color:var(--d-mut);font-size:13.5px;font-style:italic;line-height:1.4;text-align:center;}
.rc-gate{position:absolute;inset:-8px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:9px;padding:16px;border-radius:16px;background:linear-gradient(180deg,rgba(6,15,26,.5),rgba(6,15,26,.84));}
.rc-gate-h{color:var(--tx-1);font-size:15px;font-weight:800;text-align:center;line-height:1.3;max-width:240px;}
.rc-gate .wl-input{margin-top:0;max-width:290px;width:100%;}
.rc-gate .btn-glow{margin-top:2px;max-width:290px;}
.rc-badge-hd{font-size:11px;font-weight:800;letter-spacing:1.6px;text-transform:uppercase;color:var(--on-plate-3);margin-bottom:7px;}
.rc-guess-hd{font-size:11px;font-weight:800;letter-spacing:1.4px;text-transform:uppercase;color:var(--on-plate-3);margin-bottom:9px;}
.rc-share{text-align:center;color:var(--chart);font-size:13px;font-weight:800;margin-top:13px;}
.rc-together{color:var(--chart);font-size:12px;font-weight:800;letter-spacing:1px;margin-top:6px;opacity:.85;}
.rc-foot{text-align:center;margin-top:16px;font-size:11.5px;font-weight:600;letter-spacing:.4px;color:var(--d-mut);}
.rc-foot b{color:var(--chart);font-weight:800;}
.rc-gate-x{position:absolute;top:7px;right:13px;font-size:23px;line-height:1;color:var(--tx-m1);cursor:pointer;}
.rc-gate-x:hover{color:var(--tx-1);}
.rc-reopen{margin-top:12px;text-align:center;color:var(--chart);font-size:13.5px;font-weight:800;cursor:pointer;text-decoration:underline;}

/* exact-selector rules the first pass skipped by matching grouped selectors */
.rc-badge-name{color:var(--chart);font-size:27px;font-weight:900;letter-spacing:-.5px;line-height:1.05;}
.rc-grade{display:flex;align-items:center;justify-content:space-between;padding:9px 12px;border-radius:10px;margin-top:6px;}
.rc-grade span{color:var(--tx-1);font-size:14px;font-weight:700;}
.rc-grade b{color:var(--chart);font-size:16px;font-weight:900;}

.qc-lab{color:var(--tx-3);font-size:12.5px;font-weight:700;margin:14px 2px 6px;}
.qc-row{display:flex;gap:8px;}
.qc-row .q-opt{flex:1;text-align:center;}
.qc-row .q-opt.on{background:var(--chart);color:var(--ink-on-accent);border-color:var(--chart);}


/* ── Dream Job Calculator — its own surface, not a paragraph with two buttons ── */
.rc-guess{ margin-top:14px; padding:16px 15px 15px; border-radius:18px;
  background:linear-gradient(180deg,#2c343d 0%,#1c232b 55%,#11161c 100%);
  border:1px solid rgba(var(--edge-rgb),.10);
  box-shadow:inset 0 1px 0 rgba(200,214,230,.20), inset 0 -1px 0 rgba(0,0,0,.55); }
.rc-guess-hd{ display:flex; align-items:center; gap:7px; color:var(--on-plate-3); font-size:10.5px; font-weight:800;
  letter-spacing:.09em; text-transform:uppercase; }
.rc-guess-hd i{ color:var(--chart); font-size:14px; }
.rc-guess-q{ color:var(--w70); font-size:13px; margin-top:11px; }
.rc-guess-job{ color:var(--chart); font-size:24px; font-weight:900; letter-spacing:-.4px; line-height:1.15;
  margin-top:3px; }
.rc-guess-job span{ color:var(--tx-2); }
.rc-guess-btns{ display:flex; gap:9px; margin-top:14px; }
.rc-guess-btns button{ flex:1; display:flex; align-items:center; justify-content:center; gap:6px;
  font-family:inherit; font-size:13px; font-weight:750; padding:11px 8px; border-radius:12px; cursor:pointer;
  color:#dbe4f0; background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); }
.rc-guess-btns button i{ font-size:14px; }
.rc-guess-btns button.on{ color:var(--ink-on-accent); background:var(--chart); border-color:var(--chart); }
.rc-guess-note:empty{ display:none; }
.rc-guess-note{ color:var(--w70); font-size:12px; line-height:1.45; margin-top:11px; }

/* ── IN-WORLD REPORT CARD (wb-reports.js) ──────────────────────────────────────────────────
   One shape for every world, so a money report and a body report read as the same object. */
.wbr-card{ width:100%; box-sizing:border-box; margin-top:12px; border-radius:16px; padding:14px 15px;
  background:var(--plate-fill); border:var(--plate-line);
  box-shadow:var(--plate-bevel), var(--plate-lift-sm); }
.wbr-h{ display:flex; align-items:baseline; gap:10px; }
.wbr-t{ color:var(--tx-1); font-size:13.5px; font-weight:800; letter-spacing:-.2px; }
.wbr-n{ margin-left:auto; color:var(--w70); font-size:10.5px; font-weight:700;
  letter-spacing:.06em; text-transform:uppercase; }
.wbr-rows{ display:flex; flex-wrap:wrap; gap:7px; margin-top:10px; }
.wbr-m{ color:var(--tx-3a); font-size:12px; font-weight:700; padding:4px 10px; border-radius:20px;
  background:var(--chip-fill); border:var(--plate-line); box-shadow:var(--chip-bevel); }
.wbr-hi{ color:var(--tx-3); font-size:12.5px; line-height:1.45; margin-top:10px; }
.wbr-quiet{ color:var(--tx-m2); font-size:12.5px; line-height:1.5; margin-top:8px; }
.wbr-go{ display:inline-flex; align-items:center; min-height:44px; margin-top:4px;
  color:var(--chart); font-size:13px; font-weight:800; cursor:pointer; }

/* ════════════════════════════════════════════════════════════════════════════════════════════
   THE THEME LAYER — one token set per mode, decided once, never per screen
   ════════════════════════════════════════════════════════════════════════════════════════════
   Founder, Aug 29: "going with b clean swap BUT want light and dark mode configurable — dark
   mode returns to the original… BUT also landing, splash, orientation remain dark universally…
   cotton candy only comes in post onboarding… dark is early relationship no trust, light = in
   app feel better / lighter now that have relationship, trust budding."

   WHAT THE BACKDROP ENCODES. Not a preference — the arc of the relationship. Dark is the cold
   open: the pitch, the sign-up, the instrument panel of something that handles your money.
   Light is "you are inside now". So the dark->light change is a BEAT, fired once when onboarding
   completes (wb-theme.js, .wb-dawn below), and the surfaces that meet a stranger — landing,
   splash, the whole orientation chain — are pinned dark in BOTH modes by declaring
   data-theme="dark" on their own <html>. That is an opt-out those pages state, not an accident
   of load order: :root already holds the dark set, so a pinned page simply never matches any
   selector in this block, whatever the stored setting says.

   ── THE ACCENT, AND WHY IT DID NOT NEED 600 EDITS ───────────────────────────────────────────
   Chartreuse #DCE85C as a FILL on the pastel field measures 1.20:1 (computed below against the
   darkest point of the candy field). It is not an accent there, it is a smudge. The founder's
   call is that chartreuse stays the universal accent, so the colour is kept and its ROLE is
   inverted: in dark the accent is the lit SURFACE with near-black writing on it; in light the
   accent is a deep-chartreuse PLATE with the lit #DCE85C written on it. The instrument is still
   the only lit thing — it is now a dark object with a lit readout, which is arguably truer to
   "the hull is metal, only the instruments are lit" than a lit rectangle on a pale field.

   The mechanism is two tokens swapping jobs, and that is why no accent site needed touching:
     dark   --chart #DCE85C (surface)   --ink-on-accent/--ink2 #20260a/#1a3a52 (writing)
     light  --chart #4F5C0A (surface)   --ink-on-accent/--ink2 #E9F56B        (writing)
   Every accent element in the app already pairs those two tokens — 251 `background:var(--chart)`
   against 410 `color:var(--chart)` — so both populations invert correctly at once:
     · a chartreuse FILL becomes a deep-chartreuse plate carrying lit chartreuse   6.11:1
     · chartreuse TEXT on a light surface becomes the deep chartreuse              4.71:1 worst
   Same hue family throughout (66-67deg); nothing became a second brand colour.

   MEASURED, against the DARKEST point of the candy field (#FEBFDB — the pink lobe at .85 over
   the base wash) and against the white plate, because a light surface must be measured where it
   is DARKEST and a plate where it is LIGHTEST or the failing case was never tested:
     #DCE85C on candy .................... 1.20:1   FAILS — this is why the role flips
     #4F5C0A on candy .................... 4.71:1   PASSES text (4.5:1)
     #4F5C0A on white plate .............. 7.23:1   PASSES text
     #E9F56B on #4F5C0A .................. 6.11:1   PASSES text  (the lit readout)
     #1B1728 (--tx-1) on white plate .... 17.63:1
     #1B1728 on candy .................... 11.51:1
     #463F5C (--tx-3) on white plate ..... 9.86:1
     #5F5777 (--tx-m2) on candy ........... 4.66:1
   RE-MEASURED Sep 19 on the LIVE plates (the glass plate averages ~rgb(208,204,219), the settings
   plate ~rgb(196,190,212) — lilac, not white): #4F5C0A read 4.0–4.1 as text, --w70 at .64 read
   4.1–4.4, --danger-1 #A32E22 read 3.9. Hence --chart #465108, --w70 .70, --danger-1 #8F2519.
   ════════════════════════════════════════════════════════════════════════════════════════════ */
:root[data-theme="light"]{
  color-scheme:light;

  /* ── THE COTTON-CANDY FIELD. Rebuilt in CSS from backdrop-study.html, never an image: an image
     cannot respond to the theme, cannot scale to every phone without a second asset, and would
     add ~200KB to a bundle that just spent a session getting a font down from 806KB to 50KB.
     Six soft lobes over a lilac base, plus four 1px specular points — the sparkles are the candy
     field's own analogue of the starfield's hero stars, so the two modes share a gesture. ── */
  --canvas:
    radial-gradient(1.5px 1.5px at 21% 15%, rgba(255,255,255,.95), transparent 100%),
    radial-gradient(1.5px 1.5px at 69% 23%, rgba(255,255,255,.90), transparent 100%),
    radial-gradient(1.5px 1.5px at 45% 41%, rgba(255,255,255,.85), transparent 100%),
    radial-gradient(1.5px 1.5px at 79% 63%, rgba(255,255,255,.90), transparent 100%),
    radial-gradient(1.5px 1.5px at 31% 81%, rgba(255,255,255,.85), transparent 100%),
    radial-gradient(38% 26% at 22% 14%, rgba(255,182,214,.85) 0%, rgba(255,182,214,0) 70%),
    radial-gradient(34% 22% at 76% 20%, rgba(178,214,246,.80) 0%, rgba(178,214,246,0) 70%),
    radial-gradient(40% 25% at 62% 42%, rgba(168,232,220,.62) 0%, rgba(168,232,220,0) 72%),
    radial-gradient(42% 27% at 26% 56%, rgba(214,186,246,.72) 0%, rgba(214,186,246,0) 72%),
    radial-gradient(38% 24% at 74% 74%, rgba(255,190,222,.70) 0%, rgba(255,190,222,0) 72%),
    radial-gradient(44% 28% at 40% 88%, rgba(186,220,250,.62) 0%, rgba(186,220,250,0) 74%),
    linear-gradient(180deg,#F6F1FA 0%,#F2EEF8 50%,#EFF2FA 100%);

  /* accent — the ROLE FLIP. Both halves of every accent pair move together. */
  --chart:#465108;                     /* was #4F5C0A — 4.0:1 as text on the measured plates; this is 4.7+ (Sep 19) */
  --ink2:#E9F56B;
  --ink-on-accent:#E9F56B;
  --accent-fill:linear-gradient(180deg,#5E6D10,#465108 52%,#3F4A07);
  --accent-fill-press:linear-gradient(180deg,#45500A,#3C4607 52%,#333B05);
  /* A dark object CASTS, it does not emit. The chartreuse bloom is a dark shadow in light mode —
     an outward coloured glow on a pale field reads as a smear, not as light. */
  --accent-glow:0 8px 22px rgba(60,70,8,.22);
  --accent-glow-sm:0 5px 14px rgba(60,70,8,.20);
  --blue:#1F6DA8;                      /* #2680C4 is 4.23:1 on white — under the bar */
  --chart-rgb:70,81,8;                 /* every accent wash and hairline follows the flip */
  --on-accent-wash:#2F3705;            /* 7.2:1 on the light accent wash */
  --accent-orb:radial-gradient(circle at 38% 32%,#5F6E10,#465108 72%);
  --edge-rgb:90,70,120;

  /* text */
  --tx-1:#1B1728; --tx-2:#241F33; --tx-2a:#2A2439; --tx-3:#463F5C; --tx-3a:#4C4463;
  /* The muted tier COLLAPSES from five values to two in light, and that is the honest answer
     rather than a shortcut: dark has ~0.94 of luminance range above the canvas to spend on
     four grey steps, light has ~0.10 below it. Five distinguishable muted greys do not exist
     on a pastel field at 4.5:1. Two do, and they keep the one distinction that carries
     meaning — meta text vs caption. Measured against the darkest candy lobe and against the
     channel track (the lightest grey any muted text sits on): m1/m3 5.87:1, m2/m4/m5 5.08:1. */
  --tx-m1:#443D5C; --tx-m2:#4E4765; --tx-m3:#443D5C; --tx-m4:#4E4765; --tx-m5:#4E4765;
  --tx-m6:#4E4765;
  /* state colours, deepened until they clear 4.5:1 against the DARKEST candy lobe.
     Measured: ok 4.95:1 · warn 4.98:1 · info 4.77:1 · danger 4.95:1 */
  --ok-1:#3A6210; --warn-1:#7A4E06; --info-1:#215E8C; --danger-1:#8F2519;   /* was #A32E22 — 3.9:1 on the settings plate; 4.8 now */
  /* identical to the dark set — see the note at their definition */
  --on-media-1:#FFFFFF; --on-media-2:#C7D5E4; --on-media-3:#A9B4C0;
  --media-panel:#FFFFFF;
  --media-scrim:rgba(27,23,40,.30);
  --on-plate-1:#221D33; --on-plate-2:#4A4360; --on-plate-3:#5A5271;
  --icon-1:#5F5777;
  --w70:rgba(27,23,40,.70); --w85:rgba(27,23,40,.84);   /* w70 was .64 — 4.1–4.4:1 on the plates; .70 is 4.8–5.2 */
  /* --w16 is BOTH a card wash and a hairline in this codebase. A lilac veil serves both: over
     candy it reads as a recessed card, and at 1px it reads as a rule. */
  --w16:rgba(122,104,166,.14);
  --line:rgba(90,70,120,.15); --line2:rgba(90,70,120,.24); --mut:rgba(27,23,40,.62);

  /* steel ramp, inverted. Still near-neutral and still cool (~262deg at S<=22%) so the accent is
     the only chromatic thing on screen — the mechanism that makes chartreuse loud is unchanged,
     it is just running against a light hull now. */
  --st-900:#E2DCEE; --st-800:#EAE5F4; --st-700:#F3F0FA; --st-600:#FCFAFF;
  --st-500:#D9D3E8; --st-400:#CEC7E1; --st-spec:#FFFFFF;

  /* ── MATERIALS. "Solid" is about OPACITY, not darkness: every fill below is a fully opaque
     gradient, which is what keeps the money rule true in light mode (see the wb-money note). ── */
  --plate-fill:
    radial-gradient(130% 90% at 10% -14%, rgba(255,255,255,.95), transparent 58%),
    linear-gradient(158deg, #FFFFFF 0%, #FBF9FE 42%, #F6F2FB 74%, #F0EBF7 100%);
  --plate-bevel:
    inset 0 1px 0 rgba(255,255,255,.96),
    inset 1px 0 0 rgba(255,255,255,.72),
    inset 0 -1px 0 rgba(96,78,140,.16),
    inset -1px 0 0 rgba(96,78,140,.10);
  --plate-lift:4px 12px 30px rgba(96,78,140,.18);
  --plate-lift-sm:0 6px 18px rgba(96,78,140,.13);
  --plate-line:1px solid rgba(90,70,120,.15);
  --plate-grain:repeating-linear-gradient(var(--lit),
    rgba(96,78,140,.035) 0 1px, rgba(255,255,255,.5) 1px 2.5px);
  --plate-spec:linear-gradient(var(--lit),
    transparent 0%, rgba(255,255,255,.35) 22%, rgba(255,255,255,.80) 36%,
    rgba(255,255,255,.30) 48%, transparent 68%);
  --chip-fill:linear-gradient(158deg,#FFFFFF,#F1EDF8 58%,#E7E2F2);
  --chip-bevel:inset 0 1px 0 rgba(255,255,255,.96), inset 0 -1px 0 rgba(96,78,140,.18),
               0 2px 6px rgba(96,78,140,.14);
  --chip-bevel-flush:inset 0 1px 0 rgba(255,255,255,.96), inset 0 -1px 0 rgba(96,78,140,.18);
  --plate-cold-fill:linear-gradient(158deg,#EFEBF7,#E6E1F0 58%,#DDD7EA);
  --plate-cold-bevel:inset 0 1px 0 rgba(255,255,255,.9), inset 0 -1px 0 rgba(96,78,140,.18);

  --glass-fill:linear-gradient(158deg, rgba(255,255,255,.78), rgba(255,255,255,.52));
  --glass-line:1px solid rgba(90,70,120,.15);
  --glass-shadow:0 10px 30px rgba(96,78,140,.16), inset 0 1px 0 rgba(255,255,255,.95);
  --glass-shadow-sm:0 6px 18px rgba(96,78,140,.12), inset 0 1px 0 rgba(255,255,255,.9);

  --well-fill:linear-gradient(180deg, rgba(96,78,140,.13), rgba(255,255,255,.72));
  --well-bevel:inset 0 2px 4px rgba(96,78,140,.18), inset 0 -1px 0 rgba(255,255,255,.95);
  --channel-fill:linear-gradient(180deg, #E4DEF0, #F1EDF8);
  --channel-bevel:inset 0 1px 2px rgba(96,78,140,.30), inset 0 -1px 0 rgba(255,255,255,.95);
}

/* ── The pre-paint guard and the surround. html{background:#03060d} is declared inline in every
   page's <head> BEFORE the app.css link, so this rule wins on order; wb-theme.js additionally
   sets it as an inline style before first paint so there is no dark flash on navigation. ── */
:root[data-theme="light"]{ background:#F4F0FA; }
:root[data-theme="light"] body{ background:#E9E3F3; }
:root[data-theme="light"] body.wb-live{ background:#F4F0FA; }
:root[data-theme="light"] body.wb-shot{ background:#F4F0FA; }
:root[data-theme="light"] .phone{ border-color:#CFC8E0; box-shadow:0 24px 70px rgba(96,78,140,.28); }
:root[data-theme="light"] #toast{ background:linear-gradient(160deg,#FFFFFF,#F6F2FC); color:var(--tx-1);
  border:1px solid rgba(90,70,120,.15); box-shadow:0 8px 24px rgba(96,78,140,.24); }
/* ^ Sep 30 (founder: "i was in light mode and when blocking the popup was dark mode ... fix that on
   every surface"). The toast was an inverted dark pill in light mode; it now wears the light sheet. */

/* ════════ THE PRICE OF THE SWAP, PAID ONCE ════════
   Everything below is a literal that could not be tokenised because it is a MATERIAL written
   inline rather than a colour: a gradient ramp, a bevel, a scrim. Each is re-materialised here
   for light. This is deliberately ONE block in ONE file: 60+ screens re-skinned by hand is how a
   design system dies, and these selectors reach every screen because app.css declares the
   classes the screens reuse. A page's own <style> loses to `[data-theme="light"] .x` (0,2,0 vs
   0,1,0), which is what lets one file override sixty. ════════ */
[data-theme="light"] .wtabs{
  background:linear-gradient(180deg,#FFFFFF,#EFEAF7);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.95), inset 0 2px 0 rgba(96,78,140,.10),
              0 -8px 24px rgba(96,78,140,.14);
}
[data-theme="light"] .sh-grip{
  background:linear-gradient(180deg,#B7AEC9,#8B82A0); box-shadow:inset 0 -1px 0 rgba(255,255,255,.5);
}
/* The topbar hairline is the lit top edge of the hull; on a light hull the light is a SHADOW. */
[data-theme="light"] .topbar::after{
  background:linear-gradient(100deg, rgba(96,78,140,.06), rgba(96,78,140,.30) 38%, rgba(96,78,140,.10));
}
/* Machined-hardware group: milled key + lit glyph. The key is light metal now; the glyph keeps
   its job as the one lit thing, so it takes the deep chartreuse against the pale key. */
[data-theme="light"] .btn-white, [data-theme="light"] .disc-circle, [data-theme="light"] .webot-tab,
[data-theme="light"] .fab.ask, [data-theme="light"] .tier, [data-theme="light"] .wb-sugg button,
[data-theme="light"] .tl-arrow, [data-theme="light"] .orbit-cyc, [data-theme="light"] .nf-nav,
[data-theme="light"] .id-nav, [data-theme="light"] .ci-step, [data-theme="light"] .me-edit,
[data-theme="light"] .appback, [data-theme="light"] .conn-i, [data-theme="light"] .wb-ptr-d,
[data-theme="light"] .rc-guess, [data-theme="light"] .soon{
  background:linear-gradient(158deg,#FFFFFF,#F1EDF8 58%,#E6E1F1) !important;
  border:1px solid rgba(90,70,120,.15);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95), inset 0 -1px 0 rgba(96,78,140,.16),
             0 2px 6px rgba(96,78,140,.12);
}
[data-theme="light"] .btn-white{ color:var(--on-plate-1); }
[data-theme="light"] .soon{ color:var(--on-plate-2) !important; }
[data-theme="light"] .tl-arrow:active, [data-theme="light"] .orbit-cyc:active,
[data-theme="light"] .nf-nav:active, [data-theme="light"] .id-nav:active,
[data-theme="light"] .ci-step:active, [data-theme="light"] .me-edit:active,
[data-theme="light"] .appback:active{
  box-shadow: inset 0 1px 0 rgba(96,78,140,.28), inset 0 -1px 0 rgba(255,255,255,.9);
}
/* Cold steel — machined but not yet powered. Flush, not proud, in either mode. */
[data-theme="light"] .btn-locked, [data-theme="light"] .qa-soon, [data-theme="light"] .tile.covered,
[data-theme="light"] .tcd, [data-theme="light"] .idd, [data-theme="light"] .badge.locked .bmedal{
  background:var(--plate-cold-fill); border:1px solid rgba(90,70,120,.13);
  box-shadow:var(--plate-cold-bevel); color:#7B7392;
}
[data-theme="light"] .btn-locked i, [data-theme="light"] .qa-soon i,
[data-theme="light"] .badge.locked .bmedal i, [data-theme="light"] .chip-steel.cold{ color:#7B7392; }
/* Panels that were written as a dark navy wash rather than as a token. */
[data-theme="light"] .codebox, [data-theme="light"] .tour-box, [data-theme="light"] .hometour,
[data-theme="light"] .news-card, [data-theme="light"] .qa-panel, [data-theme="light"] .proj-pop-card{
  background:linear-gradient(160deg,#FFFFFF,#F5F1FB) !important;
  border:1px solid rgba(90,70,120,.15);
  box-shadow:0 12px 34px rgba(96,78,140,.18);
}
[data-theme="light"] .qa-backdrop, [data-theme="light"] .proj-pop-bg{ background:rgba(60,48,90,.34); }
/* SCRIMS (Sep 30, founder: "i was in light mode and when blocking the popup was dark mode and
   illegible ... fix that on every surface"). Every page's sheet scrim was written as a navy wash
   (rgba(3,8,15,.62–.72)); over the candy field that reads as a slate slab around a light sheet — the
   popup looks like dark mode even where its text is fine. In light the scrim is the lilac dim the
   report/block sheet (wb-moderation.js) and the report popups (home .ov.rpt) already use. Page classes
   only: scrims injected by a module are fixed in that module. .ov.side outranks .ov on wellness-cal. */
[data-theme="light"] .ov, [data-theme="light"] .ov.side, [data-theme="light"] .sq-ov,
[data-theme="light"] .st-ov, [data-theme="light"] .md-ov, [data-theme="light"] .mc-ov,
[data-theme="light"] .cf-ov, [data-theme="light"] .src-backdrop{ background:rgba(40,30,70,.34); }
/* Input wells: a groove cut into a LIGHT hull. The light still moves to the lower lip. */
[data-theme="light"] .field, [data-theme="light"] .fb-note, [data-theme="light"] .qa-search,
[data-theme="light"] .gen-row input, [data-theme="light"] .wb-inputbar input,
[data-theme="light"] .qa-specific input, [data-theme="light"] select.field{
  background:var(--well-fill); border:1px solid rgba(90,70,120,.14);
  border-bottom-color:rgba(96,78,140,.26); box-shadow:var(--well-bevel);
  color:var(--tx-1);
}
[data-theme="light"] select.field{
  background:var(--well-fill), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%231B1728' stroke-width='3'><path d='M6 9l6 6 6-6'/></svg>") no-repeat right 14px center;
}
[data-theme="light"] .field::placeholder, [data-theme="light"] .wb-inputbar input::placeholder,
[data-theme="light"] .gen-row input::placeholder{ color:rgba(27,23,40,.44); }
[data-theme="light"] .field:focus, [data-theme="light"] .wb-inputbar input:focus{ border-color:rgba(var(--chart-rgb),.6); }
/* Wellthii speaks from a plate; you speak from the accent. Both keep their jobs. */
[data-theme="light"] .bub-bot{
  color:var(--on-plate-1);
  background:linear-gradient(158deg,#FFFFFF,#F5F1FB 58%,#EFEAF7);
  border:1px solid rgba(90,70,120,.15);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95), inset 0 -1px 0 rgba(96,78,140,.14), 0 6px 18px rgba(96,78,140,.14);
}
[data-theme="light"] .bub-bot::before{
  background:linear-gradient(158deg,#FFFFFF,#EDE8F6 58%,#E3DDEF);
  border:1px solid rgba(90,70,120,.16);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.95), 0 3px 10px rgba(96,78,140,.18);
}
[data-theme="light"] .bub-bot::after{
  background:radial-gradient(circle at 38% 32%, #7E9310, #465108 55%, #394306);
  box-shadow:0 0 6px rgba(60,70,8,.35);
}
[data-theme="light"] .bub-user{ color:var(--ink-on-accent); border-color:rgba(var(--edge-rgb),.14);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16), 0 6px 18px rgba(60,70,8,.22); }
[data-theme="light"] .wb-send{ color:var(--ink-on-accent); }
[data-theme="light"] .wb-inputbar{ border-top-color:rgba(90,70,120,.14); }
[data-theme="light"] .tool-act a{ background:rgba(var(--chart-rgb),.10); border-color:rgba(var(--chart-rgb),.36); }
/* Skeletons + the one-shot sheen: light-on-dark becomes dark-on-light. */
[data-theme="light"] .wb-skel{
  background:linear-gradient(180deg, rgba(96,78,140,.13), rgba(96,78,140,.07));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.8);
}
[data-theme="light"] .wb-skel::after{
  background:linear-gradient(115deg, transparent 18%, rgba(255,255,255,.85) 50%, transparent 82%);
}
[data-theme="light"] .sheen::before{
  background:linear-gradient(115deg,transparent,rgba(96,78,140,.10),transparent);
}
/* Amber stays amber — it is a state to repair, not an invitation — but on a light plate. */
[data-theme="light"] .wb-reauth{
  background:linear-gradient(158deg,#FFF6EC,#FFF1E1 58%,#FCE9D4);
  border:1px solid rgba(180,110,40,.34);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9), inset 0 -1px 0 rgba(150,100,40,.16);
}
[data-theme="light"] .wb-reauth i.lead{ color:#A85E14; }
[data-theme="light"] .wb-reauth .ra-s{ color:#6E5232; }
/* The monolith's vein is a LIGHT noise field; on stone that is now pale it has to bite instead. */
[data-theme="light"] .monolith{ background-blend-mode:multiply, normal, normal; }
/* --w16 borders. The token is a lilac veil so it works as both a wash and a rule, but the four
   places that draw a DASHED border off --w70 need the ink to stay a line, not a smudge. */
[data-theme="light"] .coming, [data-theme="light"] .icard.bench, [data-theme="light"] .opt-add,
[data-theme="light"] .md, [data-theme="light"] .pstat.done, [data-theme="light"] .yn button{
  border-color:rgba(90,70,120,.34);
}

/* ── HI-FI SPACE STANDARD, light. The block it overrides carries !important on every line, so
   this one has to as well; the selector lists are kept identical on purpose so a class added
   there and forgotten here is findable by diffing the two. ── */
[data-theme="light"] .surface, [data-theme="light"] .tile, [data-theme="light"] .prow,
[data-theme="light"] .tool, [data-theme="light"] .glance, [data-theme="light"] .srow,
[data-theme="light"] .glass, [data-theme="light"] .gs-card, [data-theme="light"] .ins-card,
[data-theme="light"] .wl-ask, [data-theme="light"] .closer-card{
  background:var(--glass-fill) !important;
  -webkit-backdrop-filter:blur(16px) saturate(1.05); backdrop-filter:blur(16px) saturate(1.05);
  border:var(--glass-line) !important;
  box-shadow:var(--glass-shadow) !important;
}
[data-theme="light"] .surface-solid, [data-theme="light"] .sheet, [data-theme="light"] .sb-panel{
  background:linear-gradient(160deg,#FFFFFF,#F6F2FC 60%,#F0EBF7) !important;
  -webkit-backdrop-filter:blur(22px) saturate(1.05); backdrop-filter:blur(22px) saturate(1.05);
  box-shadow:0 -12px 44px rgba(96,78,140,.22), inset 0 1px 0 rgba(255,255,255,.95) !important;
}
[data-theme="light"] .inset, [data-theme="light"] .ask-menu, [data-theme="light"] .pth-row{
  background:var(--well-fill) !important;
  border:1px solid rgba(90,70,120,.13) !important;
  border-bottom-color:rgba(96,78,140,.26) !important;
  box-shadow:var(--well-bevel) !important;
}

/* ════════ MONEY IS SOLID — IN BOTH MODES ════════
   The wb-money rules above force `background:var(--plate-fill)` with !important, and until the
   theme layer existed that token was a dark ramp, so the code read as "money plates are DARK".
   It never was: the founder's rule is that a money surface may not be TRANSLUCENT —
   "transparent and difficult to read on something such as money is an instant turn off — needs
   to be solid — ie solid information that they can stand/rely on." Solid is about OPACITY, and
   the two were conflated. In light mode a money plate is a solid LIGHT plate, and it stays a
   plate: --plate-fill's bottom layer is a full-coverage opaque gradient in both token sets, and
   backdrop-filter is still killed rather than overpainted. So those rules are already correct
   here and are deliberately NOT repeated — the only thing this block owes them is the ONE thing
   the light glass above would otherwise re-introduce, which is the blur. ════════ */
[data-theme="light"] body.wb-money .surface, [data-theme="light"] body.wb-money .tile,
[data-theme="light"] body.wb-money .prow, [data-theme="light"] body.wb-money .tool,
[data-theme="light"] body.wb-money .glance, [data-theme="light"] body.wb-money .srow,
[data-theme="light"] body.wb-money .glass, [data-theme="light"] body.wb-money .gs-card,
[data-theme="light"] body.wb-money .ins-card, [data-theme="light"] body.wb-money .closer-card,
[data-theme="light"] body.wb-money .sheet, [data-theme="light"] body.wb-money .gsheet,
[data-theme="light"] body.wb-money .sh-sheet, [data-theme="light"] body.wb-money .add-sheet,
[data-theme="light"] body.wb-money .lo-sheet, [data-theme="light"] body.wb-money .pm-sheet,
[data-theme="light"] body.wb-money .surface-solid{
  background:var(--plate-fill) !important;
  border:var(--plate-line) !important;
  box-shadow:var(--plate-bevel), var(--plate-lift-sm) !important;
  -webkit-backdrop-filter:none !important; backdrop-filter:none !important;
}
[data-theme="light"] body.wb-money .grip, [data-theme="light"] body.wb-money .gs-grip,
[data-theme="light"] body.wb-money .as-grip, [data-theme="light"] body.wb-money .sh-grab{
  background:linear-gradient(180deg,#B7AEC9,#8B82A0);
  box-shadow:inset 0 -1px 0 rgba(255,255,255,.5);
}

/* ════════ THE DAWN — the dark->light change is a BEAT, not a repaint ════════
   Fired exactly once, by wb-theme.js, on the first screen after onboarding completes. The old
   dark canvas is held over the new one and dissolves upward, so the candy field is REVEALED
   rather than switched to; the content settles a beat behind it. Nothing loops, nothing repeats,
   and the flag that spends it is stored, so it can never fire twice.
   The overlay is pointer-events:none from the first frame — a decorative layer must never be
   able to eat the tap that lands during it. ════════ */
.wb-dawn-veil{
  position:absolute; inset:0; z-index:80; pointer-events:none; border-radius:inherit;
  background:radial-gradient(120% 80% at 50% 0%,#0d1826 0%,#070d16 60%,#04080f 100%);
  animation:wbDawn 1100ms cubic-bezier(.4,0,.2,1) both;
}
@keyframes wbDawn{
  0%{ opacity:1; transform:none; }
  70%{ opacity:.14; }
  100%{ opacity:0; transform:translate3d(0,-3%,0); }
}
.wb-dawn .screen > *{ animation:wbDawnRise 720ms var(--ease-out) both; animation-delay:340ms; }
@keyframes wbDawnRise{ from{ opacity:0; transform:translate3d(0,10px,0); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce){
  /* The beat still HAPPENS — it is a product moment, and suppressing it entirely would mean a
     reduced-motion user simply never learns the app changed. It just stops moving: a plain
     cross-fade at the global 1ms, no travel, no stagger. */
  .wb-dawn-veil{ animation:none; opacity:0; }
  .wb-dawn .screen > *{ animation:none; }
}
