/* Extracted verbatim from templates/onboarding.html (Foundation Stage 3B-1, 2026-09-08).
   Contiguous slice, cascade-preserved. Do not reorder relative to the other onboarding/styles/*.css files. */
/* ── Responsive ── */
@media (max-width: 520px) {
  .ob-card { padding: 24px 18px; }
  .items-grid { grid-template-columns: 1fr; }
  .ob-step-label { display: none; }
  .ob-step-item::after { top: 14px; }
}

/* ══════════════════════════════════════════════════════════════════════
   Business-Type Entry Screen (2026-08-20; full-viewport visual
   correction pass, 2026-08-20) — the new FIRST screen of /onboarding,
   pixel-faithful recreation of the approved reference. Own token
   namespace (--biz-*) so nothing here ever collides with or overrides
   the existing :root tokens the rest of the SPA relies on. Colors/
   serif-sans pairing reused verbatim from the already-approved
   static/landing_v3/landing.css design system.

   Full-viewport correction pass — root causes fixed (see the round's own
   report for the full writeup, kept out of this comment to stay short):
   (1) horizontal scrollbar — the whole row used fixed px card widths
       (194/332) that simply didn't sum to <=100% of the container at
       common desktop widths; cards now use flex-grow proportional
       weighting (1 unit unselected, 1.7 selected — §3/§18 of that
       round's own spec) capped by max-width, which structurally can
       never exceed the row's own width.
   (2) vertical scrollbar — the screen used `min-height:100vh` with
       hero/card/rail sizes hand-tuned to fit ONE specific 1536×1024
       screenshot; it's now a 100dvh CSS Grid
       (auto/auto/minmax(0,1fr)/auto/auto) where every text size and
       spacing value is a vh-aware clamp(), so the whole composition
       scales down together on a short viewport instead of overflowing.
   This is a CSS/layout-only pass — zero JS/markup/business-logic
   changes; every existing class name is reused as-is.
   ══════════════════════════════════════════════════════════════════════ */
:root {
  /* Light XkroX onboarding theme (cinematic/light two-environment round)
     — "ink" tokens are the warm off-white page/surface colours; "ivory"
     tokens (originally the light TEXT colour on black, back when this
     was a dark theme) are the dark charcoal TEXT colour on off-white.
     Refined to a more sophisticated warm ivory/stone + deep charcoal
     pairing (was a flatter, slightly muddier beige/near-black) so the
     light environment (Discover/Menu/Workspace/Ready) reads as a
     deliberate, premium contrast to the cinematic dark entry (Screens
     1-2 + /login), not a mismatched "different app." amber/green/danger
     kept as the brand accents, unchanged — amber is XkroX's own existing
     warm gold identity, used selectively (selection/primary action/
     progress/focus), never as a flood colour. */
  --biz-ink: #F7F4EE;
  --biz-ink-2: #EFE9DC;
  /* Business-onboarding light-theme colour rounds (2026-09-03+) —
     retuned to a true, neutral deep black/charcoal (was a warmer,
     slightly brownish dark stone) so BLACK reads as the dominant
     colour across Discover/Menu/Workspace/Ready, with the lavender
     accent above reserved for a short, specific list of elements. */
  --biz-ivory: #151515;
  --biz-ivory-70: rgba(21,21,21,.74);
  --biz-ivory-50: rgba(21,21,21,.54);
  --biz-ivory-30: rgba(21,21,21,.32);
  --biz-amber: #a86d16;
  --biz-amber-hi: #c07f18;
  --biz-amber-16: rgba(183,121,31,.14);
  --biz-amber-40: rgba(183,121,31,.40);
  --biz-green: #1a9d55;
  /* Post-Parse Clarity Pass (2026-08-21+) — a genuinely SEPARATE
     red-orange semantic for Needs Attention/blocking, distinct from the
     amber/gold reserved for selection/active-nav (§12: "Do NOT use amber
     for everything — that is one reason the current screen has weak
     hierarchy"). Ready keeps --biz-green above (now used consistently
     instead of ad hoc hex literals scattered across rules). */
  --biz-danger: #cf4a28;
  --biz-danger-hi: #b23c1f;
  --biz-danger-16: rgba(207,74,40,.14);
  --biz-danger-40: rgba(207,74,40,.40);
  --biz-danger-08: rgba(207,74,40,.08);
  /* Named design-token aliases (cinematic/light two-environment round) —
     the "light XkroX onboarding" design system's own vocabulary, per
     this round's explicit "create/reuse shared CSS variables" request.
     Pure aliases onto the existing --biz-* tokens above (never a second,
     independent palette) — retuning the light theme means editing the
     --biz-* values above once; these follow automatically. New CSS in
     this system should prefer these names; the many pre-existing
     var(--biz-*) call sites are untouched (a "casual rename" of ~170
     existing usages was explicitly out of this round's scope). */
  --onboarding-bg: var(--biz-ink);
  --onboarding-surface: #fff;
  --onboarding-surface-raised: var(--biz-ink-2);
  --onboarding-text: var(--biz-ivory);
  --onboarding-text-muted: var(--biz-ivory-70);
  --onboarding-border: rgba(27,26,22,.14);
  --onboarding-accent: var(--biz-amber);
  --onboarding-accent-hover: var(--biz-amber-hi);
  --onboarding-success: var(--biz-green);
  --onboarding-warning: var(--biz-amber-hi);
  --onboarding-danger: var(--biz-danger-hi);
  --biz-serif: 'Fraunces', Georgia, 'Times New Roman', serif;
  --biz-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --biz-ease: cubic-bezier(.16,1,.3,1);
  /* Global Positioning/Spacing Consistency round (2026-08-21+) — ONE
     shared shell spacing system, used by every /onboarding screen's
     outer container (business-type/Discover/Menu/Workspace/Ready) so
     KROX/stepper/Need help/Save & exit/Start over sit at IDENTICAL x/y
     everywhere. --ob-shell-x matches the real homepage nav's own
     padding-inline formula exactly (static/landing_v3/landing.css
     .nav{padding:22px clamp(24px,5vw,64px)}) — measured from source, not
     guessed.
     Header Line + Safe-Data Alignment round (2026-08-21+) — --ob-shell-top
     raised to a 28-36px target (was 16-26px, which read as "stuck to the
     ceiling" per live review) — still vh-based so a genuinely short
     screen compacts further, never a flat value that would force scroll. */
  --ob-shell-x: clamp(24px, 5vw, 64px);
  --ob-shell-top: clamp(28px, 3.2vh, 36px);
}

#bizTypeScreen {
  display: none;
  background: var(--biz-ink);
  color: var(--biz-ivory);
  font-family: var(--biz-sans);
  position: relative;
  overflow: hidden;
}
#bizTypeScreen > * { position: relative; z-index: 1; }
/* Business Type Entry Page Cleanup + Routing round (2026-08-21+), §3 —
   REMOVES the page-wide amber floor-light band this screen used to
   paint (a full-width, fixed-position `::after` anchored at the OLD
   default-Restaurant card position, plus a large 42%x40% amber radial
   blob in `::before`) — the exact "broad brown/amber glow band at the
   bottom and across the page" this round's brief names. It was also
   now structurally wrong: selection can move to any of the six cards
   (§6/§7), but this glow's position was hardcoded to where Restaurant
   used to sit, so it would visibly detach from the real selected card
   the moment a different one was picked. The genuinely local, dynamic
   "amber ring/glow around the selected card" (`.biz-card[data-state=
   "selected"]::before/::after`, below) already tracks the real selected
   DOM element automatically and is completely unchanged by this round —
   that is the ONE glow this page keeps. What remains here is a single,
   uniform, non-amber, symmetric vignette — "very soft ambient vignette
   only," per the brief. No page-wide colored wash, no bottom band. */
#bizTypeScreen::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 130% 110% at 50% 45%, transparent 55%, rgba(0,0,0,.5) 100%);
  z-index: 0;
}
#bizTypeScreen.is-active {
  display: grid;
  /* Return Position + Scrollbar Stability round (2026-08-21+), §10/§11 —
     one track (2nd) for the hidden nav-row spacer inserted between the
     topbar and .biz-hero (see renderBizTypeScreen()) — reserves the
     exact same vertical zone Discover/Menu/Workspace's REAL .ob-nav-row
     occupies, so this screen's real content starts at the same distance
     below the header as every other screen even though it has no
     genuine Back control (§23 — none is added, this row is
     visibility:hidden and non-interactive).
     Simplify Stepper + Remove Duplicate Forward CTA round (2026-08-21+),
     §8/§9 — the trailing track for the bottom progress rail is removed
     (renderBizRail()/its own call site are gone entirely); the extra
     vertical room falls to the cards row (minmax(0,1fr)) automatically,
     giving the card section more breathing room per §9's own explicit
     instruction, with no separate redesign needed. 5 tracks now: topbar
     / nav-row-spacer / hero / cards(1fr) / error. */
  grid-template-rows: auto auto auto minmax(0,1fr) auto;
  /* Global Positioning/Spacing Consistency round (2026-08-21+) — the old
     height:100dvh + max-height:100dvh + body overflow:hidden combination
     is the same "silently clip real content on a genuinely short real
     browser window" failure mode confirmed and fixed on Workspace this
     session (a real screen recording proved it there). min-height (not a
     hard ceiling) + no overflow:hidden means this page still TARGETS one
     viewport (the existing clamp() compaction below does the real work)
     but degrades to an honest, visible document scroll instead of an
     invisible clip if a real window is ever shorter than supported. */
  min-height: 100dvh; width: 100%;
  /* padding-top/left/right now match the ONE shared shell system every
     onboarding screen uses (--ob-shell-x/--ob-shell-top) — see §2/§3 of
     this round's own brief; horizontal inset now matches the real
     homepage nav exactly. row-gap is 0 — every real gap in the reference
     (topbar-to-hero, headline-to-subtitle, cards-to-rail) is encoded as
     an explicit margin on the specific element it belongs to instead of
     a uniform grid gap, since the reference's own gaps are NOT uniform. */
  padding: var(--ob-shell-top) var(--ob-shell-x) clamp(24px,3.4vh,40px);
  row-gap: 0;
}
/* §16 — scoped only to this screen: while it's active, the document
   itself never needs to scroll (the screen's own 100dvh grid already
   fits everything). Modern :has() scoping — never a global overflow
   change, and later onboarding steps (#app, its own scroll behavior)
   are completely untouched. */
/* Global Positioning/Spacing Consistency round (2026-08-21+) — removed
   the body-level overflow:hidden that paired with the old fixed
   height:100dvh (see the #bizTypeScreen.is-active comment above): with
   min-height instead of a hard ceiling, a real overflow:hidden here
   would silently clip the page's own natural growth on a genuinely
   short window instead of letting it scroll. */

/* Measured from the reference: "KROX" spans ~130px wide at ~23px cap
   height (~2.44vh) — a wide, deliberate tracking (~5.6x width:height),
   not a generic wordmark-with-some-spacing. */
.biz-logo {
  font-family: var(--biz-sans); font-size: clamp(19px,2.44vh,25px); font-weight: 600;
  line-height: 1; letter-spacing: .46em; color: var(--ready-orchid-hi);
  padding-left: .46em;
  background: linear-gradient(180deg, #fff5dc 0%, #ecc17b 60%, #ad721f 100%);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  text-shadow: 0 0 24px rgba(139,115,214,.16);
}
/* Header Line + Safe-Data Alignment round (2026-08-21+), §3.E — 16px
   sits inside BOTH requested ranges at once (16-20px Need help→Save &
   exit, 12-16px Save & exit→Start over), so one shared gap value
   satisfies both without needing per-pair overrides. */
.biz-topbar-right { display: flex; align-items: center; gap: 16px; }
.biz-help-link {
  font-size: 14px; color: var(--biz-ivory-70); text-decoration: none;
  font-family: var(--biz-sans); background: none; border: none; cursor: pointer;
}
.biz-help-link:hover { color: var(--biz-ivory); }
.biz-save-exit {
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; flex: none;
  padding: 8px 17px; border-radius: 999px;
  border: 1px solid rgba(21,21,21,.18); color: var(--biz-ivory-70);
  background: transparent; font-size: 14px; font-family: var(--biz-sans);
  cursor: pointer; text-decoration: none; transition: background .15s var(--biz-ease), border-color .15s;
}
.biz-save-exit:hover { background: rgba(21,21,21,.05); border-color: rgba(21,21,21,.32); color: var(--biz-ivory); }
.biz-save-exit svg { width: 14px; height: 14px; flex: none; }
/* Colour-correction round (2026-09-05) — Start over is BLACK/neutral now,
   same restrained outline treatment as Save & exit (no red/pink/orange/
   purple text or border) — the two must never visually compete for
   "danger" attention via colour; the DIFFERENCE between them is purely
   what each one does (a real confirmation dialog still gates the
   destructive action itself — see openStartOverConfirm(), unchanged). */
.biz-start-over {
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; flex: none;
  padding: 8px 17px; border-radius: 999px;
  border: 1px solid rgba(21,21,21,.18); color: var(--biz-ivory-70);
  background: transparent; font-size: 14px; font-family: var(--biz-sans);
  cursor: pointer; text-decoration: none; transition: background .15s var(--biz-ease), border-color .15s;
}
.biz-start-over:hover { background: rgba(21,21,21,.05); border-color: rgba(21,21,21,.32); color: var(--biz-ivory); }
/* Responsive correction round (2026-09-05) — root cause of a real
   (silently clipped, not scrolling) narrow-mobile overflow found during
   this round's own required breakpoint audit: .biz-save-exit/
   .biz-start-over/.biz-help-link are all `flex:none; white-space:nowrap`
   by design (never truncate their own label), so on a genuinely narrow
   viewport their combined natural width exceeded the available space —
   an ancestor's overflow:hidden silently clipped "Start over" rather
   than the page visibly scrolling, which is worse (an unreachable
   control, not just an inconvenient one). Compacting the same controls
   (smaller padding/font/gap, "Need help?" hidden only below 360px, where
   even the compact form no longer fits) keeps every control reachable
   without changing what any of them do. */
@media (max-width: 460px) {
  .biz-topbar-right { gap: 8px; }
  .biz-help-link { font-size: 12.5px; }
  .biz-save-exit, .biz-start-over { padding: 7px 11px; font-size: 12.5px; gap: 5px; }
  .biz-save-exit svg, .biz-start-over svg { width: 12px; height: 12px; }
}
@media (max-width: 400px) {
  .biz-help-link { display: none; }
  /* Icon-only pills, real accessible name preserved via aria-label
     (already on both buttons) — the icon alone is a well-established,
     recognizable affordance at this size, and this is what actually
     closes the real (silently clipped, not scrolling) narrow-viewport
     overflow this round's own required breakpoint audit found. */
  .biz-pill-label { display: none; }
  .biz-save-exit, .biz-start-over { padding: 8px; }
}

/* §13 — hero sized off viewport HEIGHT (vh), not just width, so a short
   laptop screen (1366×768/1280×720) shrinks the whole hero block
   together instead of pushing the page past 100dvh. */
/* Business Type Entry Page Cleanup + Routing round (2026-08-21+), §1/§4/
   §5 — margin-top trimmed to lift the whole hero/content block up, and
   to help close a real, confirmed one-viewport-fit overflow. Final
   Stability/Spacing/Selection round (2026-08-21+), §5/§6 — margin-top
   trimmed further still (the real "too much empty space above the
   hero" contributor turned out to be the nav-row-spacer below, not this
   value — see #bizTypeScreen .ob-nav-row's own comment); margin-bottom
   widened into the brief's own explicit "~26-32px, stable" target
   (was clamp(8px,1.3vh,16px), well under target) — a fixed,
   viewport-height-relative gap, never dependent on whether the
   headline happens to wrap. */
.biz-hero { position: relative; text-align: center; max-width: min(780px, 92%); margin: clamp(8px,1.8vh,20px) auto clamp(24px,3vh,32px); }
.biz-kicker {
  font-family: var(--biz-sans); font-size: clamp(11px,1.3vh,13px); font-weight: 600; letter-spacing: .19em;
  text-transform: uppercase; color: var(--ready-orchid); margin-bottom: clamp(10px,1.45vh,16px);
}
.biz-headline {
  font-family: var(--biz-serif); font-weight: 420; letter-spacing: -.026em;
  font-size: clamp(40px, min(4.2vw,5.7vh), 58px); line-height: 1.055; color: var(--biz-ivory);
  margin-bottom: clamp(10px,2.1vh,18px);
  /* §4 — a fixed 2-line reservation (the markup's own <br> already
     renders it as exactly 2 lines today; this makes that height
     explicit/guaranteed rather than "accidental," per the brief's own
     instruction — a no-op against current copy, a real safety net
     against any future copy change). */
  min-height: 2.11em;
}
.biz-headline .biz-accent { color: var(--ready-orchid-hi); }
.biz-sub { max-width: 430px; margin: 0 auto clamp(0px,0.3vh,4px); font-size: clamp(13px,1.6vh,16px); line-height: 1.4; color: var(--biz-ivory-70); }

/* ── First-page audience entry (2026-09-01, rebuilt) ─────────────────────
   Intentionally minimal foreground: black XkroX lockup → "Let's get
   started" → two identical outlined capsule pills, side by side. Behind
   it, a slow Shopify-style moving photo collage (4 skewed lanes, alt
   directions, seamless transform loop) provides atmosphere; a cream
   scrim keeps the foreground readable. Reduced-motion → static collage.
   Rendered by renderBizTypeScreen()/renderConsumerOnboardingScreen()
   into #bizTypeScreen; the entry lockup is placed over the full grid
   via .ob-entry (grid-row 1/-1), so the shared 5-track grid is
   untouched for every other screen. */
/* Entry variant fills the screen edge-to-edge (no shared shell padding /
   topbar on this screen) so the collage is truly full-bleed. */
#bizTypeScreen.ob-entry-mode.is-active { padding: 0; grid-template-rows: 1fr; }
#bizTypeScreen.is-active .ob-entry {
  grid-column: 1 / -1; grid-row: 1 / -1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  z-index: 2; padding: 40px 20px; min-height: 100dvh;
}
/* specificity (1,1,0) so it beats #bizTypeScreen > * { position:relative; z-index:1 } */
#bizTypeScreen .ob-collage {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden; pointer-events: none;
  background: var(--bg);
}
/* Cinematic entry rebuild round — all of the following are scoped to
   #bizTypeScreen.ob-cinematic-mode specifically (the class
   renderBizTypeScreen() adds), NOT bare #bizTypeScreen — that id is
   ALSO reused by renderConsumerOnboardingScreen() (/onboarding/you).
   Onboarding Background Cleanup round (2026-09-04) — the consumer
   ("For you") screen now ALSO adds .ob-cinematic-mode (see that
   function), specifically so it inherits this exact dark treatment
   instead of maintaining a second, separately-tuned light one — one
   shared visual system, not two. */
#bizTypeScreen.ob-cinematic-mode .ob-collage {
  /* a dark fallback (was the cream --bg) so any loading gap/edge reads
     as cinematic-dark, never a flash of cream. */
  background: #0b0a09;
}
/* A tighter tilt (-8deg -> -5deg, the requested -4..-6deg range) and a
   touch more scale so the rotated plane still fully covers every corner
   at the shallower angle. */
#bizTypeScreen.ob-cinematic-mode .ob-collage-rot { transform: translate(-50%, -50%) rotate(-5deg) scale(1.1); }
/* Varied lane widths (a genuine mix of small/medium/large columns, not a
   uniform repeated grid). Total width (~124vw across 6 lanes + 5 gaps)
   still fits comfortably inside the shared 148vw .ob-collage-rot. */
#bizTypeScreen.ob-cinematic-mode .ob-lane:nth-child(1) { width: 24vw; min-width: 190px; }
#bizTypeScreen.ob-cinematic-mode .ob-lane:nth-child(2) { width: 16vw; min-width: 140px; }
#bizTypeScreen.ob-cinematic-mode .ob-lane:nth-child(3) { width: 21vw; min-width: 170px; }
#bizTypeScreen.ob-cinematic-mode .ob-lane:nth-child(4) { width: 15vw; min-width: 135px; }
#bizTypeScreen.ob-cinematic-mode .ob-lane:nth-child(5) { width: 23vw; min-width: 185px; }
#bizTypeScreen.ob-cinematic-mode .ob-lane:nth-child(6) { width: 18vw; min-width: 150px; }
.ob-collage-rot {
  position: absolute; top: 50%; left: 50%;
  /* 6-row density round — widened (132vw -> 148vw) so 6 narrower lanes
     plus their gaps still fully cover every corner after rotation/scale,
     matching "rows should collectively cover the entire screen with no
     blank gaps." Height unchanged — this only affects horizontal
     coverage, never page height. */
  width: 148vw; height: 150vh;
  transform: translate(-50%, -50%) rotate(-8deg) scale(1.06);
  display: flex; gap: 1.6vw; justify-content: center;
}
/* 6-row density round — was 4 lanes at 25vw/220px min; narrower now (not
   a stretch of the same 4 lanes — a real 6th/7th... 6-lane composition,
   see OB_LANE_PLAN) so the same rotated composition still fits without
   overflowing into visible gaps. min-width lowered to match — on a
   narrow phone the collage still clips via #bizTypeScreen/#discoverScreen's
   own overflow:hidden, same as before, just with more lanes packed into
   the visible center. */
.ob-lane { position: relative; width: 19vw; min-width: 160px; overflow: hidden; }
.ob-lane-track {
  display: flex; flex-direction: column; gap: 2.2vh;
  will-change: transform;
  animation: obLaneUp 78s linear infinite;
}
.ob-lane:nth-child(2) .ob-lane-track { animation: obLaneDown 96s linear infinite; }
.ob-lane:nth-child(3) .ob-lane-track { animation: obLaneUp 88s linear infinite; }
.ob-lane:nth-child(4) .ob-lane-track { animation: obLaneDown 108s linear infinite; }
/* 6-row density round — two new lanes, continuing the same alternating-
   direction/varied-duration pattern the existing 4 already used. */
.ob-lane:nth-child(5) .ob-lane-track { animation: obLaneUp 92s linear infinite; }
.ob-lane:nth-child(6) .ob-lane-track { animation: obLaneDown 102s linear infinite; }
@keyframes obLaneUp   { from { transform: translateY(0); }      to { transform: translateY(-50%); } }
@keyframes obLaneDown { from { transform: translateY(-50%); }   to { transform: translateY(0); } }
.ob-tile {
  width: 100%; border-radius: 20px; overflow: hidden; flex: none;
  background: #e9e3d5;
  box-shadow: 0 24px 60px -30px rgba(30,24,14,.4);
}
.ob-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ob-tile.t-tall  { aspect-ratio: 3 / 4; }
.ob-tile.t-wide  { aspect-ratio: 4 / 3; }
.ob-tile.t-sq    { aspect-ratio: 1 / 1; }
/* Visual correction round — the previous scrim (a flat wash PLUS a
   radial gradient climbing to 94% cream at the edges) was a de facto
   page-wide translucent veil: even the "clear" center carried ~30%
   combined cream, and the edges — precisely the area meant to stay
   "close to original visual strength" — were nearly opaque. Legibility
   for the glass card is now entirely the card's OWN backdrop-filter
   (see .ob-entry-card) — this rule is reduced to a single, extremely
   light, UNIFORM tint (no radial falloff, so it never intensifies
   toward the edges) purely to keep the collage a background rather than
   a foreground image, well within "0-8% max" if any separation is
   needed at all. */
.ob-collage::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: rgba(244,239,228,.05);
}
/* Cinematic entry rebuild round — scoped to #bizTypeScreen.ob-cinematic-mode
   only (see the note above .ob-collage) — the reference direction flips
   ONLY the main entry screens from light/cream to dark/cinematic;
   #discoverScreen/#accountGateScreen keep the light .ob-collage::after
   above completely untouched (still out of scope — those are later
   wizard steps, not entry screens). The consumer ("For you") screen
   used to be excluded here too; Onboarding Background Cleanup round
   (2026-09-04) brings it into .ob-cinematic-mode so it gets this exact
   dark overlay instead of a second, separately-tuned light one. Three
   layers, per the brief's own "layered atmospheric treatment, not one
   flat overlay":
     1. a soft radial darkening centered behind the hero text (strongest
        readability boost exactly where it's needed, fading out well
        before the header/trust message);
     2. a wide vignette so the corners/edges read deeper than the middle;
     3. a very light flat wash so the collage reads as background
        everywhere, even where the other two layers are near-transparent.
   None of these use rgba(255,...)/rgba(245,240,230,...) — no cream/white
   veil anywhere. Color richness itself is controlled below via
   brightness/saturate/contrast on the images, never by opacity. */
#bizTypeScreen.ob-cinematic-mode .ob-collage::after {
  background:
    radial-gradient(ellipse 68% 62% at 50% 54%, rgba(5,4,3,.70) 0%, rgba(5,4,3,.34) 46%, rgba(5,4,3,0) 74%),
    radial-gradient(ellipse 125% 105% at 50% 42%, transparent 42%, rgba(3,2,2,.62) 100%),
    linear-gradient(rgba(4,3,2,.20), rgba(4,3,2,.20));
}
/* Darkens via brightness/contrast (real luminance control) rather than a
   translucent layer, so color relationships stay intact: warm amber
   lighting, red gym equipment, produce color, and nightlife contrast all
   remain recognizable, just darker overall — the brief's own explicit
   "prefer brightness/contrast tuning... rather than opacity". A small
   saturate boost compensates for the slight perceived dulling that
   darkening alone would otherwise cause. Scoped the same way — since
   the consumer screen now also carries .ob-cinematic-mode (Onboarding
   Background Cleanup round, 2026-09-04), its tiles get this exact same
   darkening treatment too, not a separate light one. */
#bizTypeScreen.ob-cinematic-mode .ob-tile img { filter: brightness(.58) saturate(1.15) contrast(1.08); }
@media (prefers-reduced-motion: reduce) {
  .ob-lane-track { animation: none !important; }
}

.ob-entry-card {
  position: relative;
  display: flex; flex-direction: column; align-items: center;
  max-width: min(560px, 92vw); width: 100%;
  /* Card spacing polish round — ~5-10% taller via padding only (max-width
     unchanged, per "do not make it much wider"). */
  padding: clamp(38px, 6.6vh, 66px) clamp(28px, 6vw, 64px);
  border-radius: 30px;
  /* Glass polish round — genuine glass, not a solid card: opacity lowered
     further (was .58) so noticeably more of the moving collage reads
     through the panel; blur raised so what shows through is frosted, not
     just dimmed; saturation nudged only slightly (was 1.35, overshot
     "slight"); border/shadow both softened to a hairline + a single
     ambient shadow — no bright inset rim, which was reading as an extra
     "card" edge rather than a glass edge. Still a warm cream tint, never
     dark glass. */
  background: rgba(255,253,247,.40);
  border: 1px solid rgba(255,255,255,.32);
  box-shadow: 0 40px 90px -42px rgba(36,31,24,.32);
  -webkit-backdrop-filter: blur(34px) saturate(1.15);
  backdrop-filter: blur(34px) saturate(1.15);
}
/* Vertical hierarchy round — wordmark on top, mark/icon below it (was a
   horizontal side-by-side lockup). Only used by the two entry-screen
   renders (renderBizTypeScreen/renderConsumerOnboardingScreen).
   Spacing polish round — more breathing room around the bird mark. */
.ob-wordmark-lockup { display: flex; flex-direction: column; align-items: center; gap: clamp(12px,2vh,20px); }
.ob-wordmark-mark { height: clamp(30px, 4.6vh, 44px); width: auto; display: block; }
.ob-wordmark {
  font-family: var(--biz-sans); font-weight: 700; line-height: 1;
  /* Spacing polish round — slightly smaller (was clamp(38px,6.6vh,62px)),
     to sit more comfortably above the bird mark with the extra gap above. */
  font-size: clamp(34px, 5.8vh, 54px); letter-spacing: -.012em;
  color: #14110c;
}
.ob-entry-kicker {
  font-family: var(--biz-sans); font-size: clamp(11px, 1.35vh, 13px); font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: #6f6656;
  /* Spacing polish round — slightly more vertical rhythm around this line. */
  margin: clamp(20px, 3.2vh, 30px) 0 clamp(24px, 3.8vh, 36px);
}
/* Cinematic entry restructuring round — Screen 2 (renderBizTypeScreen(),
   the audience choice) reuses renderXkroxLockup()/.ob-entry-kicker
   verbatim but floats them directly on the dark collage now (no card),
   so their light-card colors need a dark-mode override here. Scoped to
   .ob-cinematic so renderConsumerOnboardingScreen()'s own light card use
   of the exact same classes is completely untouched. */
.ob-cinematic .ob-wordmark { color: #fdfcfa; }
.ob-cinematic .ob-wordmark-mark { filter: brightness(0) invert(1); }
.ob-cinematic .ob-entry-kicker { color: rgba(255,255,255,.66); }
.ob-entry-pills { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; }
/* Button polish round — premium pill: 44-48px tall (explicit min-height,
   not padding math), thin neutral border (was a bold 1.5px black
   outline), a very lightly translucent base (was solid #fffef9) with its
   own soft blur so it still reads as glass-language, no shadow at rest,
   only a gentle background/lift on hover — never a gradient. */
.ob-pill {
  -webkit-appearance: none; appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 46px;
  font-family: var(--biz-sans); font-size: clamp(15px, 1.9vh, 17px); font-weight: 600;
  color: #14110c; background: rgba(255,254,249,.38);
  border: 1px solid rgba(36,31,24,.22); border-radius: 999px;
  padding: 0 34px;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: none;
  transition: background .18s var(--biz-ease), border-color .18s var(--biz-ease), transform .18s var(--biz-ease);
}
.ob-pill:hover { background: rgba(255,254,249,.62); border-color: rgba(36,31,24,.32); transform: translateY(-1px); }
.ob-pill:active { transform: translateY(0); }
.ob-pill:focus-visible { outline: 2px solid #14110c; outline-offset: 3px; }

/* Restrained top bar on the /onboarding entry screen only — XkroX left,
   Sign in right. No stepper, no marketing nav; a returning owner reaches
   /login without ever entering the audience-choice flow.
   Specificity (1,1,0) — needed to beat #bizTypeScreen > * (1,0,0), which
   would otherwise force `position: relative` onto this element and drop
   it into normal flow below the collage instead of pinning it to the
   top (the same fix already applied to .ob-collage above). */
#bizTypeScreen .ob-entry-topbar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 3;
  display: flex; align-items: center; justify-content: space-between;
  padding: clamp(16px, 2.8vh, 28px) clamp(20px, 4vw, 44px);
}
/* Cinematic entry rebuild round — dark-mode header (was dark text on a
   light pill; the whole screen is dark now). renderObEntryTopbar() is
   used ONLY by renderBizTypeScreen(), so these are edited directly
   rather than scoped-overridden. */
.ob-entry-topbar-brand {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--biz-sans); font-weight: 700; font-size: 17px; color: #fff;
}
/* The crow mark PNG is a solid dark silhouette — brightness(0) collapses
   it to solid black (preserving its real alpha edges), invert(1) flips
   that to solid white, so it reads correctly against the dark collage
   without needing a second white-only asset. */
.ob-entry-topbar-brand img { height: 24px; width: auto; display: block; filter: brightness(0) invert(1); }
.ob-entry-signin {
  -webkit-appearance: none; appearance: none; cursor: pointer;
  font-family: var(--biz-sans); font-size: clamp(13px, 1.6vh, 14.5px); font-weight: 600;
  color: #fff; background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.32); border-radius: 10px;
  padding: 9px 22px;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  transition: background .15s var(--biz-ease), border-color .15s var(--biz-ease), transform .12s var(--biz-ease);
}
.ob-entry-signin:hover { background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.5); transform: translateY(-1px); }
.ob-entry-signin:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.ob-entry-back {
  position: absolute; top: clamp(18px, 3vh, 30px); left: clamp(18px, 3vw, 34px); z-index: 3;
  background: rgba(255,254,250,.8); border-radius: 999px; padding: 2px 6px;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: 0 8px 22px -14px rgba(36,31,24,.4);
}

/* ── Cinematic entry hero (correct-onboarding-architecture visual round) ──
   LAYER 4/5 of the brief's own stack: no card, content floats directly
   over the collage. .ob-cinematic overlays the full screen exactly like
   .ob-entry does for the old card layout (same grid-row/column trick) —
   a plain flex column so the header (a sibling, unchanged) stays pinned
   at the very top, the hero block takes the remaining space and centers
   itself within it, and the trust line sits naturally at the bottom
   without any extra absolute-position math. */
#bizTypeScreen.is-active .ob-cinematic {
  grid-column: 1 / -1; grid-row: 1 / -1;
  position: relative; z-index: 2;
  display: flex; flex-direction: column;
  min-height: 100dvh; width: 100%;
}
.ob-cinematic-hero {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: clamp(90px,14vh,140px) clamp(20px,5vw,40px) clamp(24px,4vh,40px);
}
.ob-hero-headline {
  font-family: var(--biz-sans); font-weight: 800; letter-spacing: -.02em;
  font-size: clamp(38px, 6.2vw, 76px); line-height: 1.03;
  max-width: 900px; color: #fdfcfa;
  text-shadow: 0 2px 24px rgba(0,0,0,.35);
}
.ob-hero-subtext {
  margin-top: clamp(16px, 2.4vh, 24px);
  font-family: var(--biz-sans); font-size: clamp(15px, 1.7vw, 20px); line-height: 1.55;
  max-width: 640px; color: rgba(255,255,255,.72);
}
.ob-hero-ctas {
  margin-top: clamp(24px, 3.4vh, 34px);
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap; justify-content: center;
}
.ob-cta-primary, .ob-cta-secondary {
  -webkit-appearance: none; appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--biz-sans); font-size: clamp(15px, 1.7vw, 17px); font-weight: 600;
  min-height: 52px; padding: 0 30px; border-radius: 14px;
  transition: background .18s var(--biz-ease), border-color .18s var(--biz-ease), transform .18s var(--biz-ease), box-shadow .18s var(--biz-ease);
}
.ob-cta-primary svg { width: 17px; height: 17px; }
/* Primary — light/off-white fill, near-black text, a soft warm glow
   (never a hard drop-shadow) to read as THE action on the screen. */
.ob-cta-primary {
  background: #fbf8f2; color: #16130d; border: none;
  box-shadow: 0 10px 34px -10px rgba(250,220,150,.4);
}
.ob-cta-primary:hover { background: #ffffff; transform: translateY(-1px); box-shadow: 0 14px 40px -10px rgba(250,220,150,.55); }
.ob-cta-primary:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
/* Secondary — transparent/dark-glass, quieter than primary by design. */
.ob-cta-secondary {
  background: rgba(255,255,255,.05); color: #fff; border: 1px solid rgba(255,255,255,.34);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.ob-cta-secondary:hover { background: rgba(255,255,255,.1); border-color: rgba(255,255,255,.55); transform: translateY(-1px); }
.ob-cta-secondary:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
#bizProceedError.biz-proceed-error { margin-top: 16px; }
/* Cinematic entry restructuring round — Screen 1's Netflix-style email
   row: input + primary CTA sit horizontally on desktop, stack on mobile.
   Visually integrated into the dark page itself (translucent surface,
   restrained border) — never a card/panel around it. */
.ob-acq-form {
  margin-top: clamp(24px, 3.4vh, 34px);
  display: flex; align-items: stretch; gap: 10px;
  width: 100%; max-width: 480px;
}
.ob-acq-email {
  flex: 1; min-width: 0;
  font-family: var(--biz-sans); font-size: 15px; color: #fff;
  background: rgba(255,255,255,.07); border: 1px solid rgba(255,255,255,.28);
  border-radius: 14px; padding: 0 18px; min-height: 52px;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  transition: border-color .15s var(--biz-ease), background .15s var(--biz-ease);
}
.ob-acq-email::placeholder { color: rgba(255,255,255,.45); }
.ob-acq-email:focus { outline: none; border-color: rgba(255,255,255,.6); background: rgba(255,255,255,.1); }
.ob-acq-submit { flex: none; white-space: nowrap; }
.ob-acq-error { margin-top: 10px; max-width: 480px; width: 100%; box-sizing: border-box; }
/* Same shared divider language as the later Workspace step's .ws-or-divider
   — a plain text node flanked by two flex-stretched hairlines. */
.ob-acq-divider {
  margin-top: clamp(20px, 2.8vh, 28px);
  display: flex; align-items: center; gap: 12px; width: 100%; max-width: 380px;
  font-family: var(--biz-sans); font-size: 12px; color: rgba(255,255,255,.5);
  text-transform: uppercase; letter-spacing: .06em;
}
.ob-acq-divider::before, .ob-acq-divider::after { content: ''; flex: 1; height: 1px; background: rgba(255,255,255,.16); }
/* Visually secondary, per the brief's own "these should be visually
   secondary" — smaller max-width than the primary email row, no
   competing weight. */
.ob-acq-providers { margin-top: 14px; width: 100%; max-width: 280px; }
.ob-acq-google-wrap { width: 100%; min-height: 40px; }
@media (max-width: 640px) {
  .ob-acq-form { flex-direction: column; max-width: 340px; }
  .ob-acq-submit { width: 100%; }
}
/* Screen 1B — password/real-authentication step. Same cinematic hero
   shell as Screen 1/2 (.ob-cinematic-hero), same input/button language
   as .ob-acq-email/.ob-cta-primary — only a small email-confirmation
   row + "Change" link is new. */
.ob-acq-pass-form {
  margin-top: clamp(20px, 2.8vh, 28px);
  display: flex; flex-direction: column; gap: 12px;
  width: 100%; max-width: 380px;
}
.ob-acq-pass-email-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-family: var(--biz-sans); font-size: 14px; color: rgba(255,255,255,.82);
  /* Alignment fix: matches .ob-acq-email's own 18px horizontal padding
     below, so the email text's left edge and "Change"'s right edge line
     up with the password input's text inset instead of sitting flush
     against the outer form column edges. */
  padding: 0 18px;
}
.ob-acq-pass-email { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ob-acq-pass-change {
  flex: none; background: none; border: none; cursor: pointer; padding: 0;
  font-family: var(--biz-sans); font-size: 12.5px; font-weight: 600;
  color: rgba(255,255,255,.6); text-decoration: underline; text-underline-offset: 2px;
}
.ob-acq-pass-change:hover { color: #fff; }
.ob-acq-pass-form .ob-acq-submit { width: 100%; }
/* "Email me a 6-digit code" (Screen 1B) — a real secondary ACTION, not a
   footer-text link: reuses .ob-cta-secondary's already-established
   dark-glass/bordered button look verbatim (same component Screen 2's
   "For you" CTA uses), so it reads as obviously clickable while staying
   quieter than the white primary Continue button. Only width/spacing is
   added here; it matches the same 380px form-column width as the
   password input/Continue button above it (direct child of
   .ob-cinematic-hero, auto-centered by its own align-items:center). */
.ob-acq-otp-btn { margin-top: 14px; width: 100%; max-width: 380px; }

/* ── Email OTP verification screen (Screen 1C) ──────────────────────────
   The 6 code boxes deliberately reuse .ob-acq-email's own tokens — same
   translucent fill, same border tone, same blur, same focus family — so
   they read as pieces of the existing auth input, just split into six.
   Sizing is clamp()-based so they shrink gracefully on small screens
   while staying square-ish and readable; the row never exceeds the
   380px form column. */
.ob-otp-boxes {
  margin-top: clamp(20px, 2.8vh, 28px);
  display: flex; justify-content: center; gap: clamp(6px, 2vw, 10px);
  max-width: 380px;
}
.ob-otp-box {
  flex: 0 0 auto;
  width: clamp(40px, 12vw, 52px); height: clamp(48px, 13vw, 58px);
  text-align: center; caret-color: #fff;
  font-family: var(--biz-sans); font-size: clamp(18px, 5vw, 22px); font-weight: 700; color: #fff;
  background: rgba(255,255,255,.07); border: 1px solid rgba(255,255,255,.28);
  border-radius: 12px;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  -webkit-appearance: none; appearance: none;
  transition: border-color .15s var(--biz-ease), background .15s var(--biz-ease), box-shadow .15s var(--biz-ease);
}
.ob-otp-box::-webkit-outer-spin-button,
.ob-otp-box::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ob-otp-box:focus {
  outline: none; border-color: rgba(255,255,255,.7); background: rgba(255,255,255,.12);
  box-shadow: 0 0 0 3px rgba(255,255,255,.12);
}
.ob-otp-box:disabled { opacity: .6; }
/* Error state applies to the whole component at once. */
.ob-otp-boxes.is-error .ob-otp-box { border-color: rgba(239,68,68,.6); }
.ob-otp-boxes.is-error .ob-otp-box:focus { box-shadow: 0 0 0 3px rgba(239,68,68,.18); }

.ob-otp-verify-btn { margin-top: 16px; width: 100%; max-width: 380px; }

.ob-otp-actions {
  margin-top: 16px;
  display: flex; flex-direction: column; align-items: center; gap: 12px;
}
.ob-otp-textbtn {
  background: none; border: none; cursor: pointer; padding: 4px 2px;
  font-family: var(--biz-sans); font-size: 14px; font-weight: 600;
  color: rgba(255,255,255,.82);
}
.ob-otp-textbtn:hover:not([disabled]),
.ob-otp-textbtn:focus-visible { color: #fff; text-decoration: underline; text-underline-offset: 2px; }
.ob-otp-textbtn[disabled] { color: rgba(255,255,255,.45); cursor: default; }

.ob-otp-status {
  margin-top: 14px; max-width: 380px; width: 100%;
  font-family: var(--biz-sans); font-size: 13px; line-height: 1.45; text-align: center;
}
.ob-otp-status.is-info    { color: rgba(255,255,255,.7); }
.ob-otp-status.is-success { color: #6ee7b7; }
.ob-otp-status.is-error   { color: #fca5a5; }
/* Password Visibility round (2026-09-04) — reuses the shared .pw-toggle
   button/togglePw() already built for wsPass/wsPassConf (base position/
   sizing rules at the top of this stylesheet); only the icon color needs
   a dark-cinematic override here since the base rule assumes the light
   Workspace theme's --text-secondary. */
.ob-acq-pw-wrap { position: relative; }
/* Root-cause fix (not a padding tweak): a bare <input> has no CSS width
   here (.ob-acq-email's own `flex:1` only takes effect inside Screen 1's
   flex ROW — .ob-acq-pw-wrap is a plain block box), so it was rendering
   at its browser-default intrinsic width (~170-200px) and centered
   (inheriting .ob-cinematic-hero's text-align:center) instead of filling
   the same 380px column as the email row/Continue button above/below it.
   display:block + width:100% makes it a real block box that fills its
   already-380px-wide parent, matching them exactly. Scoped to this
   wrapper only — Screen 1's own .ob-acq-email flex-row usage is
   untouched. */
.ob-acq-pw-wrap input { display: block; width: 100%; padding-right: 44px; }
.ob-acq-pw-wrap .pw-toggle { color: rgba(255,255,255,.5); }
.ob-acq-pw-wrap .pw-toggle:hover { color: rgba(255,255,255,.9); }
.ob-cinematic-trust {
  flex: none; display: flex; align-items: center; gap: 10px; justify-content: center;
  margin: 0 auto clamp(28px, 5vh, 48px); width: fit-content; max-width: 92%;
  background: rgba(0,0,0,.28); border: 1px solid rgba(255,255,255,.10); border-radius: 999px;
  padding: 8px 18px 8px 14px;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.ob-cinematic-trust svg { flex: none; width: 14px; height: 14px; color: var(--biz-amber-hi); }
.ob-cinematic-trust-title { font-family: var(--biz-sans); font-size: 12.5px; font-weight: 600; color: #fff; white-space: nowrap; }
.ob-cinematic-trust-sub { font-family: var(--biz-sans); font-size: 11px; color: rgba(255,255,255,.6); white-space: nowrap; }
@media (max-width: 640px) {
  .ob-hero-ctas { flex-direction: column; width: 100%; max-width: 340px; }
  .ob-cta-primary, .ob-cta-secondary { width: 100%; }
  .ob-cinematic-trust { flex-direction: column; text-align: center; white-space: normal; padding: 12px 16px; }
  .ob-cinematic-trust-title, .ob-cinematic-trust-sub { white-space: normal; }
}

/* Consumer ("For you") reserved-space screen — as of the Onboarding
   Background Cleanup round (2026-09-04) this renders onto the SAME
   .ob-cinematic/.ob-cinematic-hero dark shell as Screen 1, so it needs no
   CSS of its own beyond a Back control (below) and reused .ob-hero-*
   classes. .ob-entry-note/.ob-entry-headline/.ob-entry-pills below are
   the OLD light-card rules this screen used to use — unused now, kept
   in place rather than removed (out of this round's asset-only scope). */
.ob-entry-note {
  max-width: 42ch; text-align: center; margin: clamp(14px,2.4vh,20px) 0 clamp(22px,3.4vh,30px);
  font-family: var(--biz-sans); font-size: clamp(14px,1.7vh,16px); line-height: 1.5; color: #4a4437;
}
.ob-entry-headline {
  font-family: var(--biz-serif); font-weight: 440; letter-spacing: -.02em;
  font-size: clamp(28px, 4.4vh, 40px); line-height: 1.1; color: #14110c; text-align: center;
  margin-top: clamp(14px, 2.4vh, 20px);
}

@media (max-width: 560px) {
  .ob-entry-pills { flex-direction: column; width: 100%; }
  .ob-pill { width: 100%; text-align: center; }
}

/* ── Discover: "website detected" block (Mode B — a URL in the same
   search field). Written directly into #bizWebsiteBlock by
   updateBizWebsiteBlock(), same in-place pattern renderBizDropdown()
   uses, so typing never loses input focus. */
.disc-website-block { margin-top: clamp(9px,1.4vh,12px); }
.disc-website-card {
  border: 1px solid var(--ready-orchid-40); background: rgba(255,255,255,.03);
  border-radius: 14px; padding: 14px 16px;
}
.disc-website-card-label {
  display: flex; align-items: center; gap: 7px;
  font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ready-orchid-hi);
}
.disc-website-card-label svg { width: 14px; height: 14px; flex: none; }
.disc-website-card-url { margin-top: 5px; font-size: 14px; color: var(--biz-ivory); word-break: break-all; }
.disc-website-continue {
  margin-top: 12px; width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 18px; border-radius: 999px; border: none; cursor: pointer;
  font-family: var(--biz-sans); font-size: 14px; font-weight: 600;
  background: var(--biz-ivory); color: var(--biz-ink);
  transition: filter .12s var(--biz-ease);
}
.disc-website-continue:hover { filter: brightness(1.04); }
.disc-website-suggest-label {
  margin: 14px 2px 6px; font-size: 12px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--biz-ivory-50);
}

/* §2/§3/§17 — the flexible middle zone. Desktop (>860px): NO horizontal
   scroll at all — .biz-cards is a flex row where every card's own
   width is a proportional SHARE of the row (flex-grow), so six cards
   structurally always sum to <=100% of the available width, never
   overflowing regardless of viewport. Mobile/tablet (<=860px, §4): the
   proportional-share layout can no longer stay readable, so this
   switches to the pre-existing horizontal-scroll card rail instead —
   see the @media block below. */
/* Top-aligned, not centered: the reference shows the card row starting
   immediately at a fixed offset from the subtitle, with all remaining
   vertical space in this flexible grid row falling BELOW the cards
   (the real, measured gap before the progress rail) — never split
   above and below. */
.biz-cards-wrap {
  position: relative; width: 100%; height: 100%; min-height: 0;
  display: flex; align-items: flex-start; justify-content: center;
}
/* Business Type Entry Page Cleanup + Routing round (2026-08-21+), §3 —
   REMOVES this row-wide warmth-pool wash: it was hardcoded to the OLD
   default-Restaurant card's position ("at 15% 96%" — the leftmost card),
   so it would visibly stay put even after a different card was selected
   (a real correctness bug once selection can move anywhere — §6/§7),
   and it duplicated the genuinely local, dynamic per-card glow
   (`.biz-card[data-state="selected"]::before/::after`, unchanged) that
   already does this job correctly. One glow source now, not two. */
.biz-cards { position: relative; z-index: 1; }
.biz-cards {
  /* flex-start, not center: the reference shows every card — selected
     and unselected alike — starting at the exact same top edge (only
     the BOTTOM edges differ, since the selected card is marginally
     taller); center-aligning would incorrectly push the shorter
     unselected cards down to vertically center against the taller one. */
  display: flex; align-items: flex-start; justify-content: center;
  gap: clamp(14px,1.4vw,22px);
  width: 100%; max-width: 1416px; height: 100%; margin: 0 auto;
  padding: 0 2px clamp(4px,0.6vh,8px);
}

.biz-card {
  position: relative;
  /* Final Stability/Spacing/Selection round (2026-08-21+), §1/§3/§4/§16 —
     ROOT FIX for a confirmed row-reflow bug: every card previously had a
     DIFFERENT outer width/height depending on data-state (selected grew
     to flex-grow:1.61/max-width:341px/a taller height clamp; unselected
     stayed at flex:1 1 0/max-width:212px/a shorter height) — switching
     selection therefore visibly resized the selected card AND reflowed
     every neighboring card's x position. Width and height are now
     IDENTICAL for every card regardless of data-state — selection is
     communicated entirely through filter/border/box-shadow/background
     (below), never through layout dimensions. Height also reduced
     (§8 — "cards are too tall/heavy") now that it's no longer driven by
     the old, taller "selected" clamp. */
  flex: 1 1 0; min-width: 0; max-width: 214px;
  height: clamp(268px, 39dvh, 420px);
  background: linear-gradient(180deg, #100d09, var(--biz-ink-2));
  border: 1px solid rgba(196,142,74,.16);
  border-radius: clamp(12px,1.3vw,18px);
  padding: 0 0 14px;
  display: flex; flex-direction: column;
  cursor: pointer;
  /* flex-grow/max-width no longer animate (both are now constant across
     states) — transition list trimmed to the properties that actually
     still change on selection. */
  transition: border-color .2s ease, box-shadow .2s ease, filter .2s ease;
  filter: brightness(.68) saturate(.82);
  outline: none;
  /* §2/§4/§8 (3D-depth correction round) — even a resting card has real
     physical presence (a soft drop shadow + the faintest warm rim),
     never zero depth until it happens to be selected — this is what
     keeps inactive cards from reading as flat cutout panels. */
  box-shadow: 0 10px 26px -14px rgba(0,0,0,.6), 0 0 0 1px rgba(139,115,214,.05) inset;
}
.biz-card:focus-visible { box-shadow: 0 0 0 3px var(--ready-orchid-40); }

/* Business Type Entry Page Cleanup + Routing round (2026-08-21+), §6/§9 —
   ALL six cards are now clickable/selectable regardless of live/
   coming-soon status (a real, confirmed behavior change: the old
   `data-state="disabled"` state made non-live cards structurally
   unclickable — aria-disabled, no onclick — which this round's brief
   explicitly rejects). The old "disabled" and "enabled-unselected"
   treatments were already visually near-identical (brightness .8 vs
   .82) — merged into one "unselected" state, applied uniformly whether
   the card is live or coming-soon; a coming-soon card is still "beautiful
   but unavailable" (readable artwork, faint warm edge) exactly as
   before, just reachable by click/keyboard now like every other card.
   Final Stability/Spacing/Selection round (2026-08-21+), §9 — brightness
   nudged up (.82 -> .90) so an unselected (incl. coming-soon) card reads
   as "muted but visibly clickable," never "almost black"/disabled-
   looking. */
.biz-card[data-state="unselected"] {
  filter: brightness(.90) saturate(.94); border-color: rgba(139,115,214,.22);
  box-shadow: 0 12px 30px -14px rgba(0,0,0,.62), 0 0 16px -6px rgba(139,115,214,.16), 0 0 0 1px rgba(139,115,214,.07) inset;
}
.biz-card[data-state="unselected"]:hover {
  filter: brightness(1) saturate(1); border-color: rgba(139,115,214,.36);
  transform: translateY(-2px);
}
.biz-card[data-state="selected"] {
  /* Final Stability/Spacing/Selection round (2026-08-21+), §3/§4 —
     REMOVES the old flex-grow:1.61/max-width:341px/taller-height
     override entirely — width and height are now identical to
     .biz-card's own base values on every card, selected or not (see
     that rule's own comment for the full root-cause explanation).
     Dominance now comes ONLY from filter/border/glow/background below,
     never from actual size. */
  filter: none;
  border-color: var(--ready-orchid);
  background: linear-gradient(180deg, var(--biz-ink-2), #100b05);
  /* §3/§4 — a real depth STACK, not one flat neon outline: a crisp 1px
     amber edge, a tight close bloom, a deeper ambient drop shadow that
     grounds the card in space, a wide diffused low-opacity bloom
     reaching well beyond the card (the "atmospheric haze" the brief
     asks for), and a restrained inset top highlight for internal edge
     lighting — five real layers, each doing one job. Final Stability/
     Spacing/Selection round (2026-08-21+), §14/§15 — the two widest,
     furthest-reaching layers (the diffused bloom and the offset haze)
     are trimmed so the glow no longer reads as a broad wash (see the
     ::before/::after rules below, whose own spill area was reduced in
     the same pass). */
  box-shadow:
    0 0 0 1px rgba(139,115,214,.95),
    0 0 16px 1px rgba(139,115,214,.4),
    0 0 28px 3px rgba(139,115,214,.14),
    0 22px 44px -18px rgba(0,0,0,.85),
    inset 0 1px 0 rgba(255,255,255,.07);
}
/* §4/§5 (3D-depth correction round) — the selected card's own grounding
   effect is two layers: `::before` is a blurred, horizontally-stretched
   "floor sheen" reading as reflected/ambient light on a polished dark
   surface; `::after` is the tighter, brighter direct ground-glow pool
   close under the card. Both are absolutely positioned with negative
   offsets, so neither contributes any layout height — nothing pushes
   the card grid or triggers scroll. Final Stability/Spacing/Selection
   round (2026-08-21+), §14/§15 — spill area substantially tightened
   (was -34%/-26% horizontal and reaching 96px below the card) — at this
   round's now-smaller, uniform card width the old spill read as a
   broad amber/brown wash bridging toward neighboring cards rather than
   a local glow "spilling slightly around the card" (the brief's own
   explicit target). Purely a size/opacity reduction — same two-layer
   concept, same colors, no page background change needed here (that's
   handled separately, see #bizTypeScreen::before). */
.biz-card[data-state="selected"]::before {
  content: ''; position: absolute; left: -14%; right: -10%; bottom: -46px; height: 84px;
  background:
    linear-gradient(90deg, transparent, rgba(139,115,214,.11) 20%, rgba(244,201,137,.24) 46%, rgba(139,115,214,.09) 76%, transparent),
    linear-gradient(180deg, rgba(139,115,214,.18), rgba(139,115,214,.04) 55%, transparent 78%);
  transform: perspective(150px) rotateX(70deg); transform-origin: 50% 0;
  filter: blur(9px); opacity: .85; pointer-events: none; z-index: -2;
}
.biz-card[data-state="selected"]::after {
  content: ''; position: absolute; left: -4%; right: 2%; bottom: -18px; height: 36px;
  background: radial-gradient(ellipse at 44% 0%, rgba(255,215,154,.42), rgba(139,115,214,.15) 44%, transparent 78%);
  filter: blur(8px); pointer-events: none; z-index: -1;
}

/* §7 — the image is a proportion of the CARD's own height (not a fixed
   4:3 slot), so it never eats a disproportionate share of a shorter
   card, plus a bottom-fade so artwork blends into the card body instead
   of cutting abruptly into it. Final Stability/Spacing/Selection round
   (2026-08-21+), §8/§16 — flex-basis reduced (54% -> 48%, "reduce image
   section height" per the brief) and the selected-only 55% override
   removed entirely — same proportion on every card regardless of
   selection, one more contributor to a perfectly stable row. */
.biz-card-media {
  position: relative; flex: 0 0 48%; min-height: 0; border-radius: inherit;
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
  overflow: hidden; background: #1a1a1a;
}
.biz-card-media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: filter .25s ease;
  /* §6/§7 (3D-depth correction round) — a touch more contrast/warmth on
     every card's own artwork so the diorama's existing depth (window
     light, reflections) reads more, never crushing blacks or blowing
     out highlights. */
  filter: contrast(1.09) saturate(1.07) brightness(.98);
}
/* §7 — the selected card's own art gets a further, deliberate lift
   ("the selected card should feel alive") — brighter, slightly more
   contrast/saturation than its resting state, on top of the card-level
   filter:none already removing the dimming filter. */
.biz-card[data-state="selected"] .biz-card-media img {
  filter: contrast(1.12) saturate(1.15) brightness(1.04);
}
/* Combined in one layer (multiple backgrounds, first-listed = topmost):
   a soft radial vignette that gently deepens the image's own corners
   for a more dimensional, "small world" read, plus the existing
   bottom-fade so the artwork blends into the card body instead of
   cutting abruptly into it. */
.biz-card-media::after {
  content: ''; position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 112% 86% at 50% 39%, transparent 49%, rgba(0,0,0,.28) 100%),
    linear-gradient(to bottom, rgba(0,0,0,.05), transparent 34%, rgba(12,10,7,.18) 68%, rgba(12,10,7,.92) 100%);
  pointer-events: none;
}
/* Selected card only: a touch of warm light gathering at the base of the
   artwork, where it meets the card body — reads as the scene's own
   window-light spilling toward the viewer rather than a flat cutoff. */
.biz-card[data-state="selected"] .biz-card-media::after {
  background:
    radial-gradient(ellipse 112% 86% at 50% 39%, transparent 49%, rgba(0,0,0,.24) 100%),
    linear-gradient(to bottom, rgba(0,0,0,.04), transparent 32%, rgba(20,13,6,.22) 66%, rgba(139,115,214,.16) 92%, rgba(15,10,5,.85) 100%);
}

.biz-badge {
  position: absolute; top: 10px; left: 10px; z-index: 1;
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(5,4,3,.72); backdrop-filter: blur(4px);
  border-radius: 999px; padding: 4px 10px 4px 8px;
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  font-family: var(--biz-sans); font-weight: 600; color: var(--biz-ivory-70);
}
.biz-badge-dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }
.biz-badge-dot.is-live { background: var(--biz-green); box-shadow: 0 0 8px 1px rgba(62,207,106,.7); }
.biz-badge-dot.is-soon { background: var(--biz-ivory-30); }
.biz-badge.is-live { color: var(--biz-ivory); }

.biz-card-body { position: relative; padding: clamp(10px,1.4vh,15px) clamp(14px,1.45vw,22px) 0; display: flex; flex-direction: column; flex: 1; min-height: 0; }
.biz-icon {
  width: clamp(30px,3.9vh,42px); height: clamp(30px,3.9vh,42px); border-radius: 50%; border: 1px solid rgba(139,115,214,.35);
  display: flex; align-items: center; justify-content: center; margin-bottom: clamp(6px,.9vh,12px);
  color: var(--ready-orchid-hi); flex: none;
}
.biz-icon svg { width: 45%; height: 45%; }
.biz-card-title {
  font-family: var(--biz-serif); font-weight: 420; letter-spacing: -.015em; font-size: clamp(17px,2.25vh,23px); color: var(--biz-ivory);
  margin-bottom: 6px; line-height: 1.15;
}
.biz-card-desc { font-size: clamp(11.5px,1.34vh,13.5px); line-height: 1.42; color: rgba(247,242,234,.56); flex: 1; min-height: 0; overflow: hidden; }
/* Final Stability/Spacing/Selection round (2026-08-21+), §1/§16/§17 — was
   scoped to `[data-state="selected"]` only, back when unselected cards
   had no CTA (and thus real spare room) and selected cards were taller.
   Every card now reserves the SAME CTA space regardless of selection
   (§2), so every card needs the SAME 2-line clamp — this is also the
   fix for §17 ("Salon & Wellness" wrapping must never change a card's
   outer height): the description's own box is now bounded the same way
   on every card, so a wrapped title/description can never push a
   card taller than its neighbors. */
.biz-card-desc {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
}

/* Final Stability/Spacing/Selection round (2026-08-21+), §2/§8/§11 — the
   CTA is now ALWAYS in the DOM (every card, every state — see
   renderBizTypeCard()) so it always reserves this same box; only
   .is-hidden's visibility/opacity/pointer-events change with selection,
   never display, so it can never affect card height. min-height/margin
   trimmed slightly (part of this round's general density reduction —
   §8) while keeping Restaurant's real CTA "strong" per §11. */
.biz-cta {
  margin-top: 9px; width: 100%; min-height: clamp(38px,4.6vh,46px);
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  /* §1/§3/§4/§17 — cards are now equal width across all six (was only
     ~341px for a selected card; now ~201-214px, matching what an
     unselected card already used) — the CTA's own font-size/padding
     shrunk to match so "Start restaurant setup" fits on one real line
     without truncating (confirmed via direct measurement: 106px
     available vs 133px needed at the old 12.6px size — this size fits
     with room to spare) rather than relying on the ellipsis fallback
     above for the common case (it stays as a genuine safety net for a
     hypothetically longer future label, not the normal rendering path). */
  padding: clamp(7px,1.1vh,10px) 10px; border-radius: 11px; border: none; cursor: pointer;
  background: linear-gradient(180deg, var(--ready-orchid-hi), var(--ready-orchid));
  color: #1B1206; font-family: var(--biz-sans); font-weight: 600; font-size: clamp(10px,1.15vh,11.5px);
  transition: filter .15s ease, transform .15s ease;
}
.biz-cta:hover { filter: brightness(1.06); }
.biz-cta:active { transform: translateY(1px); }
.biz-cta svg { width: 15px; height: 15px; }
/* §11/§17 — the label truncates (ellipsis) rather than wraps, so a long
   CTA label can never grow the button past its reserved min-height —
   the arrow stays a fixed-size sibling, never squeezed. */
.biz-cta-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.biz-cta > span[aria-hidden] { flex: none; }
/* §2 — reserved but invisible on every unselected card: visibility+
   opacity+pointer-events, NEVER display:none, so this button's own box
   still occupies its normal layout space and card height never changes
   when selection moves on/off a card. */
.biz-cta.is-hidden { visibility: hidden; opacity: 0; pointer-events: none; }
/* Business Type Entry Page Cleanup + Routing round (2026-08-21+), §9 —
   the inert "Coming soon" CTA a selected non-live card shows: visually
   distinct from the real amber action button (a real HTML `disabled`
   button — no onclick, not-allowed cursor, never navigates) but still
   readable/premium, not a flat dead rectangle. Final Stability/Spacing/
   Selection round (2026-08-21+), §10 — made deliberately smaller/quieter
   than the live CTA (reduced min-height/font-weight/letter-spacing) so
   it never reads as a primary action, "small subdued CTA" per the
   brief. */
.biz-cta-soon {
  background: rgba(247,242,234,.05); color: var(--biz-ivory-50);
  cursor: not-allowed; border: 1px solid rgba(247,242,234,.10);
  min-height: clamp(32px,3.8vh,38px); font-weight: 500; letter-spacing: .01em;
}
.biz-cta-soon:hover { filter: none; }

.biz-proceed-error {
  max-width: 1600px; margin: 0 auto; text-align: center;
  color: #f0a5a5; font-size: 13px; min-height: 0;
}

/* Simplify Stepper + Remove Duplicate Forward CTA round (2026-08-21+),
   §8/§9 — the bottom progress rail (.biz-rail-wrap/.biz-rail/
   .biz-rail-step/.biz-rail-connector/.biz-rail-num/.biz-rail-title/
   .biz-rail-desc, plus their responsive overrides below) is removed
   entirely, along with renderBizRail() and its call site — business-type
   is the entry INTO Discover, not a numbered macro step with its own
   progress indicator (§10). The page already communicates its purpose
   via the headline/cards; no replacement widget was added in its place,
   per the brief's own explicit instruction — the freed space goes to the
   card section's own breathing room automatically (grid row now
   minmax(0,1fr), see #bizTypeScreen.is-active above). */

/* Short desktop viewports need a different allocation, not a uniformly
   miniaturized version of the 1024px-high composition. Cards and the rail
   retain visual authority while top/bottom padding and gaps do the adapting. */
@media (min-width: 861px) and (max-height: 800px) {
  #bizTypeScreen.is-active {
    /* padding-top now the shared --ob-shell-top token (was a hardcoded
       18px, 10px short of Discover/Menu/Workspace's own clamped value at
       this height) — the brief's own §10 explicit requirement is that
       KROX's x/y matches on every screen, including at this breakpoint;
       the resulting few extra px of overflow (already a graceful,
       disclosed scroll at this compact size, never a clip) is an
       accepted trade-off for that consistency. */
    padding-top: var(--ob-shell-top); padding-bottom: 12px;
    /* Final Stability/Spacing/Selection round (2026-08-21+), §5/§6/§7 —
       every non-hardcoded-content track switched to `auto` (was a mix of
       hardcoded px values — 30px/114px/154px — hand-measured for an
       EARLIER round's own hero/nav-row margins; confirmed, by direct
       measurement, to go silently stale and produce a real, visible
       negative subtitle-to-cards gap the moment this round's own margin
       changes landed, since a hardcoded track size doesn't track an
       item's real content height the way `auto` does). row-gap matched
       to the base (non-mediaqueried) rule's own row-gap:0 — every real
       gap comes from each element's own margin, exactly like every other
       viewport, so there is only ONE spacing system for this screen, not
       two different ones that can drift apart. */
    grid-template-rows: auto auto auto minmax(0,1fr) auto;
    row-gap: 0;
  }
  .biz-kicker { margin-bottom: 8px; }
  .biz-headline { font-size: clamp(44px,3.5vw,50px); margin-bottom: 9px; }
  .biz-sub { max-width: 560px; font-size: 13px; line-height: 1.4; }
  /* Final Stability/Spacing/Selection round (2026-08-21+), §1/§3 — the
     old override here (`.biz-card[data-state="selected"] { height:
     min(372px, 51.7dvh); }`) reintroduced the exact selected/unselected
     height differential the base (non-mediaqueried) rules just removed
     — at this specific viewport band ONLY, meaning selecting a card at
     1366x768 would have still reflowed the row even though every other
     viewport was fixed. Removed entirely; `.biz-card`'s own single
     height below now applies identically regardless of data-state,
     exactly like the base rule. */
  .biz-card { height: min(300px, 42dvh); }
}

@media (max-width: 860px) {
  #bizTypeScreen.is-active { height: auto; min-height: 100dvh; max-height: none; overflow-y: auto; }
  body:has(#bizTypeScreen.is-active) { overflow: visible; }
  /* §4 — below this width six proportional cards can no longer stay
     readable; switch to the horizontal-scroll rail, scrollbar hidden
     (still real, native, momentum-scrollable touch behavior — just no
     visible scrollbar strip, matching the reference's own chrome-free
     look). */
  .biz-cards-wrap { justify-content: flex-start; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; }
  .biz-cards-wrap::-webkit-scrollbar { display: none; }
  .biz-cards { justify-content: flex-start; width: max-content; min-width: 100%; height: auto; }
  .biz-card { flex: 0 0 176px; max-width: 176px; height: min(360px, 62dvh); }
  .biz-card[data-state="selected"] { flex: 0 0 258px; max-width: 258px; height: min(420px, 68dvh); }
}
@media (max-width: 640px) {
  .biz-headline { font-size: clamp(26px, 8vw, 34px); }
  .biz-topbar-right { gap: 12px; }
}
@media (max-width: 380px) {
  .biz-card { flex-basis: 152px; max-width: 152px; }
  .biz-card[data-state="selected"] { flex-basis: 224px; max-width: 224px; }
}

/* ══════════════════════════════════════════════════════════════════════
   Discover Screen (2026-08-20) — business search / Google Places
   selection, manual entry, and the search-selected / manual-entry
   preview states. Second cinematic screen in the same premium visual
   system as #bizTypeScreen above (same --biz-* tokens, same atmosphere
   recipe, same topbar/logo/save-exit language) — reuses the shared
   3-step Discover/Menu/Workspace vocabulary via ONBOARDING_STEPPER_STEPS,
   shown as a compact inline rail in the topbar (business-type, the
   pre-step entry screen, carries no stepper at all — see
   renderBizTypeScreen()). Real onboarding logic (App.businessProfile/
   App.bizSelected/search+
   autocomplete/save-business) is completely unchanged — only the
   render layer below is new. See renderDiscoverScreen() in the script
   block. ══════════════════════════════════════════════════════════════ */
#discoverScreen {
  display: none; background: var(--biz-ink); color: var(--biz-ivory);
  font-family: var(--biz-sans); position: relative; overflow: hidden;
}
/* Light onboarding theme round — Discover (and every later business
   onboarding screen) no longer uses the cinematic collage at all; the
   Discover-continues-the-collage round's own scoped .ob-collage/
   .ob-collage::after overrides here were removed along with
   renderObCollage() being removed from renderDiscoverScreen()'s own
   markup — the visual "world" changes deliberately at this exact
   boundary (cinematic Screen 1/2 -> light Discover/Menu/Workspace/Ready),
   per this round's own explicit split between the two design
   environments. #discoverScreen's own plain background (below) is now
   the only ground this screen ever shows.
   Safe baseline size for every DISC_ICON svg — every icon is stamped
   with this class at the source (see DISC_ICON below); more specific
   contextual rules elsewhere in this block (.disc-btn svg,
   .disc-result-thumb svg, etc.) still win per normal CSS specificity, so
   this only fills in spots that don't already have their own sizing. */
#discoverScreen .disc-icon, #buildScreen .disc-icon { width: 16px; height: 16px; flex: none; display: inline-block; }
/* Responsive correction round (2026-09-05) — min-width:0 on every direct
   grid row prevents a classic CSS Grid "blowout": with no explicit
   grid-template-columns, the implicit column's width is normally
   determined by justify-items:stretch against the container's available
   space, but any descendant that can't shrink below its own min-content
   width (a `white-space:nowrap` label, `flex:none` control, etc.) would
   otherwise force the whole column — and everything else stacked in it —
   wider than the viewport. #discoverScreen's own overflow:hidden was
   silently CLIPPING that excess rather than causing a visible page
   scroll, which is worse (content/controls rendered past the visible
   edge with no way to reach them) — found during this round's own
   required narrow-viewport audit, not merely theoretical. */
#discoverScreen > * { position: relative; z-index: 1; min-width: 0; }
/* Discover Final Consolidation round (2026-08-21+), §30 — removed the
   page-wide amber/brown corner washes and the bottom amber+blur band
   (the "muddy brown/green ambient wash" complaint); now the exact same
   clean, uniform near-black vignette already established on the
   business-type page's #bizTypeScreen::before. Local KROX-amber
   highlights (result-item selection, Preview purple tone) are untouched
   — this only removes the broad page-level wash. */
#discoverScreen::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 130% 110% at 50% 45%, transparent 55%, rgba(0,0,0,.5) 100%);
  z-index: 0;
}
#discoverScreen.is-active {
  /* Header Line + Safe-Data Alignment round (2026-08-21+), §18 — a new
     explicit row for the shared page-nav row (Back/Return), which used
     to be nested inside .disc-left (the narrower left column) instead
     of spanning the same shell width as the topbar/.disc-grid above it. */
  display: grid; grid-template-rows: auto auto minmax(0,1fr) auto;
  /* Global Positioning/Spacing Consistency round (2026-08-21+) — same
     min-height-not-max-height safety fix as business-type/Workspace (see
     their own comments): targets one viewport, degrades to a real
     document scroll instead of silently clipping on a genuinely short
     window. Horizontal/top padding now come from the one shared shell
     system (--ob-shell-x/--ob-shell-top). */
  min-height: 100dvh; width: 100%;
  padding: var(--ob-shell-top) var(--ob-shell-x) clamp(16px,2.2vh,22px);
  /* row-gap is 0 — .ob-nav-row now supplies its own explicit
     margin-top/margin-bottom (the real, precise "gap after header"/"gap
     before title" control per §16); a nonzero row-gap here would have
     ADDED to that margin at this specific transition (topbar→nav-row)
     without affecting the other two screens' equivalent transition
     (which don't sit inside a CSS grid), reintroducing the exact
     cross-page Back-position drift this round is fixing. .disc-main's
     own margin-bottom (below) replaces row-gap's job for the one
     remaining transition that still needs it (main content → trust note). */
  row-gap: 0;
}

