/* =========================================================================
   AInnect dashboard — SHELL LAYER
   Tokens, reset, background, chrome (nav / menu / dots), hero + orb card.
   Pane-level layout lives in deck.css. No selector is defined in both files.
   ========================================================================= */

/* ---------- design tokens ---------- */
:root {
  color-scheme: light;
  /* TEXT — three weights, all verified >= 4.5:1 (WCAG AA body text) against
     every surface below, in BOTH themes. Never colour text with the --line-*
     tokens; they are decoration and fail contrast by design. */
  --text-1:   #0d1117;
  --text-2:   #2c343f;
  --text-3:   #444e59;

  --ink:      #0d1117;
  --line:        rgba(13, 17, 23, 0.10);
  --line-strong: rgba(13, 17, 23, 0.42);
  --ink-12:   rgba(13, 17, 23, 0.12);
  --ink-08:   rgba(13, 17, 23, 0.08);
  --ink-05:   rgba(13, 17, 23, 0.05);

  --pos:      #0a5c39;
  --neg:      #8f1a10;
  --link:     #4c1d95;

  --page:     #eef1f4;
  --scrim:    rgba(245, 247, 249, 0.62);
  --wash:     238, 241, 244;          /* hero copy wash, as an rgb triplet */
  --orb-opacity: 1;

  --glass-1:  rgba(255, 255, 255, 0.30);
  --glass-2:  rgba(255, 255, 255, 0.46);
  --glass-3:  rgba(255, 255, 255, 0.66);
  --glass-hi: rgba(255, 255, 255, 0.45);
  --frost:    rgba(255, 255, 255, 0.34);
  --frost-strong: rgba(255, 255, 255, 0.62);   /* surfaces over the raw orb */

  /* spacing scale (4px base) */
  --s-1: 0.25rem; --s-2: 0.5rem;  --s-3: 0.75rem; --s-4: 1rem;
  --s-5: 1.25rem; --s-6: 1.5rem;  --s-7: 2rem;    --s-8: 3rem;

  /* radii */
  --r-sm: 12px; --r-md: 16px; --r-lg: 22px; --r-xl: 30px; --r-orb: 48px;
  --r-pill: 999px;

  /* Type scale. Nothing below 12px: the previous floor was 10.9px, which is
     under the practical minimum for body-adjacent text on the web. */
  --fs-micro: 0.88rem;  /* 14.1px */
  --fs-kick:  0.92rem;  /* 14.7px */
  --fs-xs:    1.00rem;  /* 16.0px */
  --fs-sm:    1.07rem;  /* 17.1px */
  --fs-md:    1.15rem;  /* 18.4px */
  --fs-lg:    1.30rem;  /* 20.8px */
  --fs-title: 1.9rem;
  --fs-hero:  2.5rem;

  /* elevation */
  --sh-tile: 0 4px 18px -10px rgba(20, 30, 40, 0.28);
  --sh-pane: 0 12px 40px -18px rgba(20, 30, 40, 0.30);
  --sh-inset: inset 0 1.5px 2px rgba(255, 255, 255, 0.40),
              inset 0 -1px 2px rgba(0, 0, 0, 0.06);

  /* motion */
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* content measure — keeps wide screens from stranding data at the edges */
  --measure: 1560px;
}

/* ---------- dark theme ----------
   Same token names, different values, so no component needs to know which
   theme it is in. The orb is a bright clip, so it is dimmed here rather than
   left to glare against a dark page. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --text-1:   #f4f7fa;
  --text-2:   #ccd5df;
  --text-3:   #9dabb9;

  --ink:      #f4f7fa;
  --line:        rgba(255, 255, 255, 0.12);
  --line-strong: rgba(255, 255, 255, 0.38);
  --ink-12:   rgba(255, 255, 255, 0.12);
  --ink-08:   rgba(255, 255, 255, 0.09);
  --ink-05:   rgba(255, 255, 255, 0.06);

  --pos:      #5fd39b;
  --neg:      #ff8f85;
  --link:     #c3b0f5;

  --page:     #0d1014;
  --scrim:    rgba(13, 16, 20, 0.74);
  --wash:     13, 16, 20;
  --orb-opacity: 0.72;

  /* glass fills sit on the page's blue-black family, not neutral grey: the
     frosts are a dark tint OVER the bright orb, so a neutral rgb(13,16,20)
     read as a grey slab against the deep blue field around it (2026-09-03).
     The +violet lean (r 13→15, the AInnect accent) ties the glass to the
     orb's ambient glow. Keep the same family as --page/--wash. The glass-*
     lifts are TINTED (cool blue-white, not #fff): white alpha over the bright
     orb pushed the tiles to neutral grey (lum ~40 vs page ~18) — the exact
     "background is dark blue but the glass is grey" complaint. rgb(205,215,255)
     keeps the highlight but carries the page's hue into every card. */
  --glass-1:  rgba(196, 206, 250, 0.05);
  --glass-2:  rgba(196, 206, 250, 0.09);
  --glass-3:  rgba(196, 206, 250, 0.15);
  --glass-hi: rgba(196, 206, 250, 0.16);
  --frost:    rgba(12, 15, 26, 0.62);
  --frost-strong: rgba(12, 15, 26, 0.82);

  --sh-tile: 0 4px 18px -10px rgba(0, 0, 0, 0.7);
  --sh-pane: 0 12px 40px -18px rgba(0, 0, 0, 0.8);
  --sh-inset: inset 0 1.5px 2px rgba(255, 255, 255, 0.10),
              inset 0 -1px 2px rgba(0, 0, 0, 0.35);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --text-1: #f4f7fa; --text-2: #ccd5df; --text-3: #9dabb9;
    --ink: #f4f7fa;
    --line: rgba(255,255,255,.12); --line-strong: rgba(255,255,255,.38);
    --ink-12: rgba(255,255,255,.12); --ink-08: rgba(255,255,255,.09); --ink-05: rgba(255,255,255,.06);
    --pos: #5fd39b; --neg: #ff8f85; --link: #c3b0f5;
    --page: #0d1014; --scrim: rgba(13,16,20,.74); --wash: 13,16,20; --orb-opacity: .72;
    --glass-1: rgba(196,206,250,.05); --glass-2: rgba(196,206,250,.09);
    --glass-3: rgba(196,206,250,.15); --glass-hi: rgba(196,206,250,.16);
    --frost: rgba(12,15,26,.62); --frost-strong: rgba(12,15,26,.82);
    --sh-tile: 0 4px 18px -10px rgba(0,0,0,.7);
    --sh-pane: 0 12px 40px -18px rgba(0,0,0,.8);
    --sh-inset: inset 0 1.5px 2px rgba(255,255,255,.10), inset 0 -1px 2px rgba(0,0,0,.35);
  }
}

/* ---------- font (self-hosted 2026-09-02; replaces db.onlinewebfonts.com) ---------- */
@font-face {
  font-family: 'Helvetica Neue Light';
  src: url('./fonts/helvetica-neue-light.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

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

html, body {
  width: 100%; height: 100%;
  overflow: hidden;
  background: var(--page);
  color: var(--text-1);
  font-family: 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon { flex: none; }

/* Visible keyboard focus. Every interactive element gets one ring, one style. */
:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* ---------- background video ---------- */
/* The raw clip is a bubble on a BRIGHT near-white studio backdrop (bg rgb
   ~174). At 100% width that white field itself paints a big bright rectangle
   behind the theme gradient — dark mode reads it as a glowing "black box"
   panel, light mode as a flat washed tile over the vignette. The elliptical
   mask keeps only the sphere and dissolves the studio field into the page
   before the viewport edge, so the orb floats in the page's own gradient
   (which .bg-vignette / --wash provide and recolour per theme). Mask tuned
   on the real clip: bubble centre (50.3%, 50.7%), rx 0.21 ry 0.385 of frame. */
.bg-video {
  position: fixed; top: 0; left: 0;
  display: block; width: 100%; height: 100%;
  object-fit: cover;
  z-index: 0;
  pointer-events: none;
  opacity: var(--orb-opacity);
  transform-origin: 50% 50%;
  will-change: transform;
  -webkit-mask-image: radial-gradient(ellipse 32% 50% at 50.2% 50.7%,
              #000 74%, transparent 100%);
  mask-image: radial-gradient(ellipse 32% 50% at 50.2% 50.7%,
              #000 74%, transparent 100%);
}

/* The gradient that surrounds the orb: transparent over the orb itself, full
   page colour by the frame, so there is no boundary anywhere to read as a box. */
.bg-vignette {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(ellipse 60% 52% at 50% 46%,
              rgba(var(--wash), 0) 0%,
              rgba(var(--wash), 0.06) 34%,
              rgba(var(--wash), 0.26) 52%,
              rgba(var(--wash), 0.55) 68%,
              rgba(var(--wash), 0.82) 83%,
              rgba(var(--wash), 0.96) 93%,
              rgba(var(--wash), 1) 100%);
}

/* Dark mode only: a pure #0d1014 field around the orb reads as "really black".
   A soft violet-tinted glow layer (AInnect accent #8b5cf6 at low alpha, widest
   at the orb, fading before the frame) gives the darkness some depth; the
   regular --wash vignette above still does the edge fade on top of it. Light
   mode is deliberately untouched. Revert = delete this block + the mirrored
   @media block below. The dark scope is DOUBLE — explicit attr AND the OS-dark
   fallback (ui.js leaves the attr off until the user picks a theme, so
   `[data-theme="dark"]` alone would miss most dark-mode visitors). */
:root[data-theme="dark"] .bg-vignette { background:
    radial-gradient(ellipse 88% 78% at 50% 48%,
      rgba(139, 92, 246, 0.20) 0%,
      rgba(109, 70, 220, 0.13) 38%,
      rgba(60, 42, 120, 0.10) 62%,
      rgba(20, 16, 40, 0) 85%),
    radial-gradient(ellipse 60% 52% at 50% 46%,
      rgba(var(--wash), 0) 0%,
      rgba(var(--wash), 0.06) 34%,
      rgba(var(--wash), 0.26) 52%,
      rgba(var(--wash), 0.55) 68%,
      rgba(var(--wash), 0.82) 83%,
      rgba(var(--wash), 0.96) 93%,
      rgba(var(--wash), 1) 100%);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .bg-vignette { background:
      radial-gradient(ellipse 88% 78% at 50% 48%,
        rgba(139, 92, 246, 0.20) 0%,
        rgba(109, 70, 220, 0.13) 38%,
        rgba(60, 42, 120, 0.10) 62%,
        rgba(20, 16, 40, 0) 85%),
      radial-gradient(ellipse 60% 52% at 50% 46%,
        rgba(var(--wash), 0) 0%,
        rgba(var(--wash), 0.06) 34%,
        rgba(var(--wash), 0.26) 52%,
        rgba(var(--wash), 0.55) 68%,
        rgba(var(--wash), 0.82) 83%,
        rgba(var(--wash), 0.96) 93%,
        rgba(var(--wash), 1) 100%);
  }
}

/* Orb paused. The clip and the refraction loop stay out. A quiet centre
   wash takes the video's place: violet on the dark field, lavender on light. */
html[data-orb="off"] .bg-video { display: none; }
html[data-orb="off"] .bg-vignette,
html[data-orb="off"][data-theme="light"] .bg-vignette {
  background:
    radial-gradient(ellipse 74% 66% at 50% 46%,
      rgba(139, 92, 246, 0.26) 0%,
      rgba(167, 139, 250, 0.14) 36%,
      rgba(196, 181, 253, 0.05) 60%,
      rgba(238, 241, 244, 0) 80%),
    var(--page);
}
html[data-orb="off"][data-theme="dark"] .bg-vignette {
  background:
    radial-gradient(ellipse 88% 78% at 50% 48%,
      rgba(139, 92, 246, 0.30) 0%,
      rgba(109, 70, 220, 0.16) 38%,
      rgba(60, 42, 120, 0.10) 62%,
      rgba(20, 16, 40, 0) 85%),
    var(--page);
}
@media (prefers-color-scheme: dark) {
  html[data-orb="off"]:not([data-theme="light"]) .bg-vignette {
    background:
      radial-gradient(ellipse 88% 78% at 50% 48%,
        rgba(139, 92, 246, 0.30) 0%,
        rgba(109, 70, 220, 0.16) 38%,
        rgba(60, 42, 120, 0.10) 62%,
        rgba(20, 16, 40, 0) 85%),
      var(--page);
  }
}
html[data-orb="off"] .lede::before { display: none; }
html[data-orb="off"] .card,
html[data-orb="off"] .tickerbar {
  background: var(--frost-strong);
}

/* Portrait stacks the copy and the mood card straight over the orb, where the
   desktop layout keeps them side by side. Lifting the orb toward the top and
   easing it back keeps the stacked content legible. */
@media (max-width: 767px) {
  .bg-video {
    opacity: 0.55;
  }
  /* portrait lifts the orb up the screen, so the vignette's clear centre
     follows it rather than sitting behind the stacked card */
  .bg-vignette {
    background: radial-gradient(ellipse 88% 44% at 50% 30%,
                rgba(var(--wash), 0) 0%,
                rgba(var(--wash), 0.04) 38%,
                rgba(var(--wash), 0.20) 55%,
                rgba(var(--wash), 0.48) 70%,
                rgba(var(--wash), 0.78) 85%,
                rgba(var(--wash), 1) 100%);
  }
}

.glass-defs { position: absolute; width: 0; height: 0; pointer-events: none; }

/* ---------- editorial vertical rules (>=768px) ---------- */
.rule { position: absolute; top: 0; bottom: 0; display: none; flex-direction: column; align-items: center; }
.rule--left  { left: var(--s-5); }
.rule--right { right: var(--s-5); }
.rule__seg { width: 1px; background: var(--text-3); }
.rule__seg--end { height: 15%; }
.rule__seg--mid { flex: 1 1 0%; }
.rule__plus { font-size: var(--fs-xs); line-height: 1; color: var(--text-2); padding: var(--s-1) 0; }
@media (min-width: 768px) { .rule { display: flex; } }

/* ---------- top nav ---------- */
/* Fixed, not per-pane: it used to live inside the hero, so once you swiped
   into a section there was no way back to the top level except swiping. */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s-5);
}
.nav__item {
  display: inline-flex; align-items: center; gap: 0.625rem;
  color: var(--text-1); background: none; border: 0; font: inherit;
  text-decoration: none; cursor: pointer; pointer-events: auto;
  transition: opacity 300ms;
}
.nav__item:hover { opacity: 0.6; }
.nav__label { font-size: 0.875rem; line-height: 1.25rem; letter-spacing: 0.025em; }
.nav__label--menu { display: none; }
.nav::before {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(to bottom, var(--page) 20%, transparent);
  opacity: 0.92;
}
.nav__home { gap: var(--s-3); }
.nav__wordmark {
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: -0.01em; color: var(--text-1);
}
.nav__section {
  font-size: var(--fs-micro); color: var(--text-2);
  padding-left: var(--s-3); border-left: 1px solid var(--line);
}
.nav__section:empty { display: none; }
@media (max-width: 639px) { .nav__wordmark { display: none; } .nav__section { border-left: 0; padding-left: 0; } }

.nav__right { display: flex; align-items: center; gap: var(--s-5); }
.nav__link { gap: 7px; }
.nav__badge {
  padding: 1px 7px; border-radius: var(--r-pill);
  background: var(--pos); color: var(--page);
  font-size: var(--fs-micro); font-weight: 700; font-variant-numeric: tabular-nums;
}
@media (max-width: 639px) { .nav__link { display: none; } }
.nav__icon { padding: 6px; border-radius: var(--r-pill); }
.nav__icon:hover { opacity: 1; background: var(--glass-2); }
/* one icon per theme; the other is removed from the box entirely */
.icon--moon { display: none; }
:root[data-theme="dark"] .icon--sun { display: none; }
:root[data-theme="dark"] .icon--moon { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .icon--sun { display: none; }
  :root:not([data-theme="light"]) .icon--moon { display: block; }
  :root[data-theme="light"] .icon--sun { display: block; }
}
.nav__dot { width: 8px; height: 8px; border-radius: var(--r-pill); background: var(--ink); }
@media (min-width: 640px) { .nav { padding: var(--s-5) var(--s-6); } .nav__label--menu { display: inline; } }
@media (min-width: 768px) { .nav { padding: var(--s-6) var(--s-8); } }

/* ---------- hero (pane 1) type ---------- */
.lede { position: relative; z-index: 1; max-width: 27rem; pointer-events: auto; }
/* the orb drifts behind this column; a soft wash keeps the copy legible
   without drawing a visible panel edge around it */
.lede::before {
  content: ''; position: absolute; z-index: -1;
  inset: -6rem -12rem -6rem -14rem;
  background: radial-gradient(ellipse 52% 42% at 30% 50%,
              rgba(var(--wash), 0.96) 0%,
              rgba(var(--wash), 0.86) 42%,
              rgba(var(--wash), 0.45) 66%,
              rgba(var(--wash), 0) 84%);
  pointer-events: none;
}
.lede__kick {
  font-size: var(--fs-kick); text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--text-3);
}
.lede__title {
  margin-top: var(--s-2);
  font-size: 1.6rem; font-weight: 300; line-height: 1.2;
  letter-spacing: -0.025em; color: var(--text-1);
}
.lede__body {
  margin-top: var(--s-3); max-width: 300px;
  font-size: var(--fs-sm); line-height: 1.625; color: var(--text-2);
}
@media (min-width: 640px)  { .lede__title { font-size: 1.875rem; } }
@media (min-width: 768px)  { .lede__title { font-size: 2rem; } .lede__body { margin-top: var(--s-4); font-size: 0.875rem; } }
@media (min-width: 1024px) {
  .lede { width: min(32rem, 46%); max-width: none; }
  .lede__body { max-width: 28rem; }
  .lede__title { font-size: var(--fs-hero); }
}

/* ---------- lead story ---------- */
.lead {
  display: flex; flex-direction: column; gap: var(--s-1);
  margin-top: var(--s-5); padding: var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--ink-08);
  border-left: 3px solid var(--link);
  background: var(--glass-3);
  text-decoration: none; color: var(--text-1);
  transition: background 220ms, transform 220ms var(--ease), box-shadow 220ms;
}
.lead:hover {
  background: var(--frost-strong);
  transform: translateX(3px);
  box-shadow: var(--sh-tile);
}
.lead__kick {
  font-size: var(--fs-micro); text-transform: uppercase;
  letter-spacing: 0.1em; color: var(--link); font-weight: 700;
}
.lead__title {
  font-size: 1.08rem; font-weight: 600; line-height: 1.35; letter-spacing: -0.012em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.lead__meta {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  margin-top: var(--s-1);
  font-size: var(--fs-micro); color: var(--text-3);
}
.lead__go { opacity: 0; transform: translateX(-4px); transition: opacity 220ms, transform 220ms; }
.lead:hover .lead__go { opacity: 1; transform: translateX(0); }

/* ---------- chamfered CTA ---------- */
.chamfer {
  position: relative; display: flex; align-items: center; justify-content: space-between;
  width: 220px; height: 44px; margin-top: var(--s-6); padding: 0 var(--s-5);
  color: var(--text-1); background: none; border: 0; font: inherit;
  text-decoration: none; cursor: pointer; pointer-events: auto;
  transition: opacity 300ms;
}
.chamfer__glass, .chamfer__outline, .chamfer__label, .chamfer .icon {
  transition: background 220ms, border-color 220ms, color 220ms, transform 220ms var(--ease);
}
.chamfer:hover .chamfer__glass { background: var(--text-1); border-color: var(--text-1); }
.chamfer:hover .chamfer__outline { color: var(--text-1); }
.chamfer:hover .chamfer__label,
.chamfer:hover .icon { color: var(--page); }
/* label sits ON the inverted fill, so it takes the opposite surface token —
   hardcoding #fff broke in dark theme (white on --text-1's near-white fill) */
.chamfer:hover .icon { transform: translateX(4px); }
.chamfer:active { transform: scale(0.985); }
.chamfer__glass {
  position: absolute; inset: 0;
  background: var(--glass-3);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--line-strong);
  clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
}
.chamfer__outline { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.chamfer__label { position: relative; font-size: var(--fs-xs); letter-spacing: 0.025em; }
.chamfer .icon { position: relative; }
@media (min-width: 640px) {
  .chamfer { width: 260px; height: 48px; padding: 0 var(--s-6); }
  .chamfer__label { font-size: 0.875rem; }
  /* at rest the outline alone carries the shape; hover fills it in */
  .chamfer__glass { background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; border-color: transparent; }
}
@media (min-width: 768px) { .chamfer { margin-top: var(--s-7); } }

/* ---------- orb card (refracted video window) ---------- */
.card {
  position: relative; flex: none;
  display: flex; flex-direction: column; justify-content: space-between;
  width: 340px; max-width: 100%;
  /* Hug the brief. A fixed height clipped the last rows on an iPad, and the
     pane cannot scroll, so those rows never came into view. */
  height: auto; max-height: 100%;
  transition: width 300ms var(--ease);
  padding: var(--s-7);
  border-radius: var(--r-orb);
  overflow: hidden;
  background: transparent;
  border: 1px solid var(--line-strong);
  pointer-events: auto;
  animation: fade-slide-up-card 900ms var(--ease-out) both;
}
@keyframes fade-slide-up-card {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (min-width: 1024px) { .card { width: 480px; } }
@media (min-width: 1280px) { .card { width: 560px; } }
@media (min-width: 1600px) { .card { width: 620px; } }

/* ---------- shared liquid-glass surface ----------
   glass-card.js prepends .glass-dup (the refracted duplicate) and .glass-frost
   to every [data-glass] element. Real content is lifted above both. */
[data-glass] { position: relative; overflow: hidden; isolation: isolate; }
[data-glass] > .glass-dup { position: absolute; left: 0; top: 0; z-index: 0; overflow: hidden; pointer-events: none; }
[data-glass] > .glass-dup > canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  filter: url(#liquid-glass-refraction);
}
/* ---- lite tier: the WebKit / low-power substitute ----
   The SVG refraction filter above is what makes an iPad Safari deck render at
   ~1 fps during a swipe (measured; the filter raster is the entire cost, not the
   canvas draw). This replaces it with a plain blur of the same duplicate: the
   colour, composition and edge softness all survive, only the per-pixel
   displacement is gone. glass-card.js sets data-glass-lite on the root for
   touch screens at >=1.5x (including iPad, which reports pointer: fine), or any
   device that fails its frame probe.
   Scope note: this must NOT be written as :not([data-theme]) — that matches
   both themes. It keys off a different attribute entirely, so it is safe. */
/* The attribute is set before paint from a head script (iPadOS reports a fine
   primary pointer, so a (pointer: coarse) query never matches it). The media
   query covers the same devices if that script hasn't run. */
@media (any-pointer: coarse) and (min-resolution: 1.5dppx) {
  [data-glass] > .glass-dup > canvas {
    filter: blur(26px) saturate(1.05);
    transform: scale(1.06);
  }
}
:root[data-glass-lite] [data-glass] > .glass-dup > canvas {
  filter: blur(26px) saturate(1.05);
  transform: scale(1.06);   /* hides the blur's soft edge inside the clip */
}
[data-glass] > .glass-frost {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  /* 62% (was 34%, then 52%): behind this frost sits .glass-dup — a live redraw of
     the BRIGHT orb at 1.18x zoom. At low alpha the bright video washed the card to
     a grey slab (lum ~82) visibly lighter and greyer than the tinted tiles
     (lum ~49) beside it. 62% + the blue-family tint lands the card in the same
     family as the page field; the refraction still reads at the edges. */
  background: var(--frost);
  box-shadow: var(--sh-inset);
  transition: background 400ms, filter 400ms;
}
[data-glass] > *:not(.glass-dup):not(.glass-frost) { position: relative; z-index: 2; }
.card.group:hover > .glass-frost { filter: brightness(1.06); }

.card__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4);
  padding-bottom: var(--s-3); border-bottom: 1px solid var(--line);
}
.card__title { font-size: var(--fs-lg); font-weight: 500; letter-spacing: -0.025em; }
.card__index { font-size: var(--fs-xs); color: var(--text-1); font-variant-numeric: tabular-nums; }
.card__body { display: flex; flex-direction: column; gap: var(--s-3); margin-top: var(--s-4); }
.card__loading { font-size: var(--fs-xs); color: var(--text-2); }
@media (min-width: 768px) {
  .card__head { padding-bottom: var(--s-4); }
  .card__body { gap: var(--s-4); margin-top: var(--s-5); }
}

/* Portrait stacks nav + copy + lead story + CTA + the mood card into one
   viewport. The standfirst repeats what the lead story already says and the
   sparkline note is supplementary, so both give way before the card does. */
@media (max-width: 767px) {
  .card { padding: var(--s-5); }
  .card__spark { display: none; }
  .lede__body { display: none; }
  .card { height: 280px; }
}

/* ---------- daily brief (hero card) ----------
   The card used to restate the mood chart that section 02 draws in full and
   the ticker now carries too. It answers different questions instead, as
   label/value pairs — the earlier stacked version read as loose fragments. */
.brief { display: flex; flex-direction: column; gap: var(--s-4); }

.brief__lede {
  display: flex; align-items: baseline; gap: var(--s-3);
  padding-bottom: var(--s-3); border-bottom: 1px solid var(--line);
}
.brief__num {
  font-size: 2.1rem; font-weight: 300; line-height: 1;
  letter-spacing: -0.03em; color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.brief__ledeText { font-size: var(--fs-sm); line-height: 1.4; color: var(--text-2); }

.brief__rows { display: flex; flex-direction: column; }
.brief__row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; gap: var(--s-2) var(--s-3);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}
.brief__row:last-child { border-bottom: 0; }
.brief__k {
  grid-column: 1; font-size: var(--fs-xs); color: var(--text-2);
}
.brief__name {
  grid-column: 1; font-size: var(--fs-md); font-weight: 600;
  color: var(--text-1); letter-spacing: -0.012em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.brief__val {
  grid-column: 2; grid-row: 1 / span 2; align-self: center;
  font-size: var(--fs-lg); font-weight: 700;
  font-variant-numeric: tabular-nums; color: var(--text-1);
}
.brief__val.up { color: var(--pos); }
.brief__val.down { color: var(--neg); }
a.brief__row:hover .brief__name { text-decoration: underline; }
.brief__why {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  padding: 0 0 var(--s-3);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-micro);
}

/* Portrait has room for the headline count and two rows once the lead story
   and CTA are stacked above. The scoring detail, the most-discussed row and
   the model row each have a full section of their own, so they give way here
   rather than clipping. These must sit after the base rules above — an
   earlier media query would lose the cascade to them. */
@media (max-width: 767px) {
  .brief { gap: var(--s-2); }
  .brief__num { font-size: 1.6rem; }
  .brief__lede { padding-bottom: var(--s-2); gap: var(--s-2); }
  .brief__ledeText { font-size: var(--fs-xs); }
  .brief__row { padding: var(--s-2) 0; }
  .brief__why,
  .brief__row--discussed,
  .brief__row--model,
  .brief__row--agents { display: none; }
  /* :last-child is a hidden row here, so the last VISIBLE row keeps its rule */
  .brief__rows > .brief__row:nth-child(2) { border-bottom: 0; }
}

/* ---------- trend chips (shared: orb card + mood pane) ---------- */
.trend {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: var(--fs-micro); font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.trend.up   { color: var(--pos); }
.trend.down { color: var(--neg); }
.trend.flat { color: var(--text-3); }

/* ---------- section dots ---------- */
.dots {
  position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 8px; z-index: 40;
}
/* base state was missing entirely — inactive dots rendered as grey squares */
.dot {
  width: 7px; height: 7px; padding: 0; border: 0;
  border-radius: var(--r-pill);
  background: var(--text-3);
  cursor: pointer; pointer-events: auto;
  transition: width 300ms var(--ease), background 300ms;
}
/* 7px is far under the 24px minimum touch target — extend the hit area with a
   transparent ::before so taps have room but the visual stays a small dot */
.dot::before {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 24px; height: 24px;
  transform: translate(-50%, -50%);
}
.dot { position: relative; }
.dot:hover { background: var(--text-1); }
.dot.is-active { width: 22px; background: var(--ink); }

/* ---------- slide-out menu ---------- */
.menu {
  /* above the fixed nav (z-index 60) — at 50 the nav painted over the panel
     and its close button was unclickable */
  position: fixed; inset: 0; z-index: 70;
  visibility: hidden; pointer-events: none;
  transition: visibility 0s linear 500ms;
}
.menu.is-open { visibility: visible; pointer-events: auto; transition-delay: 0s; }
.menu__backdrop {
  position: absolute; inset: 0; background: rgba(0, 0, 0, 0.40);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  opacity: 0; transition: opacity 500ms;
}
.menu.is-open .menu__backdrop { opacity: 1; }
.menu__panel {
  position: absolute; top: 0; left: 0;
  display: flex; flex-direction: column;
  width: 100%; height: 100%; padding: var(--s-6) var(--s-7);
  background: var(--page);
  transform: translateX(-100%);
  transition: transform 500ms var(--ease-out);
}
.menu.is-open .menu__panel { transform: translateX(0); }
@media (min-width: 640px) { .menu__panel { width: 380px; padding: var(--s-6) 2.5rem; } }

.menu__close {
  display: inline-flex; align-items: center; gap: 0.625rem; align-self: flex-start;
  margin-bottom: var(--s-8); background: none; border: 0; font: inherit;
  font-size: 0.875rem; color: var(--text-1); cursor: pointer; transition: opacity 300ms;
}
.menu__close:hover { opacity: 0.6; }
.menu__nav { display: flex; flex-direction: column; }
.menu__legal {
  margin-top: auto; padding: var(--s-6) 0 var(--s-7);
  display: flex; gap: var(--s-5);
  border-top: 1px solid var(--line);
  opacity: 0; transform: translateY(20px);
  transition: opacity 500ms, transform 500ms;
}
.menu.is-open .menu__legal { opacity: 1; transform: translateY(0); transition-delay: 600ms; }
.menu__legal a {
  font-size: var(--fs-xs); color: var(--text-2); text-decoration: none;
}
.menu__legal a:hover { color: var(--text-1); text-decoration: underline; }
.menu__link {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s-4) 0; border-bottom: 1px solid var(--line);
  color: var(--text-1); text-decoration: none;
  opacity: 0; transform: translateY(20px);
  transition: opacity 500ms, transform 500ms;
}
.menu__linkText { font-size: var(--fs-title); font-weight: 300; letter-spacing: -0.025em; transition: transform 300ms; }
.menu__link:hover .menu__linkText { transform: translateX(8px); }
.menu__arrow { opacity: 0; transform: translateX(8px); transition: opacity 300ms, transform 300ms; }
.menu__link:hover .menu__arrow { opacity: 1; transform: translateX(0); }
@media (min-width: 640px) { .menu__linkText { font-size: 1.875rem; } }
.menu.is-open .menu__link { opacity: 1; transform: translateY(0); }
.menu.is-open .menu__link:nth-child(1) { transition-delay: 150ms; }
.menu.is-open .menu__link:nth-child(2) { transition-delay: 225ms; }
.menu.is-open .menu__link:nth-child(3) { transition-delay: 300ms; }
.menu.is-open .menu__link:nth-child(4) { transition-delay: 375ms; }
.menu.is-open .menu__link:nth-child(5) { transition-delay: 450ms; }
.menu.is-open .menu__link:nth-child(6) { transition-delay: 525ms; }
.menu.is-open 
/* ---------- reduced motion ----------
   Also stops the orb rAF loop + background video (see ui.js), not just transitions. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
