/* ============================================================
   Seeker Rewards Tracker - styles
   "Seeker field guide": warm paper background, ink text, Seeker
   green as the single functional accent, spectral wash reserved
   for the hero atmosphere.

   Tokens first; components below consume tokens only.
   Spacing uses a 4px base scale.
   ============================================================ */

:root {
  color-scheme: light;

  /* color */
  --bg: #f5f4ef;
  --surface: #ffffff;
  --surface-subtle: #efeee8;
  --ink: #11120f;
  --ink-2: #62645e;
  --border: rgba(17, 18, 15, 0.1);
  --border-strong: rgba(17, 18, 15, 0.22);
  --green: #3d987d;        /* tints, dots, large graphics only (3.1:1) */
  --green-dark: #246b59;   /* text, links, focus (6.4:1) */
  --green-darker: #1c5748;
  --green-tint: rgba(61, 152, 125, 0.1);
  --green-border: rgba(61, 152, 125, 0.28);
  --accent-fill: #246b59;        /* filled controls (active pill, primary btn) */
  --accent-fill-hover: #1c5748;
  --on-accent: #ffffff;          /* text on accent fill */
  --bar-bg: rgba(245, 244, 239, 0.93); /* translucent sticky bars */
  --backdrop: rgba(17, 18, 15, 0.45);
  --spectral: rgba(140, 124, 240, 0.12); /* hero atmosphere only */

  /* Hero light field: light through glass, kept far below the
     saturation where banding or neon starts. */
  --field-lavender: rgba(150, 138, 214, 0.16);
  --field-green: rgba(61, 152, 125, 0.10);
  --field-violet: rgba(168, 150, 232, 0.10);

  /* Navigation surface aliases. These map onto the existing palette
     rather than introducing isolated colours, so a theme change still
     only has to move the base tokens. */
  --surface-raised: var(--surface);
  --border-subtle: var(--border);
  --surface-active: var(--surface-subtle);
  --text-primary: var(--ink);
  --shadow-xs: 0 1px 2px rgba(17, 18, 15, 0.07);
  --nav-lift: rgba(17, 18, 15, 0.045);

  /* Season Guide only. The summary panel is a near-black block that
     sits inside the light page on purpose. Yellow is the guide's one
     highlight and is used in exactly one place: the panel's max-state
     values. Green remains the site accent everywhere else. */
  --panel-bg: #16170f;
  --panel-ink: #f7f5ec;
  --panel-ink-2: rgba(247, 245, 236, 0.7);
  --panel-line: rgba(247, 245, 236, 0.12); /* row dividers inside the panel */
  --panel-edge: rgba(247, 245, 236, 0.14); /* the panel's outer border */
  --guide-yellow: #f4c542;
  --warn: #965b06;         /* deadline approaching (5.0:1 on bg, 5.5:1 on surface) */
  --critical: #b3402a;     /* ending very soon */

  /* type */
  --fs-display: clamp(1.875rem, 4.5vw, 3rem);
  --fs-lead: clamp(1.25rem, 2.4vw, 1.5rem); /* view-level title, below the h1 */
  /* Season Guide only: the one view with an editorial heading scale
     of its own. Sits under the hero h1 and well above body copy. */
  --fs-guide-title: clamp(1.75rem, 4vw, 2.5rem);
  --fs-guide-h: clamp(1.625rem, 3.2vw, 2.25rem);
  --fs-title: 1.0625rem;
  --fs-body: 1rem;
  --fs-meta: 0.8125rem; /* 13px - never below 12px */

  /* space (4px scale) */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --sp-12: 48px;
  --sp-14: 56px;
  --sp-16: 64px;
  --sp-22: 88px;

  /* surface */
  --r-card: 20px;
  --r-ui: 12px;
  --shadow: 0 1px 2px rgba(17, 18, 15, 0.04), 0 6px 16px rgba(17, 18, 15, 0.05);
  --shadow-lift: 0 2px 4px rgba(17, 18, 15, 0.05), 0 10px 24px rgba(17, 18, 15, 0.07);

  --maxw: 1200px;
}

/* ---------- Dark theme ----------
   A faithful translation of the light editorial theme: same warm
   restraint, inverted. No gradients, no glow. All values verified
   WCAG AA against --bg and --surface (see git history for ratios). */
[data-theme="dark"] {
  color-scheme: dark;

  --bg: #161714;             /* deep warm near-black */
  --surface: #1f201b;
  --surface-subtle: #272823;
  --ink: #eceae2;            /* warm off-white (14.9:1) */
  --ink-2: #a6a79c;          /* muted warm gray (7.4:1) */
  --border: rgba(236, 234, 226, 0.12);
  --border-strong: rgba(236, 234, 226, 0.28);
  --green: #3d987d;
  --green-dark: #5db898;     /* text/links/focus on dark (7.5:1) */
  --green-darker: #7ccbad;
  --green-tint: rgba(61, 152, 125, 0.14);
  --green-border: rgba(93, 184, 152, 0.32);
  --accent-fill: #2b8064;    /* white on this: 4.8:1; vs bg: 3.75:1 */
  --accent-fill-hover: #256f57;
  --on-accent: #ffffff;
  --bar-bg: rgba(22, 23, 20, 0.92);
  --backdrop: rgba(0, 0, 0, 0.55);
  --spectral: rgba(140, 124, 240, 0.14);

  /* Reflected light on graphite, stronger than daylight because it is
     the only light in the scene. */
  --field-lavender: rgba(138, 124, 208, 0.20);
  --field-green: rgba(61, 152, 125, 0.14);
  --field-violet: rgba(150, 132, 224, 0.14);
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.45);
  /* Elevated navigation reads slightly warmer than the graphite hero */
  --surface-raised: #22231d;
  --nav-lift: rgba(0, 0, 0, 0.35);

  /* The page is already near-black here, so the panel drops below it
     and leans on its border to stay a distinct block. Cream and
     yellow are unchanged: they read on this surface in both themes. */
  --panel-bg: #0e0f0b;
  --panel-line: rgba(247, 245, 236, 0.16);
  /* On a near-black page the panel cannot separate by surface alone
     (1.07:1), so the edge does that work here. */
  --panel-edge: rgba(247, 245, 236, 0.26);
  --warn: #d9a05b;           /* 7.8:1 on bg */
  --critical: #e5735a;       /* 5.9:1 on bg */

  /* Shadows barely read on dark - the light borders carry separation */
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-lift: 0 2px 6px rgba(0, 0, 0, 0.35);
}

/* The Seeker wordmark is dark ink - invert it to a light wordmark on
   dark surfaces (monochrome logo, so a plain invert stays faithful) */
[data-theme="dark"] .footer-logo {
  filter: invert(1) hue-rotate(180deg);
}

/* At night the device is graphite against graphite, so it needs a rim
   of reflected light to keep its silhouette, plus a deeper pool
   beneath it instead of a daylight shadow. */
[data-theme="dark"] .hero-device {
  filter:
    drop-shadow(0 24px 40px rgba(0, 0, 0, 0.6))
    drop-shadow(-1px -1px 0 rgba(174, 158, 240, 0.5))
    drop-shadow(1px 0 0 rgba(120, 196, 168, 0.28));
}

/* Strongest illumination stays behind the device; the outer edges
   fall away earlier and softer so the glow never reaches the copy. */
[data-theme="dark"] .hero-stage::before {
  content: "";
  position: absolute;
  top: 6%;
  right: -6%;
  width: 92%;
  height: 54%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(150, 132, 224, 0.26), rgba(150, 132, 224, 0.09) 55%, transparent 82%);
  filter: blur(14px);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  font-size: var(--fs-body);
  font-weight: 400;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--green-dark); text-decoration: none; }
a:hover { text-decoration: underline; }

strong { font-weight: 600; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

/* Visible keyboard focus on every interactive element */
:focus-visible {
  outline: 2px solid var(--green-dark);
  outline-offset: 2px;
}

/* Controls with a dark green fill get a two-tone ring so the focus
   indicator reads against their own background as well */
.pill.active:focus-visible,
.btn-primary:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--green-dark);
}

/* Visually hidden, still announced by screen readers */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Scroll lock while the detail dialog is open. position:fixed (with
   the pre-lock scroll offset applied as top) is the only reliable way
   to stop iOS Safari scroll chaining; JS restores the position. */
.no-scroll {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
}

.wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--sp-5);
}

/* ---------- Hero ----------
   One device, controlled light, typography and whitespace. The light
   field is built from soft radial gradients at low opacity: light
   through glass, not a saturated gradient. Longhand padding only. */

.site-header {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding-top: var(--sp-8);
  padding-bottom: var(--sp-8);
  background-color: var(--bg);
  background-image:
    radial-gradient(52% 46% at 78% 86%, var(--field-lavender), transparent 72%),
    radial-gradient(46% 42% at 12% 8%, var(--field-green), transparent 70%),
    radial-gradient(30% 28% at 62% 22%, var(--field-violet), transparent 72%);
}

/* A stable mobile hero height keeps the device band in one place
   regardless of whether the status line wraps. */
/* The device dissolves into the hero at its foot rather than being
   cut dead by the navigation band. Sits above the device (z-index 0)
   and below the copy (z-index 2). */
.site-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 88px;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--bg) 92%);
}

.hero {
  display: block;
  position: relative;
  /* The device band opens immediately below the status line, so there
     is no dead space between the copy and the product. */
  min-height: 400px;
  --device-top: 264px;
}

.hero-text { position: relative; z-index: 2; }

.eyebrow {
  margin: 0 0 var(--sp-3);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--green-dark);
}

/* Quiet icon-only theme toggle */
.theme-toggle {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-2);
  border-radius: var(--r-ui);
}
.theme-toggle {
  flex: 0 0 auto;
}
.theme-toggle:hover { color: var(--ink); }
.theme-toggle:focus-visible {
  outline: 2px solid var(--green-dark);
  outline-offset: 2px;
}
.theme-toggle svg { width: 18px; height: 18px; }

.hero-text h1 {
  margin: 0 0 var(--sp-3);
  max-width: 11ch;
  font-size: clamp(2.625rem, 9vw, 3rem);
  font-weight: 700;
  line-height: 1.0;
  letter-spacing: -0.035em;
}

.tagline {
  margin: 0;
  max-width: 42ch;
  font-size: 1rem;
  color: var(--ink-2);
}

/* Attribution link inside the tagline: full ink so it reads a step
   above the muted copy in either theme; the underline only appears
   on hover/focus so the sentence stays quiet at rest. */
.tagline-credit {
  color: var(--ink);
  font-weight: 500;
}
.tagline-credit:hover,
.tagline-credit:focus-visible {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---------- Status line ----------
   One line, no pill around individual values. Readable without
   colour: the words carry the meaning, the dot only supports them.
   Tabular numerals so the counts do not jitter. */

.hero-status {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px 6px;
  max-width: none;
  margin: var(--sp-5) 0 0;
  font-size: 0.75rem; /* 12px - never below */
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.hero-status strong {
  font-weight: 600;
  color: var(--ink);
}

/* The dot-and-date unit never breaks internally: on narrow screens it
   wraps to the second line as one piece, giving the preferred break
   "counts / dot Updated Today". */
.status-updated {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.status-dot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 0 2px var(--green-tint);
}

.status-sep { color: var(--border-strong); }

/* Phones shorten "SKR Integrations" to "Integrations"; the status
   itself always stays visible. */
.status-long { display: none; }

/* ---------- Hero device ----------
   No transform: the three-quarter angle is already in the asset and a
   CSS rotation would double-skew it. No box-shadow either: on a
   transparent PNG it would draw a rectangle. */

/* On a phone the device occupies the lower right only: it sits beside
   the status line and never behind the headline or body copy. It
   crops at the bottom edge of the hero. */
/* Lower right only, in a band that begins below the body copy. It
   sits beside the status line and crops at the bottom of the hero. */
/* The device is 1:2.53, far taller than the hero, so it is cropped by
   the BOTTOM EDGE ONLY. The stage does no clipping of its own and
   carries no negative offsets: the left, right and top edges of the
   device are always whole, and .site-header's overflow does the
   single bottom crop. Sizing down is the answer to tight width,
   never clipping the sides. */
.hero-stage {
  position: absolute;
  top: var(--device-top, 0);
  right: 0;
  z-index: 0;
  width: 220px;
  pointer-events: none;
}

.hero-device {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 14px 22px rgba(17, 18, 15, 0.20));
}

@media (min-width: 700px) {
  .site-header {
    padding-top: var(--sp-16);
    padding-bottom: var(--sp-16);
  }

  .hero {
    display: grid;
    grid-template-columns: 60% 40%;
    align-items: center;
    min-height: 420px;
    --device-top: 0;
  }

  .hero-text h1 {
    max-width: 680px;
    font-size: clamp(3rem, 4.6vw, 4rem);
    line-height: 0.98;
  }

  .tagline {
    max-width: 40ch;
    font-size: 1.125rem;
  }

  .status-long { display: inline; }

  .hero-status {
    gap: var(--sp-2);
    max-width: none;
    font-size: 0.8125rem;
  }

  /* The rear device crops at the right hero boundary; the front one
     stays whole with its screen visible. */
  /* Top of the device sits at the top of the hero's inner padding and
     runs off the bottom edge. 340px keeps it inside the source
     resolution and puts roughly half the device inside the hero. */
  .hero-stage {
    top: 0;
    right: 0;
    bottom: auto;
    width: 360px;
  }

  .hero-device {
    filter: drop-shadow(0 30px 46px rgba(17, 18, 15, 0.26));
  }
}

/* Desktop only: a slow, small drift. Never cursor-following, never
   parallax. Disabled entirely under reduced motion. */
@media (min-width: 700px) and (prefers-reduced-motion: no-preference) {
  @keyframes device-drift {
    from { transform: translateY(0); }
    to { transform: translateY(-3px); }
  }
  .hero-device {
    animation: device-drift 7s ease-in-out infinite alternate;
  }
}

/* ---------- Compact top bar (appears after scroll) ---------- */

.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  padding-top: env(safe-area-inset-top);
  background: var(--bar-bg);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform 0.22s ease, visibility 0s linear 0.22s;
}

body.scrolled .topbar {
  transform: translateY(0);
  visibility: visible;
  transition: transform 0.22s ease;
}

.topbar-inner {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 52px;
}

.topbar-brand {
  font-weight: 600;
  font-size: var(--fs-meta);
}

.topbar-status {
  margin-left: auto;
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--green-dark);
  font-variant-numeric: tabular-nums;
}

.topbar-search {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-2);
  border-radius: var(--r-ui);
}
.topbar-search:hover { color: var(--ink); }
.topbar-search svg { width: 18px; height: 18px; }

/* ---------- Primary view navigation ----------
   Its own surface beneath the hero, never transparent text sitting on
   the hero background. Mobile is a segmented control; desktop is a
   banded row with descriptions. */

.view-tabs {
  position: relative;
  z-index: 2;
  background: var(--surface-raised);
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
  /* A very subtle upward shadow, so the layer reads as sitting on top
     of the hero rather than attached to it. */
  box-shadow: 0 -6px 18px var(--nav-lift);
  padding-top: var(--sp-5);
  padding-bottom: var(--sp-5);
}

.nav-inner {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* Mobile: a segmented control with its own container surface */
.tabs-inner {
  flex: 1 1 auto;
  display: flex;
  min-width: 0;
  gap: var(--sp-1);
  background: var(--surface-raised);
  border: 1px solid var(--border-subtle);
  border-radius: 14px;
  padding-top: var(--sp-1);
  padding-bottom: var(--sp-1);
  padding-left: var(--sp-1);
  padding-right: var(--sp-1);
}

.view-tab {
  flex: 1 1 0;
  min-width: 0;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding-left: var(--sp-1);
  padding-right: var(--sp-1);
  border-radius: 10px;
  color: var(--ink-2);
  transition: background 0.16s ease, color 0.16s ease;
}

.view-tab:hover { color: var(--text-primary); }

/* The view tabs are real links now; the global a:hover underline
   would make them read as prose links, so keep them plain here. */
a.view-tab,
a.view-tab:hover { text-decoration: none; }

/* Fill plus weight, never green text on its own */
.view-tab.active {
  background: var(--surface-active);
  color: var(--text-primary);
  box-shadow: var(--shadow-xs);
}

.view-tab.active .tab-label { font-weight: 700; }

.tab-top {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-1);
  white-space: nowrap;
}

.tab-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.tl-full { display: none; }

/* Counts and descriptions are desktop-only: the segmented control
   carries one line of label and nothing else. */
.tab-count,
.tab-desc { display: none; }

@media (min-width: 700px) {
  .view-tabs {
    padding-top: 0;
    padding-bottom: 0;
  }

  /* Banded row: no card around the navigation itself */
  .tabs-inner {
    align-items: stretch;
    gap: 0;
    min-height: 84px;
    background: none;
    border: 0;
    border-radius: 0;
    padding-top: 0;
    padding-bottom: 0;
    padding-left: 0;
    padding-right: 0;
  }

  .view-tab {
    flex: 0 1 auto;
    align-items: flex-start;
    justify-content: center;
    min-height: 84px;
    padding-top: var(--sp-5);
    padding-bottom: var(--sp-5);
    padding-left: 0;
    padding-right: var(--sp-5);
    margin-right: var(--sp-5);
    border-radius: 0;
    border-bottom: 3px solid transparent;
    margin-bottom: -1px;
    background: none;
    box-shadow: none;
    transition: color 0.16s ease, border-color 0.16s ease;
  }

  /* Selected reads before the underline is noticed: a tinted internal
     surface and dark primary text do the work, the underline confirms
     it. Never colour alone. */
  .view-tab.active {
    background: var(--surface-active);
    box-shadow: none;
    color: var(--text-primary);
    border-bottom-color: var(--green-dark);
    border-top-left-radius: var(--r-ui);
    border-top-right-radius: var(--r-ui);
    padding-left: var(--sp-4);
  }

  .view-tab:last-of-type {
    margin-right: 0;
    padding-right: 0;
  }

  .view-tab.active .tab-count {
    background: var(--green-tint);
    color: var(--green-dark);
  }

  .tab-top { gap: var(--sp-2); }

  .tab-label { font-size: var(--fs-meta); letter-spacing: 0.06em; }

  .tl-full { display: inline; }
  .tl-short { display: none; }

  /* Small secondary badges, on the two directory views only */
  .tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    padding-left: var(--sp-1);
    padding-right: var(--sp-1);
    border-radius: 999px;
    background: var(--surface-active);
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--ink-2);
    font-variant-numeric: tabular-nums;
  }

  .tab-desc {
    display: none;
    font-size: var(--fs-meta);
    color: var(--ink-2);
    font-weight: 400;
    text-transform: none;
    letter-spacing: normal;
  }
}

/* Descriptions appear only once they fit on one line beside the theme
   control. Below this the bar carries labels alone rather than
   wrapping and changing height. */
@media (min-width: 900px) {
  .tab-desc { display: block; }
}

@media (min-width: 1000px) {
  .view-tab {
    padding-right: var(--sp-8);
    margin-right: var(--sp-8);
  }
}

/* ---------- Season Guide ----------
   Sits directly under the tab bar: no second hero, no numbered
   section labels. Intro block, then the accuracy notice. */

/* padding-top only: the shared .wrap rule owns the horizontal
   padding, and a shorthand here would wipe it out */
.guide-shell { padding-top: var(--sp-8); }

/* The reading column. Bounded here so it holds its measure below the
   two-column breakpoint as well. */
.guide-main {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
  min-width: 0;
  max-width: 780px;
}

.guide-intro { max-width: 65ch; }

.guide-title {
  margin: var(--sp-2) 0 var(--sp-3);
  font-size: var(--fs-guide-title);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.guide-desc {
  margin: 0;
  color: var(--ink-2);
  max-width: 60ch;
}

.guide-meta {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-meta);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* One quiet line under the intro call to action. Deliberately not a
   card: a footnote should read as a footnote. */
.guide-infoline {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: var(--sp-4) 0 0;
  max-width: 62ch;
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

.info-icon {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  margin-top: 3px;
  opacity: 0.75;
}

.guide-cta { margin: var(--sp-5) 0 0; }

/* Guide sections. Longhand padding only - a shorthand here would
   fight the global `section` rule at each breakpoint instead of
   neutralising it once. No max-width: the overview modules fill the
   whole reading column, and prose caps its own measure below. */
.guide-section {
  padding-top: 0;
  scroll-margin-top: var(--sp-16);
}

/* Each section reads as its own unit: air, then a hairline, then the
   next number. */
.guide-section + .guide-section {
  margin-top: var(--sp-14);
  padding-top: var(--sp-12);
  border-top: 1px solid var(--border);
}

.guide-section .sec-head { margin-bottom: var(--sp-5); }

/* The section number, and a short rule in place of the directory's
   corner mark. The directory views keep their own glyph. */
.guide-section .sec-label {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
  letter-spacing: 0.12em;
}

.sec-rule {
  display: block;
  width: 28px;
  height: 2px;
  background: currentColor;
  opacity: 0.5;
}

/* The intro call to action moves focus here, so the landing point
   has to be visible even though the heading is not normally
   focusable (tabindex="-1" does not match :focus-visible). */
.guide-section .sec-head h3:focus {
  outline: 2px solid var(--green-dark);
  outline-offset: 4px;
  border-radius: var(--sp-1);
}

/* The guide's own heading scale: large and heavy enough to dominate
   at a glance, so the page reads as heading, prose, heading. */
.guide-section .sec-head h3 {
  margin: 0;
  font-size: var(--fs-guide-h);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--ink);
}

/* ---------- Guide section body ---------- */

.guide-section p {
  margin: 0 0 var(--sp-4);
  color: var(--ink-2);
  max-width: 62ch;
}

.guide-section p:last-child { margin-bottom: 0; }

/* Lead line: the section's framing sentence, in ink rather than
   muted so it reads as a statement and not as body copy */
.guide-lead {
  color: var(--ink);
  font-weight: 600;
}

/* ---------- Overview tracker modules ----------
   Four compact modules, each opening with a diagram of its own
   timing. Stacked on mobile so the descriptions stay readable at
   390px, 2x2 from the tablet breakpoint. */

.ov-modules {
  list-style: none;
  margin: 0 0 var(--sp-4);
  padding-left: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-3);
}

.ov-module {
  padding-top: var(--sp-4);
  padding-bottom: var(--sp-4);
  padding-left: var(--sp-5);
  padding-right: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
}

.ov-title {
  margin: var(--sp-3) 0 var(--sp-1);
  font-size: var(--fs-title);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.ov-timing {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--green-dark);
}

/* Reading copy, not chrome: stays at body size */
.ov-text {
  margin: 0;
  color: var(--ink-2);
}

/* ---------- Tracker diagrams ----------
   Decorative and aria-hidden: every one of them sits beside copy
   that already carries the meaning, and none relies on colour. */

.viz { display: block; }

/* two overlapping outlines */
.viz-rings {
  display: flex;
  align-items: center;
  height: 22px;
}

.viz-rings span {
  width: 20px;
  height: 20px;
  border: 2px solid var(--green-dark);
  border-radius: 50%;
}

.viz-rings span + span { margin-left: -7px; opacity: 0.55; }

/* seven uniform marks: a rhythm, never a checklist */
.viz-week {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 22px;
}

.viz-week i {
  width: 6px;
  height: 16px;
  border-radius: 2px;
  background: var(--green-dark);
  opacity: 0.55;
}

/* a rolling window, oldest fading out at the left */
.viz-window {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 22px;
}

.viz-window i {
  flex: 1 1 auto;
  height: 16px;
  border-radius: 1px;
  background: var(--green-dark);
}

.viz-window i:nth-child(1) { opacity: 0.12; }
.viz-window i:nth-child(2) { opacity: 0.2; }
.viz-window i:nth-child(3) { opacity: 0.3; }
.viz-window i:nth-child(4) { opacity: 0.4; }
.viz-window i:nth-child(5) { opacity: 0.5; }
.viz-window i:nth-child(n + 6) { opacity: 0.6; }
.viz-window i:last-child { opacity: 1; background: var(--guide-yellow); }

/* a repeating cycle - the glyph itself is now an SVG twin of the old
   bordered circle (same size, stroke, top gap and dot position), so
   the ring can draw once on entry. */
.viz-cycle {
  width: 22px;
  height: 22px;
  position: relative;
  color: var(--green-dark);
}

.viz-cycle svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.tracker-mini--staking__dot {
  fill: currentColor;
  transform-box: view-box;
  transform-origin: 11px 11px;
  /* resting spot: the old dot's top-right position, ~32deg off top */
  transform: rotate(32deg) translateY(-13px);
}

/* ---------- Tracker icon ambient loops ----------
   One shared 7.5s period for all four icons, running continuously and
   seamlessly while visible: no play-once, no settle-and-hold, no idle
   stretch, no visible reset. Every animated layer's 0% and 100%
   frames are identical, so the loop has no findable seam. Legibility
   comes from controlled geometry and real resting-vs-active contrast,
   never from near-invisible opacity deltas - and every highlight is
   green-based (currentColor / --green-dark), because the previous
   white glows vanished against the light card.

   Gated by .is-ambient (grid on screen AND tab visible); play-state
   pausing preserves phase, so resume continues mid-loop. */

.tracker-symbol { --ambient-ease: cubic-bezier(0.37, 0, 0.63, 1); }

/* 1. dApp Exploration, relational motion: the rings slide toward each
   other, the overlap compresses and its intersection brightens at the
   midpoint, then they part again - connecting, parting, reconnecting.
   Foreground emphasis alternates between the rings; nothing rotates. */
.tracker-mini--dapps { position: relative; }

.tracker-mini--dapps span:nth-child(1) {
  animation: amb-ring-a 7.5s var(--ambient-ease) infinite paused;
}

.tracker-mini--dapps span:nth-child(2) {
  animation: amb-ring-b 7.5s var(--ambient-ease) infinite paused;
}

@keyframes amb-ring-a {
  0% { opacity: 1; transform: translateX(0) scale(1.04); filter: brightness(1.1); }
  50% { opacity: 0.58; transform: translateX(3.5px) scale(0.97); filter: brightness(0.96); }
  100% { opacity: 1; transform: translateX(0) scale(1.04); filter: brightness(1.1); }
}

@keyframes amb-ring-b {
  0% { opacity: 0.58; transform: translateX(0) scale(0.96); filter: brightness(0.96); }
  50% { opacity: 1; transform: translateX(-3.5px) scale(1.05); filter: brightness(1.1); }
  100% { opacity: 0.58; transform: translateX(0) scale(0.96); filter: brightness(0.96); }
}

/* the shared intersection brightens once per loop, at maximum
   compression. Fixed px anchor: the wrapper is a card-wide flex row,
   so 50% would miss the icon - the ring overlap centres 17px from the
   wrapper's left edge. Green-based so it reads on the light card. */
.tracker-mini--dapps::after {
  content: "";
  position: absolute;
  left: 17px;
  top: 50%;
  width: 8px;
  height: 12px;
  margin: -6px 0 0 -4px;
  border-radius: 50%;
  color: var(--green-dark);
  background: radial-gradient(ellipse, currentColor, transparent 72%);
  opacity: 0;
  pointer-events: none;
  animation: amb-ring-cross 7.5s var(--ambient-ease) infinite paused;
}

@keyframes amb-ring-cross {
  0% { opacity: 0; transform: scale(0.7); }
  36% { opacity: 0.06; transform: scale(0.85); }
  50% { opacity: 0.45; transform: scale(1.05); }
  64% { opacity: 0.06; transform: scale(0.85); }
  100% { opacity: 0; transform: scale(0.7); }
}

/* 2. Daily Use, the clearest shape change: one coherent wave travels
   bar one to bar seven and back inside the 7.5s. The seven keyframe
   blocks are derived from a single triangle timeline - bar i peaks at
   (i-1)/12 of the loop on the way out and at its mirror on the way
   back - rather than one animation copied with arbitrary delays.
   Humps are wide enough (12% half-width vs 8.3% peak spacing) that
   the wave spans two to three bars and the strip is never entirely
   at baseline. Bars rest darker (about 68% brightness) so the active
   bar's rise to 135% height, full opacity and soft green glow reads
   on the light card. */
.tracker-mini--daily i {
  opacity: 0.85;
  color: var(--green-dark);
  transform-origin: bottom;
  animation: amb-daily-b1 7.5s var(--ambient-ease) infinite paused;
}

.tracker-mini--daily i:nth-child(2) { animation-name: amb-daily-b2; }
.tracker-mini--daily i:nth-child(3) { animation-name: amb-daily-b3; }
.tracker-mini--daily i:nth-child(4) { animation-name: amb-daily-b4; }
.tracker-mini--daily i:nth-child(5) { animation-name: amb-daily-b5; }
.tracker-mini--daily i:nth-child(6) { animation-name: amb-daily-b6; }
.tracker-mini--daily i:nth-child(7) { animation-name: amb-daily-b7; }

/* bar 1: single peak astride the wrap (0% == 100% == peak) */
@keyframes amb-daily-b1 {
  0% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  12% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  88% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  100% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
}

@keyframes amb-daily-b2 {
  0% { opacity: 0.82; transform: scaleY(1.12); filter: brightness(0.88) saturate(1); }
  8.3% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  20.3% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  79.7% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  91.7% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  100% { opacity: 0.82; transform: scaleY(1.12); filter: brightness(0.88) saturate(1); }
}

@keyframes amb-daily-b3 {
  0% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  4.7% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  16.7% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  28.7% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  71.3% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  83.3% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  95.3% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  100% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
}

@keyframes amb-daily-b4 {
  0% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  13% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  25% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  37% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  63% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  75% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  87% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  100% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
}

@keyframes amb-daily-b5 {
  0% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  21.3% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  33.3% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  45.3% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  54.7% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  66.7% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  78.7% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  100% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
}

/* bar 6: its two peaks sit close to the turn, so their humps overlap
   and the bar only half-settles between them */
@keyframes amb-daily-b6 {
  0% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  29.7% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  41.7% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  50% { opacity: 0.82; transform: scaleY(1.12); filter: brightness(0.9) saturate(1); }
  58.3% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  70.3% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  100% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
}

/* bar 7: the turn - one peak at the loop's midpoint */
@keyframes amb-daily-b7 {
  0% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  38% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  50% { opacity: 1; transform: scaleY(1.35); filter: brightness(1.18) saturate(1.15) drop-shadow(0 0 2.5px currentColor); }
  62% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
  100% { opacity: 0.7; transform: scaleY(1); filter: brightness(0.68) saturate(0.92); }
}

/* 3. Onchain, the clearest directional movement - and the icon the
   diagnosis caught silently failing: the old white overlay sweep was
   invisible against the light card. Rebuilt as per-cell animations
   with computed staggered delays, so the deltas are real geometry: a
   band about four cells wide travels left to right across the full
   7.5s, each cell inside it brighter, more saturated and raised 1px,
   strongest at the band's centre. The 26-slot delay grid (24 cells +
   2 silent slots) gives the band a brief off-strip beat, so it fades
   at the right and re-enters left with no visible seam. Negative
   delays start every cell mid-phase - the band is already travelling
   on first paint. The yellow Today cell never moves and never joins
   the band: it answers with one restrained warm pulse as the band
   arrives, then the cycle continues. Cell order and colours are
   untouched. */
.tracker-mini--onchain i {
  animation: amb-window-band 7.5s var(--ambient-ease) infinite paused;
  animation-delay: calc((var(--i, 0) - 26) * 0.2885s);
}

@keyframes amb-window-band {
  0% { transform: translateY(0); filter: brightness(1) saturate(1); }
  3.8% { transform: translateY(-1px); filter: brightness(1.32) saturate(1.22); }
  7.7% { transform: translateY(-0.5px); filter: brightness(1.14) saturate(1.1); }
  11.5% { transform: translateY(0); filter: brightness(1) saturate(1); }
  100% { transform: translateY(0); filter: brightness(1) saturate(1); }
}

/* Today: fixed at the far right, one warm pulse timed to the band's
   arrival (the last green cell peaks at ~88% of the shared period) */
.tracker-mini--onchain i:last-child {
  animation: amb-window-today 7.5s var(--ambient-ease) infinite paused;
  animation-delay: 0s;
}

@keyframes amb-window-today {
  0% { transform: translateY(0); filter: brightness(1) saturate(1); }
  88% { transform: translateY(0); filter: brightness(1) saturate(1); }
  93.5% { transform: translateY(-1px); filter: brightness(1.35) saturate(1.3) drop-shadow(0 0 2.5px var(--guide-yellow)); }
  99% { transform: translateY(0); filter: brightness(1.02) saturate(1.02); }
  100% { transform: translateY(0); filter: brightness(1) saturate(1); }
}

/* 4. SKR Staking, the calmest: value held in place, quiet energy
   radiating outward. The incomplete outer ring is geometrically
   stationary - no rotation, no chasing arc, nothing loader-shaped -
   flexing only 0.97 to 1.04. The centre dot breathes 0.92 to 1.12 and
   stays visible throughout. Once per loop a soft circular pulse
   travels outward and dissolves before the icon boundary; as it
   passes the ring's radius, a short fixed section of the ring
   brightens briefly in answer. */
.viz-cycle { overflow: visible; }

.tracker-mini--staking__ring {
  transform-box: view-box;
  transform-origin: 11px 11px;
  animation: amb-staking-ring 7.5s var(--ambient-ease) infinite paused;
}

.tracker-mini--staking__dot {
  animation: amb-staking-dot 7.5s var(--ambient-ease) infinite paused;
  animation-delay: -0.9s;
}

/* the arc element no longer travels: it is a fixed short section on
   the ring's lower-left, lit only as the pulse crosses the radius */
.tracker-mini--staking__arc {
  transform-box: view-box;
  transform-origin: 11px 11px;
  transform: rotate(120deg);
  stroke: currentColor;
  animation: amb-staking-section 7.5s var(--ambient-ease) infinite paused;
}

@keyframes amb-staking-ring {
  0% { opacity: 1; transform: scale(0.97); }
  50% { opacity: 0.88; transform: scale(1.04); }
  100% { opacity: 1; transform: scale(0.97); }
}

@keyframes amb-staking-dot {
  0% { opacity: 0.88; transform: rotate(32deg) translateY(-13px) scale(0.92); filter: brightness(0.95); }
  50% { opacity: 1; transform: rotate(32deg) translateY(-13px) scale(1.12); filter: brightness(1.25); }
  100% { opacity: 0.88; transform: rotate(32deg) translateY(-13px) scale(0.92); filter: brightness(0.95); }
}

@keyframes amb-staking-section {
  0% { opacity: 0; transform: rotate(120deg); }
  22% { opacity: 0; transform: rotate(120deg); }
  30% { opacity: 0.55; transform: rotate(120deg); }
  42% { opacity: 0; transform: rotate(120deg); }
  100% { opacity: 0; transform: rotate(120deg); }
}

/* the outward pulse, dissolving before the icon boundary */
.tracker-mini--staking {
  position: relative;
}

.tracker-mini--staking::before {
  content: "";
  position: absolute;
  /* px anchor: the wrapper is a card-wide flex row, so 50% would sit
     at the card's centre - the 22px svg lives at its left edge */
  left: 11px;
  top: 50%;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border-radius: 50%;
  border: 1px solid currentColor;
  color: var(--green-dark);
  opacity: 0;
  pointer-events: none;
  animation: amb-staking-pulse 7.5s var(--ambient-ease) infinite paused;
}

@keyframes amb-staking-pulse {
  0% { opacity: 0; transform: scale(0.3); }
  8% { opacity: 0.42; transform: scale(0.5); }
  34% { opacity: 0; transform: scale(0.92); }
  100% { opacity: 0; transform: scale(0.3); }
}

/* The gate: motion runs only while the grid is on screen and the tab
   is visible. */
.ov-modules.is-ambient .tracker-mini--dapps span:nth-child(1),
.ov-modules.is-ambient .tracker-mini--dapps span:nth-child(2),
.ov-modules.is-ambient .tracker-mini--dapps::after,
.ov-modules.is-ambient .tracker-mini--daily i,
.ov-modules.is-ambient .tracker-mini--onchain i,
.ov-modules.is-ambient .tracker-mini--staking__ring,
.ov-modules.is-ambient .tracker-mini--staking__dot,
.ov-modules.is-ambient .tracker-mini--staking__arc,
.ov-modules.is-ambient .tracker-mini--staking::before {
  animation-play-state: running;
}

/* Reduced motion: every icon static in its resting geometry. No
   blanket transform reset - the staking dot's resting position and
   the fixed ring section ARE transforms, so they are restated
   explicitly. */
@media (prefers-reduced-motion: reduce) {
  .tracker-symbol,
  .tracker-symbol * {
    animation: none !important;
    transition: none !important;
    filter: none !important;
  }

  .tracker-mini--dapps span:nth-child(1) { opacity: 1 !important; }
  .tracker-mini--dapps span + span { opacity: 0.55 !important; }
  .tracker-mini--dapps::after { opacity: 0 !important; }
  .tracker-mini--daily i { opacity: 0.85 !important; transform: scaleY(1) !important; }
  .tracker-mini--onchain i { transform: translateY(0) !important; }
  .tracker-mini--staking__ring { stroke-dashoffset: 0 !important; opacity: 1 !important; transform: scale(1) !important; }
  .tracker-mini--staking__dot { transform: rotate(32deg) translateY(-13px) !important; opacity: 1 !important; }
  .tracker-mini--staking__arc { transform: rotate(120deg) !important; }
  .tracker-mini--staking__arc,
  .tracker-mini--staking::before { opacity: 0 !important; }
}

/* (former .viz-cycle span dot now lives inside the SVG) */

.viz-glyph {
  width: 26px;
  height: 26px;
  color: var(--green-dark);
}

.viz-glyph svg { width: 100%; height: 100%; }

/* ---------- Paired submodules ---------- */

.sub-modules {
  list-style: none;
  margin: 0 0 var(--sp-5);
  padding-left: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-3);
}

.sub-module {
  padding-top: var(--sp-4);
  padding-bottom: var(--sp-4);
  padding-left: var(--sp-5);
  padding-right: var(--sp-5);
  background: var(--surface-subtle);
  border-radius: var(--r-ui);
}

.sub-title {
  margin: var(--sp-3) 0 var(--sp-1);
  font-size: var(--fs-title);
  font-weight: 600;
  color: var(--ink);
}

.sub-text {
  margin: 0;
  color: var(--ink-2);
}

/* ---------- Numbered action sequence ---------- */

.guide-sequence {
  list-style: none;
  margin: 0 0 var(--sp-5);
  padding-left: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  max-width: 62ch;
}

.guide-sequence li {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
}

.seq-num {
  flex: 0 0 auto;
  min-width: 2ch;
  font-size: var(--fs-meta);
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--green-dark);
  font-variant-numeric: tabular-nums;
}

.seq-text { color: var(--ink-2); }

/* ---------- Compact flow ----------
   Reads left to right where there is room, and stacks below it. */

.guide-flow {
  list-style: none;
  margin: 0 0 var(--sp-5);
  padding-left: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  counter-reset: flow;
}

.guide-flow li {
  counter-increment: flow;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding-top: var(--sp-2);
  padding-bottom: var(--sp-2);
  padding-left: var(--sp-3);
  padding-right: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

.guide-flow li::before {
  content: counter(flow);
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--green-tint);
  color: var(--green-dark);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---------- Compact insight ---------- */

.guide-insight {
  margin: 0 0 var(--sp-4);
  padding-top: var(--sp-4);
  padding-bottom: var(--sp-4);
  padding-left: var(--sp-5);
  padding-right: var(--sp-5);
  background: var(--surface-subtle);
  border-left: 3px solid var(--green-dark);
  border-radius: 0 var(--r-ui) var(--r-ui) 0;
  max-width: 60ch;
}

.guide-insight p {
  margin: 0;
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

/* ---------- Quiet supporting detail ---------- */

.guide-detail {
  font-size: var(--fs-meta);
  color: var(--ink-2);
  max-width: 62ch;
}

/* ---------- Prominent takeaway ---------- */

.guide-takeaway {
  margin: 0 0 var(--sp-4);
  font-size: clamp(1.125rem, 2vw, 1.3125rem);
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.01em;
  color: var(--ink);
  max-width: 46ch;
}

/* ---------- Weekly rhythm strip ----------
   Uniform marks with day letters. No completion state, so it cannot
   be mistaken for a checklist. */

.week-strip { margin: 0 0 var(--sp-5); }

/* ---------- Seven day tiles ----------
   Softly illuminated tiles that communicate continuity, not
   completion. Identical construction on every day - warm translucent
   base, one light bloom, hairline border, inner highlight, one small
   orb - with only the bloom position drifting per tile, so no day
   ever reads as more done than another.

   The tint sequence is a pale spectral walk, mint to warm pearl; the
   seventh carries a restrained green reflection back toward the
   first. Pale washes, never seven saturated boxes. */
.week-strip {
  --day-t1a: #a9ebd2; --day-t1b: #7ed2b5; /* soft mint */
  --day-t2a: #9fe8df; --day-t2b: #72cdc5; /* mint-cyan */
  --day-t3a: #9edff0; --day-t3b: #72c5dd; /* cool cyan */
  --day-t4a: #a7d3f4; --day-t4b: #7fb5e2; /* pale blue */
  --day-t5a: #bebff3; --day-t5b: #999be0; /* soft violet */
  --day-t6a: #d5afea; --day-t6b: #b583d5; /* lavender */
  --day-t7a: #e2dfb7; --day-t7b: #c7c080; /* warm pearl, green reflection */
}

.ws-days {
  list-style: none;
  margin: 0;
  padding-left: 0;
  display: flex;
  justify-content: flex-start;
  gap: 8px;
}

.ws-days li {
  flex: 0 0 auto;
  width: clamp(37px, 10.5vw, 43px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  /* The aura is a negative-z pseudo behind the tile: the item is the
     stacking boundary, and nothing here may clip it. */
  position: relative;
  isolation: isolate;
}

/* Polished pastel glass resting just above the ivory surface: a
   bottom refraction pool of the tile's own accent, a restrained
   bloom, an upper-left highlight and lower-right shade cut into the
   edge, and a soft spectral aura beneath. No overflow clipping: the
   aura lives outside the tile, and backgrounds clip to the radius on
   their own. */
.day-tile {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1.06;
  border-radius: 12px;
  background:
    radial-gradient(circle at var(--bloom-x, 38%) var(--bloom-y, 28%), rgba(255, 255, 255, 0.62) 0%, rgba(255, 255, 255, 0.18) 24%, transparent 52%),
    radial-gradient(ellipse at 50% 105%, rgba(var(--day-accent-rgb), 0.58) 0%, transparent 64%),
    linear-gradient(145deg, var(--tint-a), var(--tint-b));
  border: 1px solid rgba(38, 44, 40, 0.17);
  box-shadow:
    inset 1px 1px 0 rgba(255, 255, 255, 0.78),
    inset -1px -1px 0 rgba(34, 41, 37, 0.08),
    0 1px 2px rgba(28, 32, 29, 0.08),
    0 12px 28px rgba(28, 32, 29, 0.11);
  /* The resting state. The reveal's final frame matches this exactly,
     and under reduced motion it simply applies statically. */
  filter: saturate(1.28) brightness(1.08);
}

/* Spectral aura: the tile's own colour pooling beneath and around
   its lower half. Never a glowing rectangle. */
.day-tile::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 16% 10% -18%;
  border-radius: 40%;
  background: var(--day-accent);
  filter: blur(17px);
  opacity: 0.27;
  transform: scale(0.88);
}

/* One restrained specular reflection in the upper-left. Surfaces on
   close inspection rather than dominating. */
.day-tile::after {
  content: "";
  position: absolute;
  inset: 1px;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.34) 0%, rgba(255, 255, 255, 0.08) 26%, transparent 48%);
  mix-blend-mode: soft-light;
}

/* Each tile's accent is its own gradient end colour; the -rgb triplet
   feeds exact rgba() fallbacks where color-mix() is unsupported. */
.day-1 { --tint-a: var(--day-t1a); --tint-b: var(--day-t1b); --bloom-x: 30%; --bloom-y: 22%; --day-accent: #7ed2b5; --day-accent-rgb: 126, 210, 181; }
.day-2 { --tint-a: var(--day-t2a); --tint-b: var(--day-t2b); --bloom-x: 42%; --bloom-y: 28%; --day-accent: #72cdc5; --day-accent-rgb: 114, 205, 197; }
.day-3 { --tint-a: var(--day-t3a); --tint-b: var(--day-t3b); --bloom-x: 36%; --bloom-y: 20%; --day-accent: #72c5dd; --day-accent-rgb: 114, 197, 221; }
.day-4 { --tint-a: var(--day-t4a); --tint-b: var(--day-t4b); --bloom-x: 28%; --bloom-y: 30%; --day-accent: #7fb5e2; --day-accent-rgb: 127, 181, 226; }
.day-5 { --tint-a: var(--day-t5a); --tint-b: var(--day-t5b); --bloom-x: 40%; --bloom-y: 24%; --day-accent: #999be0; --day-accent-rgb: 153, 155, 224; }
.day-6 { --tint-a: var(--day-t6a); --tint-b: var(--day-t6b); --bloom-x: 33%; --bloom-y: 27%; --day-accent: #b583d5; --day-accent-rgb: 181, 131, 213; }
.day-7 { --tint-a: var(--day-t7a); --tint-b: var(--day-t7b); --bloom-x: 38%; --bloom-y: 22%; --day-accent: #c7c080; --day-accent-rgb: 199, 192, 128; }

/* One small abstract mark: a translucent orb with a single, extremely
   subtle ring. Not an icon, not a state. */
/* The focal point: brightest element in the visualization, lit from
   the upper-left, with a faint pool of the tile's accent around it. */
.day-orb {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 38%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 28%,
    rgba(255, 255, 255, 0.96) 0%,
    rgba(255, 255, 255, 0.68) 28%,
    rgba(255, 255, 255, 0.25) 62%,
    rgba(45, 55, 49, 0.15) 100%);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.90),
    inset 0 -2px 4px rgba(37, 48, 41, 0.12),
    0 4px 10px rgba(38, 48, 42, 0.20),
    0 0 14px rgba(var(--day-accent-rgb), 0.35);
}

.day-orb::after {
  content: "";
  position: absolute;
  inset: -26%;
  border-radius: 50%;
  border: 1px solid rgba(45, 54, 49, 0.16);
}

.ws-day {
  font-size: 0.75rem; /* 12px - never below */
  font-weight: 500;
  color: rgba(39, 42, 38, 0.72);
}

[data-theme="dark"] .ws-day { color: rgba(239, 238, 232, 0.68); }

/* ---------- The week awakening ----------
   A light wave travels Monday to Sunday, Sunday arrives warm, the
   completed week holds still, exhales right to left, and rests.
   Organic and atmospheric - never a progress indicator, never seven
   loading buttons. Replaces the old one-time reveal entirely.

   All animation filters COMPOSE with the permanent resting filters
   (saturate 1.28 / brightness 1.08 light, 1.42 / 1.22 dark): every
   keyframe below is the spec value multiplied by the theme's resting
   factors, so the quiet state is a dimmed version of the current
   look, not a reversion to the older palette.

   The dimmed rest is opt-in via .is-animated, which only the
   sequencer adds - before the loop starts, without JS, or under
   reduced motion the tiles keep their full resting appearance. */

.week-strip { position: relative; --week-ease: cubic-bezier(0.25, 0.8, 0.25, 1); }

/* Compositor hints only while something is actually moving - the
   sequencers add is-animating for movement segments and remove it
   for every hold and rest. */
.rolling-window.is-animating .rolling-cell,
.week-strip.is-animating .day-tile {
  will-change: transform, filter;
}

.week-strip.is-animated .day-tile {
  transform: translateY(0) scale(0.985);
  filter: saturate(1.20) brightness(1.02);
  transition: filter 600ms ease, transform 600ms ease;
}

[data-theme="dark"] .week-strip.is-animated .day-tile {
  filter: saturate(1.33) brightness(1.15);
}

/* Awake and settled: marginally above the resting product, never a
   different colour. Same values as the awaken keyframes' 100% frame,
   so the class handoff is invisible. */
.week-strip .day-tile.is-complete {
  transform: translateY(0) scale(1);
  filter: saturate(1.33) brightness(1.12);
}

[data-theme="dark"] .week-strip .day-tile.is-complete {
  filter: saturate(1.48) brightness(1.27);
}

.day-tile.is-awakening {
  animation: week-day-awaken 900ms var(--week-ease) both;
}

[data-theme="dark"] .day-tile.is-awakening {
  animation-name: week-day-awaken-dark;
}

/* Sunday resolves the sequence with a slightly fuller arrival. */
.day-7.is-awakening { animation-name: week-sunday-arrival; }
[data-theme="dark"] .day-7.is-awakening { animation-name: week-sunday-arrival-dark; }

.day-tile.is-awakening .day-orb {
  animation: week-orb-awaken 900ms var(--week-ease) both;
  animation-delay: 110ms;
}

.day-tile.is-exhaling {
  animation: week-day-exhale 560ms var(--week-ease) both;
}

[data-theme="dark"] .day-tile.is-exhaling {
  animation-name: week-day-exhale-dark;
}

/* Orb auras: bright while awakening, reduced once settled. */
.day-tile.is-awakening .day-orb {
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.90),
    inset 0 -2px 4px rgba(37, 48, 41, 0.12),
    0 4px 10px rgba(38, 48, 42, 0.20),
    0 0 22px rgba(var(--day-accent-rgb), 0.62);
}

.day-tile.is-complete .day-orb {
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.90),
    inset 0 -2px 4px rgba(37, 48, 41, 0.12),
    0 4px 10px rgba(38, 48, 42, 0.20),
    0 0 12px rgba(var(--day-accent-rgb), 0.28);
}

[data-theme="dark"] .day-tile.is-awakening .day-orb {
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.42),
    inset 0 -2px 5px rgba(0, 0, 0, 0.32),
    0 5px 12px rgba(0, 0, 0, 0.40),
    0 0 22px rgba(var(--day-accent-rgb), 0.62);
}

[data-theme="dark"] .day-tile.is-complete .day-orb {
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.42),
    inset 0 -2px 5px rgba(0, 0, 0, 0.32),
    0 5px 12px rgba(0, 0, 0, 0.40),
    0 0 12px rgba(var(--day-accent-rgb), 0.28);
}

/* Genuine stillness during the hold: the large exterior auras come
   down roughly 15% while the completed week rests. Sunday's golden
   accent is excluded - it IS the arrival. */
.week-strip.is-complete .day-tile:not(.day-7)::before { opacity: 0.23; }
[data-theme="dark"] .week-strip.is-complete .day-tile:not(.day-7)::before { opacity: 0.41; }

/* Sunday's settled warmth: a restrained golden aura, perfectly still. */
.day-7.is-complete::before {
  opacity: 0.34;
  background: rgba(235, 211, 84, 0.48);
}

/* Labels answer the completed week with contrast only - no movement,
   no bolding. */
.week-strip.is-animated .ws-day {
  opacity: 0.64;
  transition: opacity 320ms ease, color 320ms ease;
}

.week-strip.is-complete .ws-day {
  opacity: 0.90;
  color: var(--text-primary);
}

/* One soft specular reflection crossing the group, positioned in px
   from the active tile's centre and coloured through the week via a
   registered custom property, so mint glides into blue, violet and
   pearl-gold instead of swapping. */
@property --week-light-color {
  syntax: "<color>";
  inherits: true;
  initial-value: rgba(180, 246, 225, 0.20);
}

.week-light {
  position: absolute;
  z-index: 2;
  top: -16px;
  height: 92px;
  left: var(--week-light-x, 0px);
  width: 76px;
  transform: translateX(-50%);
  pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(255, 255, 255, 0.44) 0%, var(--week-light-color, rgba(180, 246, 225, 0.20)) 38%, transparent 72%);
  filter: blur(12px);
  opacity: var(--week-light-opacity, 0);
  mix-blend-mode: screen;
  transition: opacity 380ms ease, left 260ms linear, --week-light-color 480ms linear;
}

@keyframes week-day-awaken {
  0% { transform: translateY(0) scale(0.985); filter: brightness(1.02) saturate(1.20); }
  42% { transform: translateY(var(--lift, -2px)) scale(var(--wave-scale, 1.022)); filter: brightness(1.25) saturate(1.43); }
  68% { transform: translateY(-1px) scale(1.012); filter: brightness(1.17) saturate(1.37); }
  100% { transform: translateY(0) scale(1); filter: brightness(1.12) saturate(1.33); }
}

@keyframes week-day-awaken-dark {
  0% { transform: translateY(0) scale(0.985); filter: brightness(1.15) saturate(1.33); }
  42% { transform: translateY(var(--lift, -2px)) scale(var(--wave-scale, 1.022)); filter: brightness(1.42) saturate(1.59); }
  68% { transform: translateY(-1px) scale(1.012); filter: brightness(1.32) saturate(1.50); }
  100% { transform: translateY(0) scale(1); filter: brightness(1.27) saturate(1.48); }
}

@keyframes week-sunday-arrival {
  0% { transform: translateY(0) scale(0.985); filter: brightness(1.05) saturate(1.23); }
  46% { transform: translateY(var(--lift, -2px)) scale(var(--wave-scale, 1.022)); filter: brightness(1.30) saturate(1.46); }
  72% { transform: translateY(-1px) scale(1.015); filter: brightness(1.19) saturate(1.39); }
  100% { transform: translateY(0) scale(1); filter: brightness(1.15) saturate(1.36); }
}

@keyframes week-sunday-arrival-dark {
  0% { transform: translateY(0) scale(0.985); filter: brightness(1.17) saturate(1.36); }
  46% { transform: translateY(var(--lift, -2px)) scale(var(--wave-scale, 1.022)); filter: brightness(1.47) saturate(1.62); }
  72% { transform: translateY(-1px) scale(1.015); filter: brightness(1.35) saturate(1.53); }
  100% { transform: translateY(0) scale(1); filter: brightness(1.30) saturate(1.51); }
}

@keyframes week-orb-awaken {
  0% { transform: translate(-50%, -50%) scale(0.92); filter: brightness(0.94); }
  48% { transform: translate(-50%, -50%) scale(var(--orb-peak, 1.07)); filter: brightness(1.20); }
  72% { transform: translate(-50%, -50%) scale(var(--wave-scale, 1.022)); filter: brightness(1.12); }
  100% { transform: translate(-50%, -50%) scale(1); filter: brightness(1.06); }
}

@keyframes week-day-exhale {
  0% { transform: translateY(0) scale(1); filter: brightness(1.12) saturate(1.33); }
  45% { transform: translateY(1px) scale(0.975); filter: brightness(0.99) saturate(1.15); }
  100% { transform: translateY(0) scale(0.985); filter: brightness(1.02) saturate(1.20); }
}

@keyframes week-day-exhale-dark {
  0% { transform: translateY(0) scale(1); filter: brightness(1.27) saturate(1.48); }
  45% { transform: translateY(1px) scale(0.975); filter: brightness(1.12) saturate(1.28); }
  100% { transform: translateY(0) scale(0.985); filter: brightness(1.15) saturate(1.33); }
}

/* 360px class devices: tighter gaps; the clamp() width handles the
   tiles, and everything stays on one line. */
@media (max-width: 374px) {
  .ws-days { gap: 7px; }
}


/* Coloured glass objects softly illuminated in a dark room: the
   colour lives in the raised surface, the refraction pool deepens,
   the border catches controlled light. Never neon, never an app
   icon. */
[data-theme="dark"] .day-tile {
  background:
    radial-gradient(circle at var(--bloom-x, 38%) var(--bloom-y, 25%), rgba(255, 255, 255, 0.28) 0%, rgba(255, 255, 255, 0.08) 27%, transparent 52%),
    radial-gradient(ellipse at 50% 105%, rgba(var(--day-accent-rgb), 0.72) 0%, transparent 68%),
    linear-gradient(145deg, var(--tint-da), var(--tint-db));
  border-color: rgba(255, 255, 255, 0.21);
  box-shadow:
    inset 1px 1px 0 rgba(255, 255, 255, 0.18),
    inset -1px -1px 0 rgba(0, 0, 0, 0.34),
    0 1px 2px rgba(0, 0, 0, 0.42),
    0 14px 32px rgba(0, 0, 0, 0.38);
  filter: saturate(1.42) brightness(1.22);
}

[data-theme="dark"] .day-tile::before {
  filter: blur(19px);
  opacity: 0.48;
}

[data-theme="dark"] .day-tile::after {
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.23) 0%, rgba(255, 255, 255, 0.05) 26%, transparent 50%);
}

/* --day-orb-mid is the precomputed color-mix(accent 42%, #b8c0bb)
   fallback for each tile's orb midtone. */
[data-theme="dark"] .day-1 { --tint-da: #3d8b70; --tint-db: #245846; --day-accent: #3d8b70; --day-accent-rgb: 61, 139, 112; --day-orb-mid: #84aa9c; }
[data-theme="dark"] .day-2 { --tint-da: #398f88; --tint-db: #245d58; --day-accent: #398f88; --day-accent-rgb: 57, 143, 136; --day-orb-mid: #83aba6; }
[data-theme="dark"] .day-3 { --tint-da: #3b849b; --tint-db: #275a6b; --day-accent: #3b849b; --day-accent-rgb: 59, 132, 155; --day-orb-mid: #84a7ae; }
[data-theme="dark"] .day-4 { --tint-da: #4278a7; --tint-db: #2d5075; --day-accent: #4278a7; --day-accent-rgb: 66, 120, 167; --day-orb-mid: #86a2b3; }
[data-theme="dark"] .day-5 { --tint-da: #6267ad; --tint-db: #414679; --day-accent: #6267ad; --day-accent-rgb: 98, 103, 173; --day-orb-mid: #949bb5; }
[data-theme="dark"] .day-6 { --tint-da: #805d98; --tint-db: #583f6c; --day-accent: #805d98; --day-accent-rgb: 128, 93, 152; --day-orb-mid: #a096ac; }
[data-theme="dark"] .day-7 { --tint-da: #7a7657; --tint-db: #53503a; --day-accent: #7a7657; --day-accent-rgb: 122, 118, 87; --day-orb-mid: #9ea191; }

/* Light plus a trace of the tile's own colour, not metallic grey. */
[data-theme="dark"] .day-orb {
  background: radial-gradient(circle at 34% 27%,
    rgba(255, 255, 255, 0.88) 0%,
    rgba(235, 242, 238, 0.62) 25%,
    var(--day-orb-mid) 58%,
    rgba(13, 17, 15, 0.34) 100%);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.42),
    inset 0 -2px 5px rgba(0, 0, 0, 0.32),
    0 5px 12px rgba(0, 0, 0, 0.40),
    0 0 20px rgba(var(--day-accent-rgb), 0.62);
}

[data-theme="dark"] .day-orb::after { border-color: rgba(255, 255, 255, 0.18); }

/* Small screens: rein the aura in so adjacent tiles never merge into
   one continuous glow. AFTER both themes' aura rules, so it wins the
   equal-specificity cascade in dark as well as light. */
@media (max-width: 479px) {
  .day-tile { border-radius: 11px; }
  .day-tile::before { filter: blur(10px); opacity: 0.24; }
  [data-theme="dark"] .day-tile::before { filter: blur(11px); opacity: 0.38; }

  /* Reduced effects, identical timing: smaller lift, quieter orb
     peak, tighter light. */
  .week-light {
    width: 46px;
    height: 66px;
    filter: blur(6px);
    opacity: calc(var(--week-light-opacity, 0) * 0.72);
  }

  /* same timing as desktop - only the motion shrinks */
  .week-strip {
    --lift: -1px;
    --wave-scale: 1.015;
    --orb-peak: 1.07;
  }
}

/* Where color-mix() is supported, the accent mixes replace the
   precomputed rgba() fallbacks above - same colours, derived from the
   single --day-accent source instead of the duplicated triplet. */
@supports (background: color-mix(in srgb, red 34%, transparent)) {
  .day-tile {
    background:
      radial-gradient(circle at var(--bloom-x, 38%) var(--bloom-y, 28%), rgba(255, 255, 255, 0.62) 0%, rgba(255, 255, 255, 0.18) 24%, transparent 52%),
      radial-gradient(ellipse at 50% 105%, color-mix(in srgb, var(--day-accent) 58%, transparent) 0%, transparent 64%),
      linear-gradient(145deg, var(--tint-a), var(--tint-b));
  }

  .day-orb {
    box-shadow:
      inset 0 1px 1px rgba(255, 255, 255, 0.90),
      inset 0 -2px 4px rgba(37, 48, 41, 0.12),
      0 4px 10px rgba(38, 48, 42, 0.20),
      0 0 14px color-mix(in srgb, var(--day-accent) 35%, transparent);
  }

  [data-theme="dark"] .day-tile {
    background:
      radial-gradient(circle at var(--bloom-x, 38%) var(--bloom-y, 25%), rgba(255, 255, 255, 0.28) 0%, rgba(255, 255, 255, 0.08) 27%, transparent 52%),
      radial-gradient(ellipse at 50% 105%, color-mix(in srgb, var(--day-accent) 72%, transparent) 0%, transparent 68%),
      linear-gradient(145deg, var(--tint-da), var(--tint-db));
  }

  [data-theme="dark"] .day-orb {
    background: radial-gradient(circle at 34% 27%,
      rgba(255, 255, 255, 0.88) 0%,
      rgba(235, 242, 238, 0.62) 25%,
      color-mix(in srgb, var(--day-accent) 42%, #b8c0bb) 58%,
      rgba(13, 17, 15, 0.34) 100%);
    box-shadow:
      inset 0 1px 1px rgba(255, 255, 255, 0.42),
      inset 0 -2px 5px rgba(0, 0, 0, 0.32),
      0 5px 12px rgba(0, 0, 0, 0.40),
      0 0 20px color-mix(in srgb, var(--day-accent) 62%, transparent);
  }

  /* Week-awakening orb auras from the same accent source: bright
     while awakening, reduced once settled. */
  .day-tile.is-awakening .day-orb {
    box-shadow:
      inset 0 1px 1px rgba(255, 255, 255, 0.90),
      inset 0 -2px 4px rgba(37, 48, 41, 0.12),
      0 4px 10px rgba(38, 48, 42, 0.20),
      0 0 22px color-mix(in srgb, var(--day-accent) 62%, transparent);
  }

  .day-tile.is-complete .day-orb {
    box-shadow:
      inset 0 1px 1px rgba(255, 255, 255, 0.90),
      inset 0 -2px 4px rgba(37, 48, 41, 0.12),
      0 4px 10px rgba(38, 48, 42, 0.20),
      0 0 12px color-mix(in srgb, var(--day-accent) 28%, transparent);
  }

  [data-theme="dark"] .day-tile.is-awakening .day-orb {
    box-shadow:
      inset 0 1px 1px rgba(255, 255, 255, 0.42),
      inset 0 -2px 5px rgba(0, 0, 0, 0.32),
      0 5px 12px rgba(0, 0, 0, 0.40),
      0 0 22px color-mix(in srgb, var(--day-accent) 62%, transparent);
  }

  [data-theme="dark"] .day-tile.is-complete .day-orb {
    box-shadow:
      inset 0 1px 1px rgba(255, 255, 255, 0.42),
      inset 0 -2px 5px rgba(0, 0, 0, 0.32),
      0 5px 12px rgba(0, 0, 0, 0.40),
      0 0 12px color-mix(in srgb, var(--day-accent) 28%, transparent);
  }
}

.ws-caption {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

.cap-sep { color: var(--border-strong); }

/* ---------- Rolling window strip ---------- */

.window-strip { margin: 0 0 var(--sp-5); }

/* The ONLY statement of the Onchain level scale: a small label on the
   diagram, not a sentence in the prose. Real text, read by assistive
   technology. */
.viz-tag {
  display: inline-block;
  margin: 0 0 var(--sp-2);
  padding-top: 2px;
  padding-bottom: 2px;
  padding-left: var(--sp-2);
  padding-right: var(--sp-2);
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--ink-2);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}

/* ---------- The animated rolling window ----------
   Thirty slim polished segments. A soft light travels left to right,
   each passed cell settles into its own point on a sage-to-green-to-
   mint-to-lime progression, the last two resolve into warm amber, the
   whole strip rests, dims together, and begins again. Light passing
   through material - deliberately NOT a progress bar: nothing here
   tracks the reader, and the sequencing lives in app.js because the
   long completed hold is hard to keep honest with chained CSS delays.
   Under reduced motion the finished state renders statically. */

.rolling-window {
  margin: 0;
  /* the restored, stronger green system */
  --window-neutral: #e1e9e5;
  --window-green-start: #9fbdb4;
  --window-green-middle: #78a99b;
  --window-green-end: #60a18f;
  --window-highlight: #a9ead5;
}

[data-theme="dark"] .rolling-window {
  --window-neutral: #23322d;
  --window-green-start: #456e62;
  --window-green-middle: #558f80;
  --window-green-end: #61aa96;
  --window-highlight: #8de4c8;
}

.rolling-window__cells {
  display: grid;
  grid-template-columns: repeat(30, minmax(0, 1fr));
  gap: 2px;
  position: relative;
}

/* One quiet reflection following the activating area - never a
   permanent glow on every cell. Positioned by custom properties the
   sequencer updates, faded out as the amber cells settle. */
/* The restored mint light: spans two to three cells, never a pale
   block, never a thin flashing line. Pure mint - it fades away as the
   amber cells arrive rather than warming. */
.rolling-window__cells::after {
  content: "";
  position: absolute;
  top: -7px;
  bottom: -7px;
  left: var(--light-position, 0%);
  width: 56px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse, rgba(157, 238, 211, 0.38) 0%, rgba(125, 214, 187, 0.18) 42%, transparent 72%);
  filter: blur(6px);
  pointer-events: none;
  opacity: calc(var(--light-opacity, 0) * 0.62);
  mix-blend-mode: screen;
  transition: opacity 420ms ease, left 150ms linear;
}

[data-theme="dark"] .rolling-window__cells::after {
  opacity: calc(var(--light-opacity, 0) * 0.72);
}

.rolling-cell {
  height: 46px;
  border-radius: 5px;
  background: var(--window-neutral);
  border: 1px solid rgba(17, 18, 15, 0.06);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.42);
  /* The rest phase stays clearly visible - the component must never
     appear empty. */
  opacity: 0.72;
  transform: scale(0.97);
  transition:
    background-color 360ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 360ms ease,
    transform 360ms cubic-bezier(0.22, 1, 0.36, 1),
    filter 360ms ease;
  /* Each cell's colour: overridden per band below, graded per cell
     where color-mix is available. */
  --window-cell-color: var(--window-green-middle);
}

[data-theme="dark"] .rolling-cell {
  border-color: rgba(236, 234, 226, 0.06);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
  opacity: 0.78;
}

/* Entering: a continuous wave - each cell begins before the previous
   finishes, and settles bright. No darkening ever reaches the
   completed state; the desaturated values live in the exit only. */
.rolling-cell.is-active {
  background: var(--window-cell-color);
  opacity: 1;
  transform: scaleY(1);
  animation: guide-onchain-cell-enter 480ms cubic-bezier(0.25, 0.8, 0.25, 1) both;
}

.rolling-cell.is-exiting {
  animation: guide-onchain-cell-exit 520ms ease both;
}

@keyframes guide-onchain-cell-enter {
  0% { opacity: 0.58; transform: translateY(0) scaleY(0.96); filter: brightness(0.96) saturate(0.92); }
  52% { opacity: 1; transform: translateY(-1px) scaleY(1.06); filter: brightness(1.16) saturate(1.10); }
  100% { opacity: 1; transform: translateY(0) scaleY(1); filter: brightness(1.03) saturate(1.04); }
}

@keyframes guide-onchain-cell-exit {
  from { opacity: 1; transform: scaleY(1); filter: brightness(1.03) saturate(1.04); }
  to { opacity: 0.62; transform: scaleY(0.97); filter: brightness(0.94) saturate(0.78); }
}

.rolling-window__labels {
  display: flex;
  justify-content: space-between;
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

/* "Today" answers the arrival with contrast, never with amber. */
.rolling-window__today {
  opacity: 0.62;
  transition: opacity 360ms ease, color 360ms ease;
}

.rolling-window.is-complete .rolling-window__today {
  opacity: 1;
  color: var(--text-primary);
}

/* Where color-mix is supported, the cell colours grade per cell:
   start-green into middle across days 1-14, middle into end-green
   across 15-26, brightening slightly toward Today; the border becomes
   a true 6% of the text colour; the mint light's core takes the
   highlight token. */
@supports (background: color-mix(in srgb, red 34%, transparent)) {
  .rolling-cell {
    border-color: color-mix(in srgb, currentColor 6%, transparent);
    --window-cell-color: color-mix(in srgb, var(--window-green-middle) calc((var(--day-index) + 1) * 7%), var(--window-green-start));
  }

  .rolling-cell:nth-child(n + 15):nth-child(-n + 26) {
    --window-cell-color: color-mix(in srgb, var(--window-green-end) calc((var(--day-index) - 13) * 8%), var(--window-green-middle));
  }

  .rolling-cell.is-active {
    background: linear-gradient(180deg, color-mix(in srgb, var(--window-cell-color) 82%, white), var(--window-cell-color));
  }

  .rolling-window__cells::after {
    background: radial-gradient(ellipse, color-mix(in srgb, var(--window-highlight) 62%, transparent) 0%, rgba(125, 214, 187, 0.18) 42%, transparent 72%);
  }
}

/* ---------- The arrival into Today ----------
   A deliberate transition rather than a green-to-yellow jump: 27
   green-lime, 28 lime-yellow, 29 gold, 30 amber - the endpoint at
   the right edge, no green after amber. Single per-cell colours,
   scoped to this component's cells; placed AFTER the @supports block
   so they outrank the graded greens. */
.rolling-cell:nth-child(27).is-active { --window-cell-color: #9fcf78; }
.rolling-cell:nth-child(28).is-active { --window-cell-color: #d8d65e; }
.rolling-cell:nth-child(29).is-active { --window-cell-color: #f5ca4f; }
.rolling-cell:nth-child(30).is-active { --window-cell-color: #f5ad31; }

/* Light-mode greens would glare on graphite: 27 and 28 deepen in the
   dark theme, while gold and amber stay the luminous endpoint. */
[data-theme="dark"] .rolling-cell:nth-child(27).is-active { --window-cell-color: #6da457; }
[data-theme="dark"] .rolling-cell:nth-child(28).is-active { --window-cell-color: #b3b148; }

.rolling-cell:nth-child(30).is-active {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.58), 0 0 15px rgba(245, 173, 49, 0.18);
}

/* Stillness during the completed hold: the amber glow eases ~15%. */
.rolling-window.is-complete .rolling-cell:nth-child(30).is-active {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.58), 0 0 13px rgba(245, 173, 49, 0.15);
}

/* Phones: one line always, tighter and quieter - reduce the effects,
   never the duration. */
@media (max-width: 480px) {
  .rolling-window__cells { gap: 1px; }

  .rolling-window__cells::after {
    width: 34px;
    filter: blur(4px);
    opacity: calc(var(--light-opacity, 0) * 0.66);
  }

  .rolling-cell {
    height: 28px;
    border-radius: 2px;
    border-width: 0;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
  }

  .rolling-cell:nth-child(30).is-active {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30), 0 0 7px rgba(245, 173, 49, 0.18);
  }
}

/* ---------- Three principles ---------- */

.guide-principles {
  list-style: none;
  margin: 0 0 var(--sp-4);
  padding-left: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-5);
}

.guide-principles li {
  padding-top: var(--sp-4);
  border-top: 2px solid var(--border-strong);
}

.pr-label {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-title);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.pr-text {
  margin: 0;
  color: var(--ink-2);
}

/* ---------- Small metric cards ---------- */

.guide-metrics {
  list-style: none;
  margin: 0 0 var(--sp-4);
  padding-left: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-2);
}

.guide-metrics li {
  padding-top: var(--sp-3);
  padding-bottom: var(--sp-3);
  padding-left: var(--sp-4);
  padding-right: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-ui);
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

/* ---------- Routine timeline ----------
   Vertical and static: a reading device, not a control. */

.guide-timeline {
  list-style: none;
  margin: 0 0 var(--sp-6);
  padding-left: 0;
}

.tl-item {
  position: relative;
  padding-left: var(--sp-8);
  padding-bottom: var(--sp-6);
  border-left: 2px solid var(--border);
}

.tl-item:last-child {
  padding-bottom: 0;
  border-left-color: transparent;
}

.tl-item::before {
  content: "";
  position: absolute;
  left: -7px;
  top: 4px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--green-dark);
}

.tl-when {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-title);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.tl-text {
  margin: 0;
  color: var(--ink-2);
}

.guide-closing {
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  color: var(--ink);
  font-weight: 600;
}

/* ---------- Video feature ----------
   An editorial feature, not a media box: one 16:9 media frame, no
   nested cards. Click to load, so nothing reaches YouTube until the
   visitor asks. */

.video-feature {
  padding-top: 0;
  margin-top: var(--sp-14);
  margin-bottom: var(--sp-14);
  scroll-margin-top: var(--sp-16);
}

.video-title {
  margin: var(--sp-2) 0 var(--sp-2);
  font-size: var(--fs-guide-h);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.video-desc {
  margin: 0 0 var(--sp-5);
  color: var(--ink-2);
  max-width: 62ch;
}

/* The same reserved box before and after loading, so swapping the
   preview for the iframe shifts nothing. */
.video-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--surface-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: 16px;
  box-shadow: var(--shadow-xs);
}

.video-frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* A real button, so Enter and Space work with no extra handling */
.yt-preview {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.yt-thumb {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.yt-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 68px;
  height: 48px;
  transition: opacity 0.16s ease;
}

.yt-play svg { display: block; width: 100%; height: 100%; }

/* A small red accent is enough: no oversized brand decoration */
.yt-play-bg { fill: #1f1f1f; opacity: 0.85; }
.yt-play-arrow { fill: #ffffff; }

.yt-preview:hover .yt-play-bg { fill: #cc0000; opacity: 1; }
.yt-preview:focus-visible { outline: 2px solid var(--green-dark); outline-offset: -4px; }

.video-cta { margin: var(--sp-4) 0 0; }

.video-cta a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--fs-meta);
  font-weight: 600;
}

@media (min-width: 700px) {
  .video-frame { border-radius: 20px; }
}

/* Toolbar and its topbar shortcut do not apply to the guide.
   display:flex on .topbar-search would otherwise defeat [hidden]. */
.topbar-search[hidden] { display: none; }

@media (min-width: 700px) {
  .guide-shell {
    padding-top: var(--sp-12);
    gap: var(--sp-8);
  }

  .ov-modules {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-4);
  }

  .sub-modules { grid-template-columns: repeat(2, 1fr); }

  .guide-principles { grid-template-columns: repeat(3, 1fr); }

  .guide-metrics { grid-template-columns: repeat(2, 1fr); }

  /* Larger tiles on desktop; still one left-aligned line, never
     stretched across the full column. */
  .ws-days { gap: 11px; }
  .ws-days li { width: 55px; gap: 10px; }
  .day-tile { border-radius: 14px; }
  .ws-day { font-size: 0.8125rem; }
}

/* Mobile density: the guide stays fully scannable but shorter. The
   module grids keep their desktop two-column shape instead of
   stacking, air between sections comes down, card padding tightens,
   and importance is carried by the typography rather than the gaps. */
@media (max-width: 699px) {
  .guide-section + .guide-section {
    margin-top: var(--sp-8);
    padding-top: var(--sp-6);
  }

  .guide-section .sec-head { margin-bottom: var(--sp-3); }

  .week-strip,
  .window-strip { margin-bottom: var(--sp-4); }

  .ov-modules {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-3);
  }

  .sub-modules {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-3);
  }

  .ov-module,
  .sub-module {
    padding-top: var(--sp-3);
    padding-bottom: var(--sp-3);
    padding-left: var(--sp-4);
    padding-right: var(--sp-4);
  }

  .video-feature {
    margin-top: var(--sp-6);
    margin-bottom: var(--sp-6);
  }

  .guide-principles li { padding-top: var(--sp-3); }

  /* Four short facts read fine as a 2x2, exactly as on desktop. */
  .guide-metrics {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-3);
  }

  .guide-metrics li {
    padding-top: var(--sp-2);
    padding-bottom: var(--sp-2);
    padding-left: var(--sp-3);
    padding-right: var(--sp-3);
  }

  .guide-insight {
    padding-top: var(--sp-3);
    padding-bottom: var(--sp-3);
    padding-left: var(--sp-4);
    padding-right: var(--sp-4);
  }

  .tl-item { padding-bottom: var(--sp-4); }

  .guide-flow li {
    padding-top: var(--sp-1);
    padding-bottom: var(--sp-1);
    padding-left: var(--sp-2);
    padding-right: var(--sp-3);
  }
}

/* ---------- Guide rail ----------
   Desktop only. Never rendered on mobile, so it is never sticky
   there either: the whole block, position included, lives inside the
   two-column breakpoint. */

.guide-rail { display: none; }

@media (min-width: 1000px) {
  .guide-shell {
    display: grid;
    grid-template-columns: 220px minmax(0, 760px);
    column-gap: var(--sp-16);
    align-items: start;
  }

  .guide-rail {
    display: block;
    position: sticky;
    top: 68px;
    align-self: start;
  }

  .guide-rail ol {
    margin: 0;
    padding-left: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
  }

  .rail-link {
    display: flex;
    align-items: center;
    min-height: 44px;
    gap: var(--sp-3);
    padding-top: var(--sp-2);
    padding-bottom: var(--sp-2);
    padding-left: var(--sp-4);
    padding-right: var(--sp-2);
    border-left: 2px solid var(--border);
    font-size: var(--fs-meta);
    line-height: 1.35;
    color: var(--ink-2);
    transition: color 0.16s ease, border-color 0.16s ease;
  }

  .rail-link:hover {
    color: var(--ink);
    border-left-color: var(--border-strong);
    text-decoration: none;
  }

  .rail-link.is-current {
    color: var(--ink);
    font-weight: 600;
    border-left-color: var(--green-dark);
  }

  .rail-num { font-variant-numeric: tabular-nums; }
  .rail-link.is-current .rail-num { color: var(--green-dark); }
}

/* SKR Utility section chrome: small source attribution under the
   intro, quiet informational note after the groups, and the card
   availability line. All meta-sized and muted - no banners. */
.utility-note {
  margin: var(--sp-8) 0 0;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
  font-size: var(--fs-meta);
  color: var(--ink-2);
  max-width: 65ch;
}


/* ---------- Toolbar (search + filters) ---------- */

/* NOT sticky: the compact top bar is the single sticky layer - its
   search icon jumps back down here. The toolbar scrolls away with
   the page so cards get the full viewport while browsing. */
.controls {
  background: var(--bar-bg);
  border-bottom: 1px solid var(--border);
  padding: var(--sp-2) 0;
}

.controls-inner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.search-box { position: relative; }

.search-box input {
  width: 100%;
  min-height: 48px;
  padding: var(--sp-2) var(--sp-12) var(--sp-2) var(--sp-4);
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-ui);
  outline: none;
}

.search-box input:focus { border-color: var(--green-dark); }
.search-box input:focus-visible {
  outline: 2px solid var(--green-dark);
  outline-offset: 2px;
}
.search-box input::placeholder { color: var(--ink-2); }
.search-box input::-webkit-search-cancel-button { display: none; }

.search-clear {
  position: absolute;
  right: var(--sp-1);
  top: 50%;
  transform: translateY(-50%);
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-2);
  border-radius: var(--r-ui);
}
.search-clear:hover { color: var(--ink); }
.search-clear svg { width: 14px; height: 14px; }

.filters-wrap { min-width: 0; }

.filters {
  display: flex;
  gap: var(--sp-2);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* Right-edge fade signals that the row scrolls */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent);
}
.filters::-webkit-scrollbar { display: none; }
.filters[hidden] { display: none; } /* display:flex must not defeat hidden */

/* Same bug class as above: the closed sheet/backdrop must never keep
   a layout box - an invisible fixed element over the toolbar was
   swallowing clicks on the filter pills. */
.sheet[hidden],
.sheet-backdrop[hidden] { display: none; }
.filters.at-end {
  -webkit-mask-image: none;
  mask-image: none;
}

.pill {
  flex: 0 0 auto;
  min-height: 44px;
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  transition: color 0.16s ease, border-color 0.16s ease, background 0.16s ease;
}

.pill:hover { color: var(--ink); border-color: var(--border-strong); }

.pill.active {
  color: var(--on-accent);
  background: var(--accent-fill);
  border-color: var(--accent-fill);
}

/* ---------- Sections ---------- */

/* Mobile: short runway to the first card; desktop restores air */
section { padding: var(--sp-6) 0 0; }

.sec-head { margin-bottom: var(--sp-6); }

.sec-label {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--green-dark);
  font-variant-numeric: tabular-nums;
}

.sec-label .arrow { margin-left: var(--sp-1); }

/* h3 here is the guide's section level - same editorial treatment as
   the h2 the directory views use under their own numbered label */
.sec-head h2,
.sec-head h3 {
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-title);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.section-sub {
  margin: 0;
  color: var(--ink-2);
  max-width: 56ch;
}

.count-note {
  font-weight: 400;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* ---------- Active Rewards group rails ----------
   Compact editorial rails one step below the numbered sections:
   small uppercase label + muted count + muted copy on a single
   line (desktop), with a thin rule filling the leftover width.
   Numbered labels stay reserved for top-level sections. */

.group-rail {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--sp-3);
  row-gap: var(--sp-1);
  margin-bottom: var(--sp-4);
  font-size: var(--fs-meta);
  line-height: 1.45;
}

.rail-label {
  margin: 0;
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.rail-count {
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.rail-sub {
  margin: 0;
  color: var(--ink-2);
  /* Mobile: supporting copy takes its own row, no decorative rule */
  flex-basis: 100%;
}

/* Division between groups: whitespace plus one subtle top border
   before the second group only (adjacent-sibling, so never after
   the last group and never below the first rail) */
.reward-group + .reward-group {
  margin-top: var(--sp-8);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
}

/* Groups read as nested inside Active Rewards, not as new sections */
#active-rewards .sec-head { margin-bottom: var(--sp-4); }

@media (min-width: 700px) {
  .group-rail { margin-bottom: var(--sp-5); }

  .rail-sub { flex-basis: auto; }

  /* Thin rule fills the remaining width after the text */
  .group-rail::after {
    content: "";
    flex: 1;
    min-width: var(--sp-8);
    border-top: 1px solid var(--border);
    align-self: center;
  }

  .reward-group + .reward-group {
    margin-top: var(--sp-12);
    padding-top: var(--sp-6);
  }
}

/* ---------- Card grid ---------- */

.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-4);
}

/* Result updates: quiet fade/rise on newly rendered cards */
@keyframes card-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
}

.card {
  position: relative; /* anchor for the stretched Details hit area */
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  text-align: left;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: var(--sp-6);
  box-shadow: var(--shadow);
  cursor: pointer;
  animation: card-in 0.18s ease backwards;
  transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}

.card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-lift);
  transform: translateY(-2px);
}

.card-top {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
}

.logo-box {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: var(--r-ui);
  border: 1px solid var(--border);
  background: var(--surface-subtle);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.logo-box img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.logo-box.fallback {
  font-weight: 600;
  font-size: var(--fs-title);
  color: var(--ink-2);
  border-radius: 50%;
}

/* Utility logo placeholder: same dimensions as project logos, neutral
   palette tint (never random colors), two-character initials. Also
   the graceful fallback when a mapped image fails to load. */
.logo-box.util.fallback {
  border-radius: var(--r-ui);
  background: var(--green-tint);
  color: var(--green-dark);
  font-size: var(--fs-meta);
  letter-spacing: 0.05em;
}

/* Tab-level empty state (individual sections hide whole) */
.tab-empty { padding-top: var(--sp-8); }

/* Retired-campaign notice: same callout idiom as the sheet, placed
   above the first section instead of inside a detail panel. */
.ended-notice { padding-top: var(--sp-8); }

/* Secondary website text link in the utility detail sheet */
.link-website {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-height: 44px;
  padding: 0 var(--sp-2);
  font-size: var(--fs-meta);
  color: var(--ink-2);
}
.link-website:hover { color: var(--ink); text-decoration: underline; }
.link-website svg { width: 12px; height: 12px; }

/* Utility action rows share a reserved height and sit at a common
   baseline, so rows align across cards with different action sets */
#utility-groups .card-actions-row {
  margin-top: auto;
  min-height: 44px;
}

/* Sheet: informational "find it in the store" line - deliberately
   NOT styled as a button (there is nothing to click) */
.store-note {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  min-height: 44px;
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--ink-2);
}
.store-note svg { width: 15px; height: 15px; flex: 0 0 auto; }

/* Calm risk disclosure (wagering entries) */
.risk-note {
  margin: 0 0 var(--sp-5);
  font-size: var(--fs-meta);
  color: var(--ink-2);
  max-width: 60ch;
}

/* In a campaign sheet the note closes the About block, so its own
   bottom margin would double up with the block's. */
.pb-about .risk-note:last-child { margin-bottom: 0; }

.card-name { min-width: 0; flex: 1; }

.card-name h3,
.card-name h4 {
  margin: 0;
  font-size: var(--fs-title);
  font-weight: 600;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-1);
}

.tag {
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

.tag + .tag::before {
  content: "·" / "";  /* decorative - empty alt text for SRs */
  margin-right: var(--sp-2);
}

.card-summary {
  margin: 0;
  color: var(--ink-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(1.6em * 2);
}

/* Utility summaries run longer than campaign one-liners: allow a
   third line before truncation so none clamp mid-thought */
#utility-groups .card-summary {
  -webkit-line-clamp: 3;
}

/* Deadline: value first, exact date secondary */
.card-deadline {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-variant-numeric: tabular-nums;
}

.deadline-main {
  font-weight: 600;
  color: var(--ink);
}
.deadline-main.tone-warn { color: var(--warn); }
.deadline-main.tone-critical { color: var(--critical); }

.deadline-sub {
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

.card-actions-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

/* Stretched-link pattern: the Details button's hit area covers the
   whole card via a pseudo-element, making "tap any project" literal.
   Sibling actions (Follow, Claim) stack above it with their own
   z-index and keep working; Details stays the only focusable control
   for opening, so keyboard and SR behavior are unchanged. */
.card [data-details]::after,
.card [data-udetails]::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--r-card);
  cursor: pointer;
}

.card-actions-row a {
  position: relative;
  z-index: 1;
}

.card-meta {
  margin: 0;
  font-size: var(--fs-meta);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* ---------- Action buttons ---------- */

.btn-primary,
.btn-secondary {
  min-height: 44px;
  padding: var(--sp-2) var(--sp-5);
  border-radius: 999px;
  font-size: var(--fs-meta);
  font-weight: 600;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.16s ease, border-color 0.16s ease;
}

.btn-primary {
  background: var(--accent-fill);
  border: 1px solid var(--accent-fill);
  color: var(--on-accent);
}
.btn-primary:hover { background: var(--accent-fill-hover); border-color: var(--accent-fill-hover); }

/* Anchor-styled buttons must not underline */
a.btn-primary:hover, a.btn-secondary:hover { text-decoration: none; }

.btn-secondary {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--ink);
}
.btn-secondary:hover { background: var(--surface-subtle); }

/* ---------- Pill buttons (external links) ---------- */

.btn-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-1) var(--sp-4);
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  white-space: nowrap;
  transition: background 0.16s ease, border-color 0.16s ease;
}

.btn-pill:hover {
  text-decoration: none;
  background: var(--surface-subtle);
}

.btn-pill svg {
  width: 13px;
  height: 13px;
  flex: 0 0 auto;
}

.btn-pill.btn-lg {
  min-height: 44px;
  padding: var(--sp-2) var(--sp-5);
  font-size: var(--fs-body);
}

.btn-pill.btn-lg svg {
  width: 15px;
  height: 15px;
}

/* ---------- Detail dialog: bottom sheet (mobile) / modal (desktop) ---------- */

.sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--backdrop);
  opacity: 0;
  transition: opacity 0.26s ease;
}
.sheet-backdrop.open { opacity: 1; }

.sheet {
  position: fixed;
  z-index: 41;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 92vh;
  max-height: 92dvh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card) var(--r-card) 0 0;
  transform: translateY(100%);
  transition: transform 0.28s ease;
  overscroll-behavior: none;
  touch-action: pan-y;
}
.sheet.open { transform: translateY(0); }

/* Transitions off while the sheet follows the finger */
.sheet.dragging { transition: none; }

/* Drag handle (mobile bottom sheet only) */
.sheet-grabber {
  flex: 0 0 auto;
  display: flex;
  justify-content: center;
  padding: var(--sp-2) 0 0;
}

.sheet-grabber span {
  width: 36px;
  height: 4px;
  border-radius: 999px;
  background: var(--border-strong);
}

.sheet-head {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
}

.sheet-head .logo-box { width: 44px; height: 44px; }

.sheet-head-text { min-width: 0; flex: 1; }

.sheet-head-text h3 {
  margin: 0;
  font-size: var(--fs-title);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sheet-sub {
  margin: 2px 0 0;
  font-size: var(--fs-meta);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.sheet-close {
  min-height: 44px;
  min-width: 44px;
  padding: var(--sp-2) var(--sp-4);
  border-radius: 999px;
  border: 1px solid var(--border);
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--ink-2);
}
.sheet-close:hover { color: var(--ink); border-color: var(--border-strong); }

.sheet-body {
  position: relative;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: var(--sp-5) var(--sp-5) var(--sp-6);
}

.sheet-ends {
  margin: 0 0 var(--sp-5);
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

.sheet-body h4 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.panel-block { margin-bottom: var(--sp-6); }

.panel-block.pb-perks h4,
.panel-block.pb-quests h4 { color: var(--green-dark); }

.sheet-actionbar {
  padding: var(--sp-3) var(--sp-5) calc(var(--sp-3) + env(safe-area-inset-bottom));
  border-top: 1px solid var(--border);
}
.sheet-actionbar .btn-primary { width: 100%; }

/* ---------- Callout (e.g. $SKR allocation bonus) ---------- */

.callout {
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  background: var(--green-tint);
  border-radius: var(--r-ui);
}

.callout-label {
  display: block;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--green-dark);
}

.callout p {
  margin: 0;
  font-weight: 400;
  color: var(--ink-2);
}

.sheet-body p {
  margin: 0 0 var(--sp-2);
  color: var(--ink-2);
  max-width: 65ch;
}
.sheet-body p:last-child { margin-bottom: 0; }

.sheet-body ul, .sheet-body ol {
  margin: 0;
  padding-left: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  color: var(--ink-2);
  max-width: 65ch;
}

.link-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.panel-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: var(--fs-meta);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.empty {
  grid-column: 1 / -1;
  padding: var(--sp-12) 0;
  text-align: center;
  color: var(--ink-2);
}

.empty p { margin: 0 0 var(--sp-4); }

/* ---------- About ---------- */

.about-grid {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.about-copy { color: var(--ink-2); max-width: 56ch; }
.about-copy p { margin: 0 0 var(--sp-4); }
.about-copy strong { color: var(--ink); }

.methodology {
  margin: var(--sp-5) 0;
  border: 1px solid var(--border);
  border-radius: var(--r-ui);
  padding: var(--sp-4);
  background: var(--surface);
}

.methodology summary {
  display: flex;
  align-items: center;
  cursor: pointer;
  font-weight: 600;
  color: var(--ink);
  min-height: 44px;
  margin: calc(-1 * var(--sp-2)) 0;
}
.methodology summary::before {
  content: "▸";
  color: var(--ink-2);
  margin-right: var(--sp-2);
  transition: transform 0.16s ease;
}
.methodology[open] summary::before { transform: rotate(90deg); }
.methodology summary::-webkit-details-marker { display: none; }

.methodology p { margin: var(--sp-3) 0 0; }

.submit-btn { margin-top: var(--sp-2); }
a.submit-btn:hover { text-decoration: none; }

/* ---------- Footer ---------- */

.site-footer {
  margin-top: var(--sp-16);
  padding: var(--sp-8) 0 var(--sp-14);
  border-top: 1px solid var(--border);
  color: var(--ink-2);
  font-size: var(--fs-meta);
}

.footer-grid {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.footer-head {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.footer-brand p { max-width: 42ch; }

.footer-social {
  list-style: none;
  margin: 0;
  padding-left: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Icon plus visible label, never icon-only */
.footer-social a {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding-left: var(--sp-3);
  padding-right: var(--sp-4);
  border: 1px solid var(--border-subtle);
  border-radius: 999px;
  background: var(--surface-raised);
  color: var(--ink);
  font-weight: 600;
  transition: border-color 0.16s ease, background 0.16s ease;
}

.footer-social a:hover {
  text-decoration: none;
  border-color: var(--border-strong);
  background: var(--surface-active);
}

.social-mark {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

.footer-checked {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
  max-width: 65ch;
}

.footer-strong {
  font-weight: 600;
  color: var(--ink);
}

.site-footer p { margin: 0 0 var(--sp-2); }

.footer-note {
  margin-top: var(--sp-5);
  max-width: 65ch;
}

.disclaimer {
  margin-top: var(--sp-2);
  max-width: 65ch;
}

.footer-logo {
  height: 14px;
  width: auto;
  display: block;
  margin-top: var(--sp-4);
  opacity: 0.5;
}

/* ---------- Larger screens ---------- */

@media (min-width: 700px) {
  .site-header {
    padding-top: var(--sp-16);
    padding-bottom: var(--sp-16);
  }

  /* Headline column 600 to 720px, supporting copy narrower still */
  .hero-text h1 { max-width: 15ch; }
  .tagline { max-width: 46ch; }

  .eyebrow-tools { position: static; }

  .freshness { gap: var(--sp-2); }

  .fresh-stat {
    gap: var(--sp-2);
    padding-top: var(--sp-2);
    padding-bottom: var(--sp-2);
    padding-left: var(--sp-4);
    padding-right: var(--sp-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
  }

  .controls-inner {
    flex-direction: row;
    align-items: center;
    gap: var(--sp-4);
  }
  .search-box { flex: 0 0 320px; }
  .filters-wrap { flex: 1; min-width: 0; }

  section { padding: var(--sp-22) 0 0; }

  .grid { grid-template-columns: repeat(2, 1fr); }

  /* Desktop: centered modal instead of bottom sheet */
  .sheet {
    left: 50%;
    right: auto;
    bottom: auto;
    top: 50%;
    width: min(720px, calc(100vw - 48px));
    max-height: 85vh;
    border-radius: var(--r-card);
    opacity: 0;
    transform: translate(-50%, -50%) translateY(8px);
    transition: opacity 0.22s ease, transform 0.22s ease;
  }
  .sheet.open {
    opacity: 1;
    transform: translate(-50%, -50%);
  }
  .sheet-actionbar { display: none; }
  .sheet-grabber { display: none; }
  .sheet-body { padding: var(--sp-6) var(--sp-8) var(--sp-8); }

  .about-grid {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: var(--sp-12);
  }

  .footer-grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--sp-12);
  }

  .site-footer { padding-top: var(--sp-12); }
}

@media (min-width: 1000px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
}

/* ---------- Reduced motion ---------- */

/* Blanket rule rather than a hand-maintained selector list: any
   component added later is covered without having to remember to add
   it here. Motion is reduced to an imperceptible duration rather than
   removed outright, so transitionend listeners still fire. */
@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;
  }

  html { scroll-behavior: auto; }
  .card:hover { transform: none; }
}

