/* TechBag IQ — Bright Card on Geometric Canvas theme */
:root {
  /* Canvas + cards — SINGLE SOURCE. Content lives on bright white "story cards"
     floating on a light geometric canvas (no neon gradients). */
  --bg-dark: #edf1f7;          /* light surface (drawers/panels that read this token) */
  --story-block: linear-gradient(180deg, rgba(255,255,255,0.86), rgba(249,251,255,0.80));  /* frosted-glass story block */
  --bg-surface: #f3f6fb;       /* inputs / subtle inset surfaces */
  --bg-card: #ffffff;          /* the bright story card */
  --bg-card-hover: #f6f9fd;
  --bg-elevated: #ffffff;
  --border-color: rgba(18, 42, 78, 0.11);
  --border-accent: rgba(10, 126, 164, 0.38);

  --text-main: #14273e;        /* ink */
  --text-light: #14273e;       /* alias — was "light text on dark"; now ink on light */
  --text-muted: #566880;
  --text-dim: #5b6b82;         /* darkened to clear WCAG AA (was #6a7a90 = 3.7:1 on the pane) */

  /* Brand palette — muted, restrained (no neon blue/purple). */
  --accent-blue: #2f6bc4;
  --accent-cyan: #0a7ea4;      /* deep teal replaces neon cyan */
  --accent-green: #0f9a72;
  --accent-amber: #bd7d13;
  --accent-red: #d83a3a;
  --accent-purple: #6f5bd0;
  --grad-brand: linear-gradient(135deg, #0a7ea4, #2f6bc4);

  /* Softened "storyboard tile" accents — muted / pastel versions of the ADA
     palette, used ONLY on the dashboard nav tiles (via inline --tile-accent).
     The global --accent-* tokens above are left at full strength so body text,
     charts and badges keep their AA contrast. Fulfillment keeps true red. */
  --tile-red: #d83a3a;      /* Fulfillment — unchanged, stays urgent */
  --tile-gold: #c07f57;     /* gold  → terracotta   */
  --tile-blue: #6079a6;     /* blue  → slate blue    */
  --tile-purple: #897bc4;   /* purple → muted lavender */
  --tile-green: #57a084;    /* green → sage          */
  --tile-cyan: #4b97ab;     /* cyan  → soft teal     */

  /* ---- TYPE SCALE ------------------------------------------------------------
     The audit counted 17 distinct font sizes in active use, most of them one-off
     literals. This is the scale they collapse onto. It is anchored to the values
     the earlier #step-1-landing pass already landed on and Zach signed off by eye,
     so migrating a rule onto a token does not move any type he has already
     approved — the token names an existing decision rather than inventing a new one.

     --fs-micro is a FLOOR, not a size to reach for. 12px is where an all-caps
     eyebrow or a badge stops being comfortable, and prose must never be set at it:
     the storefront complaint that started this pass ("text is too small everywhere")
     was almost entirely rules sitting at 0.6–0.72rem, i.e. 9.6–11.5px.

     rem, deliberately, not em — these must not compound inside nested components.
     Migration is incremental on purpose: dashboard literals are left alone until
     each is looked at, because a blanket find-and-replace onto the nearest token
     would silently restyle several hundred rules with nobody's eye on the result. */
  --fs-micro: 0.75rem;   /* 12.0px — all-caps eyebrows, badges, column heads. FLOOR. */
  --fs-2xs:   0.84rem;   /* 13.4px — dense metadata, table cells                     */
  --fs-xs:    0.92rem;   /* 14.7px — secondary prose, controls                       */
  --fs-sm:    0.98rem;   /* 15.7px — body prose                                      */
  --fs-md:    1.1rem;    /* 17.6px — card titles                                     */
  --fs-lg:    1.24rem;   /* 19.8px — section titles                                  */
  --fs-xl:    1.3rem;    /* 20.8px — panel headings                                  */
  --fs-2xl:   1.8rem;    /* 28.8px — screen headings                                 */
  --fs-3xl:   2.8rem;    /* 44.8px — the landing wordmark                            */

  /* ---- ON-DARK PALETTE -------------------------------------------------------
     Two surfaces in this app are deliberately dark and stay that way: the Live Map
     stage (a network map; a light map is the unusual choice) and the Savings Model
     hero band (the money number is meant to be dramatic). They are dark FEATURES
     inside a light product, not evidence of a dark theme.

     They read as "a different product" for a much more mundane reason than theme
     confusion: their colours were off-palette. The stage was drawn in the same
     pre-rebrand neon cyan (#22d3ee) that was retired everywhere else, over a black
     (#0b1120) that appears nowhere in the canvas. These tokens are the app's own
     dark canvas stops and a lift of --accent-cyan to the lightness a glowing node
     needs — same hue, so the map now looks like this product at night rather than
     like a different one. */
  --dark-canvas-1: #243049;   /* matches body.dark-theme's gradient start */
  --dark-canvas-2: #171f30;   /* ...and its end                          */
  --dark-ink:      #101a2c;   /* outline/knockout stroke on dark stages   */
  --on-dark-cyan:    #3fb0d6; /* --accent-cyan (hue 193) lifted for dark  */
  --on-dark-cyan-hi: #8fd8ef; /* its highlight/hover step                 */

  --shadow-soft: 0 2px 12px rgba(20, 40, 80, 0.08);
  --shadow-card: 0 10px 30px rgba(20, 40, 80, 0.10);
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  /* A pill is not a 999px corner — it is "round the ends completely". Naming it
     stops the value drifting (this file had both 999px and 99px doing the same
     job) and makes a global change to pill shape one edit instead of thirty. */
  --radius-pill: 999px;
  /* The two ink colours that carry the amber and green semantic states. They were
     spelled as raw hex at fifteen sites; both are contrast-checked against the
     surfaces they sit on, so a hand-typed near-miss is an accessibility bug. */
  --accent-amber-ink: #92640f;
  --accent-green-ink: #0f7d5c;

  /* Aliases referenced by a few inline styles / JS-rendered markup */
  --surface-card: #ffffff;
  --surface-light: #f3f6fb;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body.dark-theme {
  background-color: #212c43;
  background-image:
    radial-gradient(ellipse 70% 55% at 15% -10%, rgba(74, 108, 168, 0.28) 0px, transparent 60%),
    radial-gradient(ellipse 60% 50% at 88% 8%, rgba(50, 84, 146, 0.24) 0px, transparent 55%),
    radial-gradient(ellipse 80% 60% at 50% 116%, rgba(42, 66, 116, 0.28) 0px, transparent 60%),
    linear-gradient(165deg, #243049 0%, #171f30 100%);
  background-attachment: fixed;
  color: var(--text-main);
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 15px;
  min-height: 100vh; line-height: 1.7;
}

/* Layer 1 (::before) — soft BOKEH: out-of-focus light discs drifting slowly.
   Layer 2 (::after) — visible abstract GEOMETRY: outlined shapes that gently float.
   Both oversized + offset so the slow drift never reveals an edge; the geometry
   differs between storefront and dashboard (via :has on the active screen). */
body.dark-theme::before, body.dark-theme::after {
  content: '';
  position: fixed;
  top: -22%; left: -22%; width: 144%; height: 144%;
  pointer-events: none;
  z-index: 0;
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  /* No cursor parallax here any more. These layers used to `translate` by --gx/--gy,
     which meant a mousemove handler wrote two custom properties onto <body> on every
     pointer sample. Custom properties INHERIT, so writing one on <body> invalidates
     computed style for the entire document subtree — a full-document style recalc at
     pointer rate, to move a blurred bokeh field 26px behind an 86%-opaque panel.
     That was a top contributor to the whole-page flashing; the layers keep their own
     slow keyframe drift, which reads the same and costs nothing per pointer move.
     Deliberately NO `will-change` here: these boxes are 144% of the viewport each, and
     their running `animation` already promotes them. Adding will-change would pin two
     more oversized layers in GPU memory, and memory pressure is itself a cause of the
     tile eviction that looks like flashing. */
}
body.dark-theme::before {
  background-image:
    radial-gradient(circle 200px at 12% 22%, rgba(212,224,246,0.11), transparent 66%),
    radial-gradient(circle 120px at 82% 14%, rgba(200,216,242,0.10), transparent 66%),
    radial-gradient(circle 270px at 74% 82%, rgba(190,210,240,0.08), transparent 64%),
    radial-gradient(circle 90px at 30% 78%, rgba(222,230,250,0.12), transparent 68%),
    radial-gradient(circle 60px at 55% 40%, rgba(222,230,250,0.11), transparent 70%),
    radial-gradient(circle 150px at 46% 96%, rgba(198,214,242,0.08), transparent 64%);
  animation: floatA 78s ease-in-out infinite;
}
/* ::after is now a faint SECOND bokeh layer for depth — the abstract geometry
   moved to the animated inline #bg-geo SVG so each shape can move on its own. */
body.dark-theme::after {
  opacity: 0.5;
  background-image:
    radial-gradient(circle 240px at 84% 30%, rgba(196,214,242,0.07), transparent 66%),
    radial-gradient(circle 180px at 20% 84%, rgba(210,222,246,0.06), transparent 66%);
  animation: floatB 104s ease-in-out infinite;
}

/* ===== Animated abstract geometry layer (#bg-geo) =====
   Fixed full-viewport SVG behind all content. Each shape group has its own keyframe
   animation; depth now comes from opacity + scale, not from a cursor-driven translate.

   PERF (this layer caused visible flashing): it is full-viewport and permanently
   animating, so anything here is paid for on every frame, forever.
   - `filter: blur(0.6px)` was a full-viewport filter pass per frame. Removed — at
     0.6px it was doing almost nothing visually and everything to the frame budget.
   - `contain: layout style` stops this subtree's constant churn from participating in
     layout or style resolution for the rest of the document.
   Note what is deliberately NOT here: `contain: paint`/`size` (paint containment clips,
   and size containment on an inline <svg> root risks collapsing it) and `will-change`
   (the child animations already promote what needs promoting; pinning another
   full-viewport layer in GPU memory works against the fix).
   The layer's own paint is still soft: the shapes are low-opacity strokes on a dark
   canvas, which is what actually made it read as bokeh. */
#bg-geo {
  position: fixed; inset: 0; width: 100%; height: 100%;
  z-index: 0; pointer-events: none; opacity: 0.4;
  contain: layout style;
}
body.dark-theme:has(#step-4-dashboard.active) #bg-geo { opacity: 0.3; } /* calmer behind the wide pane */
/* rotate/scale around each shape's own centre */
#bg-geo .an-blob, #bg-geo .an-blob-b, #bg-geo .an-spin-cw, #bg-geo .an-spin-ccw,
#bg-geo .an-spin-cw-slow, #bg-geo .an-breathe {
  transform-box: fill-box; transform-origin: center;
}
#bg-geo .an-blob        { animation: geoBlob 26s ease-in-out infinite; }
#bg-geo .an-blob-b      { animation: geoBlob 31s ease-in-out infinite; animation-delay: -11s; }
#bg-geo .an-spin-cw     { animation: geoSpinCW 90s linear infinite; }
#bg-geo .an-spin-cw-slow{ animation: geoSpinCW 150s linear infinite; }
#bg-geo .an-spin-ccw    { animation: geoSpinCCW 116s linear infinite; }
#bg-geo .an-breathe     { animation: geoBreathe 12s ease-in-out infinite; }
/* `.an-flow` used to run `geoFlow 3.6s` — a stroke-dashoffset animation on the one
   path that carries it. stroke-dashoffset is NOT a compositor property, so that was a
   repaint of this full-viewport SVG on every single frame, permanently, for a dashed
   line travelling behind a 40%-opacity background. The dash pattern is kept; the
   perpetual repaint is not. If you want motion back here, animate transform/opacity. */
#bg-geo .an-flow        { stroke-dashoffset: 0; }
#bg-geo .an-wave        { animation: geoWave 21s ease-in-out infinite; }
#bg-geo .an-wave2       { animation: geoWave2 25s ease-in-out infinite; }
#bg-geo .an-tw          { animation: geoTwinkle 5s ease-in-out infinite; }
#bg-geo .an-tw.d1 { animation-delay: -1s; }
#bg-geo .an-tw.d2 { animation-delay: -2.3s; }
#bg-geo .an-tw.d3 { animation-delay: -3.5s; }
@keyframes geoBlob    { 0%,100% { transform: rotate(0deg) scale(1); } 50% { transform: rotate(7deg) scale(1.045); } }
@keyframes geoSpinCW  { to { transform: rotate(360deg); } }
@keyframes geoSpinCCW { to { transform: rotate(-360deg); } }
@keyframes geoBreathe { 0%,100% { transform: scale(1); opacity: 0.85; } 50% { transform: scale(1.05); opacity: 1; } }
@keyframes geoTwinkle { 0%,100% { opacity: 0.28; } 50% { opacity: 1; } }
@keyframes geoFlow    { to { stroke-dashoffset: -160; } }
@keyframes geoWave    { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }
@keyframes geoWave2   { 0%,100% { transform: translateY(0); } 50% { transform: translateY(10px); } }

/* Varied twinkle periods → organic shimmer instead of a synchronized blink. */
#bg-geo .an-tw.s2 { animation-duration: 6.8s; }
#bg-geo .an-tw.s3 { animation-duration: 8.3s; }

/* Depth-of-field, done with opacity instead of blur.
   These were `filter: blur(0.5px / 1.6px / 3px)` on three groups inside a full-viewport
   SVG that never stops animating — three separate filter regions re-rasterizing every
   frame, on top of the layer-wide blur that used to sit on #bg-geo itself. Recession
   reads just as well from opacity here, because the shapes are already low-contrast
   strokes on a dark canvas, and opacity is a compositor-only property: it costs nothing
   per frame. Do not put `filter` back on these groups. */
#bg-geo .gp-near { opacity: 0.95; }
#bg-geo .gp-mid  { opacity: 0.62; }
#bg-geo .gp-deep { opacity: 0.34; }

/* A very slow drift + rotation of the WHOLE field. Superposed with the shorter
   per-shape loops (coprime periods), the visible motion never obviously repeats. */
#bg-geo .geo-root { transform-box: view-box; transform-origin: 750px 475px; animation: geoField 190s ease-in-out infinite; }
@keyframes geoField {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  33%      { transform: translate(1.1%, -0.8%) rotate(0.55deg); }
  66%      { transform: translate(-0.9%, 0.6%) rotate(-0.5deg); }
}

/* Free-traveling particles: drift along their own long curves (not looping in place). */
#bg-geo .an-travel { fill: #d4e0f2; stroke: none; opacity: 0.5; }
#bg-geo .t1 { offset-path: path('M-60,300 C300,170 700,430 1120,240 C1360,150 1520,300 1580,255'); animation: travelMove 47s linear infinite, geoTwinkle 7s ease-in-out infinite; }
#bg-geo .t2 { offset-path: path('M1580,650 C1200,770 780,560 360,730 C120,810 -40,650 -100,705'); animation: travelMove 61s linear infinite, geoTwinkle 8.5s ease-in-out infinite; animation-delay: -12s; }
#bg-geo .t3 { offset-path: path('M760,-40 C900,220 560,470 780,700 C900,840 700,960 760,1000'); animation: travelMove 54s linear infinite, geoTwinkle 6s ease-in-out infinite; animation-delay: -26s; }
@keyframes travelMove { from { offset-distance: 0%; } to { offset-distance: 100%; } }

/* ===== Ambient aurora glow layer =====
   PERF: this used to carry `filter: blur(72px) saturate(1.2)` on the FIXED, FULL-VIEWPORT
   wrapper while four `mix-blend-mode: screen` children animated inside it forever. A
   parent filter forces the whole subtree to rasterize into one buffer and re-blur it at
   72px every frame any child moves — the most expensive single declaration on the page,
   and it never stopped. It is gone: the children are radial gradients that already fade
   to transparent at 66%, i.e. they are *already* blurs. The look survives; the per-frame
   72px convolution does not.
   `contain: layout style` only — not `paint`, because this box is deliberately inset by
   -12% and its children hang past its edges (`left: -5vw`, `bottom: -10vh`); paint
   containment would clip exactly the overhang that keeps the glow from showing a seam. */
#bg-aurora {
  position: fixed; inset: -12%; z-index: 0; pointer-events: none;
  contain: layout style;
}
#bg-aurora b { position: absolute; display: block; border-radius: 50%; mix-blend-mode: screen; will-change: transform; }
#bg-aurora .a1 { width: 46vw; height: 46vw; left: -5vw; top: 4vh;  background: radial-gradient(circle, rgba(12,132,170,0.24), transparent 66%); animation: auroraA 37s ease-in-out infinite; }
#bg-aurora .a2 { width: 42vw; height: 42vw; right: -7vw; top: 20vh; background: radial-gradient(circle, rgba(47,107,196,0.20), transparent 66%); animation: auroraB 43s ease-in-out infinite; }
#bg-aurora .a3 { width: 40vw; height: 40vw; left: 24vw; bottom: -10vh; background: radial-gradient(circle, rgba(111,91,208,0.15), transparent 66%); animation: auroraC 31s ease-in-out infinite; }
#bg-aurora .a4 { width: 34vw; height: 34vw; right: 14vw; bottom: -6vh; background: radial-gradient(circle, rgba(15,154,114,0.13), transparent 66%); animation: auroraB 49s ease-in-out infinite reverse; }
@keyframes auroraA { 0%,100% { transform: translate(0,0) scale(1); }    50% { transform: translate(6vw,4vh) scale(1.15); } }
@keyframes auroraB { 0%,100% { transform: translate(0,0) scale(1.05); } 50% { transform: translate(-5vw,6vh) scale(0.9); } }
@keyframes auroraC { 0%,100% { transform: translate(0,0) scale(1); }    50% { transform: translate(4vw,-5vh) scale(1.12); } }

@keyframes floatA {
  0%, 100% { transform: translate(0, 0) scale(1.02); }
  50% { transform: translate(2.5%, -2%) scale(1.08); }
}
@keyframes floatB {
  0%, 100% { transform: translate(0, 0) rotate(0deg) scale(1.02); }
  50% { transform: translate(-2%, 1.6%) rotate(-2.5deg) scale(1.06); }
}
@media (prefers-reduced-motion: reduce) {
  body.dark-theme::before, body.dark-theme::after { animation: none; }
  #bg-geo .an-blob, #bg-geo .an-blob-b, #bg-geo .an-spin-cw, #bg-geo .an-spin-cw-slow, #bg-geo .an-spin-ccw,
  #bg-geo .an-breathe, #bg-geo .an-flow, #bg-geo .an-wave, #bg-geo .an-wave2, #bg-geo .an-tw,
  #bg-geo .an-travel, #bg-geo .geo-root, #bg-aurora b {
    animation: none;
  }
  #bg-geo .gp { transition: none; }
}

/* Type scale */
h1 { font-size: 2rem; font-weight: 800; color: var(--text-main); letter-spacing: -0.02em; line-height: 1.2; }
h2 { font-size: 1.5rem; font-weight: 700; color: var(--text-main); letter-spacing: -0.01em; line-height: 1.3; }
h3 { font-size: 1.2rem; font-weight: 700; color: var(--text-main); line-height: 1.35; }
h4 { font-size: 1rem; font-weight: 600; color: var(--text-main); line-height: 1.4; }
p, span, div { font-size: inherit; }

.text-muted { color: var(--text-muted); }
/* Text utilities use AA-safe deeper shades for small text (the brighter --accent-*
   tokens stay for fills, icons, borders, and large numbers, which only need 3:1). */
/* These five stay flagged on purpose. They are utility classes sprinkled onto
   elements that already have a colour from a more specific component rule — a
   .text-green inside .stat-card h4, say — so the flag is doing the one job
   !important is actually for. A spot-check of two of them on one screen came back
   identical without the flag, which proves nothing about the other call sites;
   that is why they were not swept with the rest. */
.text-green { color: #0b7e5c !important; }
.text-cyan { color: var(--accent-cyan) !important; }
.text-blue { color: var(--accent-blue) !important; }
.text-purple { color: var(--accent-purple) !important; }
.text-amber { color: var(--accent-amber-ink) !important; }

/* Baseline visible focus indicator for keyboard users. Component-specific
   :focus-visible rules (inputs, footer, nav tiles) override where they define
   their own ring; everything else at least gets this clear outline. */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 2px;
  border-radius: 8px;
}

/* Global 4-Step Progress Bar */
.global-flow-bar {
  max-width: 800px; margin: 28px auto 0; display: flex; align-items: center; justify-content: space-between;
  padding: 12px 24px; background: rgba(18,42,78,0.04); border: 1px solid var(--border-color); border-radius: var(--radius-xl);
  position: relative; z-index: 1;
}
.flow-step-node { font-size: 0.78rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; }
.flow-step-node.active { color: var(--accent-cyan); }
.flow-line { flex: 1; height: 2px; background: rgba(18,42,78,0.09); margin: 0 12px; }

/* Screen Flow Switcher */
.flow-screen { display: none; animation: fadeIn 0.35s cubic-bezier(0.16, 1, 0.3, 1); position: relative; z-index: 1; }
.flow-screen.active { display: block; }

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* SLEEK CUSTOM DARK DROPDOWNS */
select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  background-color: var(--bg-surface);
  background-image: url("data:image/svg+xml;utf8,<svg fill='%230a7ea4' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/></svg>");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 18px;
  border: 1px solid var(--border-color); border-radius: var(--radius-md);
  color: var(--text-main); font-family: inherit; font-weight: 600;
  padding: 12px 40px 12px 16px; outline: none; cursor: pointer;
  transition: border-color 0.2s ease, box-shadow 0.2s ease; box-shadow: var(--shadow-soft);
}
select:hover, select:focus { border-color: var(--accent-cyan); box-shadow: 0 0 0 3px rgba(10, 126, 164, 0.12); }

select option { background-color: #ffffff; color: #14273e; padding: 12px; font-size: 0.9rem; }
select option:hover, select option:focus, select option:checked { background-color: #e6f2f6 !important; color: #0a7ea4 !important; }

/* STEP 1: LANDING PAGE TAPPABLE PICTURE CARDS */
.landing-hero-container { max-width: 1200px; margin: 40px auto; padding: 24px; text-align: center; }
.landing-header .logo-icon.large {
  width: 72px; height: 72px; font-size: 2.2rem; margin: 0 auto 20px; border-radius: var(--radius-lg);
  background: linear-gradient(135deg, var(--accent-blue), var(--accent-cyan));
  display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 20px rgba(91,141,239,0.2); color: #fff;
}
/* The header is now just the logo and the wordmark — the tagline and explainer paragraph
   were removed from the markup. Their margins used to be what separated the header from
   the switcher below, so that gap lives here now. `.landing-header` appears exactly once
   in the app (step 1), so this margin is safe to own at the wrapper level.
   `.landing-subtitle` / `.landing-explainer` were deleted along with them — no markup or
   script referenced either class, so the rules were dead weight. */
.landing-header { margin-bottom: 26px; }
.landing-header h1 { font-size: 2.8rem; letter-spacing: -1.5px; margin-bottom: 6px; font-weight: 800; }
.landing-header h1 span { color: var(--accent-cyan); }
.brand-mark { color: var(--text-main); }
.brand-mark span { color: var(--accent-cyan); }

.picture-bag-card {
  background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-xl);
  overflow: hidden; cursor: pointer; text-align: left;
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.25s ease, box-shadow 0.25s ease;
  display: flex; flex-direction: column; justify-content: space-between;
  box-shadow: var(--shadow-card);
}
.picture-bag-card:hover {
  transform: translateY(-5px); border-color: rgba(18,42,78,0.11);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
}
.picture-bag-card.highlight {
  border-color: var(--accent-blue); box-shadow: 0 8px 30px rgba(59, 130, 246, 0.2);
}

.bag-card-img-wrap {
  width: 100%; height: 160px; background: rgba(18,42,78,0.06);
  display: flex; align-items: center; justify-content: center; position: relative;
  border-bottom: 1px solid var(--border-color);
}
.bag-hero-img {
  width: 76px; height: 76px; object-fit: cover; border-radius: var(--radius-md);
  background: #ffffff; padding: 4px; border: 1px solid var(--border-color);
  box-shadow: 0 4px 15px rgba(0,0,0,0.4);
}
.bag-type-badge {
  position: absolute; top: 12px; right: 12px; background: rgba(15, 23, 42, 0.85);
  border: 1px solid var(--accent-cyan); color: var(--accent-cyan); font-weight: 800;
  font-size: var(--fs-micro); text-transform: uppercase; padding: 3px 10px; border-radius: 12px;
}

.bag-card-body { padding: 20px; flex: 1; display: flex; flex-direction: column; justify-content: space-between; }
.bag-card-body h3 { font-size: 1.1rem; margin-bottom: 4px; }
.bag-card-body p { font-size: var(--fs-2xs); line-height: 1.5; color: var(--text-muted); }

.bag-specs-pill {
  margin-top: 14px; background: rgba(18,42,78,0.05); border: 1px solid var(--border-color);
  padding: 6px 12px; border-radius: var(--radius-md); font-family: 'JetBrains Mono', monospace;
  font-size: 0.8rem; font-weight: 700; color: var(--accent-cyan); display: inline-flex; gap: 8px; justify-content: center;
}

/* STEP 2: SLOT-BASED BUILDER & TEMPLATES */
.step-container { max-width: 720px; margin: 40px auto; padding: 24px; }
.flow-card {
  background: var(--bg-card); border: 1px solid var(--border-color); padding: 32px; border-radius: var(--radius-xl);
  margin-top: 20px; box-shadow: var(--shadow-card);
}
.flow-card-header h2 { font-size: 1.45rem; margin-bottom: 6px; }

.template-pills-grid { display: flex; flex-wrap: wrap; gap: 12px; }
.template-pill-btn {
  padding: 10px 16px; border-radius: var(--radius-md); border: 1px solid var(--border-color);
  background: rgba(18,42,78,0.05); color: var(--text-main); font-weight: 600; font-size: 0.88rem;
  cursor: pointer; transition: all 0.2s ease; display: inline-flex; align-items: center; gap: 8px;
}
.template-pill-btn:hover { background: rgba(18,42,78,0.06); border-color: rgba(18,42,78,0.13); }
.template-pill-btn.active {
  background: rgba(10,126,164,0.08);
  border-color: var(--accent-cyan); color: var(--accent-cyan); box-shadow: 0 0 0 3px rgba(10, 126, 164, 0.08);
}

.slot-add-pills { display: flex; flex-wrap: wrap; gap: 10px; }

.slots-grid-container { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media (max-width: 680px) { .slots-grid-container { grid-template-columns: 1fr; } }

.slot-card-dashed {
  background: rgba(18,42,78,0.03); border: 2px dashed var(--border-accent);
  border-radius: var(--radius-lg); padding: 20px; cursor: pointer; transition: all 0.2s ease;
  display: flex; flex-direction: column; justify-content: space-between; min-height: 140px;
}
.slot-card-dashed:hover { background: rgba(59, 130, 246, 0.08); border-color: var(--accent-cyan); transform: translateY(-3px); }
.slot-card-dashed.filled { border-style: solid; border-color: var(--accent-green); background: rgba(16, 185, 129, 0.08); }

.slot-card-header { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.slot-icon-badge {
  width: 36px; height: 36px; border-radius: 8px; background: var(--bg-surface);
  display: flex; align-items: center; justify-content: center; font-size: 1.1rem; color: var(--accent-cyan); border: 1px solid var(--border-color);
}
.slot-card-dashed.filled .slot-icon-badge { background: rgba(16, 185, 129, 0.2); color: var(--accent-green); }

/* STEP 3: DISCOVERY & CONFIRMATION */
.discovery-card {
  background: var(--bg-card); border: 1px solid var(--border-accent); padding: 32px; border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card);
}
.discovery-header { display: flex; align-items: center; gap: 18px; border-bottom: 1px solid var(--border-color); padding-bottom: 20px; margin-bottom: 24px; }
.discovered-items-container { display: flex; flex-direction: column; gap: 16px; }

.discovered-item-row {
  background: rgba(18,42,78,0.06); border: 1px solid var(--border-color); padding: 18px; border-radius: var(--radius-lg);
  display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap; animation: fadeIn 0.3s ease;
}

/* SIDE-BY-SIDE CATEGORY COLUMNS FOR VERTICAL INNOVATION TREE */
.vertical-tree-canvas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 22px;
  align-items: start;
}

.vertical-tree-group {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  padding: 18px;
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  height: 100%;
}

/* CRISP HIGH-CONTRAST LINEAGE HEADER ROOT CARD (ELECTRIC BLUE ACCENT) */
.vtree-root-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-accent);
  border-radius: var(--radius-lg);
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  box-shadow: var(--shadow-soft);
}

.node-img-thumb {
  width: 44px; height: 44px;
  border-radius: var(--radius-md);
  object-fit: cover;
  border: 1px solid rgba(18,42,78,0.13);
  background: #ffffff;
  padding: 2px;
  flex-shrink: 0;
}

.vtree-connector-line {
  width: 2px;
  height: 18px;
  background: linear-gradient(to bottom, var(--accent-blue), var(--accent-cyan));
  margin: 0 auto;
  position: relative;
}
.vtree-connector-line::after {
  content: '';
  position: absolute; bottom: 0; left: -4px;
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--accent-cyan);
}

.vtree-branches-list { display: flex; flex-direction: column; gap: 10px; }

.vbranch-card {
  background: rgba(18,42,78,0.05);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 12px 14px;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  gap: 10px;
  position: relative;
}
.vbranch-card:hover {
  background: rgba(18,42,78,0.09);
  border-color: var(--accent-cyan);
  transform: translateY(-2px);
}

/* DISCREET TOP-RIGHT HEADER SYNC PILL WIDGET */
.header-sync-pill {
  background: rgba(6, 182, 212, 0.12); border: 1px solid var(--accent-cyan);
  padding: 4px 12px; border-radius: var(--radius-xl); display: inline-flex;
  align-items: center; gap: 8px; margin-right: 4px;
}

/* STEP 4: DASHBOARD & RESTRUCTURED FLOW WITH EXPANDED 64PX VERTICAL TAB SPACING */
.app-container {
  max-width: 1360px; width: calc(100% - 64px); margin: 34px auto 132px; padding: 40px 48px; position: relative; z-index: 1;
  box-sizing: border-box;
  /* THE flashing fix. This used to be `backdrop-filter: blur(30px) saturate(1.3)`.
     backdrop-filter re-samples and re-blurs everything painted beneath it whenever the
     backdrop changes — and the backdrop here is #bg-geo + #bg-aurora + two body
     pseudo-elements, ~20 infinite animations that NEVER stop changing. So the browser
     was re-blurring a 1360px-wide, full-page-tall region every single frame for the life
     of the session, and `contain` on the background layers cannot prevent that (a
     backdrop root samples everything below it regardless). Under that load Chrome
     eventually drops composited tiles and re-rasterizes, which is what read as the whole
     page "flashing" — and why a refresh temporarily helped.
     The frosted look is kept by making the panel's own fill do the work instead: a
     slightly denser version of --story-block's own gradient. --story-block was already
     80-86% white, so the 30px blur only ever contributed ~15% of each pixel — and what it
     was blurring is a backdrop made of soft radial blobs with no high-frequency detail,
     so there was almost nothing there for a blur to smooth in the first place. The extra
     ~7% alpha here covers the one thing that did sharpen: #bg-geo's SVG linework, which
     no longer carries its own blur either. Translucency itself is kept and is cheap — a
     plain alpha blend is compositor work; it is `filter` that is not.
     Do not reintroduce backdrop-filter on a region this large. */
  background: linear-gradient(180deg, rgba(255,255,255,0.93), rgba(249,251,255,0.90));
  border: 1px solid rgba(255,255,255,0.72);
  border-radius: 32px;
  box-shadow: 0 44px 100px rgba(4, 11, 30, 0.52), 0 14px 34px rgba(4, 11, 30, 0.30), 0 0 0 1px rgba(255,255,255,0.10), inset 0 1px 0 rgba(255,255,255,0.85);
}
/* Brand Logo Area styling */
.logo-area { display: flex; align-items: center; gap: 14px; }
.logo-icon {
  width: 40px; height: 40px; border-radius: var(--radius-md); background: linear-gradient(135deg, var(--accent-blue), var(--accent-cyan));
  display: flex; align-items: center; justify-content: center; font-size: 1.2rem; color: #fff;
}
.logo-text h1 { font-size: 1.35rem; }
.logo-text h1 span { color: var(--accent-cyan); }
.logo-text .tagline { font-size: 0.75rem; color: var(--text-muted); }

.app-header {
  display: flex; justify-content: space-between; align-items: center; padding-bottom: 20px; border-bottom: 1px solid var(--border-color);
  margin-bottom: 32px; flex-wrap: nowrap; gap: 16px;
}

/* Header Integrated Navigation Tabs */
.header-integrated-tabs {
  display: flex;
  gap: 4px;
  background: rgba(18,42,78,0.03);
  padding: 3px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
}
.header-integrated-tabs .tab-btn {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-weight: 700;
  font-size: 0.8rem;
  padding: 8px 14px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s ease;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.header-integrated-tabs .tab-btn:hover {
  color: var(--text-main);
  background: rgba(18, 42, 78, 0.05);
}
.header-integrated-tabs .tab-btn.active {
  background: var(--bg-elevated);
  color: var(--accent-cyan);
  box-shadow: var(--shadow-soft);
}

/* ACTIVE BAG INVENTORY SECTION WITH CLEAR NEGATIVE SPACE */
.active-bag-inventory-section {
  margin-bottom: 28px; padding-bottom: 24px; border-bottom: 1px solid rgba(18,42,78,0.07);
}

.section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 22px; }
.section-header h3 { font-size: 1.2rem; }
.section-header p { font-size: 0.85rem; color: var(--text-muted); margin-top: 4px; }

.bag-items-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; }
/* No backdrop-filter here — see .metrics-ribbon-6. It was blur(12px) under an opaque
   #ffffff fill, and .bag-card is the most-repeated element on the storefront grid, so
   this was N invisible full-blur regions all re-sampling the animated background every
   frame. This is the single largest contributor to the landing page flashing. */
.bag-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 18px; }
.card-top { display: flex; justify-content: space-between; margin-bottom: 8px; }
.card-category { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; color: var(--accent-cyan); }
.card-actions-btn { background: transparent; border: none; color: var(--text-muted); cursor: pointer; }

.mapper-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-xl); padding: 28px; box-shadow: var(--shadow-card); }

.drawer-overlay {
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
  background: rgba(0, 0, 0, 0.7); z-index: 2500;
  opacity: 0; pointer-events: none; transition: opacity 0.3s ease;
}
/* The blur moved from the base rule to `.active` on purpose. This overlay is
   position:fixed, full-viewport, and always in the DOM — it hides with opacity, not
   display — so a backdrop-filter declared on the base rule keeps a viewport-sized
   backdrop root alive over the animated background for the entire session, even though
   nothing is on screen. There are three overlays like this; all three are now gated.
   The blur still appears when the overlay opens, hidden inside the 0.3s fade. */
.drawer-overlay.active { opacity: 1; pointer-events: auto; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }

.drawer-body {
  padding: 24px; overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 18px;
}

.bag-compare-selectors { display: grid; grid-template-columns: 1fr 40px 1fr; gap: 14px; align-items: center; }
.compare-matrix-table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: 0.88rem; }
.compare-matrix-table th, .compare-matrix-table td { padding: 10px 14px; border: 1px solid var(--border-color); text-align: left; }
.compare-matrix-table th { background: rgba(18,42,78,0.06); font-weight: 700; }

.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 11px 20px; border-radius: var(--radius-md); font-weight: 600; font-size: 0.9rem; cursor: pointer; border: 1px solid transparent; transition: all 0.2s ease; }
.btn-block { width: 100%; }
.btn-lg { padding: 14px 28px; font-size: 1.05rem; }
.btn-sm { padding: 7px 14px; font-size: 0.82rem; }
.btn-primary { background: var(--accent-blue); color: #fff; }
.btn-primary:hover { background: #4e7fe0; }
.btn-secondary { background: var(--bg-elevated); color: var(--text-main); border: 1px solid var(--border-color); }
.btn-outline { background: transparent; color: var(--text-main); border: 1px solid rgba(18,42,78,0.10); }
.btn-outline:hover { background: rgba(18,42,78,0.05); border-color: rgba(18,42,78,0.13); }

/* blur(16px) removed — --bg-card is opaque #ffffff, so it rendered nothing, and this
   element is permanently in the DOM (hidden with opacity), so it was holding a backdrop
   root open over the animated background at all times for zero visual return. */
.hover-tooltip { position: fixed; z-index: 1000; width: 300px; background: var(--bg-card); border: 1px solid var(--accent-blue); color: var(--text-main); border-radius: var(--radius-lg); padding: 14px; pointer-events: none; opacity: 0; transform: scale(0.95); transition: opacity 0.15s ease, transform 0.15s ease; }
.hover-tooltip.visible { opacity: 1; transform: scale(1); }

/* MODAL CONTAINER & VIEWPORT HEIGHT FIX */
.modal-overlay {
  position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.75);
  z-index: 2000; display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity 0.2s ease; padding: 24px;
}
/* blur gated to .active — see .drawer-overlay for why. */
.modal-overlay.active { opacity: 1; pointer-events: auto; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }

.modal-card {
  background: var(--bg-elevated); border: 1px solid rgba(18,42,78,0.09); width: 100%; max-width: 600px;
  max-height: 85vh; overflow-y: auto; border-radius: var(--radius-xl); padding: 32px; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
}

.modal-header { display: flex; justify-content: space-between; margin-bottom: 18px; }
.modal-close { background: transparent; border: none; color: var(--text-muted); font-size: 1.2rem; cursor: pointer; }
.form-group { margin-bottom: 14px; display: flex; flex-direction: column; gap: 6px; }
.form-group label { font-size: 0.8rem; color: var(--text-muted); font-weight: 600; }
.form-group input { padding: 10px 14px; border-radius: var(--radius-md); background: rgba(18,42,78,0.06); border: 1px solid var(--border-color); color: var(--text-main); outline: none; font-size: 0.88rem; }
.form-group input:focus-visible, .form-input:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: none; border-color: var(--accent-cyan); box-shadow: 0 0 0 2px rgba(10, 126, 164, 0.35); }
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 12px; }
.input-with-button { display: flex; gap: 8px; }
.input-with-button input { flex: 1; }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 22px; }

/* DASHBOARD SIDE-BY-SIDE NO-SCROLL LAYOUT styles */
.dashboard-story-layout {
  display: flex;
  gap: 32px;
  align-items: flex-start;
  margin-top: 20px;
}
.dashboard-left-panel {
  flex: 7;
  min-width: 0;
}
.dashboard-right-sidebar {
  flex: 3;
  min-width: 280px;
  position: sticky;
  top: 20px;
}
.sidebar-sticky-panel {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  padding: 20px;
  /* blur(12px) removed — opaque --bg-card above it, see .metrics-ribbon-6. */
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.sidebar-block-title {
  font-size: 0.82rem;
  font-weight: 800;
  text-transform: uppercase;
  color: var(--accent-cyan);
  border-bottom: 1px solid rgba(18,42,78,0.07);
  padding-bottom: 8px;
}
.metrics-sidebar-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.metric-sidebar-row {
  background: rgba(18,42,78,0.03);
  border: 1px solid rgba(18,42,78,0.06);
  border-radius: var(--radius-md);
  padding: 8px 12px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.metric-sidebar-row i {
  font-size: 1rem;
}
.metric-sidebar-info {
  display: flex;
  flex-direction: column;
}
.metric-sidebar-info .label {
  font-size: 0.65rem;
  color: var(--text-muted);
  font-weight: 700;
  text-transform: uppercase;
}
.metric-sidebar-info strong {
  font-size: 1rem;
  font-family: 'JetBrains Mono', monospace;
  color: var(--text-main);
}

/* GUIDED STORY CHECKLIST CARD */
.guided-story-card {
  background: rgba(59, 130, 246, 0.05);
  border: 1px solid rgba(59, 130, 246, 0.2);
  border-radius: var(--radius-lg);
  padding: 16px;
}
.guided-story-card h4 {
  font-size: 0.95rem;
  margin-bottom: 10px;
}

@media (max-width: 1024px) {
  .dashboard-story-layout {
    flex-direction: column;
  }
  .dashboard-right-sidebar {
    width: 100%;
    position: static;
  }
}

/* Top tab router view contents */
.dashboard-view-content { display: none; }
.dashboard-view-content.active { display: block; animation: slideUp 0.3s ease-out; }
/* Non-home views get top spacing to clear the breadcrumb */
.dashboard-view-content.active:not(#view-dashboard-home) { padding-top: 8px; }

/* The .dashboard-nav-tile hover rules that used to sit here were dead AND harmful.
   Dead: the live block near the bottom of this file (search `DASHBOARD STORY TILES`)
   redeclares transform, box-shadow and border-color at the same 0-1-0 specificity and
   wins on source order — including the `!important` border-color, since its own is
   `!important` too and later.
   Harmful: this one carried `transition: all 0.2s ease`. `all` transitions every
   animatable property that changes, so moving between story tiles animated background,
   border, shadow and layout properties at once — on cards sitting inside what was then
   a backdrop-filtered container, forcing that whole filtered region to re-composite per
   frame. That is the "hovering story block to story block flashes the whole page"
   report. The live block transitions exactly three named properties instead.
   Never use `transition: all` on these tiles. */

.people-directory-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
  margin-top: 20px;
}
.person-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 20px;
  position: relative;
  transition: all 0.2s ease;
  box-shadow: var(--shadow-soft);
}
.person-card:hover {
  border-color: rgba(18,42,78,0.11);
  background: var(--bg-card-hover);
  transform: translateY(-2px);
}
.person-card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 10px;
}
/* Gamification — Provisioning Score pill + badges */
.score-pill { display:inline-flex; align-items:center; gap:5px; font-size:0.68rem; font-weight:700;
  border:1px solid var(--border-color); border-radius:var(--radius-pill); padding:3px 9px; white-space:nowrap; background:var(--bg-card); flex-shrink:0; }
.score-badge { display:inline-flex; align-items:center; gap:6px; font-size:0.72rem; font-weight:700;
  border:1px solid var(--border-color); border-radius:var(--radius-pill); padding:5px 11px; background:var(--bg-surface); color:var(--text-main); }
.score-badge i { font-size:0.72rem; }
.lb-tabs { display:inline-flex; gap:6px; background:var(--bg-surface); border:1px solid var(--border-color); border-radius:12px; padding:5px; margin-bottom:20px; }
.lb-tab { font:inherit; font-size:0.82rem; font-weight:700; color:var(--text-muted); background:transparent; border:none; cursor:pointer;
  padding:8px 16px; border-radius:8px; transition:.15s; display:inline-flex; align-items:center; gap:7px; }
.lb-tab:hover { color:var(--text-main); }
.lb-tab.active { background:var(--bg-card); color:var(--accent-cyan); box-shadow:var(--shadow-soft); }
.lb-rank-list { display:flex; flex-direction:column; gap:10px; }
.lb-rank-row { display:flex; align-items:center; gap:14px; background:var(--bg-card); border:1px solid var(--border-color);
  border-radius:var(--radius-md); padding:12px 16px; transition:transform .14s ease, box-shadow .14s ease, border-color .14s ease; }
.lb-rank-row:hover { transform:translateY(-2px); box-shadow:0 12px 26px rgba(20,40,80,0.12); border-color:var(--border-accent); }

.person-avatar {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-green), var(--accent-cyan));
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 0.95rem;
  color: #000;
}
.person-info {
  display: flex;
  flex-direction: column;
}
.person-info h4 {
  font-size: 0.98rem;
  margin-bottom: 2px;
}
.person-info span {
  font-size: var(--fs-micro);
  color: var(--text-muted);
}
.person-bag-badge {
  background: rgba(18,42,78,0.06);
  border: 1px solid var(--border-color);
  padding: 4px 8px;
  border-radius: 8px;
  font-size: 0.74rem;
  margin: 10px 0;
  display: inline-block;
  font-weight: 600;
}
.person-device-pill-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.person-device-tag {
  background: rgba(16, 185, 129, 0.15);
  color: #6ee7b7;
  font-size: 0.68rem;
  padding: 2px 6px;
  border-radius: 6px;
  font-weight: 700;
}

/* Separator border with negative space before Lineage centerpiece */
.lineage-centerpiece-section {
  border-top: 1px solid rgba(18,42,78,0.07);
  margin-top: 48px;
  padding-top: 36px;
  box-shadow: inset 0 20px 20px -20px rgba(59, 130, 246, 0.08);
}

/* Hover Quick View Link Button overlay for Tree cards */
.vbranch-card .quick-view-hover-btn {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  background: rgba(6, 182, 212, 0.1);
  border: 1px solid rgba(6, 182, 212, 0.3);
  color: var(--accent-cyan);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  opacity: 0;
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 10;
}
.vbranch-card:hover .quick-view-hover-btn {
  opacity: 1;
  transform: scale(1.1);
}
.vbranch-card .quick-view-hover-btn:hover {
  background: var(--accent-cyan);
  color: #0b0f19;
  border-color: var(--accent-cyan);
  box-shadow: 0 0 8px rgba(6, 182, 212, 0.4);
}

/* Highlight active bag parent card on branch hover */
.vtree-root-card.upgrade-target-highlight {
  border-color: var(--accent-cyan) !important;
  box-shadow: 0 0 20px rgba(6, 182, 212, 0.45) !important;
  transform: scale(1.02);
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Hover Quick View Link Button for Active Bag Inventory cards */
.bag-card .bag-card-hover-link-btn {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 26px;
  height: 26px;
  border-radius: 6px;
  background: rgba(6, 182, 212, 0.1);
  border: 1px solid rgba(6, 182, 212, 0.3);
  color: var(--accent-cyan);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  opacity: 0;
  transition: all 0.2s ease;
  z-index: 10;
}
.bag-card:hover .bag-card-hover-link-btn {
  opacity: 1;
}
.bag-card .bag-card-hover-link-btn:hover {
  background: var(--accent-cyan);
  color: #0b0f19;
  border-color: var(--accent-cyan);
  box-shadow: 0 0 8px rgba(6, 182, 212, 0.4);
}

.btn-xs {
  padding: 4px 6px;
  font-size: 0.68rem;
  line-height: 1.1;
  border-radius: 4px;
}

/* Landing bag cards: uniform story cards in a wrapping grid (no full-width hero card). */
.picture-bag-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
  margin-top: 20px;
  align-items: stretch;
}
#landing-all-template-cards {
  display: contents;
}

@media print {
  body { background: #ffffff !important; color: #000000 !important; }
  .global-flow-bar, .app-header, .metrics-ribbon-6, .view-selector, .tab-content, .modal-close, .modal-actions, .drawer-card, .drawer-overlay { display: none !important; }
  .modal-overlay { position: static !important; background: transparent !important; opacity: 1 !important; pointer-events: auto !important; }
  .modal-card { max-width: 100% !important; max-height: none !important; border: none !important; box-shadow: none !important; background: #ffffff !important; color: #000000 !important; }
}

/* Compact Landing Page Layout (No Scroll) */
#step-1-landing {
  min-height: 100vh;
  overflow-y: auto;
  /* The landing step paints nothing of its own — the animated canvas behind it is
     the background. Merged here from a second #step-1-landing block further down. */
  background-color: transparent;
  background-image: none;
}
#step-1-landing .landing-hero-container {
  max-width: 1080px;
  margin: 34px auto 132px;
  padding: 40px 40px 44px;
  /* Height follows the content — the frosted pane grows/shrinks with how many kit
     cards exist, instead of forcing a tall block with empty space below. */
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 18px;
  box-sizing: border-box;
  position: relative;
  z-index: 1;
  /* More intriguing frost: a slightly more translucent pane with soft teal/blue
     light pooling in the corners, so the floating morphism drifts through it. */
  background:
    radial-gradient(130% 62% at 50% -12%, rgba(10,126,164,0.10), transparent 58%),
    radial-gradient(90% 60% at 108% 112%, rgba(47,107,196,0.09), transparent 55%),
    radial-gradient(70% 50% at -8% 90%, rgba(15,154,114,0.06), transparent 55%),
    linear-gradient(180deg, rgba(255,255,255,0.90), rgba(248,251,255,0.86));
  /* `backdrop-filter: blur(32px) saturate(1.4)` removed — same reasoning as .app-container,
     and this is the landing page specifically, the surface Zach reported flashing on. It
     was a full-hero-sized blur region re-sampling four permanently-animating background
     layers every frame. The corner light-pooling gradients above are what actually make
     this pane look frosted; they are unchanged. The base gradient's alpha is lifted ~8%
     to absorb the backdrop detail the blur used to soften. */
  border: 1px solid rgba(255,255,255,0.72);
  border-radius: 32px;
  box-shadow: 0 44px 100px rgba(4, 11, 30, 0.52), 0 14px 34px rgba(4, 11, 30, 0.30), 0 0 0 1px rgba(255,255,255,0.10), inset 0 1px 0 rgba(255,255,255,0.9);
}
#step-1-landing .landing-header {
  text-align: center;
}
#step-1-landing .logo-icon.large {
  width: 46px;
  height: 46px;
  font-size: 1.4rem;
  margin: 0 auto 2px;
}
#step-1-landing .landing-header h1 {
  font-size: 1.8rem;
  margin: 2px 0;
}
/* The .landing-subtitle / .landing-explainer overrides that used to sit here are gone with
   the paragraphs themselves. This is the compact-hero variant, so it tightens the wrapper
   margin the header now carries instead. */
#step-1-landing .landing-header {
  margin-bottom: 18px;
}
#step-1-landing .picture-bag-grid {
  gap: 20px;
  margin-top: 6px;
}
#step-1-landing .picture-bag-card {
  border-width: 1px;
  min-height: 250px;
  box-shadow: 0 10px 25px rgba(0,0,0,0.3);
}
#step-1-landing .bag-card-img-wrap {
  height: 125px;
}
#step-1-landing .bag-card-img-wrap i {
  font-size: 3.2rem !important;
}
#step-1-landing .bag-hero-img {
  width: 60px;
  height: 60px;
}
/* TYPE SCALE — storefront/landing only.
   The whole storefront measured 15-20% under a normal reading size (audited with a
   TreeWalker over every visible text node: badge 10.4px, spec pill 12.2px, card body
   13.6px, card heading 18.4px, against a 16px browser default). Everything below is
   bumped ~13-18%, keeping the existing ratios between the levels so the hierarchy is
   unchanged — only the floor moves up.

   Every bump lives in this #step-1-landing block rather than on the base rule, because
   .bag-card-body, .bag-type-badge, .bag-specs-pill and .btn are all SHARED with the
   Command Center dashboard, which was not part of the complaint and must not resize.
   The root `html { font-size }` lever was rejected for the same reason: rem resolves
   against <html>, so it would scale the dashboard too. */
#step-1-landing .bag-type-badge {
  top: 10px;
  right: 10px;
  font-size: 0.75rem; /* was 0.65rem — measured 10.4px, the smallest text on the page */
  padding: 3px 9px;
}
#step-1-landing .bag-card-body {
  padding: 14px 18px;
}
#step-1-landing .bag-card-body h3 {
  font-size: 1.3rem; /* was 1.15rem — measured 18.4px */
  margin-bottom: 4px;
  font-weight: 800;
}
#step-1-landing .bag-card-body p {
  font-size: 0.98rem; /* was 0.85rem — measured 13.6px */
  /* line-height tightened from 1.45 as the type grew: leading is a RATIO, so holding
     1.45 while the font grows 15% would add proportionally more space between the lines
     than inside them, and the description would gain a whole line of height in a card
     with a fixed min-height. 1.4 keeps the rendered block near its previous depth. */
  line-height: 1.4;
  margin-bottom: 8px;
}
#step-1-landing .bag-specs-pill {
  margin-top: 6px;
  padding: 5px 9px;
  font-size: 0.86rem; /* was 0.76rem — measured 12.2px; carries "$209.96 | 1.4 lbs | 265W" */
}
#step-1-landing .btn {
  padding: 9px 16px;
  font-size: 0.92rem; /* was 0.8rem — measured 12.8px. Scoped here on purpose: the GLOBAL
                         .btn rule computes to the same 12.8px on 53 dashboard nodes. */
}

/* Slide-out Right Panel for Corporate Location Creation */
.slide-out-drawer-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.7);
  z-index: 100000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

/* blur gated to .active — see .drawer-overlay for why. */
.slide-out-drawer-overlay.active {
  opacity: 1;
  pointer-events: auto;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.slide-out-drawer {
  position: absolute;
  top: 0;
  right: 0;
  width: 440px;
  max-width: 92vw;
  height: 100vh;
  background: #0f172a;
  border-left: 1px solid var(--border-accent);
  box-shadow: -15px 0 50px rgba(0, 0, 0, 0.7);
  padding: 24px;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
  overflow-y: auto;
}

.slide-out-drawer-overlay.active .slide-out-drawer {
  transform: translateX(0);
}

.drawer-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border-color);
  background: rgba(18,42,78,0.03);
  margin-bottom: 20px;
}

.drawer-header h3 {
  font-size: 1.1rem;
  margin: 0;
}

.drawer-close {
  background: rgba(18,42,78,0.06);
  border: 1px solid var(--border-color);
  border-radius: 50%;
  width: 32px;
  height: 32px;
  color: var(--text-muted);
  font-size: 1.1rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
}

.drawer-close:hover {
  color: #fff;
  background: rgba(239, 68, 68, 0.2);
  border-color: var(--accent-red);
}

/* Dashed Device Story Slot Cards */
.device-dashed-slot {
  border: 2px dashed rgba(6, 182, 212, 0.35);
  background: rgba(6, 182, 212, 0.02);
  border-radius: var(--radius-md);
  padding: 14px 10px;
  text-align: center;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 85px;
}

.device-dashed-slot:hover {
  border-color: var(--accent-cyan);
  background: rgba(6, 182, 212, 0.08);
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(6, 182, 212, 0.15);
}

.device-filled-slot {
  border: 1px solid rgba(16, 185, 129, 0.4);
  background: rgba(16, 185, 129, 0.08);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 85px;
}

/* Softer scrollbar for dark theme */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(18,42,78,0.07); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: rgba(18,42,78,0.11); }

/* Enhanced view transition */
@keyframes slideUp {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Modal open animation */
@keyframes modalIn {
  from { opacity: 0; transform: scale(0.96) translateY(8px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
.modal-overlay.active .modal-card {
  animation: modalIn 0.25s ease-out;
}

/* Empty state styling */
.empty-state {
  text-align: center;
  padding: 64px 24px;
  color: var(--text-dim);
}
.empty-state i {
  font-size: 2.2rem;
  margin-bottom: 14px;
  display: block;
  opacity: 0.25;
}
.empty-state p:first-of-type {
  font-size: 1rem;
  font-weight: 600;
  margin: 0;
  color: var(--text-muted);
}
.empty-state p:last-of-type {
  font-size: 0.85rem;
  margin: 6px 0 0;
  opacity: 0.6;
}

/* ──── MOBILE RESPONSIVE ──── */

/* ── THE BREAKPOINT LADDER ──────────────────────────────────────────────
   Four global widths, and only four. Every layout-wide rule uses one of
   these; a component may declare its own width ONLY when its own content
   dictates the wrap point (the Kit DNA grid at 820px, the liquidity hero
   at 900px), and those are marked "component-local" where they appear.

     1024px  tablet     — three- and four-up grids fall to two
      860px  narrow     — the fulfillment queue's fixed 320px rail unstacks
      680px  phone      — everything single-column, header stacks
      400px  small      — gutters and type step down again

   Do not invent a fifth. The 640px step that used to sit between 680 and
   400 is why the three-up grids were briefly WIDER on a 600px phone than
   on a 660px one: two rules matched, the later one won, and the later one
   said two columns. One ladder, descending, no overlap.
   ────────────────────────────────────────────────────────────────────── */

/* Two components whose whole layout used to live in a style attribute, which is
   why the phone rules below needed !important to restack them: the override was
   fighting the very declaration it was trying to change. Declared here, the
   mobile block is ordinary cascade. */
.app-header-two-layer {
  display: flex; justify-content: space-between; align-items: center;
  border-bottom: 1px solid var(--border-color);
  padding-bottom: 16px; margin-bottom: 0;
}
#admin-kpi-strip { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }

/* Named layout primitives. The column count lives HERE, not in an inline
   style attribute, which is the whole point: these used to be matched with
   div[style*="repeat(3, 1fr)"], a selector that reached into every one of
   the 21 coexisting views at once and needed !important to beat the very
   inline style it was keyed off. Now the responsive steps below are plain
   cascade — no !important, and no chance of catching an unrelated div that
   happens to share a substring. */
.tb-grid2 { display: grid; grid-template-columns: 1fr 1fr; }
.tb-grid3 { display: grid; grid-template-columns: repeat(3, 1fr); }
.tb-grid4 { display: grid; grid-template-columns: repeat(4, 1fr); }
.tb-split-side { display: grid; grid-template-columns: 1fr 320px; }
.tb-xscroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Tablet: ≤1024px */
@media (max-width: 1024px) {
  .app-container { padding: 24px 28px; }
  .tb-grid3, .tb-grid4 { grid-template-columns: repeat(2, 1fr); }
}

/* Narrow: ≤860px — only the fixed-rail split needs to go early. */
@media (max-width: 860px) {
  .tb-split-side { grid-template-columns: 1fr; }
}

/* Mobile: ≤680px */
@media (max-width: 680px) {
  /* Tighten the frosted-pane gutter so content gets real width on a phone
     (was a 32px-per-side margin — far too fat at 390px). */
  .app-container { width: calc(100% - 20px); margin: 18px auto 116px; padding: 18px 14px; }
  .mapper-card { padding: 16px; }
  
  h1 { font-size: 1.5rem; }
  h2 { font-size: 1.3rem; }
  h3 { font-size: 1.1rem; }
  
  /* Stack header */
  .app-header-two-layer {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
  
  /* Every named grid primitive collapses to one column here. */
  .tb-grid2, .tb-grid3, .tb-grid4, .tb-split-side, .people-directory-grid {
    grid-template-columns: 1fr;
  }
  
  /* Modal full-width on mobile */
  .modal-card {
    max-width: 100%;
    margin: 8px;
    padding: 20px;
    border-radius: 16px;
  }
  

  
  /* Landing page */
  .landing-hero-container {
    padding: 22px 18px 26px !important;
  }
  .picture-bag-grid {
    grid-template-columns: 1fr !important;
  }
  
  /* KPI strip wrap */
  #admin-kpi-strip {
    gap: 10px;
  }
  
  /* Buttons slightly larger tap target */
  .btn { padding: 12px 20px; }
  .btn-sm { padding: 9px 14px; }
}

/* Small phone: ≤400px */
@media (max-width: 400px) {
  .app-container { width: calc(100% - 12px); padding: 14px 11px; }
  .mapper-card { padding: 13px; }
  h1 { font-size: 1.3rem; }
  .modal-card { padding: 16px; }
}

/* ============================================================
   FEATURE STYLES: Mission Control, Kit DNA, Tour, Budget
   ============================================================ */

/* Activity Feed scroll */
#activity-feed-container::-webkit-scrollbar { width: 4px; }
#activity-feed-container::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 4px; }
#activity-feed-container > div:last-child { border-bottom: none !important; }

/* Budget planner range slider */
#budget-slider { height: 6px; border-radius: 4px; }
#budget-slider::-webkit-slider-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent-cyan); cursor: pointer; border: 2px solid var(--bg-card);
  box-shadow: 0 2px 8px rgba(34, 211, 238, 0.3);
}

/* Kit DNA canvas glow */
#kit-dna-canvas { box-shadow: 0 0 60px rgba(34, 211, 238, 0.08); }

/* (A second dead .dashboard-nav-tile hover block lived here — same story as the one
   above: overridden wholesale by the DASHBOARD STORY TILES block later in this file.
   Three rules for one hover state is how the `transition: all` version stayed alive
   unnoticed. There is now exactly one.) */

/* Responsive: stack insights on mobile */
@media (max-width: 680px) {
  #view-mission-control .mapper-card { padding: 16px; }
}

/* =====================================================================
   Responsive & touch optimization (desktop · iPad · iPhone · touch)
   Added for cross-device deployment. Fixes off-canvas horizontal
   overflow, iOS input-zoom, hover-only affordances, and fixed grids.
   ===================================================================== */
html, body { overflow-x: hidden; }
* { -webkit-tap-highlight-color: rgba(0,0,0,0); }

/* iOS Safari zooms the page when a focused input is < 16px — prevent it. */
@media (pointer: coarse) {
  input, select, textarea { font-size: 16px !important; }
}

/* Touch devices: reveal hover-only affordances and enlarge key tap targets. */
@media (hover: none), (pointer: coarse) {
  .bag-card-hover-link-btn { opacity: 1 !important; }
  .tab-btn { min-height: 42px; }
  .dashboard-nav-tile { min-height: 44px; }
}

/* Momentum scrolling for the one hand-rolled scroller that predates .tb-xscroll. */
.leaderboard-multi-column-grid { -webkit-overflow-scrolling: touch; }

/* (The 860 / 640 / 400 attribute-selector reflow block that lived here is gone.
   It was a second, contradictory copy of the ladder above: its 640px step set
   the three-up grids back to TWO columns after the 680px step had already put
   them at one, so a 600px phone got a wider layout than a 660px one. The 860px
   step it also carried — the fulfillment rail — is preserved verbatim up in the
   ladder. Its "tour banner" 640px block was empty. If a fifth width ever looks
   necessary, it is almost certainly this bug coming back.) */
/* Top view tabs: let them scroll horizontally rather than clip on small screens. */
.view-selector.main-top-tabs, .main-top-tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap; }
.view-selector.main-top-tabs::-webkit-scrollbar { height: 0; }

/* ==========================================================================
   TWO-TIER THEME
   • DASHBOARD  = "meet in the middle": dark cards lifted toward the light on a
     slightly deeper canvas, with gradient bridging accents (top hairlines,
     gradient active tabs). Text stays light for dense admin legibility.
   • STOREFRONT = full light concept: bright light-grey cards floating on a
     DARKER gradient canvas, dark card text, gradient bridging.
   The theme tokens now live in the single :root at the top of this file.
   ========================================================================== */

/* Bright cards float on the light geometric canvas — soft blue-shadow lift. */
.mapper-card,
.sim-panel {
  background: var(--bg-card) !important;
  border: 1px solid var(--border-color);
  box-shadow: var(--shadow-card);
}

/* DASHBOARD STORY TILES — distinct, engaging nav cards.
   Each tile carries its own accent via inline `--tile-accent`; the accent drives a
   left rail, the icon chip glow and the hover lift so the tiles read as a set of
   individual destinations instead of one grey grid. */
.dashboard-nav-tile {
  position: relative;
  background:
    radial-gradient(circle at 100% 0%, color-mix(in srgb, var(--tile-accent, #0a7ea4) 13%, transparent), transparent 46%),
    linear-gradient(180deg, #ffffff, color-mix(in srgb, var(--tile-accent, #0a7ea4) 4%, #ffffff));
  /* These four used to be inline on all twelve tiles in index.html, which is why
     the three above once needed !important to beat them. The inline styles are
     gone; only --tile-accent stays inline, because that is the one value that
     differs per tile and it is what gives Fulfillment its true red. */
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 24px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: transform 0.16s ease, box-shadow 0.16s ease, border-color 0.16s ease;
}
/* Gradient left rail */
.dashboard-nav-tile::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0; width: 5px;
  background: linear-gradient(180deg, var(--tile-accent, var(--accent-cyan)), color-mix(in srgb, var(--tile-accent, #0a7ea4) 35%, transparent));
}
/* Large faint thematic watermark glyph (added per tile in JS) */
.dashboard-nav-tile .tile-watermark {
  position: absolute; right: -12px; bottom: -18px;
  font-size: 5.5rem; line-height: 1;
  color: var(--tile-accent, var(--accent-cyan));
  opacity: 0.09; pointer-events: none;
  transform: rotate(-8deg);
  transition: transform 0.25s ease, opacity 0.25s ease;
}
.dashboard-nav-tile:hover .tile-watermark, .dashboard-nav-tile:focus-visible .tile-watermark {
  opacity: 0.16; transform: rotate(-8deg) scale(1.08);
}
/* Hover arrow */
.dashboard-nav-tile::after {
  content: '\f061'; /* fa arrow-right */
  font-family: 'Font Awesome 6 Free'; font-weight: 900;
  position: absolute; right: 16px; top: 18px;
  font-size: 0.72rem; color: var(--tile-accent, var(--accent-cyan));
  opacity: 0; transform: translateX(-4px);
  transition: opacity 0.16s ease, transform 0.16s ease;
  z-index: 1;
}
.dashboard-nav-tile:hover, .dashboard-nav-tile:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 20px 40px color-mix(in srgb, var(--tile-accent, #0a7ea4) 22%, rgba(20,40,80,0.14));
  border-color: var(--tile-accent, var(--accent-cyan)) !important;
  outline: none;
}
.dashboard-nav-tile:hover::after, .dashboard-nav-tile:focus-visible::after {
  opacity: 0.85; transform: translateX(0);
}
/* Tile head row + icon chip.
   These used to be addressed as `.dashboard-nav-tile > div:first-child >
   div:first-child`, which meant inserting any element at the top of a tile —
   a badge, a pin, a skeleton — silently restyled the wrong node. They are
   .tile-head / .tile-ico now. The !important flags are gone with the inline
   width/height/background they existed to outrank. */
.dashboard-nav-tile .tile-head {
  display: flex; align-items: center; gap: 12px; margin-bottom: 12px;
}
.dashboard-nav-tile .tile-ico {
  position: relative; z-index: 1;
  width: 42px; height: 42px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(140deg, color-mix(in srgb, var(--tile-accent, #0a7ea4) 78%, #ffffff), var(--tile-accent, #0a7ea4));
  box-shadow: 0 6px 16px color-mix(in srgb, var(--tile-accent, #0a7ea4) 40%, transparent);
}
.dashboard-nav-tile .tile-ico i {
  color: #ffffff; font-size: 1rem;
}
/* ---- Tile metric line (injected by tilestats.js) ------------------------
   Bottom-anchored so every tile in a row shares one baseline for its number —
   that shared baseline is what turns twelve cards into a readable dashboard
   instead of twelve independent posters. margin-top:auto rather than a fixed
   gap, because the descriptions wrap to different line counts.
   The tile is made a flex column here (it was block) purely so `auto` has
   something to push against; the existing children stack identically. */
.dashboard-nav-tile .tile-metric {
  position: relative; z-index: 1;
  margin-top: auto; padding-top: 14px;
  display: flex; align-items: baseline; gap: 8px;
  /* A hairline rule, not a full border: it separates the figure from the prose
     without drawing a second box inside the box. */
  border-top: 1px solid color-mix(in srgb, var(--tile-accent, #0a7ea4) 18%, transparent);
}
.dashboard-nav-tile .tm-v {
  font-size: 1.85rem; font-weight: 800; line-height: 1;
  letter-spacing: -0.02em;
  color: var(--tile-accent, var(--accent-cyan));
  font-variant-numeric: tabular-nums;
}
.dashboard-nav-tile .tm-l {
  font-size: 0.66rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: 1.4px;
  color: var(--text-dim);
}

/* ---- Quick Access favorites (star to pin story tiles) ------------------- */
/* Star toggle lives in the top-right of each Insights / Command Center+ tile.
   Faintly visible by default (discoverable on touch, where hover doesn't fire),
   full-strength gold when pinned or on hover/focus. */
.tile-star {
  position: absolute; top: 11px; right: 11px; z-index: 2;
  width: 30px; height: 30px; border-radius: 9px;
  border: 1px solid var(--border-color);
  background: var(--bg-card);
  color: #b6c0cd;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.74rem; cursor: pointer; padding: 0;
  opacity: 0.42;
  transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease, border-color 0.15s ease, transform 0.12s ease;
}
.dashboard-nav-tile:hover .tile-star,
.tile-star:hover, .tile-star:focus-visible, .tile-star.on { opacity: 1; }
.tile-star:hover { color: #d8a13a; border-color: rgba(216,161,58,0.5); transform: scale(1.06); }
.tile-star:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; }
.tile-star.on {
  color: #d8a13a;
  background: rgba(216,161,58,0.14);
  border-color: rgba(216,161,58,0.45);
}
/* On tiles that carry a star, drop the hover arrow so the two don't collide. */
.dashboard-nav-tile.has-star::after { display: none !important; }

/* Pinned tiles live in the Manage grid (the old standalone "Quick Access" row is gone —
   two identical-looking tile grids on one screen was one too many). A pinned tile is a
   clone of an Insights / Command Center+ tile, so it already matches its neighbours;
   all it needs here is to shrug off any collapsed-subsection state inherited from its
   source. Deliberately NOT given a gold edge treatment: every tile paints a left stripe
   in its own --tile-accent, so a gold stripe overwrote the tile's colour identity and
   made a pinned Data Blog stop looking like Data Blog. The gold star already on the
   tile, plus the "N pinned" count on the Manage label, carry that signal instead. */
#manage-tile-grid .qa-tile { opacity: 1; display: block; }
/* "N pinned" hint appended to the Manage label — sentence case against the label's
   tracked-out caps so it reads as an aside, not a second heading. */
.mg-pin-hint {
  margin-left: 10px; text-transform: none; letter-spacing: 0;
  font-weight: 600; font-size: 0.72rem; color: var(--text-muted);
}
.mg-pin-hint > i { color: #d8a13a; font-size: 0.7rem; margin-right: 4px; }

/* ---- STOREFRONT LANDING: bright story cards on the geometric canvas ----- */
/* No neon canvas — the storefront shares the global light geometric background. */
/* Bright white cards with a muted teal hairline, floating with a soft blue shadow */
/* The seven !important flags this block used to carry were checked by measurement,
   not by reading: the page was rendered twice, once with them and once without, and
   every computed property matched. The selector is (1,2,0) — an id, two classes and
   a :not() — which already outranks everything it competes with. */
#step-1-landing .picture-bag-card:not(.byo-card) {
  background: var(--grad-brand) top left / 100% 3px no-repeat, #ffffff;
  border: 1px solid var(--border-color);
  color: var(--text-main);
  box-shadow: 0 12px 30px rgba(20,40,80,0.12);
}
#step-1-landing .picture-bag-card:not(.byo-card):hover {
  transform: translateY(-3px);
  box-shadow: 0 20px 42px rgba(20,40,80,0.18);
  border-color: var(--border-accent);
}
#step-1-landing .picture-bag-card:not(.byo-card) .bag-card-body h3 { color: var(--text-main); }
#step-1-landing .picture-bag-card:not(.byo-card) .bag-card-body h3 i { color: var(--accent-cyan); opacity: 1; }
#step-1-landing .picture-bag-card:not(.byo-card) .bag-card-body p,
#step-1-landing .picture-bag-card:not(.byo-card) .text-muted { color: var(--text-muted); }
#step-1-landing .picture-bag-card:not(.byo-card) .bag-card-img-wrap {
  background:
    radial-gradient(circle at 28% 22%, rgba(10,126,164,0.12), transparent 58%),
    radial-gradient(circle at 82% 90%, rgba(47,107,196,0.10), transparent 55%),
    linear-gradient(150deg, #eef3fa, #dde6f2);
  border-bottom: 1px solid #dbe3ee;
}
#step-1-landing .picture-bag-card:not(.byo-card) .bag-card-img-wrap i {
  transition: transform 0.2s ease;
}
#step-1-landing .picture-bag-card:not(.byo-card):hover .bag-card-img-wrap i {
  transform: scale(1.08);
}
#step-1-landing .picture-bag-card:not(.byo-card) .bag-type-badge {
  background: var(--grad-brand); color: #ffffff; border-color: transparent;
  box-shadow: 0 4px 12px rgba(10,126,164,0.30);
}
#step-1-landing .picture-bag-card:not(.byo-card) .bag-specs-pill {
  background: #eef2f8; border: 1px solid #dde5f0; color: #0a5a72;
}

/* Storefront-only mode (?store=1): hide every admin entry point. */
body.store-only .store-hide { display: none !important; }

/* ==========================================================================
   COLLAPSIBLE ACCORDION BARS (Insights / Platform section headers)
   Turns a small text label into an obvious, tappable expand/collapse bar.
   ========================================================================== */
.collapsible-bar {
  display: flex !important;
  align-items: center;
  gap: 10px;
  padding: 14px 18px !important;
  margin: 0 0 16px !important;
  background: rgba(18,42,78,0.04);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  cursor: pointer;
  user-select: none;
  font-size: 0.82rem !important;
  color: var(--text-main) !important;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.collapsible-bar:hover,
.collapsible-bar:focus-visible {
  background: rgba(10, 126, 164, 0.07);
  border-color: rgba(10, 126, 164, 0.4);
  outline: none;
}
.collapsible-bar.is-open {
  background: rgba(18,42,78,0.06);
}
.collapsible-bar .collapsible-hint {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}
.collapsible-bar .collapsible-hint-text {
  font-size: 0.62rem;
  color: var(--accent-cyan);
  text-transform: uppercase;
  letter-spacing: 1.2px;
  font-weight: 800;
}
.collapsible-bar .collapsible-chev {
  font-size: 0.72rem;
  color: var(--accent-cyan);
  transition: transform 0.2s ease;
}

/* Insights + Command Center+ live as a fixed pill switch at the top. Opening one
   never pushes the other bar down — the two toggle buttons stay put and their
   content appears in the panel region below. Both can be open at once. */
.dash-switch {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 18px;
}
.dash-switch-btn {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  width: 100%;
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 15px 20px;
  cursor: pointer;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--text-dim);
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.dash-switch-btn > span:first-child {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.dash-switch-btn i { font-size: 0.92rem; opacity: 0.9; }
.dash-switch-btn:hover { color: var(--text-main); border-color: var(--border-accent); }
.dash-switch-btn.open {
  background: var(--bg-card);
  color: var(--accent-cyan);
  border-color: var(--border-accent);
  box-shadow: var(--shadow-soft);
}
.dash-switch-right { display: inline-flex; align-items: center; gap: 9px; }
.dash-switch-hint {
  font-size: 0.64rem; /* ADA floor */
  letter-spacing: 1.4px;
  color: var(--text-dim);
}
.dash-switch-btn.open .dash-switch-hint { color: var(--accent-cyan); }
.dash-switch-chev { transition: transform 0.2s ease; font-size: 0.72rem; }
.dash-switch-btn.open .dash-switch-chev { transform: rotate(180deg); }

/* Panel region below the switch. One panel open → full width. Both open → two
   columns so neither pushes the other down. */
.dash-switch-panels {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  align-items: start;
}
.dash-switch-panels.both { grid-template-columns: 1fr 1fr; }
/* Each panel is a size container, so the tile grids inside reflow to the PANEL's
   width (half when both are open) instead of the viewport — no more 4-up cramming. */
.dash-switch-panels .dsp { min-width: 0; container-type: inline-size; }

/* Shared tile grid for both Insights and Command Center+ panels. Column count keys
   off the container (panel) width via @container, so a half-width panel shows fewer,
   roomier columns and a full-width panel spreads out. */
.dash-tile-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}
@container (min-width: 780px) {
  .dash-tile-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@container (min-width: 1080px) {
  .dash-tile-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; }
}
@container (max-width: 430px) {
  .dash-tile-grid { grid-template-columns: 1fr; }
}
/* On smaller laptops, keep the switch buttons side by side but stack open panels
   so tiles never get cramped into narrow columns. */
@media (max-width: 1100px) {
  .dash-switch-panels.both { grid-template-columns: 1fr; }
}
@media (max-width: 620px) {
  .dash-switch { grid-template-columns: 1fr; gap: 8px; }
}

/* ---- Storefront section switcher (Available kits / Kit Genome / poll) --------
   A segmented control, not a second row of category pills. It sits one level above
   #landing-category-filter in the hierarchy — it swaps whole panels, where the filter
   narrows the grid inside one — so it gets a solid inset track to read as a container
   of choices rather than a loose row of tags. Only one panel is mounted at a time, so
   the kits stay at the top of the fold and the Genome/poll don't push them down.
   sfSwitchSync() (app.js) hides the whole bar when fewer than 2 pills have content. */
.sf-switch {
  display: inline-flex; flex-wrap: wrap; gap: 2px; justify-content: center;
  margin: 0 auto 20px; padding: 4px;
  background: rgba(18,42,78,0.055); border: 1px solid rgba(18,42,78,0.07);
  border-radius: var(--radius-pill);
  /* Inset only. An OUTER shadow here would sit directly under the active pill's own
     shadow and read as two stacked drop shadows on one control — the track is a recessed
     groove, so it gets a groove's lighting, not a lift. */
  box-shadow: inset 0 1px 2px rgba(18,42,78,0.07);
}
/* The bar is inline-flex so the track hugs its pills; this centers it in the column. */
#sf-switch { display: flex; width: max-content; max-width: 100%; }
.sf-pill {
  /* 0.92rem, up from 0.82rem (measured 13.1px). Safe to bump on the base rule rather
     than a scoped override because .sf-pill exists only on the storefront switcher —
     it has no dashboard instances, unlike .btn and .bag-card-body. */
  font: inherit; font-size: var(--fs-xs); font-weight: 700; color: var(--text-muted);
  letter-spacing: -0.005em;
  background: transparent; border: 1px solid transparent;
  border-radius: var(--radius-pill); padding: 9px 18px; cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 8px;
  transition: color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
/* The icon tracks the label: it was 0.78rem against a 0.82rem label (~0.95x), so it
   moves to 0.88rem against the new 0.92rem to hold the same relationship. Left behind,
   the icon would look shrunken next to its own text. */
.sf-pill i { font-size: 0.88rem; opacity: 0.8; }
.sf-pill:hover { color: var(--text-main); background: rgba(255,255,255,0.55); }
.sf-pill:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; }
/* Active = a white THUMB riding in the groove, not a brand-gradient chip.
   Two reasons it is white rather than var(--grad-brand):
   1. Contrast. The gradient runs #0a7ea4 → #2f6bc4 — both dark — and this rule used to
      paint #04121a (near-black) on top of it, which failed contrast badly. White thumb +
      --text-main label is ~13:1 and needs no per-stop tuning of the gradient.
   2. Hierarchy. #landing-category-filter below is ALSO a row of pills and DOES use the
      brand gradient for its active chip. When both rows painted the same gradient chip
      they read as one repeated control. The switcher swaps whole panels; the filter
      narrows the grid inside one. Different jobs now look different.
   Weight and padding are deliberately identical to the inactive state — this is a
   background/colour repaint only, so pills never change width and the row never jitters
   as the selection moves. */
.sf-pill.active {
  color: var(--text-main); background: #ffffff; border-color: rgba(18,42,78,0.06);
  /* One shadow, and a tight one: the thumb lifts just off the groove floor. It stays
     inside the track, so there is no second halo bleeding past the track's own edge. */
  box-shadow: 0 1px 3px rgba(18,42,78,0.18);
}
.sf-pill.active i { opacity: 1; color: var(--accent-cyan); }
.sf-pill[hidden] { display: none; }
/* [hidden] alone loses to the display rule below, so it is repeated with the panel. */
.sf-panel { display: none; }
.sf-panel.active { display: block; }
.sf-panel[hidden] { display: none; }
/* This override has to move WITH the base rule, or it silently cancels the whole bump
   below 620px — which is most phones, i.e. the case where small type is worst. Scaled
   by the same factor as the base (0.82→0.92 is 1.12x, so 0.74→0.84).

   The icons come off here rather than at some narrower phone-only breakpoint, because
   with the icon font actually LOADED the three pills want ~422px and the track offers
   ~424px at 620 — a two-pixel margin, which is not a margin. Any device whose font
   metrics round differently drops the switcher onto two lines. Below 620 there is no
   width to spend on decoration: the labels say "Available kits", "Kit Genome" and
   "Shape what's next", which need no icon to be understood. Measured against a
   simulated 1em glyph box, not against this sandbox, where the blocked icon font
   renders zero-width and hides the entire problem. */
@media (max-width: 620px) {
  .sf-switch { gap: 3px; padding: 3px; }
  .sf-pill { font-size: 0.84rem; padding: 7px 12px; gap: 0; }
  .sf-pill i { display: none; }
}
/* Very narrow phones. The wrap allowance below is the safety net, but the goal is to
   NOT need it: a switcher that breaks onto two lines stops reading as one control.
   Measured at 390px (iPhone 14/15 width) the three pills wanted 368px of a 352px track
   once the type went up, so the space is bought back here rather than by shrinking the
   labels again — the labels being too small is the entire problem this change fixes.
   Dropping the icons is the right trade at this width: they are decorative, the three
   labels are self-describing, and they are the only element on the pill that costs
   width without carrying meaning. (They are already gone by this point — the 620px
   block above drops them — so what is left to give back here is padding and a little
   type.) 0.8rem is still comfortably above the 0.74rem this rule set before the bump,
   so even the narrowest phone ends up with larger text than it had, which is the
   request; it just gives back some of the gain to keep the control on one line.
   Below ~360px the labels genuinely do not fit and the track wraps — that is the
   intended fallback, and it beats a horizontal scrollbar across the hero. */
@media (max-width: 400px) {
  #sf-switch { width: 100%; justify-content: center; }
  .sf-pill { font-size: 0.8rem; padding: 7px 8px; }
}

/* Storefront category filter bar (auto-appears when there are 2+ kit categories) */
#landing-category-filter {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 0 0 18px;
}
.cat-filter-pill {
  /* 0.88rem, up from 0.78rem (measured 12.5px). Storefront-only selector, so like
     .sf-pill this is bumped at the base rule with no dashboard fallout. */
  font: inherit; font-size: var(--fs-xs); font-weight: 700; color: var(--text-muted);
  background: rgba(18,42,78,0.05); border: 1px solid var(--border-color);
  border-radius: var(--radius-pill); padding: 8px 16px; cursor: pointer; transition: 0.15s;
}
/* Border was rgba(34,189,214,0.4) — the pre-rebrand neon cyan, which survives in a few
   places and matches nothing in the current palette. Retinted to --accent-cyan (#0a7ea4),
   the same colour the active state's gradient starts on. */
.cat-filter-pill:hover { color: var(--text-main); border-color: rgba(10,126,164,0.45); }
/* White label, not #04121a. --grad-brand is #0a7ea4 → #2f6bc4 — two dark blues — so the
   near-black text this used to carry was dark-on-dark and effectively unreadable. The old
   glow was also keyed to the pre-rebrand neon cyan (34,189,214), which no longer matches
   either end of the gradient; it is now tinted to the gradient itself. */
.cat-filter-pill.active {
  color: #ffffff; background: var(--grad-brand); border-color: transparent;
  box-shadow: 0 3px 10px rgba(16,80,140,0.26);
}

/* Floating "Back" button — obvious return to the Command Center from any sub-view.
   Hidden by default; JS shows it (inline-flex) when a sub-view is open.

   This was a 40px dark-glass circle whose "Back" label only faded in on :hover. Two
   problems with that: the dark fill read as background geometry rather than a control
   on a light page, and there is no hover on touch, so on a phone it was a permanently
   unlabelled dark dot. It is now a light pill that always shows its label.

   CONSTANT SIZE still holds — it just holds for a different reason. The old build kept
   the hit target fixed by floating the label outside the button; this one keeps it fixed
   by never changing size at all (the label is always laid out, and :hover only repaints
   colour/shadow plus a transform nudge). Either way the pointer never lands on an edge
   that moves out from under it, which is what caused the old hover-resize flicker loop.
   Do not reintroduce a width/padding change on :hover. */
#dashboard-back-btn {
  position: fixed; left: 18px; top: 50%; transform: translateY(-50%); z-index: 60;
  display: none; align-items: center; justify-content: center; gap: 8px;
  height: 40px; padding: 0 17px 0 15px;
  background: rgba(255,255,255,0.94); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  color: var(--text-main);
  font: inherit; font-size: 0.78rem; font-weight: 800; letter-spacing: 0.2px;
  border: 1px solid rgba(10,126,164,0.42); border-radius: var(--radius-pill);
  /* Three layers on purpose: a wide ambient shadow to lift it off the page, a tight
     contact shadow so the edge stays crisp, and a cyan halo so the eye finds it. */
  box-shadow: 0 10px 30px rgba(20,40,80,0.22), 0 2px 6px rgba(20,40,80,0.12), 0 0 0 4px rgba(10,126,164,0.11);
  cursor: pointer; white-space: nowrap;
  transition: background 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
#dashboard-back-btn i { font-size: 0.8rem; flex-shrink: 0; color: var(--accent-cyan); }
#dashboard-back-btn span { font-size: 0.76rem; font-weight: 800; }
#dashboard-back-btn:hover, #dashboard-back-btn:focus-visible {
  background: #fff; border-color: var(--accent-cyan); outline: none;
  transform: translateY(-50%) translateX(2px);
  box-shadow: 0 14px 36px rgba(20,40,80,0.28), 0 2px 6px rgba(20,40,80,0.14), 0 0 0 5px rgba(10,126,164,0.18);
}
#dashboard-back-btn:active { transform: translateY(-50%) translateX(0); }
@media (max-width: 680px) {
  /* Sits above the floating dock at bottom:20px, so it clears it rather than stacking on it. */
  #dashboard-back-btn { top: auto; bottom: 78px; left: 12px; transform: none; height: 38px; padding: 0 15px 0 13px; }
  #dashboard-back-btn:hover, #dashboard-back-btn:focus-visible,
  #dashboard-back-btn:active { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  #dashboard-back-btn, #dashboard-back-btn:hover, #dashboard-back-btn:focus-visible { transition: none; }
}

/* ================= PERSISTENT GLOBAL FOOTER (all pages) ================= */
#global-footer-bar {
  position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%);
  z-index: 70;
  display: flex; align-items: center; gap: 4px;
  padding: 7px 10px 7px 14px;
  /* Apple "liquid glass" — dark translucent, heavily blurred, bright rim, floats on
     the morph canvas with a real drop shadow (readable over dark canvas or the pane). */
  background: linear-gradient(180deg, rgba(32,43,66,0.64), rgba(20,28,45,0.54));
  backdrop-filter: blur(26px) saturate(1.7); -webkit-backdrop-filter: blur(26px) saturate(1.7);
  border: 1px solid rgba(255,255,255,0.22);
  border-radius: var(--radius-pill);
  box-shadow: 0 20px 50px rgba(0,0,0,0.52), inset 0 1px 0 rgba(255,255,255,0.28), inset 0 -1px 0 rgba(0,0,0,0.2);
}
#global-footer-bar .gfb-link {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 14px;
  background: transparent; border: none; border-radius: var(--radius-pill);
  color: rgba(255,255,255,0.82); font: inherit; font-size: 0.8rem; font-weight: 600;
  cursor: pointer; transition: color 0.15s ease, background 0.15s ease;
}
#global-footer-bar .gfb-link i { font-size: 0.82rem; }
#global-footer-bar .gfb-link:hover, #global-footer-bar .gfb-link:focus-visible {
  color: #fff; background: rgba(255,255,255,0.16); outline: none;
}
#global-footer-bar .gfb-sep { color: rgba(255,255,255,0.32); font-size: 0.8rem; }
/* Green demo on/off pill — an extra segment on the right of the footer. */
#global-footer-bar .gfb-demo {
  display: inline-flex; align-items: center; gap: 7px;
  margin-left: 6px; padding: 6px 14px;
  border-radius: var(--radius-pill); border: 1px solid rgba(255,255,255,0.2);
  background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.7);
  font: inherit; font-size: 0.78rem; font-weight: 700; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
#global-footer-bar .gfb-demo i { font-size: 0.8rem; }
#global-footer-bar .gfb-demo:hover, #global-footer-bar .gfb-demo:focus-visible { background: rgba(255,255,255,0.13); color: #fff; outline: none; }
#global-footer-bar .gfb-demo.demo-on {
  background: var(--accent-green); border-color: var(--accent-green); color: #05231a;
  box-shadow: 0 4px 14px rgba(15,154,114,0.5);
}
/* Off = muted grey dot; on = solid, matching the button text colour */
#global-footer-bar .gfb-demo .gfb-demo-dot {
  width: 7px; height: 7px; border-radius: 50%; background: rgba(255,255,255,0.4); opacity: 1;
}
#global-footer-bar .gfb-demo.demo-on .gfb-demo-dot { background: currentColor; }
@media (max-width: 680px) {
  #global-footer-bar .gfb-demo span { display: none; }
}
@media (max-width: 680px) {
  #global-footer-bar { gap: 0; padding: 6px 8px; bottom: 12px; }
  #global-footer-bar .gfb-link { padding: 6px 10px; font-size: 0.74rem; }
  #global-footer-bar .gfb-link span { display: none; }
  #global-footer-bar .gfb-link i { font-size: 0.95rem; }
  #global-footer-bar .gfb-sep { display: none; }
}

/* (The story block now ends above the footer via its bottom margin, so no extra
   footer-clearance padding is needed inside the block.) */

/* ==========================================================================
   LARGE-SCREEN SCALING (wide 27"–32"+ / 4K monitors)
   The kit preview modal and slot builder were capped narrow and looked tiny on
   big displays — scale the containers, grids and key controls up in two steps.
   ========================================================================== */
@media (min-width: 1700px) {
  body.dark-theme { font-size: 15.5px; }
  .app-container { max-width: 1560px; }
  #step-1-landing .landing-hero-container { max-width: 1300px; }
  .picture-bag-grid { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 28px; }
  /* Kit preview modal */
  #modal-bag-preview .modal-card { max-width: 840px !important; }
  #modal-bag-preview #bag-preview-items { gap: 14px; }
  /* Slot builder */
  #step-2-add-items .step-container { max-width: 1200px !important; }
  .slots-grid-container { gap: 26px; }
  .slot-card-dashed { padding: 26px; min-height: 168px; }
  .slot-icon-badge { width: 44px; height: 44px; font-size: 1.3rem; }
}
@media (min-width: 2200px) {
  body.dark-theme { font-size: 16.5px; }
  .app-container { max-width: 1820px; }
  #step-1-landing .landing-hero-container { max-width: 1540px; }
  .picture-bag-grid { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 34px; }
  #step-1-landing .picture-bag-card { min-height: 300px; }
  #step-1-landing .bag-card-img-wrap { height: 160px; }
  /* Kit preview modal */
  #modal-bag-preview .modal-card { max-width: 1020px !important; }
  #modal-bag-preview #bag-preview-title { font-size: 1.45rem; }
  #modal-bag-preview #bag-preview-items { gap: 16px; }
  /* Slot builder */
  #step-2-add-items .step-container { max-width: 1460px !important; }
  .slots-grid-container { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 32px; }
  .slot-card-dashed { padding: 32px; min-height: 190px; }
  .slot-icon-badge { width: 50px; height: 50px; font-size: 1.5rem; }
  /* Dashboard tiles a touch larger */
  .dashboard-nav-tile { padding: 30px; }
}

/* ================= FULFILLMENT QUEUE + PICK LIST (current ethos) ================= */
.fq-order { position:relative; display:flex; justify-content:space-between; align-items:center; gap:12px;
  background:var(--bg-card); border:1px solid var(--border-color); border-left:4px solid var(--fq-accent,var(--accent-cyan));
  border-radius:var(--radius-md); padding:13px 16px; margin-bottom:10px; cursor:pointer;
  transition:transform .14s ease, box-shadow .14s ease, border-color .14s ease; }
.fq-order:hover { transform:translateY(-2px); box-shadow:0 12px 26px rgba(20,40,80,0.12); border-color:var(--fq-accent,var(--accent-cyan)); }
.fq-order-title { font-weight:800; color:var(--text-main); font-size:0.92rem; }
.fq-order-sub { font-size:0.78rem; color:var(--text-muted); margin-top:3px; }
.fq-order-sub strong { color:var(--text-main); }
.fq-order-side { display:flex; align-items:center; gap:10px; flex-shrink:0; }
.fq-status { font-size:0.66rem; font-weight:800; display:inline-flex; align-items:center; gap:5px; }
.fq-priority { font-size:0.58rem; font-weight:800; text-transform:uppercase; letter-spacing:0.5px; padding:3px 8px; border-radius:6px; }
.fq-chev { color:var(--text-dim); font-size:0.72rem; }
.pick-row { display:flex; align-items:center; gap:11px; padding:9px 12px; background:var(--bg-card); border:1px solid var(--border-color);
  border-radius:var(--radius-md); margin-bottom:8px; cursor:pointer; transition:border-color .14s ease, background .14s ease; }
.pick-row:hover { border-color:var(--accent-cyan); }
.pick-row.picked { background:rgba(15,154,114,0.06); border-color:rgba(15,154,114,0.28); }
.pick-check { width:20px; height:20px; border-radius:6px; border:1.5px solid var(--border-color); display:flex; align-items:center; justify-content:center; flex-shrink:0; color:transparent; }
.pick-row.picked .pick-check { background:var(--accent-green); border-color:var(--accent-green); color:#fff; }
.pick-name { flex:1; min-width:0; font-weight:700; color:var(--text-main); font-size:0.82rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pick-row.picked .pick-name { color:var(--accent-green); text-decoration:line-through; }
.pick-cat { font-size:0.64rem; color:var(--text-dim); text-transform:uppercase; letter-spacing:0.5px; font-weight:600; }
.pick-count { font-size:0.72rem; font-weight:800; color:var(--accent-amber); background:rgba(189,125,19,0.12); padding:2px 9px; border-radius:6px; flex-shrink:0; }
.pick-row.picked .pick-count { color:var(--accent-green); background:rgba(15,154,114,0.14); }

/* ================= LOCATIONS — country / state hierarchy ================= */
.loc-country { margin-bottom: 28px; }
.loc-country-head { display:flex; justify-content:space-between; align-items:center; gap:12px; padding:8px 0 12px; border-bottom:2px solid var(--border-color); margin-bottom:16px; flex-wrap:wrap; }
.loc-country-title { font-size:1.05rem; font-weight:800; color:var(--text-main); display:flex; align-items:center; gap:9px; }
.loc-country-title i { color:var(--accent-cyan); }
.loc-country-meta { font-size:0.78rem; color:var(--text-muted); }
.loc-country-meta b { color:var(--text-main); font-family:'JetBrains Mono',monospace; }
/* One tiling grid per country (matches People) — cards tile instead of each taking a full row. */
.loc-cards, .loc-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:18px; }
.loc-card { background:var(--bg-card); border:1px solid var(--border-color); border-left:4px solid var(--accent-cyan); border-radius:var(--radius-md); padding:16px 18px; transition:transform .14s ease, box-shadow .14s ease; }
.loc-region-chip { display:inline-flex; align-items:center; gap:5px; margin:9px 0 2px; padding:2px 9px; border-radius:var(--radius-pill); background:rgba(10,126,164,0.1); color:var(--accent-cyan); font-size:0.62rem; font-weight:800; letter-spacing:0.6px; text-transform:uppercase; }
.loc-region-chip i { font-size:0.58rem; }

/* ===== Mission Control — live ops center ===== */
#mc-ops { margin-bottom: 22px; }
.mc-topline { display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-bottom:16px; }
.mc-live { display:inline-flex; align-items:center; gap:8px; font-size:0.66rem; font-weight:800; letter-spacing:1.8px; color:var(--accent-red); background:rgba(216,58,58,0.08); border:1px solid rgba(216,58,58,0.28); border-radius:var(--radius-pill); padding:5px 13px; }
.mc-live-dot { width:7px; height:7px; border-radius:50%; background:var(--accent-red); animation:mcPulseR 1.8s ease-out infinite; }
@keyframes mcPulseR { 0%{box-shadow:0 0 0 0 rgba(216,58,58,0.5);} 70%{box-shadow:0 0 0 7px rgba(216,58,58,0);} 100%{box-shadow:0 0 0 0 rgba(216,58,58,0);} }
.mc-status { display:inline-flex; align-items:center; gap:14px; flex-wrap:wrap; font-size:0.74rem; }
.mc-svc { display:inline-flex; align-items:center; gap:6px; font-weight:700; color:var(--text-main); }
.mc-pulse { width:7px; height:7px; border-radius:50%; background:var(--accent-green); animation:mcPulseG 2.2s ease-out infinite; }
@keyframes mcPulseG { 0%{box-shadow:0 0 0 0 rgba(15,154,114,0.45);} 70%{box-shadow:0 0 0 6px rgba(15,154,114,0);} 100%{box-shadow:0 0 0 0 rgba(15,154,114,0);} }
.mc-status-txt { color:var(--accent-green); font-weight:800; }
.mc-stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(152px,1fr)); gap:12px; }

/* (2) GROUP CAPTION. The six tiles are two different kinds of number: three
   stages of one request pipeline, then two standing counts of what exists.
   Rendered as one undifferentiated row they invited the reading that "0
   shipped" (a pipeline that has not moved) and "0 people" (a directory that
   is empty) mean the same kind of nothing. They do not. */
.mc-stat-grp { display:flex; align-items:center; gap:10px; font-size:0.6rem; text-transform:uppercase; letter-spacing:1.1px; font-weight:800; color:var(--text-dim); margin:0 0 9px; }
.mc-stat-grp::after { content:''; flex:1; height:1px; background:var(--border-color); }

/* The two groups sit SIDE BY SIDE at desk widths. Stacked, three tiles had a
   full 1400px row to share and each one stretched to ~450px of mostly empty
   card — the grouping was legible but the density was worse than the
   undifferentiated six-up it replaced. Paired, the tiles keep their old size
   and the captions still separate the two kinds of number. */
.mc-groups { display:grid; grid-template-columns:1fr 1fr; gap:14px 26px; }
@media (max-width: 1024px) { .mc-groups { grid-template-columns:1fr; } }

/* min-height, because the two groups are two INDEPENDENT grids and their rows
   therefore do not align to each other. "Awaiting approval" wraps to two lines
   at tile width and "Sites live" does not, so without a floor the left group
   sits ~20px taller than the right and the pair reads as misaligned rather
   than as two groups. */
.mc-stat { position:relative; display:flex; align-items:center; gap:12px; min-height:86px; background:var(--bg-surface); border:1px solid var(--border-color); border-left:3px solid var(--c); border-radius:var(--radius-md); padding:13px 15px; }
.mc-stat-b { flex:1; min-width:0; }
.mc-stat-ic { width:34px; height:34px; border-radius:9px; background:color-mix(in srgb, var(--c) 14%, transparent); color:var(--c); display:flex; align-items:center; justify-content:center; font-size:0.85rem; flex-shrink:0; }
.mc-stat-v { font-size:1.42rem; font-weight:800; color:var(--text-main); font-family:'JetBrains Mono',ui-monospace,monospace; line-height:1; }
.mc-stat-l { font-size:0.66rem; text-transform:uppercase; letter-spacing:0.6px; color:var(--text-dim); font-weight:700; margin-top:4px; } /* ADA floor */

/* (1) SHARE-OF-GROUP BAR. Six bare integers carry no sense of proportion —
   "12 awaiting, 3 shipped" and "12 awaiting, 300 shipped" look identical at a
   glance. The fill width is the tile's value over the largest value in its own
   group, computed at render time and passed in as --pct, so this needs no
   charting library: Chart.js is a CDN dependency and Mission Control has to
   render when that CDN is unreachable. */
.mc-stat-bar { height:3px; border-radius:2px; background:color-mix(in srgb, var(--c) 13%, transparent); margin-top:9px; overflow:hidden; }
.mc-stat-bar > span { display:block; height:100%; border-radius:2px; background:var(--c); width:var(--pct,0%); transition:width .5s cubic-bezier(.2,.7,.3,1); }

/* (1b) A ZERO IS QUIET, NOT BROKEN. A fresh install showed six full-strength
   zeros in six saturated accent colours, which reads as a failed load rather
   than as an empty system. Drained of colour they read as what they are. */
.mc-stat.is-zero { border-left-color:var(--border-color); }
.mc-stat.is-zero .mc-stat-v { color:var(--text-dim); }
.mc-stat.is-zero .mc-stat-ic { background:var(--bg-card); color:var(--text-dim); }
.mc-stat.is-zero .mc-stat-bar { background:var(--border-color); }

.mc-timeline { position:relative; padding-left:32px; }
/* Rail stops short of the bottom so it meets the end cap instead of fading
   into whatever whitespace happens to be below the last event. */
.mc-timeline::before { content:''; position:absolute; left:16px; top:8px; bottom:30px; width:2px; background:linear-gradient(var(--border-color) 70%, transparent); }

/* (3) DAY DIVIDERS. Every row said "3m ago" / "2h ago" and nothing said which
   day. Sticky inside #activity-feed-container, which is the scroll container
   (max-height 600px, overflow-y auto) — sticky resolves against that, not the
   page, so the divider for the block you are reading stays pinned. */
.mc-day { position:sticky; top:0; z-index:2; margin:0 0 4px -32px; padding:8px 0 8px 32px; background:linear-gradient(var(--bg-card) 74%, transparent); font-size:0.62rem; text-transform:uppercase; letter-spacing:1.2px; font-weight:800; color:var(--text-dim); }
.mc-evt + .mc-day { margin-top:12px; }

/* --c moved up from .mc-dot to the row so the hover tint, the dot and the type
   pill all read the same one declaration. */
.mc-evt { position:relative; padding:13px 12px 13px 0; border-bottom:1px solid var(--border-color); border-radius:var(--radius-sm); transition:background-color .16s ease; }
.mc-evt:last-child { border-bottom:none; }
/* (4) ROW HOVER. Tint only — no width, padding or size change, because the
   dot is absolutely positioned against this row and a geometry change on
   hover is the flicker loop we have already fixed twice elsewhere. */
.mc-evt:hover { background:color-mix(in srgb, var(--c) 7%, transparent); }
.mc-evt:hover .mc-dot { box-shadow:0 4px 13px color-mix(in srgb, var(--c) 32%, transparent); }
.mc-dot { position:absolute; left:-32px; top:11px; width:34px; height:34px; border-radius:10px; background:color-mix(in srgb, var(--c) 15%, var(--bg-card)); color:var(--c); display:flex; align-items:center; justify-content:center; font-size:0.8rem; border:2px solid var(--bg-card); box-shadow:0 2px 6px rgba(20,40,80,0.08); transition:box-shadow .16s ease; }
.mc-evt-b { padding-left:12px; }
.mc-evt-msg { font-size:0.88rem; font-weight:600; color:var(--text-main); line-height:1.4; }
.mc-evt-meta { font-size:0.72rem; color:var(--text-dim); margin-top:3px; display:flex; align-items:center; gap:9px; }
.mc-evt-type { font-size:0.58rem; text-transform:uppercase; letter-spacing:0.5px; font-weight:800; color:var(--c); background:color-mix(in srgb, var(--c) 12%, transparent); padding:2px 8px; border-radius:var(--radius-pill); }

/* (5) END CAP. The rail used to dangle into empty space, which on a one-event
   feed made the view look like it had failed to finish loading. A hollow
   terminator says the log has an end and you have reached it. */
.mc-end { position:relative; padding:14px 0 2px 12px; font-size:0.68rem; letter-spacing:0.4px; color:var(--text-dim); }
/* -21px, not a round -24: the cap sits inside .mc-end's own 12px padding, so
   the offset that centres its 11px circle on the 2px rail at left:16px is
   32 - 21 + 11/2 = 16.5. Eyeballed values here land visibly off the rail. */
.mc-end::before { content:''; position:absolute; left:-21px; top:16px; width:11px; height:11px; border-radius:50%; border:2px solid var(--border-color); background:var(--bg-card); }

@media (prefers-reduced-motion: reduce) {
  .mc-live-dot, .mc-pulse { animation:none; }
  .mc-stat-bar > span { transition:none; }
}

/* ===== Live Provisioning Map ===== */
.lm-legend { display:flex; gap:15px; font-size:0.72rem; color:var(--text-muted); flex-wrap:wrap; }
.lm-legend span { display:inline-flex; align-items:center; gap:6px; font-weight:600; }
.lm-lg { width:10px; height:10px; border-radius:50%; display:inline-block; }
.lm-lg-flow { background:var(--on-dark-cyan-hi); width:15px; height:3px; border-radius:2px; }
.lm-stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:12px; margin-bottom:16px; }
.lm-stat { display:flex; align-items:center; gap:11px; background:var(--bg-surface); border:1px solid var(--border-color); border-left:3px solid var(--c); border-radius:var(--radius-md); padding:12px 14px; }
.lm-stat-ic { width:32px; height:32px; border-radius:9px; background:color-mix(in srgb,var(--c) 14%,transparent); color:var(--c); display:flex; align-items:center; justify-content:center; font-size:0.82rem; flex-shrink:0; }
.lm-stat-v { font-size:1.12rem; font-weight:800; color:var(--text-main); font-family:'JetBrains Mono',ui-monospace,monospace; line-height:1; }
.lm-stat-l { font-size:0.66rem; /* ADA floor */ text-transform:uppercase; letter-spacing:0.5px; color:var(--text-dim); font-weight:700; margin-top:3px; }
.lm-stage { position:relative; border-radius:16px; overflow:hidden; border:1px solid rgba(255,255,255,0.06);
  background:radial-gradient(120% 130% at 50% -10%, var(--dark-canvas-1) 0%, var(--dark-canvas-2) 55%, var(--dark-ink) 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,0.05), 0 22px 55px rgba(4,11,30,0.4); }
.lm-svg { display:block; width:100%; height:auto; }
.lm-grid line { stroke:rgba(150,185,225,0.08); stroke-width:1; }
.lm-arc { fill:none; stroke:rgba(120,195,230,0.30); stroke-width:1.2; stroke-dasharray:3 6; }
.lm-packet { fill:var(--on-dark-cyan-hi); filter:drop-shadow(0 0 4px rgba(143,216,239,0.95)); animation-name:lmPacket; animation-timing-function:linear; animation-iteration-count:infinite; }
@keyframes lmPacket { from { offset-distance:0%; } to { offset-distance:100%; } }
.lm-radar { transform-box:view-box; animation:lmRadar 9s linear infinite; }
@keyframes lmRadar { to { transform:rotate(360deg); } }
.lm-node { cursor:pointer; outline:none; }
.lm-dot { fill:var(--on-dark-cyan); stroke:var(--dark-ink); stroke-width:2; filter:drop-shadow(0 0 6px rgba(63,176,214,0.7)); transition:fill .15s; }
.lm-node:hover .lm-dot, .lm-node:focus .lm-dot, .lm-node:focus-visible .lm-dot { fill:var(--on-dark-cyan-hi); }
.lm-node:focus-visible .lm-halo { fill:url(#lmGlow); }
.lm-halo { fill:url(#lmGlow); }
.lm-pulse { fill:none; stroke:var(--on-dark-cyan); stroke-width:1.4; transform-box:fill-box; transform-origin:center; opacity:0; animation:lmPulse 3.4s ease-out infinite; }
@keyframes lmPulse { 0% { transform:scale(1); opacity:0.55; } 70% { opacity:0; } 100% { transform:scale(3); opacity:0; } }
.lm-label { fill:#cad8ec; font-size:12px; font-weight:700; text-anchor:middle; paint-order:stroke; stroke:var(--dark-ink); stroke-width:3; letter-spacing:0.2px; }
.lm-hub-dot { fill:#f5a623; stroke:var(--dark-ink); stroke-width:2; filter:drop-shadow(0 0 8px rgba(245,166,35,0.85)); }
.lm-hub-ring { fill:none; stroke:rgba(245,166,35,0.55); stroke-width:1.5; }
.lm-hub-pulse { fill:none; stroke:#f5a623; stroke-width:1.4; transform-box:fill-box; transform-origin:center; opacity:0; animation:lmPulse 3s ease-out infinite; }
.lm-hub-label { fill:#f2c785; font-size:10px; font-weight:800; letter-spacing:2px; text-anchor:middle; paint-order:stroke; stroke:var(--dark-ink); stroke-width:3; }
.lm-info { position:absolute; top:14px; right:14px; min-width:180px; max-width:244px; background:rgba(15,23,40,0.82); backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px); border:1px solid rgba(255,255,255,0.12); border-radius:12px; padding:13px 15px; color:#dce6f2; box-shadow:0 12px 30px rgba(0,0,0,0.4); }
.lm-info-h { font-size:0.95rem; font-weight:800; color:#fff; margin-bottom:6px; }
.lm-info-sub { font-size:0.72rem; color:#9fb2c9; }
.lm-info-hint { font-size:0.68rem; color:#8195ad; margin-top:7px; line-height:1.45; }
.lm-info-row { display:flex; justify-content:space-between; gap:12px; font-size:0.76rem; color:#9fb2c9; padding:3px 0; }
.lm-info-row b { color:#fff; font-family:'JetBrains Mono',ui-monospace,monospace; }
.lm-scan { position:absolute; left:0; right:0; height:2px; top:0; pointer-events:none; background:linear-gradient(90deg,transparent,rgba(100,215,255,0.35),transparent); animation:lmScan 7s ease-in-out infinite; }
@keyframes lmScan { 0%,100% { top:0; opacity:0; } 12% { opacity:1; } 55% { top:100%; opacity:0.55; } 92% { opacity:0; } }
@media (max-width:560px){ .lm-info { position:static; margin:12px; max-width:none; } }
@media (prefers-reduced-motion: reduce){ .lm-packet, .lm-radar, .lm-pulse, .lm-hub-pulse, .lm-scan { animation:none; } .lm-packet { display:none; } }
/* Live Map — network drill-down (people fanned out from a selected site) */
.lm-node.sel .lm-dot { fill:var(--on-dark-cyan-hi); filter:drop-shadow(0 0 11px rgba(143,216,239,0.95)); }
.lm-expansion { animation:lmFade .25s ease; }
@keyframes lmFade { from { opacity:0; } to { opacity:1; } }
.lm-plink { stroke:rgba(140,205,240,0.38); stroke-width:1.2; stroke-dasharray:2 4; }
.lm-pnode { cursor:pointer; outline:none; }
.lm-pdot { fill:#1c2942; stroke:#5cc7f0; stroke-width:1.6; filter:drop-shadow(0 0 5px rgba(92,199,240,0.5)); transition:fill .15s; }
.lm-pnode:hover .lm-pdot, .lm-pnode:focus-visible .lm-pdot { fill:#2a456b; }
.lm-pinit { fill:#cfe6f6; font-size:10px; font-weight:800; text-anchor:middle; }
.lm-plabel { fill:#b0c1d6; font-size:10px; font-weight:600; text-anchor:middle; paint-order:stroke; stroke:var(--dark-ink); stroke-width:2.6; }
.lm-pchip { display:inline-block; font-size:0.66rem; color:#cfe0f0; background:rgba(120,190,225,0.12); border:1px solid rgba(120,190,225,0.2); border-radius:var(--radius-pill); padding:2px 8px; margin:3px 3px 0 0; }
.lm-info-people { margin-top:9px; padding-top:8px; border-top:1px solid rgba(255,255,255,0.1); }
.lm-info-plabel { font-size:0.62rem; text-transform:uppercase; letter-spacing:0.6px; color:#8195ad; font-weight:800; margin-bottom:5px; }
@media (prefers-reduced-motion: reduce){ .lm-expansion { animation:none; } }
/* Device ring (3rd level) + site health */
.lm-dlink { stroke:rgba(140,205,240,0.28); stroke-width:1; stroke-dasharray:1.5 3; }
.lm-dnode { cursor:default; }
.lm-ddot { stroke:var(--dark-ink); stroke-width:1.4; filter:drop-shadow(0 0 4px rgba(120,220,255,0.5)); }
.lm-dlabel { fill:#8195ad; font-size:9px; text-anchor:middle; paint-order:stroke; stroke:var(--dark-ink); stroke-width:2; }
.lm-attn-ring { fill:none; stroke:#f87171; stroke-width:1.6; transform-box:fill-box; transform-origin:center; animation:lmPulse 2.4s ease-out infinite; }
.lm-node.attn .lm-label { fill:#f5c98a; }
.lm-dname { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:150px; display:inline-block; }
/* Themed/Blueprint mode switch + health legend */
.lm-modeswitch { display:inline-flex; background:var(--bg-surface); border:1px solid var(--border-color); border-radius:var(--radius-pill); padding:2px; margin-right:4px; }
.lm-mode { border:none; background:none; font:inherit; font-size:0.66rem; /* ADA floor */ font-weight:800; letter-spacing:0.5px; text-transform:uppercase; color:var(--text-dim); padding:5px 12px; border-radius:var(--radius-pill); cursor:pointer; transition:.15s; }
.lm-mode.on { background:var(--accent-cyan); color:#fff; }
.lm-lgset { display:inline-flex; gap:13px; flex-wrap:wrap; align-items:center; }

/* ===== Blueprint mode — clean schematic diagram ===== */
.lm-stage.lm-blueprint { background:#eaf0f8; box-shadow:inset 0 0 0 1px rgba(18,42,78,0.1), 0 16px 40px rgba(20,40,80,0.12); }
.lm-blueprint .lm-scan, .lm-blueprint .lm-radar, .lm-blueprint .lm-halo, .lm-blueprint .lm-pulse, .lm-blueprint .lm-hub-pulse, .lm-blueprint .lm-attn-ring { display:none; }
.lm-blueprint .lm-grid line { stroke:rgba(47,107,196,0.14); }
.lm-blueprint .lm-arc { stroke:rgba(47,107,196,0.4); stroke-dasharray:4 4; }
.lm-blueprint .lm-packet { fill:#2f6bc4; filter:none; }
.lm-blueprint .lm-dot { stroke:#fff; stroke-width:2.5; filter:none; }
.lm-blueprint .lm-label { fill:#14273e; stroke:#eaf0f8; }
.lm-blueprint .lm-node.attn .lm-label { fill:#a86612; }
.lm-blueprint .lm-hub-dot { fill:#14273e; filter:none; }
.lm-blueprint .lm-hub-ring { stroke:rgba(20,39,62,0.45); }
.lm-blueprint .lm-hub-label { fill:#566880; stroke:#eaf0f8; }
.lm-blueprint .lm-plink, .lm-blueprint .lm-dlink { stroke:rgba(47,107,196,0.45); stroke-dasharray:none; }
.lm-blueprint .lm-pdot { fill:#fff; stroke:#2f6bc4; stroke-width:1.8; filter:none; }
.lm-blueprint .lm-pinit { fill:#2f6bc4; }
.lm-blueprint .lm-plabel, .lm-blueprint .lm-dlabel { fill:#566880; stroke:#eaf0f8; }
.lm-blueprint .lm-ddot { stroke:#fff; stroke-width:1.5; filter:none; }
.lm-blueprint .lm-info { background:rgba(255,255,255,0.94); border-color:rgba(18,42,78,0.12); color:#14273e; }
.lm-blueprint .lm-info-h { color:#14273e; }
.lm-blueprint .lm-info-sub, .lm-blueprint .lm-info-hint, .lm-blueprint .lm-info-row, .lm-blueprint .lm-info-plabel { color:#566880; }
.lm-blueprint .lm-info-row b { color:#14273e; }
.lm-blueprint .lm-info-people { border-top-color:rgba(18,42,78,0.1); }
.lm-blueprint .lm-pchip { color:#2f6bc4; background:rgba(47,107,196,0.08); border-color:rgba(47,107,196,0.2); }
@media (prefers-reduced-motion: reduce){ .lm-attn-ring { animation:none; } }

/* ===== Provisioning Autopilot ===== */
.ap-power { display:inline-flex; align-items:center; gap:8px; font-size:0.68rem; font-weight:800; letter-spacing:1.4px; text-transform:uppercase; color:var(--accent-purple); background:rgba(111,91,208,0.1); border:1px solid rgba(111,91,208,0.28); border-radius:var(--radius-pill); padding:5px 13px; }
.ap-power-dot { width:7px; height:7px; border-radius:50%; background:var(--accent-purple); animation:apPulse 1.9s ease-out infinite; }
@keyframes apPulse { 0%{box-shadow:0 0 0 0 rgba(111,91,208,0.5);} 70%{box-shadow:0 0 0 7px rgba(111,91,208,0);} 100%{box-shadow:0 0 0 0 rgba(111,91,208,0);} }
.ap-metric { display:flex; align-items:center; gap:12px; background:var(--bg-surface); border:1px solid var(--border-color); border-left:3px solid var(--c); border-radius:var(--radius-md); padding:14px 16px; }
.ap-explain { font-size:0.8rem; color:var(--text-muted); background:linear-gradient(135deg,rgba(111,91,208,0.06),rgba(10,126,164,0.05)); border:1px solid var(--border-color); border-radius:var(--radius-md); padding:11px 14px; margin-bottom:18px; line-height:1.55; }
.ap-explain i { color:var(--accent-purple); margin-right:5px; }
.ap-explain b { color:var(--text-main); }

/* ---- Autopilot assumption line -----------------------------------------
   Sits directly under the four hero metrics and states, in words, how the
   dollar estimate beside it is computed. The two <input>s ARE the formula —
   styled as underlined inline fields rather than boxed form controls so the
   sentence still reads as a sentence, and so it is obvious the numbers are
   editable without the row turning into a settings panel. */
.ap-assume {
  font-size: 0.82rem; color: var(--text-muted);
  background: rgba(10,126,164,0.045);
  border: 1px dashed var(--border-color);
  border-radius: var(--radius-md);
  padding: 10px 14px; margin: -6px 0 16px;
  line-height: 1.85;
}
.ap-assume i { color: var(--accent-cyan); margin-right: 5px; }
.ap-assume b { color: var(--text-main); }
.ap-in {
  width: 52px; padding: 1px 4px; margin: 0 1px;
  font: inherit; font-weight: 700; color: var(--text-main);
  text-align: center;
  background: transparent;
  border: none; border-bottom: 2px solid var(--accent-cyan);
  border-radius: 0;
  -moz-appearance: textfield; appearance: textfield;
}
.ap-in-w { width: 68px; }
/* Chrome's spinner arrows steal a third of a 52px field and only appear on
   hover, so the field visibly reflows under the cursor. Hidden; the arrow keys
   and typing both still work. */
.ap-in::-webkit-outer-spin-button, .ap-in::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ap-in:focus { outline: none; background: rgba(10,126,164,0.10); }
/* Own line: it is a caveat, not part of the arithmetic, and inlining it made the
   sentence too long to scan at a glance. */
.ap-assume-n { display: block; font-size: 0.74rem; opacity: 0.85; line-height: 1.5; margin-top: 4px; }
.ap-list { display:grid; grid-template-columns:repeat(auto-fill,minmax(340px,1fr)); gap:16px; }
.ap-card { background:var(--bg-card); border:1px solid var(--border-color); border-radius:var(--radius-lg); padding:18px; box-shadow:var(--shadow-soft); transition:box-shadow .15s, transform .15s; position:relative; overflow:hidden; }
.ap-card::before { content:''; position:absolute; left:0; top:0; bottom:0; width:3px; background:linear-gradient(var(--accent-purple),var(--accent-cyan)); }
.ap-card:hover { transform:translateY(-2px); box-shadow:0 14px 30px rgba(20,40,80,0.13); }
.ap-card.ap-done { opacity:0.9; }
.ap-card.ap-done::before { background:var(--accent-green); }
.ap-card-top { display:flex; align-items:center; gap:12px; margin-bottom:11px; }
.ap-av { width:40px; height:40px; border-radius:50%; background:linear-gradient(140deg,var(--accent-purple),var(--accent-cyan)); color:#fff; display:flex; align-items:center; justify-content:center; font-size:0.85rem; font-weight:800; flex-shrink:0; }
.ap-name { font-size:0.98rem; font-weight:800; color:var(--text-main); }
.ap-role { font-size:0.74rem; color:var(--text-dim); }
.ap-tag { color:var(--accent-purple); font-weight:700; }
.ap-tag i { font-size:0.68rem; }
.ap-conf { margin-left:auto; font-size:0.66rem; font-weight:800; color:var(--accent-cyan); background:rgba(10,126,164,0.1); border-radius:var(--radius-pill); padding:3px 10px; white-space:nowrap; }
.ap-reason { font-size:0.82rem; color:var(--text-muted); line-height:1.5; margin-bottom:11px; }
.ap-reason i { color:var(--accent-purple); margin-right:4px; }
.ap-reason b { color:var(--text-main); }
.ap-items { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:13px; }
.ap-chip { font-size:0.68rem; font-weight:600; padding:3px 9px; border-radius:var(--radius-pill); border:1px solid var(--border-color); }
.ap-foot { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; border-top:1px solid var(--border-color); padding-top:12px; }
.ap-hygiene { font-size:0.7rem; color:var(--text-dim); font-weight:600; }
.ap-hygiene i { color:var(--accent-red); margin-right:4px; }
.ap-ready { font-size:0.78rem; font-weight:800; color:var(--accent-green); display:inline-flex; align-items:center; gap:6px; }
@media (prefers-reduced-motion: reduce){ .ap-power-dot { animation:none; } }

/* Landing-page community poll.
   This used to sit at the bottom of the storefront under a rule, so it carried a 34px
   top margin and a border-top to separate itself from the kits above it. It now lives
   in its own switcher panel with nothing above it, so both are gone — the separator
   was drawing a line under nothing and the margin was just dead space at the top. */
.landing-poll-wrap { margin-top: 4px; }
.landing-poll-eyebrow { font-size: var(--fs-micro); font-weight: 800; text-transform: uppercase; letter-spacing: 1.4px; color: var(--text-dim); margin-bottom: 12px; display: flex; align-items: center; gap: 7px; }
.landing-poll-eyebrow i { color: var(--accent-cyan); }

/* ===== Custom Kit Builder ===== */
#modal-custom-kit-builder .modal-card { max-width: 780px; }
.ck-section { margin-bottom: 30px; }
.ck-section:last-of-type { margin-bottom: 4px; }
.ck-section-h { font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 1.3px; color: var(--text-main); display: flex; align-items: center; gap: 9px; margin-bottom: 16px; flex-wrap: wrap; }
.ck-step { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 50%; background: linear-gradient(140deg, var(--accent-blue), var(--accent-cyan)); color: #fff; font-size: 0.7rem; font-weight: 800; flex-shrink: 0; }
.ck-section-hint { font-weight: 600; text-transform: none; letter-spacing: 0; font-size: 0.74rem; color: var(--text-dim); }
.ck-slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.ck-filled-slot { position: relative; background: linear-gradient(135deg, rgba(10,126,164,0.09), rgba(47,107,196,0.06)); border: 1px solid rgba(10,126,164,0.3); border-radius: var(--radius-md); padding: 14px 12px; text-align: center; min-height: 86px; display: flex; flex-direction: column; justify-content: center; }
.ck-remove { position: absolute; top: 5px; right: 5px; background: none; border: none; color: var(--accent-red); cursor: pointer; font-size: 0.72rem; padding: 3px; opacity: 0.7; transition: opacity .15s; }
.ck-remove:hover { opacity: 1; }
.ck-fname { font-size: 0.74rem; font-weight: 700; color: var(--text-main); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ck-fmeta { font-size: 0.62rem; color: var(--accent-cyan); margin-top: 3px; font-family: 'JetBrains Mono', ui-monospace, monospace; }
.ck-empty-slot { border: 2px dashed rgba(10,126,164,0.45); background: rgba(10,126,164,0.035); border-radius: var(--radius-md); padding: 14px 12px; min-height: 86px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 7px; color: var(--accent-cyan); cursor: pointer; transition: border-color .15s, background .15s, transform .15s; }
.ck-empty-slot:hover, .ck-empty-slot:focus-visible { border-color: var(--accent-cyan); background: rgba(10,126,164,0.09); transform: translateY(-2px); outline: none; }
.ck-empty-slot i { font-size: 1.05rem; }
.ck-empty-slot span { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.2px; }
/* Running totals are secondary — a small pill that's "also there", not a headline. */
.ck-summary { display: inline-flex; flex-wrap: wrap; gap: 5px 18px; margin-top: 14px; padding: 8px 16px; background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--radius-pill); }
.ck-summary > div { display: inline-flex; align-items: baseline; gap: 5px; }
.ck-sv { font-size: 0.82rem; font-weight: 800; font-family: 'JetBrains Mono', ui-monospace, monospace; }
.ck-sl { font-size: 0.66rem; /* ADA floor — see note in the DESIGN AUDIT PASS block */ text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); font-weight: 700; }

/* Catalog items — image + title + category + top spec */
/* The min track width lives here and only here. It used to be declared twice —
   200px in an inline style attribute and 216px in this rule with !important to
   beat it — which meant the number you found first was the wrong one. */
#ck-peripheral-catalog { display: grid; grid-template-columns: repeat(auto-fill, minmax(216px, 1fr)); }
.ck-cat-item { display: flex; gap: 11px; align-items: center; background: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 9px 11px; cursor: pointer; transition: border-color .15s, background .15s, transform .15s; }
.ck-cat-item:hover { border-color: var(--border-accent); background: var(--bg-card-hover); transform: translateY(-1px); }
.ck-cat-item.added { border-color: rgba(15,154,114,0.5); background: rgba(15,154,114,0.07); }
.ck-cat-img { position: relative; width: 48px; height: 48px; border-radius: 10px; background: #fff; border: 1px solid var(--border-color); flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 1.25rem; overflow: hidden; }
.ck-cat-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; padding: 4px; background: #fff; }
.ck-cat-body { min-width: 0; flex: 1; }
.ck-cat-cat { font-size: 0.56rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); font-weight: 800; }
.ck-cat-name { font-size: 0.78rem; font-weight: 700; color: var(--text-main); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin: 1px 0; }
.ck-cat-name .fa-check-circle { color: var(--accent-green); margin-left: 4px; }
.ck-cat-spec { font-size: 0.64rem; color: var(--text-muted); }
.ck-cat-spec b { color: var(--accent-cyan); font-family: 'JetBrains Mono', ui-monospace, monospace; }
.loc-card:hover { transform:translateY(-2px); box-shadow:0 12px 26px rgba(20,40,80,0.12); }
.loc-card-head { display:flex; justify-content:space-between; align-items:flex-start; gap:8px; }
.loc-card-head h4 { font-size:0.95rem; color:var(--text-main); margin:0 0 3px; }
.loc-card-head h4 i { color:var(--accent-cyan); }
.loc-card-addr { font-size:0.72rem; color:var(--text-muted); }
.loc-stats { display:flex; gap:10px; margin-top:12px; }
.loc-stats>div { flex:1; background:var(--bg-surface); border:1px solid var(--border-color); border-radius:var(--radius-sm); padding:8px 11px; }
.loc-stats .l { display:block; font-size:0.56rem; text-transform:uppercase; letter-spacing:0.5px; color:var(--text-dim); font-weight:700; }
.loc-stats .v { font-family:'JetBrains Mono',monospace; font-weight:800; font-size:0.92rem; margin-top:2px; }

/* ================= KIT INSIGHTS PANEL (Kit Library) ================= */
.ki-panel { background:var(--bg-card); border:1px solid var(--border-color); border-radius:var(--radius-lg); padding:20px 22px; margin-bottom:26px; box-shadow:var(--shadow-soft); position:relative; overflow:hidden; }
.ki-panel::before { content:''; position:absolute; top:0; left:0; right:0; height:3px; background:var(--grad-brand); opacity:0.7; }
.ki-head { display:flex; align-items:baseline; gap:14px; flex-wrap:wrap; margin-bottom:16px; }
.ki-head h3 { font-size:1.05rem; margin:0; }
.ki-story { font-size:0.85rem; color:var(--text-muted); }
.ki-metrics { display:grid; grid-template-columns:repeat(5,1fr); gap:10px; margin-bottom:18px; }
@media(max-width:680px){ .ki-metrics{ grid-template-columns:repeat(2,1fr); } }
.ki-metric { background:var(--bg-surface); border:1px solid var(--border-color); border-radius:var(--radius-md); padding:11px 13px; }
.ki-m-l { display:block; font-size:0.6rem; text-transform:uppercase; letter-spacing:0.8px; color:var(--text-dim); font-weight:700; }
.ki-m-v { font-family:'JetBrains Mono',monospace; font-weight:800; font-size:1.15rem; color:var(--text-main); margin-top:3px; display:block; }
.ki-m-v small { font-size:0.7rem; color:var(--text-dim); }
.ki-grid { display:grid; grid-template-columns:1fr 1fr; gap:22px; margin-bottom:16px; }
@media(max-width:820px){ .ki-grid{ grid-template-columns:1fr; } }
.ki-sub { font-size:0.64rem; font-weight:800; text-transform:uppercase; letter-spacing:1.2px; color:var(--text-dim); margin-bottom:9px; }
.ki-bar { display:flex; height:14px; border-radius:7px; overflow:hidden; box-shadow:inset 0 0 0 1px rgba(18,42,78,0.06); }
.ki-bar>div { height:100%; }
.ki-legend { display:flex; flex-wrap:wrap; gap:5px 14px; margin-top:10px; }
.ki-lg { font-size:0.72rem; color:var(--text-muted); display:inline-flex; align-items:center; gap:6px; }
.ki-lg i { width:9px; height:9px; border-radius:3px; }
.ki-callouts { display:flex; flex-direction:column; gap:9px; }
.ki-callout { display:flex; align-items:center; gap:11px; background:var(--bg-surface); border:1px solid var(--border-color); border-radius:var(--radius-md); padding:9px 12px; }
.ki-callout-ic { width:32px; height:32px; border-radius:9px; display:flex; align-items:center; justify-content:center; font-size:0.82rem; flex-shrink:0; }
.ki-callout-l { display:block; font-size:0.6rem; text-transform:uppercase; letter-spacing:0.6px; color:var(--text-dim); font-weight:700; }
.ki-callout-v { display:block; font-size:0.82rem; color:var(--text-main); font-weight:600; }
.ki-flags { display:flex; flex-wrap:wrap; gap:8px; }
.ki-flag { font-size:0.74rem; font-weight:700; display:inline-flex; align-items:center; gap:7px; padding:6px 12px; border-radius:var(--radius-pill); border:1px solid; }
.ki-gap { color:var(--accent-amber); border-color:rgba(189,125,19,0.35); background:rgba(189,125,19,0.08); }
.ki-dup { color:var(--accent-blue); border-color:rgba(47,107,196,0.3); background:rgba(47,107,196,0.08); }
.ki-ok { color:var(--accent-green); border-color:rgba(15,154,114,0.3); background:rgba(15,154,114,0.08); }

/* ============================================================
   KIT GENOME — self-learning peer recommender (storefront)
   ============================================================ */
/* Sizing note: the Genome used to be a full-width block stacked under the kit grid,
   so it was scaled like a section of its own. It is now one panel of the storefront
   switcher, sitting where the kits sit — so it is a tier smaller across the board
   (type, padding, gutters) and its 34px top margin is gone, since there is no longer
   anything above it to separate itself from. */
.kg-wrap { margin-top: 4px; background: var(--bg-card); border: 1px solid var(--border-color);
  border-radius: var(--radius-lg); padding: 18px 20px; box-shadow: var(--shadow-card);
  background-image: radial-gradient(circle at 100% 0%, color-mix(in srgb, var(--accent-cyan) 8%, transparent), transparent 42%);
  /* The landing hero centres its text, and the Genome sits inside it. That centring
     fought the panel's own content: the ranked rows are flex and stay left, so headings
     and captions floated to the middle above left-aligned data. Reset it here — this is
     a table of numbers, and a ragged-left column is what makes it scannable. */
  text-align: left; }
.kg-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }
/* Kit Genome type is on the scale as of the tokenization pass. Note this reads as a
   reversal of the earlier "shrink Kit Genome a tier" request and is not one: that
   request was about the BLOCK — it dominated the storefront and pushed the kits out
   of the fold — and the padding, gutters and margins that did that work are untouched
   here. What was also shrunk, as a side effect, was the type, down to 0.6–0.66rem
   (9.6–10.6px). That is what "text is too small everywhere on the storefront" is
   pointing at. The block stays compact; the numbers inside it become readable. */
.kg-eyebrow { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: 1.8px; font-weight: 800; color: var(--accent-cyan); display: flex; align-items: center; gap: 6px; }
.kg-title { font-size: var(--fs-md); font-weight: 800; color: var(--text-main); margin-top: 3px; letter-spacing: -0.3px; }
.kg-sub { font-size: var(--fs-2xs); color: var(--text-muted); margin-top: 2px; max-width: 46ch; }
.kg-sub b { color: var(--text-main); }
.kg-roles { display: flex; gap: 5px; flex-wrap: wrap; }
.kg-role { font-size: var(--fs-micro); font-weight: 700; padding: 5px 11px; border-radius: var(--radius-pill); cursor: pointer;
  border: 1px solid var(--border-color); background: var(--bg-card); color: var(--text-muted); transition: all 0.14s ease; }
.kg-role:hover { border-color: var(--accent-cyan); color: var(--accent-cyan); }
.kg-role.on { background: linear-gradient(135deg, var(--accent-cyan), var(--accent-blue)); color: #fff; border-color: transparent; box-shadow: 0 4px 12px rgba(10,126,164,0.25); }
.kg-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 20px; }
.kg-col-h { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: 1.4px; font-weight: 800; color: var(--text-dim); margin-bottom: 11px; }
.kg-item { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.kg-rank { width: 20px; height: 20px; flex: none; border-radius: 6px; background: color-mix(in srgb, var(--accent-cyan) 12%, transparent);
  color: var(--accent-cyan); font-size: var(--fs-micro); font-weight: 800; display: flex; align-items: center; justify-content: center; font-family: 'JetBrains Mono', monospace; }
.kg-item-b { flex: 1; min-width: 0; }
.kg-item-n { font-size: var(--fs-xs); font-weight: 700; color: var(--text-main); display: flex; align-items: center; gap: 6px; }
.kg-item-c { font-size: var(--fs-micro); color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.6px; margin: 1px 0 4px; }
.kg-bar { height: 5px; background: rgba(20,40,80,0.07); border-radius: 5px; overflow: hidden; }
.kg-bar > span { display: block; height: 100%; background: linear-gradient(90deg, var(--accent-cyan), var(--accent-blue)); border-radius: 5px; }
.kg-pct { font-size: var(--fs-2xs); font-weight: 800; color: var(--accent-cyan); font-family: 'JetBrains Mono', monospace; min-width: 36px; text-align: right; }
.kg-tag { font-size: var(--fs-micro); font-weight: 800; text-transform: uppercase; letter-spacing: 0.6px; padding: 2px 7px; border-radius: var(--radius-pill); }
.kg-tag.ess { color: var(--accent-green-ink); background: rgba(15,154,114,0.12); }
.kg-tag.pop { color: var(--accent-blue); background: rgba(47,107,196,0.1); }
.kg-pair { display: flex; align-items: flex-start; gap: 9px; padding: 8px 11px; background: rgba(20,40,80,0.03); border: 1px solid var(--border-color); border-radius: var(--radius-md); margin-bottom: 7px; font-size: var(--fs-2xs); color: var(--text-main); }
.kg-pair > i { color: var(--accent-cyan); margin-top: 3px; }
.kg-pair b { font-weight: 700; }
.kg-pair-s { font-size: var(--fs-micro); color: var(--text-muted); margin-top: 2px; }
.kg-pair-empty { font-size: var(--fs-2xs); color: var(--text-dim); padding: 10px; }
.kg-tip { margin-top: 10px; padding: 9px 12px; background: color-mix(in srgb, var(--accent-cyan) 6%, transparent); border-left: 3px solid var(--accent-cyan); border-radius: 0 8px 8px 0; font-size: var(--fs-2xs); color: var(--text-muted); line-height: 1.5; }
.kg-tip b { color: var(--text-main); }
.kg-tip > i { color: var(--accent-amber); margin-right: 5px; }
.kg-cta { margin-top: 12px; border-color: var(--accent-cyan); color: var(--accent-cyan); }
@media (max-width: 680px) { .kg-grid { grid-template-columns: 1fr; gap: 18px; } .kg-wrap { padding: 16px; } }

/* ============================================================
   RECLAIM — internal hardware liquidity market (admin view)
   ============================================================ */
.liq-hero { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 16px; }
.liq-metric { display: flex; align-items: center; gap: 12px; background: var(--bg-card); border: 1px solid var(--border-color);
  border-left: 4px solid var(--c); border-radius: var(--radius-lg); padding: 14px 16px; box-shadow: var(--shadow-soft); }
.liq-metric-ic { width: 36px; height: 36px; flex: none; border-radius: 10px; background: color-mix(in srgb, var(--c) 14%, transparent);
  color: var(--c); display: flex; align-items: center; justify-content: center; font-size: 1rem; }
.liq-metric-v { font-size: 1.3rem; font-weight: 800; color: var(--text-main); letter-spacing: -0.5px; font-family: 'JetBrains Mono', monospace; }
.liq-metric-l { font-size: 0.68rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.6px; font-weight: 700; margin-top: 1px; }
/* NOTE: this was display:flex. The note bodies are raw prose with inline <b> tags, and
   flex turns every text run and every <b> into its own flex item — the sentences got
   shredded into side-by-side columns ("An | option | is the right — not the obligation").
   Block flow with an absolutely-positioned icon keeps the copy as one paragraph. */
.liq-note { display: block; position: relative; padding: 12px 15px 12px 40px; background: color-mix(in srgb, var(--accent-green) 7%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent-green) 22%, transparent); border-radius: var(--radius-md); font-size: 0.8rem; color: var(--text-muted); line-height: 1.55; margin-bottom: 14px; }
.liq-note > i { position: absolute; left: 15px; top: 14px; color: var(--accent-green); }
.liq-note b { color: var(--text-main); }
.liq-locked { display: flex; align-items: center; gap: 9px; padding: 11px 15px; background: rgba(15,154,114,0.1); border: 1px solid rgba(15,154,114,0.28);
  border-radius: var(--radius-md); font-size: 0.85rem; color: var(--accent-green-ink); font-weight: 600; margin-bottom: 16px; } .liq-locked b { color: #0b6a4f; }
.liq-cols { display: grid; grid-template-columns: 1.5fr 1fr; gap: 18px; }
.liq-h { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 1.5px; font-weight: 800; color: var(--text-dim); margin-bottom: 12px; display: flex; align-items: center; justify-content: space-between; }
.liq-h span { color: var(--accent-cyan); }
.liq-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 15px 17px; margin-bottom: 12px; box-shadow: var(--shadow-soft); transition: box-shadow 0.15s, transform 0.15s; }
.liq-card:hover { box-shadow: var(--shadow-card); transform: translateY(-2px); }
.liq-card.liq-done { opacity: 0.72; background: rgba(15,154,114,0.04); }
.liq-card-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.liq-move { display: flex; align-items: center; gap: 10px; font-size: 0.98rem; color: var(--text-main); } .liq-move b { font-weight: 800; }
.liq-ic { width: 32px; height: 32px; flex: none; border-radius: 9px; background: color-mix(in srgb, var(--c) 15%, transparent); color: var(--c); display: flex; align-items: center; justify-content: center; font-size: 0.85rem; }
.liq-save { font-size: 0.78rem; color: var(--text-muted); font-weight: 600; } .liq-save b { color: var(--accent-green-ink); font-size: 0.92rem; }
.liq-route { display: flex; align-items: center; gap: 12px; margin: 12px 0 8px; }
.liq-site { font-size: 0.86rem; font-weight: 700; padding: 5px 12px; border-radius: 8px; }
.liq-site.from { background: rgba(189,125,19,0.1); color: var(--accent-amber-ink); } .liq-site.to { background: rgba(10,126,164,0.1); color: var(--accent-cyan); }
.liq-route > i { color: var(--text-dim); }
.liq-meta { font-size: 0.76rem; color: var(--text-muted); line-height: 1.5; } .liq-meta > i { color: var(--accent-blue); margin-right: 4px; }
.liq-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--border-color); flex-wrap: wrap; }
.liq-refurb { font-size: 0.72rem; font-weight: 700; color: var(--accent-green-ink); } .liq-refurb > i { margin-right: 4px; }
.liq-ready { font-size: 0.8rem; font-weight: 700; color: var(--accent-green); } .liq-ready > i { margin-right: 4px; }
.liq-side .liq-siterow { padding: 11px 0; border-bottom: 1px solid var(--border-color); }
.liq-sitename { font-size: 0.84rem; font-weight: 700; color: var(--text-main); margin-bottom: 7px; } .liq-sitename > i { color: var(--accent-cyan); margin-right: 5px; }
.liq-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.liq-idle-chip { font-size: 0.68rem; font-weight: 700; color: var(--accent-amber-ink); background: rgba(189,125,19,0.1); border: 1px solid rgba(189,125,19,0.2); padding: 2px 8px; border-radius: var(--radius-pill); }
.liq-idle-none { font-size: 0.72rem; color: var(--text-dim); font-style: italic; }
.liq-excl { margin-top: 14px; font-size: 0.72rem; color: var(--text-dim); line-height: 1.5; } .liq-excl > i { color: var(--accent-red); margin-right: 5px; }
@media (max-width: 900px) { .liq-hero { grid-template-columns: repeat(2, 1fr); } .liq-cols { grid-template-columns: 1fr; } }

/* ============================================================
   RECLAIM TRADING DESK — index, ticker, carbon slider, tabs,
   forwards (futures), order book + supply/demand cross
   ============================================================ */
.liq-desk { display: grid; grid-template-columns: 1.1fr 1fr; gap: 14px; margin-bottom: 12px; }
.liq-idx { background: linear-gradient(135deg, #12233d, #1c3a63); color: #fff; border-radius: var(--radius-lg); padding: 15px 18px; box-shadow: 0 10px 26px rgba(18,42,78,0.22); }
.liq-idx-l { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 1.4px; font-weight: 800; opacity: 0.82; }
.liq-idx-l > i { margin-right: 5px; }
.liq-idx-row { display: flex; align-items: baseline; gap: 10px; margin-top: 5px; }
.liq-idx-val { font-size: 1.85rem; font-weight: 800; font-family: 'JetBrains Mono', monospace; letter-spacing: -0.5px; }
.liq-idx-delta { font-size: 0.76rem; font-weight: 800; padding: 2px 8px; border-radius: var(--radius-pill); }
.liq-idx-delta.up { color: #7ee6b8; background: rgba(45,212,160,0.16); }
.liq-idx-delta.down { color: #ffb3b3; background: rgba(248,113,113,0.16); }
.liq-idx-sub { font-size: 0.72rem; opacity: 0.85; margin-top: 6px; } .liq-idx-sub b { color: #7ee6b8; font-family: 'JetBrains Mono', monospace; }
.liq-carbon { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 15px 18px; box-shadow: var(--shadow-soft); display: flex; flex-direction: column; justify-content: center; }
.liq-carbon-top { display: flex; align-items: center; justify-content: space-between; font-size: 0.8rem; color: var(--text-muted); font-weight: 600; }
.liq-carbon-top > span > i { color: var(--accent-green); margin-right: 5px; }
.liq-carbon-top b { font-size: 1.05rem; color: var(--text-main); font-family: 'JetBrains Mono', monospace; }
.liq-slider { width: 100%; margin: 12px 0 6px; accent-color: var(--accent-green); height: 5px; cursor: pointer; }
.liq-carbon-scale { display: flex; justify-content: space-between; font-size: 0.62rem; color: var(--text-dim); }
.liq-carbon-scale > span:nth-child(2) { color: var(--text-muted); }
/* Ticker */
.liq-ticker { overflow: hidden; background: #0f1e33; border-radius: 10px; padding: 8px 0; margin-bottom: 16px; border: 1px solid rgba(255,255,255,0.06); }
.liq-ticker-track { display: inline-flex; white-space: nowrap; will-change: transform; animation: liqMarquee 46s linear infinite; }
@keyframes liqMarquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.liq-ticker:hover .liq-ticker-track { animation-play-state: paused; }
.liq-tick { display: inline-flex; align-items: center; gap: 7px; padding: 0 22px; font-size: 0.76rem; color: #b9c6da; border-right: 1px solid rgba(255,255,255,0.07); font-family: 'JetBrains Mono', monospace; }
.liq-tick b { color: #fff; font-weight: 700; }
.liq-tick i.up { color: #57e3a6; font-style: normal; font-weight: 700; }
.liq-tick i.dn { color: #86b8ff; font-style: normal; }
@media (prefers-reduced-motion: reduce) { .liq-ticker-track { animation: none; } }
/* Tabs */
.liq-tabs { display: flex; gap: 6px; margin-bottom: 16px; border-bottom: 1px solid var(--border-color); }
.liq-tab { font-size: 0.82rem; font-weight: 700; padding: 9px 16px; border: none; background: none; color: var(--text-muted); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; transition: color 0.14s, border-color 0.14s; }
.liq-tab:hover { color: var(--accent-cyan); }
.liq-tab.on { color: var(--accent-cyan); border-bottom-color: var(--accent-cyan); }
.liq-tab > i { margin-right: 5px; }
/* Forwards */
.liq-note-fwd { background: color-mix(in srgb, var(--accent-purple) 7%, transparent); border-color: color-mix(in srgb, var(--accent-purple) 22%, transparent); }
.liq-note-fwd > i { color: var(--accent-purple); }
.liq-fwd-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 12px; }
.liq-fwd { background: var(--bg-card); border: 1px solid var(--border-color); border-left: 4px solid var(--accent-purple); border-radius: var(--radius-lg); padding: 15px 17px; box-shadow: var(--shadow-soft); transition: box-shadow 0.15s, transform 0.15s; }
.liq-fwd:hover { box-shadow: var(--shadow-card); transform: translateY(-2px); }
.liq-fwd.liq-done { opacity: 0.74; background: rgba(111,91,208,0.05); }
.liq-fwd-settle { font-size: 0.72rem; font-weight: 700; color: var(--accent-purple); background: rgba(111,91,208,0.1); padding: 3px 9px; border-radius: var(--radius-pill); white-space: nowrap; }
.liq-fwd-settle > i { margin-right: 4px; }
/* Order book */
.liq-bookcats { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
.liq-bookcat { font-size: 0.74rem; font-weight: 700; padding: 5px 13px; border-radius: var(--radius-pill); border: 1px solid var(--border-color); background: var(--bg-card); color: var(--text-muted); cursor: pointer; transition: all 0.14s; }
.liq-bookcat:hover { border-color: var(--accent-cyan); color: var(--accent-cyan); }
.liq-bookcat.on { background: var(--accent-cyan); color: #fff; border-color: transparent; }
.liq-ob-wrap { display: grid; grid-template-columns: 1fr 190px 1fr; gap: 14px; align-items: start; }
.liq-ob-col { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-md); overflow: hidden; }
.liq-ob-h { font-size: 0.74rem; font-weight: 800; padding: 10px 13px; display: flex; align-items: center; justify-content: space-between; }
.liq-ob-h.bid { background: rgba(15,154,114,0.08); color: var(--accent-green-ink); } .liq-ob-h.ask { background: rgba(189,125,19,0.08); color: var(--accent-amber-ink); }
.liq-ob-h span { font-size: 0.66rem; font-weight: 700; opacity: 0.85; }
.liq-ob-head { display: grid; grid-template-columns: 1fr 44px 66px; padding: 6px 13px; font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.6px; color: var(--text-dim); font-weight: 700; border-bottom: 1px solid var(--border-color); }
.liq-ob-head span:not(:first-child), .liq-ob-row span:not(:first-child) { text-align: right; }
.liq-ob-row { display: grid; grid-template-columns: 1fr 44px 66px; padding: 7px 13px; font-size: 0.78rem; border-bottom: 1px solid var(--border-color); align-items: center; }
.liq-ob-row:last-child { border-bottom: none; }
.liq-ob-site { font-weight: 700; color: var(--text-main); }
.liq-ob-qty { font-family: 'JetBrains Mono', monospace; color: var(--text-muted); }
.liq-ob-row.bid .liq-ob-price { color: var(--accent-green-ink); font-weight: 800; font-family: 'JetBrains Mono', monospace; }
.liq-ob-row.ask .liq-ob-price { color: var(--accent-amber-ink); font-weight: 800; font-family: 'JetBrains Mono', monospace; }
.liq-ob-empty { padding: 16px 13px; font-size: 0.76rem; color: var(--text-dim); font-style: italic; text-align: center; }
.liq-ob-mid { display: flex; flex-direction: column; align-items: center; gap: 4px; padding-top: 6px; }
.liq-ob-mid-l { font-size: 0.6rem; text-transform: uppercase; letter-spacing: 1px; color: var(--text-dim); font-weight: 800; }
.liq-ob-spread { font-size: 0.72rem; font-weight: 800; color: var(--accent-cyan); font-family: 'JetBrains Mono', monospace; }
.liq-sd { width: 100%; height: auto; }
.liq-sd-ax { stroke: var(--border-color); stroke-width: 1; }
.liq-sd-dem { fill: none; stroke: #0f9a72; stroke-width: 2; }
.liq-sd-sup { fill: none; stroke: #bd7d13; stroke-width: 2; }
.liq-sd-clearline { stroke: var(--accent-cyan); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0.6; }
.liq-sd-clear { fill: var(--accent-cyan); stroke: #fff; stroke-width: 1.5; }
.liq-sd-t { font-size: 7px; fill: var(--text-dim); font-weight: 700; } .liq-sd-dem-t { fill: #0f9a72; }
.liq-ob-clear { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 16px; padding: 14px 16px; background: linear-gradient(135deg, rgba(10,126,164,0.06), rgba(15,154,114,0.06)); border: 1px solid var(--border-color); border-radius: var(--radius-md); }
.liq-ob-clear-v { font-size: 1.2rem; font-weight: 800; color: var(--text-main); font-family: 'JetBrains Mono', monospace; letter-spacing: -0.5px; }
.liq-ob-clear-l { font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.6px; color: var(--text-muted); font-weight: 700; margin-top: 2px; }
@media (max-width: 900px) {
  .liq-desk { grid-template-columns: 1fr; }
  .liq-ob-wrap { grid-template-columns: 1fr; }
  .liq-ob-mid { order: 3; }
  .liq-ob-clear { grid-template-columns: repeat(2, 1fr); }
  .liq-tabs { overflow-x: auto; }
}

/* Reclaim — Options tab (reserve-with-expiry) */
.liq-note-opt { background: color-mix(in srgb, var(--accent-amber) 8%, transparent); border-color: color-mix(in srgb, var(--accent-amber) 24%, transparent); }
.liq-note-opt > i { color: var(--accent-amber); }
.liq-opt { border-left-color: var(--accent-amber); }
.liq-opt.liq-opt-lapsed { opacity: 0.6; }
/* Overrides .liq-fwd-settle (line ~2539) on source order — same specificity, later
   in the file. It carried two !important flags that changed nothing. */
.liq-opt-exp { color: var(--accent-amber-ink); background: rgba(189,125,19,0.1); }
.liq-opt-conf { font-size: 0.68rem; font-weight: 800; padding: 2px 8px; border-radius: var(--radius-pill); margin-right: 3px; }
.liq-opt-conf.hi { color: var(--accent-green-ink); background: rgba(15,154,114,0.12); }
.liq-opt-conf.mid { color: var(--accent-amber-ink); background: rgba(189,125,19,0.12); }
.liq-opt-conf.lo { color: #b4453b; background: rgba(216,58,58,0.1); }
.liq-opt-hold { font-size: 0.74rem; font-weight: 700; color: var(--accent-amber-ink); } .liq-opt-hold > i { margin-right: 4px; }
.liq-opt-acts { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
.liq-lapsed { font-size: 0.78rem; font-weight: 700; color: var(--text-dim); } .liq-lapsed > i { margin-right: 4px; }

/* ==========================================================================
   DESIGN AUDIT PASS — layout, clearance, art fallback and ADA minimums
   ========================================================================== */

/* --- 1. Floating dock clearance -------------------------------------------
   #global-footer-bar is fixed at bottom:20px and ~46px tall, so it was sitting
   on top of the last card on every long page (the poll, the Build-Your-Own kit
   CTA, the Reclaim footnotes). Reserve the space instead of overlapping it.
   The landing hero already clears it via its own 132px bottom margin, and
   .dashboard-container does not exist under #step-4-dashboard — the scroll column is
   .app-container — so those two selectors were dead weight and are not listed here. */
#step-4-dashboard .app-container,
#step-4-dashboard .mapper-card:last-child { padding-bottom: 96px; }
body { scroll-padding-bottom: 96px; }

/* --- 2. Kit art fallback ---------------------------------------------------
   When a product photo 404s the browser drew its broken-image glyph on the most
   important screen in the app. Swap in a themed silhouette on the kit's own icon. */
.bag-card-img-wrap.no-art { background: linear-gradient(135deg, rgba(10,126,164,0.10), rgba(96,121,166,0.14)); }
.bag-art-fallback {
  display: flex; align-items: center; justify-content: center;
  width: 76px; height: 76px; border-radius: var(--radius-md);
  background: #fff; border: 1px solid var(--border-color);
  box-shadow: 0 4px 15px rgba(20,40,80,0.10);
  color: var(--accent-cyan); font-size: 1.9rem;
}

/* --- 3. Mobile: subsections behave as a real accordion ---------------------
   The two toggle buttons live in .dash-switch and the two panels in
   .dash-switch-panels. Side by side that reads fine, but stacked it produced
   [Insights][Command Center+][Insights tiles][Command Center+ tiles] — each
   header sitting above the other section's content. display:contents on the two
   wrappers promotes all four children into one column so they can interleave. */
@media (max-width: 860px) {
  .dash-sections { display: grid; grid-template-columns: 1fr; }
  .dash-sections > .dash-switch,
  .dash-sections > .dash-switch-panels { display: contents; }
  .dash-switch-btn:nth-child(1) { order: 1; }
  #dsp-insights { order: 2; }
  .dash-switch-btn:nth-child(2) { order: 3; }
  #dsp-platform { order: 4; }
  .dash-switch-btn { margin-bottom: 12px; }
  #dsp-insights, #dsp-platform { margin-bottom: 22px; }
  .dash-switch-panels.both { grid-template-columns: 1fr; }
}

/* --- 4. ADA: minimum hit area and minimum legible size --------------------
   Audit found 22px-tall category chips and 9-10px labels. WCAG 2.5.8 asks for a
   24px minimum target; small caps below 10px stop being legible for many people. */
.btn-xs, .btn-sm { min-height: 32px; }
.ck-cat-btn { min-height: 30px; }
.modal-close, .drawer-close { min-width: 36px; min-height: 36px; }

/* The five font-size floors this block used to re-declare have been folded into
   the base rules for .ck-sl, .dash-switch-hint, .lm-stat-l and .lm-mode — each is
   marked "ADA floor" there. Two reasons, and the second is the one that bit:
   .ck-sl needed !important here purely because a second copy of the same selector
   sat further up the file, and .bag-type-badge was re-declaring var(--fs-micro),
   which its base rule at line ~404 already set — a no-op that read like a fix.
   A floor stated twice is a floor that will be raised in one place only. The
   minimum-target rules above stay because they add a property the base rules
   genuinely do not have. */

/* --- 5. Tile rows line up across the two panels ---------------------------
   Insights descriptions run two lines and Command Center+ mostly one, so the two
   grids drifted out of phase and the rows read as ragged. Give every tile the
   same minimum body height so rows share a baseline. */
.dash-tile-grid .dashboard-nav-tile { min-height: 132px; }
.dash-tile-grid .dashboard-nav-tile p { min-height: 2.6em; }

/* --- 6. Savings Model loading state ---------------------------------------
   The ROI model is an iframe that takes 1.5-2.5s to paint; until it did, the view
   was a tall blank rectangle that read as broken. Shimmer underneath it instead. */
.roi-frame-wrap { position: relative; min-height: 320px; }
.roi-frame-wrap::before {
  content: ""; position: absolute; inset: 0; border-radius: 14px; z-index: 0;
  background: linear-gradient(100deg, rgba(20,40,80,0.05) 30%, rgba(20,40,80,0.10) 50%, rgba(20,40,80,0.05) 70%);
  background-size: 220% 100%; animation: roiShimmer 1.25s linear infinite;
}
.roi-frame-wrap.loaded::before { display: none; }
.roi-frame-wrap > iframe { position: relative; z-index: 1; }
@keyframes roiShimmer { from { background-position: 120% 0; } to { background-position: -120% 0; } }
@media (prefers-reduced-motion: reduce) { .roi-frame-wrap::before { animation: none; } }

/* ===========================================================================
   INFO DOTS + EXPLANATION POPOVER  (glossary.js)
   ---------------------------------------------------------------------------
   The "i" glyph is drawn with ::after generated content, never a text node and
   never a Font Awesome <i>. This is load-bearing in two directions:

     - generated content is invisible to element.textContent, so dropping a dot
       into a heading cannot change a decision made by code that reads text.
       sfSwitchSync (app.js:350-381) hides a storefront pill when its panel's
       textContent is empty; a dot that contributed real characters would keep
       an empty panel's pill on screen.
     - the CDN that serves Font Awesome is exactly the thing that fails on a
       slow or filtered network, which is when an explanation is most wanted.
       A CSS glyph always paints.

   The dot lands inside headings that inherit uppercase, wide letter-spacing,
   800 weight and italics from their host, so every inheritable text property
   is reset explicitly below. Without that, .kg-eyebrow renders a capital "I"
   pushed 1.8px off centre.
   =========================================================================== */
.info-dot {
  /* An opaque light chip rather than a tinted one. Dots land on white cards in
     the storefront AND on the dashboard's dark #212c43 chrome; a translucent
     fill would drop to ~3:1 on the dark surface. White reads on both. */
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; min-width: 15px; padding: 0; margin: 0 0 0 6px;
  flex: 0 0 auto;
  vertical-align: middle;
  border: 1px solid rgba(10, 126, 164, 0.45);
  border-radius: 50%;
  background: #ffffff;
  color: var(--accent-cyan);
  cursor: help;
  box-shadow: none;
  /* reset everything inheritable — see the note above */
  font-family: inherit; font-size: 10px; font-weight: 700; font-style: normal;
  line-height: 1; letter-spacing: 0; text-transform: none; text-indent: 0;
  -webkit-appearance: none; appearance: none;
  transition: background-color 0.14s ease, color 0.14s ease, border-color 0.14s ease;
}
.info-dot::after { content: "i"; display: block; transform: translateY(-0.5px); }

/* Written by glossary.js around the heading's LAST WORD plus the dot, so the pair
   wraps together instead of leaving a lone "i" stranded on its own line. Nothing
   else may use this class — it is emitted, never authored. */
.gl-nb { white-space: nowrap; }
.info-dot:hover, .info-dot.active {
  background: var(--accent-cyan); color: #ffffff; border-color: var(--accent-cyan);
}
.info-dot:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; }

/* Cramped hosts: micro-labels, uppercase eyebrows and chips that are already
   only 9-11px tall. A 15px dot would set the line height of its own row. */
.bag-type-badge > .info-dot, .card-category > .info-dot, .kg-eyebrow > .info-dot,
.ck-section-h > .info-dot, .liq-h > .info-dot,
.ki-sub > .info-dot, .lm-info-h > .info-dot, .tooltip-tag > .info-dot {
  width: 13px; height: 13px; min-width: 13px; font-size: 9px; margin-left: 5px;
}
h2 > .info-dot { width: 17px; height: 17px; min-width: 17px; font-size: 11px; margin-left: 8px; }

@media (prefers-reduced-motion: reduce) { .info-dot { transition: none; } }

/* --- the popover ---------------------------------------------------------
   position: fixed because place() anchors from getBoundingClientRect(), which
   is viewport-relative. z-index clears the drawer (2600) but stays under the
   toast layer (100000). */
.info-pop {
  position: fixed; z-index: 3000;
  width: 320px; max-width: calc(100vw - 20px);
  box-sizing: border-box;
  padding: 15px 17px 14px;
  background: var(--bg-card);
  color: var(--text-main);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: 0 18px 44px rgba(20, 40, 80, 0.22);
  font-size: 0.82rem; line-height: 1.5; text-align: left;
  opacity: 0; transform: translateY(-4px);
  transition: opacity 0.13s ease, transform 0.13s ease;
}
.info-pop.visible { opacity: 1; transform: translateY(0); }
.info-pop[hidden] { display: none; }
.info-pop-h {
  font-size: 0.88rem; font-weight: 800; color: var(--text-main);
  letter-spacing: -0.01em; line-height: 1.3; margin: 0 22px 7px 0;
}
.info-pop-w { margin: 0; color: var(--text-main); font-size: 0.82rem; line-height: 1.52; }
.info-pop-sec { margin-top: 11px; padding-top: 10px; border-top: 1px solid var(--border-color); }
.info-pop-sec p { margin: 0; color: var(--text-muted); font-size: 0.79rem; line-height: 1.5; }
.info-pop-lbl {
  display: block; margin-bottom: 4px;
  font-size: 0.62rem; font-weight: 800; text-transform: uppercase; letter-spacing: 1.1px;
  color: var(--accent-cyan);
}
.info-pop b { font-weight: 700; color: var(--text-main); }
.info-pop-x {
  position: absolute; top: 8px; right: 9px;
  width: 24px; height: 24px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: 0; border-radius: 6px;
  color: var(--text-muted); font-size: 17px; line-height: 1; cursor: pointer;
}
.info-pop-x:hover { background: rgba(18, 42, 78, 0.07); color: var(--text-main); }
.info-pop-x:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 1px; }
@media (prefers-reduced-motion: reduce) { .info-pop { transition: none; } }

/* ===========================================================================
   GLOBAL UNDO PILL  (undo.js)
   ---------------------------------------------------------------------------
   Bottom-left is the one fixed corner nothing else claims: #dashboard-back-btn
   sits mid-left, #global-footer-bar bottom-centre, #pm-toast-root bottom-right.

   NOTHING HERE MAY RESIZE ON :hover. The note above #dashboard-back-btn spells
   out why — a floating pill that grows under the pointer pushes its own edge
   out from under the cursor, which un-hovers it, which shrinks it back, and the
   result is a flicker loop. This control lives in the same corner of the same
   viewport and obeys the same rule: hover changes colour and nudges 1px, and
   that is all. The pill's width does change when its label changes, but that is
   driven by application state, never by the pointer.

   z-index 2400 puts it over the footer (70) and the back button (60) and under
   the modal (2500), the drawer (2600), the explanation popover (3000) and the
   toast layer. An action taken inside a modal should not leave an undo control
   floating on top of the modal that produced it.
   =========================================================================== */
.tb-undo {
  position: fixed; left: 18px; bottom: 20px; z-index: 2400;
  display: flex; align-items: center; gap: 4px;
  padding: 4px;
  background: linear-gradient(180deg, rgba(255,255,255,0.96), rgba(246,249,252,0.94));
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(10,126,164,0.30);
  border-radius: var(--radius-pill);
  box-shadow: 0 10px 30px rgba(20,40,80,0.20), 0 2px 6px rgba(20,40,80,0.10);
}
.tb-undo[hidden] { display: none; }

.tb-undo-btn {
  display: inline-flex; align-items: center; gap: 8px;
  height: 34px; padding: 0 15px 0 12px;
  background: transparent; border: 0; border-radius: var(--radius-pill);
  color: var(--text-main);
  font: inherit; font-size: 0.82rem; font-weight: 800; letter-spacing: 0.1px;
  line-height: 1; white-space: nowrap; cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.tb-undo-ic {
  /* A text glyph, deliberately not a Font Awesome <i> — see undo.js's build().
     Sized and nudged so the hooked arrow sits on the label's optical centre. */
  font-size: 1.05rem; line-height: 1; color: var(--accent-cyan);
  transform: translateY(-1px); flex-shrink: 0;
}
.tb-undo-btn:hover, .tb-undo-btn:focus-visible {
  background: rgba(10,126,164,0.10); outline: none; transform: translateX(1px);
}
.tb-undo-btn:focus-visible { box-shadow: 0 0 0 2px var(--accent-cyan); }
.tb-undo-btn:active { transform: translateX(0); }

.tb-undo-redo {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0;
  background: transparent; border: 0; border-left: 1px solid var(--border-color);
  border-radius: 0 var(--radius-pill) var(--radius-pill) 0;
  color: var(--accent-cyan);
  font: inherit; font-size: 1.05rem; line-height: 1; cursor: pointer;
  transition: background-color 0.15s ease;
}
.tb-undo-redo[hidden] { display: none; }
.tb-undo-redo:hover, .tb-undo-redo:focus-visible { background: rgba(10,126,164,0.10); outline: none; }
.tb-undo-redo:focus-visible { box-shadow: 0 0 0 2px var(--accent-cyan); }

/* Redo still available but nothing left to undo: keep the control reachable,
   stop it advertising an action it cannot perform. */
.tb-undo.is-empty .tb-undo-btn { opacity: 0.45; pointer-events: none; }

@media (max-width: 680px) {
  /* Stacks above #dashboard-back-btn (bottom 78px, 38px tall), which itself
     sits above the floating dock at bottom 20px. */
  .tb-undo { left: 12px; bottom: 124px; }
  .tb-undo-btn { height: 32px; padding: 0 13px 0 11px; font-size: 0.8rem; }
  .tb-undo-redo { width: 32px; height: 32px; }
}
@media (prefers-reduced-motion: reduce) {
  .tb-undo-btn, .tb-undo-redo { transition: none; }
  .tb-undo-btn:hover, .tb-undo-btn:focus-visible, .tb-undo-btn:active { transform: none; }
}

/* ════════════════════════════════════════════════════════════════════
   PASS: STRUCTURE & HIERARCHY (website equivalents of the deck fixes)
   Three additions, in the order the audit ranked them:
     1. .empty-state.es-shaped  — shaped skeletons, one per view, so the
        four "nothing here yet" screens stop being the same screen.
     2. .tb-hero                — the dark emphasis surface. Savings Model
        proved it works; it lived in the ROI iframe and nowhere else, so
        the app had no top hierarchy tier. Now it has one, used 3×.
     3. .grid-fill-last         — kills the lone card that drops to row 2
        on device-pulse / leaderboard / data-blog. (A dashboard-home
        feature grid was tried here too and reverted — see section 3.)
   ════════════════════════════════════════════════════════════════════ */

/* ──── 1. SHAPED EMPTY STATES ──────────────────────────────────────
   The old .empty-state is a centered glyph + two lines, 64px of padding,
   used verbatim by live-map, liquidity, people and locations — which is
   why those four views were indistinguishable. A shaped skeleton says
   what the view WILL look like once it has data, and the reduced padding
   fixes the other half of the problem: an empty page should not be the
   tallest page in the product. */
.empty-state.es-shaped {
  padding: 26px 22px 24px;
  text-align: left;
  display: grid;
  gap: 16px;
  justify-items: stretch;
}
.empty-state.es-shaped .es-copy { text-align: center; }
.empty-state.es-shaped i {
  font-size: 1.5rem;
  opacity: 0.34;
  margin-bottom: 8px;
}
/* the skeleton itself — never interactive, never announced */
.es-skel {
  border: 1px dashed var(--border-color);
  border-radius: 12px;
  background: rgba(18, 42, 78, 0.018);
  padding: 14px;
  opacity: 0.85;
}
.es-bar {
  background: linear-gradient(90deg, rgba(18,42,78,0.09), rgba(18,42,78,0.045));
  border-radius: 5px;
  height: 9px;
}
.es-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 2px;
}
.es-row + .es-row { border-top: 1px solid var(--border-color); }
.es-dot {
  width: 26px; height: 26px; border-radius: 50%;
  background: rgba(18,42,78,0.07); flex: none;
}
.es-sq { width: 26px; height: 26px; border-radius: 7px; background: rgba(18,42,78,0.07); flex: none; }
.es-lines { flex: 1; display: grid; gap: 6px; }

/* live map: a dimmed region outline with ghost pins, so the empty state
   already reads as a map rather than as a generic card */
.es-map { position: relative; height: 200px; overflow: hidden; }
.es-map svg { width: 100%; height: 100%; display: block; }

/* hardware reclaim: two columns with an arrow between them — the whole
   point of the view stated visually before any data exists */
.es-cols {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 14px;
}
.es-cols .es-arrow { color: var(--text-muted); opacity: 0.4; font-size: 1.05rem; }
.es-col-label {
  font-size: var(--fs-micro, 0.75rem);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  opacity: 0.7;
  margin-bottom: 8px;
}
@media (max-width: 640px) {
  .es-cols { grid-template-columns: 1fr; }
  .es-cols .es-arrow { transform: rotate(90deg); justify-self: center; }
}

/* ──── 2. THE DARK HERO ────────────────────────────────────────────
   One emphasis tier above the white card. Deliberately restrained: it
   carries ONE number. If two heroes ever appear on one view, neither is
   a hero. Uses the existing dark-canvas tokens so it matches the landing
   surface and the Savings Model hero it was derived from. */
.tb-hero {
  background: radial-gradient(120% 140% at 12% -20%,
              var(--dark-canvas-1) 0%, var(--dark-canvas-2) 58%, var(--dark-ink) 100%);
  border-radius: var(--radius-lg);
  padding: 22px 26px;
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  color: #fff;
}
.tb-hero-main { display: flex; align-items: center; gap: 18px; min-width: 0; }
.tb-hero-mark {
  width: 46px; height: 46px; flex: none;
  border-radius: 13px;
  display: grid; place-items: center;
  font-size: 1.15rem;
  background: rgba(63, 176, 214, 0.16);
  border: 1px solid rgba(63, 176, 214, 0.32);
  color: var(--on-dark-cyan-hi, #8fd8ef);
}
.tb-hero-figure {
  font-size: 2.1rem;
  font-weight: 800;
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.tb-hero-label {
  font-size: 0.86rem;
  color: var(--on-dark-cyan-hi, #8fd8ef);
  opacity: 0.82;
  margin-top: 3px;
}
/* the right-hand rail: two or three supporting figures, never more —
   past three they compete with the hero figure and the tier collapses */
.tb-hero-rail { display: flex; gap: 28px; flex-wrap: wrap; }
.tb-hero-stat { min-width: 74px; }
.tb-hero-stat b {
  display: block;
  font-size: 1.15rem;
  font-weight: 700;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.tb-hero-stat span {
  font-size: var(--fs-micro, 0.75rem);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgba(255,255,255,0.56);
}
.tb-hero.is-alert .tb-hero-mark {
  background: rgba(224, 122, 95, 0.18);
  border-color: rgba(224, 122, 95, 0.36);
  color: #f0b8a6;
}
@media (max-width: 700px) {
  .tb-hero { padding: 18px; }
  .tb-hero-figure { font-size: 1.7rem; }
  .tb-hero-rail { gap: 18px; }
}

/* ──── 3. GRID RHYTHM ──────────────────────────────────────────────
   A feature-grid (2fr/1fr) and a per-tile metric footer were both tried
   on the dashboard home and both REVERTED — recorded here so neither is
   reintroduced. tilestats.js already gives every nav tile an honest
   metric AND derives tile height from φ applied to the tile's measured
   width, so a footer duplicated the metric and grid-column:span
   desynchronised the row's heights and orphaned the last tile. Emphasis
   on the home row comes from the Fulfillment tile's true-red accent, not
   from width. What survives here is only the orphan fix below. */

/* auto-fit grids drop a single card onto its own row and it reads as a
   mistake. Let the last child span the leftover tracks instead. */
.grid-fill-last > *:last-child:nth-child(3n + 1) { grid-column: 1 / -1; }
.grid-fill-last > *:last-child:nth-child(4n + 1) { grid-column: 1 / -1; }
