/* OpeningMatrix shell: fixed left sidebar.
   Palette = deep-blue surfaces + theme-aware neon signal. */

html[data-design="sigma"] {
  /* The rail is driven from here, so the whole thing is tunable in one place.

     The rail used to be far wider, with 50px rows and a 1.34rem glyph. All three
     of those were too big for the content: the labels are one short word each,
     so the rail was mostly empty, and a large glyph on a tall row is furniture
     scaled for a dashboard tile rather than for a list of links.

     It is now 296px. The rows come down with it and the sections spread apart to
     take the space back — 6 rows x -6px is 36px returned, and the group gap goes
     26px -> 32px, so the rail is about the same height as before but every row
     has air around it. Shrinking the rail without widening the rhythm would just
     have produced the same cramped list in a narrower box.

     --sidebar-nav-icon and --sidebar-nav-stroke are the two numbers that scale
     the glyphs. They are separate on purpose: a thinner glyph at the old size
     goes anaemic and disappears, and a thicker one at the new size shouts over
     the label beside it. Both have to move together.

     Deliberately not a round number, and deliberately not the value the drawer
     used to hardcode in a media query — test_sidebar_scale.py forbids that
     literal outright so it cannot come back as a width that ignores the token. */
  --sidebar-w: 296px;
  /* The folded width. One number, read by the same three places the open rail
     reads --sidebar-w from — the rail, the page offset and the flyout panel's
     edge — so collapsing moves all three together and a flyout still hangs off
     the narrow rail instead of floating over the page.

     96px, not the 76px this was. At 76px the strip cleared its 1.15rem glyph
     with so little to spare that the icons were the smallest aimable thing on
     the page at the exact moment the labels had gone and the glyphs were all
     that was left to recognise a row by. Widening the strip and re-pointing
     --sidebar-nav-icon up inside the fold (see the is-sidebar-collapsed block)
     are one decision: a wider strip carrying the old small glyphs is a rail
     with dead space in it, and a bigger glyph in the old narrow strip is a
     glyph that has outgrown its box. 96px still sits well under half the open
     rail, so this is a roomier strip and not a second layout.

     A token rather than a literal for the same reason --sidebar-w is one. */
  --sidebar-w-collapsed: 96px;
  --sidebar-nav-icon: 1.15rem;
  --sidebar-nav-stroke: 1.25;
  /* Vertical rhythm, and the two are deliberately different numbers for two
     different jobs rather than one spacing value used everywhere.

     --sidebar-row-gap is the gap between any two adjacent CARDS. Because every
     section in the rail is one row, this is also the gap between sections in
     practice, and it has to be big enough to see the rail between two cards —
     below about 6px the borders merge into one box and the rail reads as a
     stack of panels instead of a list of destinations.

     --sidebar-group-gap is the TOTAL gap at a section boundary, so it is
     applied as an increment on top of the row gap rather than instead of it.
     Sections therefore step once further than ordinary neighbours, which is
     what lets the eye find the boundary without a heavy rule.

     Both are tokens because the drawer inherits them. */
  --sidebar-row-gap: 8px;
  --sidebar-group-gap: 16px;
  /* Motion. Only one number is left.

     --sidebar-card-in is how long the entrance takes. It has to outrun the
     stagger below, or the last row is still arriving after the stagger has
     finished talking.

     The hover raise and the sheen that used to sit beside these are gone, and
     both are gone for the same reason: they were card-only. A raise needs a card
     to lift, and a travelling sheen needs a surface to travel across. On a flush
     row they read as a label floating off the page and as a light streak over the
     rail respectively, so the wash and the icon's own response carry the hover on
     their own. */
  --sidebar-card-in: 460ms;
  /* Flush rows want a tighter radius than cards did. A card stood alone and
     needed the rounding to stop its corners catching the eye before the glyph; a
     flush row sits edge to edge with its neighbours, and at 12px the radius was
     wide enough to see the rail through the gap between two rows. */
  --radius-nav: 10px;
  --radius-card: 12px;
  --om-brass: var(--gold);
  --om-brass-bright: var(--gold-bright);
  /* Practice streak.

     The flame tracks the accent, and it always has for one reason rather than
     decoration: the streak card is the largest coloured object in the rail, so
     leaving it on a second hue makes the shell read as two palettes stacked
     instead of one. Every theme so far has rejected the flame that did not
     match — first the green one, then the blue one — and the accent has now
     come round to green a second time.

     So this is the green plasma ramp: deep at the core, brightest at the tip,
     which is the shape a flame has and also the shape a neon filament has. The
     core is deliberately deeper and more saturated than --gold, because --gold
     is a text and border colour tuned for contrast on a dark field and at card
     scale that same value reads washed out. */
  --streak-core: #0a7a1f;
  --streak-mid: #17a83a;
  --streak-edge: #39ff14;
  --streak-ink: #b6ffcf;
}

/* ——— OM tokens: deep blue surfaces + neon signal ———

   NOTE: these duplicate the surface and accent tokens from style_dark.css, and
   this copy is the one that wins — it is scoped to
   html[data-design="sigma"][data-theme="dark"] and this file loads after
   style_dark.css. Retinting only one of the two leaves the design rendering its
   own value, which reads as the change having had no effect at all. They have
   to be edited together; tests/test_theme_tokens.py enforces that they match.

   The --data-* ramp is the deliberate exception and is NOT duplicated here:
   style_dark.css owns it and this file inherits it through :root, so a result
   colour can never come to mean two different things. */
html[data-design="sigma"][data-theme="dark"] {
  /* Deep Blue + Neon (dark). The surfaces are a blue-black rather than the warm
     charcoal this replaced, because a near-black carrying a blue cast lets the
     accent read as a light source IN the room instead of a colour painted on top
     of one. That is the whole intent: neon on deep blue is the pairing where the
     signal colour looks like it is emitting.

     The accent is the opposite of the light theme. Here the neon itself is the
     legible step (14.4:1 on --bg), so --gold-bright is the LIGHTER neighbour
     and --gold-deep carries fills and gradients.

     --ink sits ON the accent as button type, so it is a green-cast near-black
     rather than a neutral one. It has to stay genuinely dark (tests assert
     luminance < 80) or the accent buttons stop being dark-on-light. */
  --bg: #080d14;
  --bg-2: #0e141d;
  --bg-3: #151d28;
  --cream: #eef4fa;
  --cream-dim: #9fb1c4;
  --gold: #39ff14;
  --gold-bright: #7cff4a;
  --gold-deep: #00cc22;
  --felt: #111925;
  --felt-deep: #070b11;
  --text: #eef4fa;
  --muted: #8fa3b8;
  --line: rgba(190, 220, 255, 0.1);
  --line-strong: rgba(190, 220, 255, 0.18);
  --panel: rgba(14, 20, 29, 0.96);
  --shadow: rgba(0, 0, 0, 0.5);
  --font: "Outfit", "Segoe UI", sans-serif;
  --serif: "Outfit", "Segoe UI", sans-serif;
  --ink: #04120a;
  --on-solid: #04120a;
  --on-gold: #04120a;
  --fill-subtle: rgba(238, 244, 250, 0.05);
  --hover-fill: rgba(238, 244, 250, 0.085);
  --danger: #f3aaa0;
  --danger-bg: rgba(122, 49, 40, 0.24);
  --danger-border: rgba(204, 111, 96, 0.58);
  --danger-text: #ffd1c9;
  --stat-white: #eef4fa;
  --paper: #151d28;
  --paper-2: #111925;
  --header-bg: rgba(8, 13, 20, 0.92);
  --footer-bg: #080d14;
  --wash-top: #080d14;
  --wash-mid: #080d14;
  --wash-bottom: #0e141d;
  /* The gradient runs light -> deeper as it descends, the same relationship the
     previous accent had, so the button still has somewhere to go. */
  --gold-btn-from: #39ff14;
  --gold-btn-to: #00cc22;
  --gold-btn-border: #39ff14;
  --gold-btn-from-hover: #7cff4a;
  --gold-btn-to-hover: #39ff14;
  --board-mat: #0e141d;
  --input-bg: #111925;
  --input-text: #eef4fa;
  --thumb-bg: #1b2534;
  --overlay-bg: rgba(4, 7, 12, 0.78);
  /* Glows follow the accent. These are literals rather than var(--gold) because
     they are baked into shadow stacks, so leaving them behind is exactly what
     produced a blue halo around warm panels last time. */
  --glow-line: rgba(57, 255, 20, 0.4);
  --panel-glow:
    inset 0 1px 0 rgba(190, 220, 255, 0.055),
    0 12px 30px rgba(0, 0, 0, 0.34);
  --panel-glow-hover:
    inset 0 1px 0 rgba(190, 220, 255, 0.08),
    0 14px 32px rgba(0, 0, 0, 0.4),
    0 0 0 1px rgba(57, 255, 20, 0.4),
    0 0 18px rgba(57, 255, 20, 0.14);

/* ════════════════════════════════════════════════════════════════════
     PREMIUM DESIGN TOKENS — Elevation, Motion, Typography, Surfaces
     ════════════════════════════════════════════════════════════════════ */

  /* Elevation system — four levels from surface to floating modal.
     Each level adds depth without changing the surface colour.
     Values are tuned for the dark blue bg so shadows read as void, not grey. */
  --elev-1: 0 1px 2px rgba(0,0,0,0.35), 0 1px 1px rgba(0,0,0,0.25);
  --elev-2: 0 4px 12px rgba(0,0,0,0.4), 0 2px 4px rgba(0,0,0,0.3);
  --elev-3: 0 12px 28px rgba(0,0,0,0.45), 0 4px 8px rgba(0,0,0,0.35);
  --elev-4: 0 20px 48px rgba(0,0,0,0.5), 0 8px 16px rgba(0,0,0,0.4);

  /* Glassmorphism surfaces — for cards that sit above content. */
  --glass-bg: rgba(14, 20, 29, 0.72);
  --glass-border: rgba(190, 220, 255, 0.08);
  --glass-glow: inset 0 1px 0 rgba(190, 220, 255, 0.06);

  /* Softer accent variants — for large fills where raw neon vibrates. */
  --gold-soft: color-mix(in srgb, var(--gold) 14%, transparent);
  --gold-soft-hover: color-mix(in srgb, var(--gold) 22%, transparent);
  --gold-soft-strong: color-mix(in srgb, var(--gold) 28%, transparent);
  --gold-glow: rgba(57, 255, 20, 0.35);
  --gold-glow-strong: rgba(57, 255, 20, 0.55);

  /* Motion tokens — spring physics for premium feel. */
  --motion-fast: 120ms;
  --motion-base: 200ms;
  --motion-slow: 320ms;
  --motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --motion-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --motion-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --stagger-base: 32ms;

  /* Typography scale — hierarchical, not arbitrary. */
  --text-xs: 0.7rem;
  --text-sm: 0.8125rem;
  --text-base: 0.9375rem;
  --text-lg: 1.0625rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5625rem;
  --text-3xl: 2rem;
  --text-4xl: 2.5rem;
  --text-display: clamp(2.5rem, 4vw, 3.5rem);

  /* Font weights — named for intent. */
  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extrabold: 800;

  /* Line heights. */
  --leading-tight: 1.15;
  --leading-snug: 1.35;
  --leading-normal: 1.55;
  --leading-relaxed: 1.7;

  /* Focus rings — branded, accessible, consistent. */
  --focus-ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--gold);
  --focus-ring-inset: inset 0 0 0 2px var(--gold);

  /* Radius scale. */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 18px;
  --radius-2xl: 24px;
  --radius-pill: 999px;

  /* Transition presets. */
  --transition-fast: var(--motion-fast) var(--motion-ease-out);
  --transition-base: var(--motion-base) var(--motion-ease-out);
  --transition-slow: var(--motion-slow) var(--motion-ease-out);
  --transition-spring: var(--motion-slow) var(--motion-spring);

  /* Z-index scale. */
  --z-base: 1;
  --z-dropdown: 10;
  --z-sticky: 20;
  --z-modal: 40;
  --z-toast: 50;
  --z-tooltip: 60;

  /* Semantic surfaces — clearer intent than raw colours. */
  --surface-1: var(--bg);           /* Page background */
  --surface-2: var(--bg-2);         /* Raised panel */
  --surface-3: var(--bg-3);         /* Interactive surface */
  --surface-panel: var(--panel);    /* Glass panel */
  --surface-glass: var(--glass-bg); /* Frosted glass */
}

html[data-design="sigma"][data-theme="light"] {
  /* White + Neon (light). Surfaces are true white with a faint green cast, so
     the page reads as paper rather than as a tinted panel.

     The accent is a reinterpreted neon — brighter and more saturated than the
     previous deep forest green, so the light theme shares the brand's neon
     personality instead of feeling like a separate palette. Raw neon (#39ff14)
     on white is about 1.4:1 and cannot set type at all, so --gold-bright stays
     a dark step for text readability while --gold carries the vibrant accent
     and the glows deliver the neon atmosphere through shadows and hover states.
     Dark mode inverts this the other way, where neon itself is the legible
     step. */
  --bg: #ffffff;
  --bg-2: #f4f8f4;
  --bg-3: #e8f0e8;
  --cream: #0b1a10;
  --cream-dim: #4a5f52;
  --gold: #22c55e;
  --gold-bright: #16a34a;
  --gold-deep: #0f7d28;
  --felt: #f4f8f4;
  --felt-deep: #e8f0e8;
  --ruby: #7a1f32;
  --text: #0b1a10;
  --muted: #52655a;
  --line: rgba(11, 26, 16, 0.14);
  --line-strong: rgba(11, 26, 16, 0.26);
  --panel: #ffffff;
  --shadow: rgba(11, 26, 16, 0.1);
  --font: "Outfit", "Segoe UI", sans-serif;
  --serif: "Outfit", "Segoe UI", sans-serif;
  --ink: #0b1a10;
  --on-solid: #ffffff;
  --on-gold: #ffffff;
  --fill-subtle: rgba(11, 26, 16, 0.045);
  --hover-fill: rgba(11, 26, 16, 0.07);
  --danger: #b42318;
  --danger-bg: #fef3f2;
  --danger-border: rgba(180, 35, 24, 0.28);
  --danger-text: #b42318;
  --stat-white: #4a5f52;
  --paper: #ffffff;
  --paper-2: #f7faf7;
  --header-bg: rgba(255, 255, 255, 0.92);
  --footer-bg: #ffffff;
  --wash-top: #ffffff;
  --wash-mid: #f4f8f4;
  --wash-bottom: #e8f0e8;
  /* Buttons carry the DEEP green, not the neon: white type on #39ff14 would be
     unreadable. --glow-line is where this theme gets its neon. */
  --gold-btn-from: #16a34a;
  --gold-btn-to: #0f7d28;
  --gold-btn-border: #16a34a;
  --gold-btn-from-hover: #22c55e;
  --gold-btn-to-hover: #16a34a;
  --board-mat: #f4f8f4;
  --input-bg: #ffffff;
  --input-text: #0b1a10;
  --thumb-bg: #22c55e;
  --overlay-bg: rgba(255, 255, 255, 0.94);
  --glow-line: rgba(34, 197, 92, 0.5);
  --panel-glow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 1px 2px rgba(11, 26, 16, 0.05),
    0 10px 24px rgba(11, 26, 16, 0.07);
  --panel-glow-hover:
    inset 0 1px 0 rgba(255, 255, 255, 1),
    0 8px 16px rgba(11, 26, 16, 0.07),
    0 22px 40px rgba(11, 26, 16, 0.1),
    0 0 0 1px rgba(34, 197, 92, 0.5),
    0 0 24px rgba(34, 197, 92, 0.2);
/* ════════════════════════════════════════════════════════════════════
     PREMIUM DESIGN TOKENS — Light Theme
     ════════════════════════════════════════════════════════════════════ */

  /* Elevation — softer for light theme, using ink colour not black. */
  --elev-1: 0 1px 2px rgba(11,26,16,0.08), 0 1px 1px rgba(11,26,16,0.06);
  --elev-2: 0 4px 12px rgba(11,26,16,0.1), 0 2px 4px rgba(11,26,16,0.08);
  --elev-3: 0 12px 28px rgba(11,26,16,0.12), 0 4px 8px rgba(11,26,16,0.1);
  --elev-4: 0 20px 48px rgba(11,26,16,0.15), 0 8px 16px rgba(11,26,16,0.12);

  /* Glassmorphism for light theme. */
  --glass-bg: rgba(255, 255, 255, 0.88);
  --glass-border: rgba(11, 26, 16, 0.08);
  --glass-glow: inset 0 1px 0 rgba(255, 255, 255, 0.9);

  /* Softer accent variants — green-based for light theme. */
  --gold-soft: color-mix(in srgb, var(--gold) 18%, transparent);
  --gold-soft-hover: color-mix(in srgb, var(--gold) 28%, transparent);
  --gold-soft-strong: color-mix(in srgb, var(--gold) 36%, transparent);
  --gold-glow: rgba(34, 197, 92, 0.4);
  --gold-glow-strong: rgba(34, 197, 92, 0.6);

  /* Motion tokens — shared with dark. */
  --motion-fast: 120ms;
  --motion-base: 200ms;
  --motion-slow: 320ms;
  --motion-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --motion-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --motion-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --stagger-base: 32ms;

  /* Typography scale — shared. */
  --text-xs: 0.7rem;
  --text-sm: 0.8125rem;
  --text-base: 0.9375rem;
  --text-lg: 1.0625rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5625rem;
  --text-3xl: 2rem;
  --text-4xl: 2.5rem;
  --text-display: clamp(2.5rem, 4vw, 3.5rem);

  /* Font weights — shared. */
  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extrabold: 800;

  /* Line heights — shared. */
  --leading-tight: 1.15;
  --leading-snug: 1.35;
  --leading-normal: 1.55;
  --leading-relaxed: 1.7;

  /* Focus rings — branded, accessible. */
  --focus-ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--gold);
  --focus-ring-inset: inset 0 0 0 2px var(--gold);

  /* Radius scale — shared. */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 18px;
  --radius-2xl: 24px;
  --radius-pill: 999px;

  /* Transition presets — shared. */
  --transition-fast: var(--motion-fast) var(--motion-ease-out);
  --transition-base: var(--motion-base) var(--motion-ease-out);
  --transition-slow: var(--motion-slow) var(--motion-ease-out);
  --transition-spring: var(--motion-slow) var(--motion-spring);

  /* Z-index scale — shared. */
  --z-base: 1;
  --z-dropdown: 10;
  --z-sticky: 20;
  --z-modal: 40;
  --z-toast: 50;
  --z-tooltip: 60;

  /* Semantic surfaces — light theme. */
  --surface-1: var(--bg);
  --surface-2: var(--bg-2);
  --surface-3: var(--bg-3);
  --surface-panel: var(--panel);
  --surface-glass: var(--glass-bg);
}

html[data-design="sigma"][data-theme="dark"] .btn-gold {
  /* Matches --ink. The label sits on a neon fill, so it wants the green-cast
     near-black rather than a neutral black, which would read faintly warm
     against that much green. */
  color: #04120a;
}

html[data-design="sigma"][data-theme="light"] .btn-gold {
  color: #ffffff;
}

/* ——— Shell: fixed left sidebar + scrolling main frame ——— */
html[data-design="sigma"] body {
  display: block;
  min-height: 100vh;
  min-height: 100dvh;
}

html[data-design="sigma"] .site-sidebar {
  display: flex;
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: var(--sidebar-w);
  height: 100vh;
  height: 100dvh;
  z-index: 120;
  flex-direction: column;
  gap: 7px;
  padding: 16px 12px 14px;
  /* A quiet hairline where the rail meets the page — neutral theme line, no
     glow. The rail already carries depth from its darker base; the edge just
     needs to draw the boundary. */
  border-right: 1px solid var(--line);
  box-shadow: none;
  /* One step deeper than --bg-2, so the sidebar reads as a plane behind the
     content rather than the same surface as it. The gold wash at the top is
     unchanged; only the base is darker. */
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--gold) 6%, transparent), transparent 28%),
    var(--bg);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* The fold. Width and the horizontal padding move together, so the icon strip
     is genuinely narrower and not just the same rail with its content clipped.
     The margin-left below carries the page with it. Reduced motion opts out. */
  transition:
    width 0.24s cubic-bezier(0.22, 1, 0.36, 1),
    padding 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}

html[data-design="sigma"] .site-frame {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 100vh;
  min-height: 100dvh;
  margin-left: var(--sidebar-w);
  width: auto;
  background: var(--bg);
  /* Kept in step with the rail's own fold above, so the page slides across with
     it rather than snapping a frame early. */
  transition: margin-left 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}

html[data-design="sigma"] .site-header {
  background: transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: 0;
  contain: none;
}

html[data-design="sigma"] .site-header::after {
  /* The header's bottom edge mirrors the rail's right edge but runs hotter: a
     thick neon core drawn from the solid accent (--gold, so it stays fully
     opaque) with the bloom stacked in three layers off the theme's own glow
     channel (--glow-line). The bloom is pushed down (positive y offsets) so
     the light spills onto the page below rather than haloing the bar. */
  height: 3px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in srgb, var(--gold) 75%, transparent) 22%,
    var(--gold) 50%,
    color-mix(in srgb, var(--gold) 75%, transparent) 78%,
    transparent 100%
  );
  opacity: 1;
  box-shadow:
    0 0 6px color-mix(in srgb, var(--glow-line) 95%, transparent),
    0 0 18px var(--glow-line),
    0 8px 32px -6px color-mix(in srgb, var(--glow-line) 90%, transparent);
}

html[data-design="sigma"] .site-header--utility .site-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: min(1240px, calc(100% - 32px));
  margin: 0 auto;
  min-height: 52px;
  padding: 8px 0;
}

html[data-design="sigma"] .site-header-note {
  display: none;
}

html[data-design="sigma"] .header-sale {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  max-width: min(100%, 640px);
  padding: 7px 10px 7px 8px;
  border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--om-brass) 45%, var(--line));
  background:
    linear-gradient(105deg, color-mix(in srgb, var(--om-brass) 14%, transparent), transparent 58%),
    var(--fill-subtle);
  color: var(--cream);
  text-decoration: none;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--om-brass) 18%, transparent),
    0 0 18px color-mix(in srgb, var(--om-brass) 12%, transparent);
  transition: border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}

html[data-design="sigma"] .header-sale:hover,
html[data-design="sigma"] .header-sale:focus-visible {
  border-color: color-mix(in srgb, var(--om-brass) 70%, var(--line));
  background:
    linear-gradient(105deg, color-mix(in srgb, var(--om-brass) 20%, transparent), transparent 60%),
    var(--hover-fill);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--om-brass) 24%, transparent),
    0 0 22px color-mix(in srgb, var(--om-brass) 22%, transparent);
  outline: none;
}

html[data-design="sigma"] .header-sale-badge {
  flex: 0 0 auto;
  padding: 4px 8px;
  border-radius: 999px;
  background: var(--om-brass);
  color: var(--on-gold);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  animation: header-sale-pulse 2s ease-in-out infinite;
}

html[data-design="sigma"] .header-sale-copy {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 8px;
  min-width: 0;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--cream-dim);
}

html[data-design="sigma"] .header-sale-copy strong {
  color: var(--om-brass-bright);
  font-weight: 800;
  letter-spacing: -0.02em;
}

html[data-design="sigma"] .header-sale-was {
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 600;
  text-decoration: line-through;
  text-decoration-thickness: 1.4px;
  opacity: 0.78;
}

html[data-design="sigma"] .header-sale-cta {
  flex: 0 0 auto;
  margin-left: 2px;
  padding: 5px 10px;
  border-radius: 8px;
  background: #f4f4f5;
  color: var(--on-solid);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

html[data-design="sigma"][data-theme="light"] .header-sale-cta {
  background: var(--gold-btn-from);
  color: var(--on-gold);
}

html[data-design="sigma"] .site-header-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  margin-left: auto;
  flex: 0 0 auto;
}

@keyframes header-sale-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--om-brass) 0%, transparent); }
  50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--om-brass) 20%, transparent); }
}

@media (prefers-reduced-motion: reduce) {
  html[data-design="sigma"] .header-sale-badge {
    animation: none;
  }
}

html[data-design="sigma"] .header-day-run {
  border-color: var(--line);
  background: transparent;
  color: var(--cream-dim);
}

html[data-design="sigma"] .header-day-run:hover,
html[data-design="sigma"] .header-day-run[aria-current="page"] {
  border-color: color-mix(in srgb, var(--om-brass) 45%, var(--line));
  color: var(--cream);
  background: var(--fill-subtle);
}

html[data-design="sigma"] .header-day-run-value {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}

html[data-design="sigma"] .header-theme {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: transparent;
}

html[data-design="sigma"] .header-theme button {
  border: 0;
  min-height: 34px;
  min-width: 58px;
  padding: 0 12px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

html[data-design="sigma"] .header-theme button + button {
  border-left: 1px solid var(--line);
}

html[data-design="sigma"] .header-theme button.is-active {
  color: var(--on-solid);
  background: #f4f4f5;
}

html[data-design="sigma"][data-theme="light"] .header-theme button.is-active {
  color: var(--on-solid);
  background: var(--gold-btn-from);
}

/* ——— Interface sound toggle ———
   Sits beside the theme switch and matches its height and radius. Off is the
   default state, so the resting appearance is deliberately quiet: muted grey
   with a cross through the waves, not a red error treatment. */
html[data-design="sigma"] .header-sound {
  display: block;
  margin-left: 8px;
}

html[data-design="sigma"] .header-sound-btn {
  display: grid;
  place-items: center;
  width: 38px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.18s ease, background-color 0.18s ease, border-color 0.18s ease;
}

html[data-design="sigma"] .header-sound-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Only one of the two glyph sets is ever shown, driven by aria-pressed. */
html[data-design="sigma"] .header-sound-mute {
  display: none;
}

html[data-design="sigma"] .header-sound-btn[aria-pressed="false"] .header-sound-wave {
  display: none;
}

html[data-design="sigma"] .header-sound-btn[aria-pressed="false"] .header-sound-mute {
  display: block;
}

html[data-design="sigma"] .header-sound-btn:hover {
  color: var(--cream);
  background: var(--hover-fill);
}

html[data-design="sigma"] .header-sound-btn.is-on {
  color: var(--on-solid);
  background: #f4f4f7;
  border-color: transparent;
}

html[data-design="sigma"][data-theme="light"] .header-sound-btn.is-on {
  background: var(--gold-btn-from);
}

html[data-design="sigma"] .header-sound-btn:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--om-brass) 68%, transparent);
  outline-offset: 2px;
}

html[data-design="sigma"] .header-signin {
  display: none;
}

html[data-design="sigma"] .site-footer {
  background: var(--bg);
  border-top-color: var(--line);
}

html[data-design="sigma"] .footer-brand em {
  color: var(--om-brass-bright);
  font-style: normal;
}

html[data-design="sigma"] .footer-col a:hover {
  color: var(--om-brass-bright);
}

html[data-design="sigma"] .page-shell {
  background: transparent;
}

/* Keep cards/panels on the same lifted zinc as the shell. */
html[data-design="sigma"][data-theme="dark"] {
  --track-zinc: var(--bg-2);
  --track-gold: var(--gold);
}

html[data-design="sigma"][data-theme="dark"] .opening-card,
html[data-design="sigma"][data-theme="dark"] .profile-card,
html[data-design="sigma"][data-theme="dark"] .repertoire-guest-card,
html[data-design="sigma"][data-theme="dark"] .members-card,
html[data-design="sigma"][data-theme="dark"] .dash-card,
html[data-design="sigma"][data-theme="dark"] .dash-kpi,
html[data-design="sigma"][data-theme="dark"] .dash-speed,
html[data-design="sigma"][data-theme="dark"] .dash-rate,
html[data-design="sigma"][data-theme="dark"] .dash-insight,
html[data-design="sigma"][data-theme="dark"] .om-dash,
html[data-design="sigma"][data-theme="dark"] .om-dash-metric,
html[data-design="sigma"][data-theme="dark"] .track-console,
html[data-design="sigma"][data-theme="dark"] .stats-board,
html[data-design="sigma"][data-theme="dark"] .stats-map-btn,
html[data-design="sigma"][data-theme="dark"] .home-integrations-card,
html[data-design="sigma"][data-theme="dark"] .roadmap-card,
html[data-design="sigma"][data-theme="dark"] #features-container,
html[data-design="sigma"][data-theme="dark"] #premium-features-container,
html[data-design="sigma"][data-theme="dark"] #subscriptions-container,
html[data-design="sigma"][data-theme="dark"] #about-container,
html[data-design="sigma"][data-theme="dark"] .register-box,
html[data-design="sigma"][data-theme="dark"] .save-progress-card {
  background: var(--paper);
  border-color: var(--line);
  box-shadow: var(--panel-glow);
}

html[data-design="sigma"][data-theme="dark"] .opening-card:hover,
html[data-design="sigma"][data-theme="dark"] .profile-card:hover,
html[data-design="sigma"][data-theme="dark"] .stats-map-btn:hover {
  background: color-mix(in srgb, var(--paper) 92%, #fff 8%);
  border-color: color-mix(in srgb, var(--om-brass) 35%, var(--line));
  box-shadow: var(--panel-glow-hover);
}

html[data-design="sigma"] .site-sidebar-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
  padding: 2px 6px 12px;
  border-bottom: 1px solid var(--line);
}

html[data-design="sigma"] .site-sidebar-brand .brand {
  flex: 1;
  min-width: 0;
}

html[data-design="sigma"] .site-sidebar-brand .brand-name {
  font-size: 1.18rem;
  letter-spacing: -0.04em;
}

html[data-design="sigma"] .site-sidebar-brand .brand em {
  color: var(--om-brass-bright);
  font-style: normal;
}

/* ——— The collapse toggle ———
   A circular handle straddling the rail's right edge at mid-height,
   half in and half out — the classic rail-collapse pattern. It is taken out
   of the brand row's flow entirely (position: fixed, tracked against the
   rail's own width token) so it rides the edge at both widths and never
   competes with the wordmark. Round and filled with a neutral hairline, so
   it reads as part of the edge: quiet at rest, brightening on hover. The
   chevron rotates to point which way the rail will go, and the
   whole thing is hidden on the phone drawer, where the rail is already a
   slide-over and has no folded state to offer. */
html[data-design="sigma"] .sidebar-collapse-toggle {
  position: fixed;
  left: calc(var(--sidebar-w) - 15px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 130;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: var(--bg-2);
  color: var(--cream-dim);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
  transition:
    left 0.24s cubic-bezier(0.22, 1, 0.36, 1),
    color 0.18s ease,
    background 0.18s ease,
    border-color 0.18s ease,
    box-shadow 0.18s ease;
}

html[data-design="sigma"] .sidebar-collapse-toggle:hover {
  color: var(--cream);
  background: var(--bg-3);
  border-color: var(--cream-dim);
}

html[data-design="sigma"] .sidebar-collapse-toggle:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--om-brass) 68%, transparent);
  outline-offset: 2px;
}

html[data-design="sigma"] .sidebar-collapse-toggle svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* The flip. Left-pointing at rest ("fold me away to the left"), it turns to
     point right when the rail is folded, so the same glyph always names the
     next action. */
  transition: transform 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}

/* ——— The folded rail: an icon strip —————————————————————————————————————
   One class on <html>, `is-sidebar-collapsed`, set by the toggle and replayed
   from storage before first paint. Everything below reads from the same tokens
   the open rail does, so the fold is a change of state, not a second layout:
   the rail, the page offset and the flyout panel's edge all move to
   --sidebar-w-collapsed together, and every label steps aside to leave the
   glyphs.

   Scoped to `min-width: 981px` on purpose. Below that the rail is the phone
   drawer — a slide-over with its own open/close — and there is no folded state
   to offer there, so none of this may leak into it. The toggle itself is hidden
   on the drawer for the same reason (see the max-width block further down). */
@media (min-width: 981px) {
  html[data-design="sigma"].is-sidebar-collapsed {
    /* Re-point the three shared reads at the narrow width. This is the whole
       mechanism: nothing below hardcodes the folded width, so the rail,
       `.site-frame`'s offset and the flyout panel all collapse by the same
       token. */
    --sidebar-w: var(--sidebar-w-collapsed);
    /* And the glyphs scale up with the strip they sit in. The labels are gone
       here, so the icon is the only thing identifying a row — at the open
       rail's 1.15rem it was a 18px mark in the middle of a 96px strip. This
       re-points the same token `.sidebar-link-icon` already reads, so every
       glyph in the fold grows together and nothing below needs a second size.

       rem, not px, for the same reason the open rail's value is: the glyph has
       to scale with the reader's font size. The stroke stays on its own token
       at 1.25 — the shapes are line art on a 24-grid and a heavier weight at
       this size would start filling in the closed counters. */
    --sidebar-nav-icon: 1.4rem;
  }

  html[data-design="sigma"].is-sidebar-collapsed .site-sidebar {
    /* A touch less side padding at this width, so the glyph sits on the optical
       centre of the strip rather than hugging the left edge it had as a label's
       leading margin. */
    padding-left: 10px;
    padding-right: 10px;
  }

  html[data-design="sigma"].is-sidebar-collapsed .sidebar-flyout-panel {
    /* The panel still hangs off the rail's right edge — now the narrow one — so
       the hover/flyout system works unchanged: hover an icon, its section opens
       beside the strip. Reading the token keeps it glued if the width is ever
       retuned. */
    left: var(--sidebar-w-collapsed);
  }

  /* ——— The brand row leaves the strip ———
     The folded rail is an icon strip: the wordmark has no room in it and
     there is no badge to take its place, so the whole brand link drops out
     and the nav rows start straight under the brand row's own divider. The
     toggle is position: fixed on the rail's edge, so it still rides the strip
     at this width without being part of this flow. */
  html[data-design="sigma"].is-sidebar-collapsed .site-sidebar-brand .brand {
    display: none;
  }

  /* The chevron turns to point back the way it will reopen. */
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-collapse-toggle svg {
    transform: rotate(180deg);
  }

  /* ——— Every row becomes a centred icon ———
     The label leaves, the horizontal padding that indented it goes with it, and
     the glyph centres in the row. min-height is untouched, so a row is still a
     44px target — the fold narrows the rail, it does not shrink the hit area. */
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-flyout-trigger {
    justify-content: center;
    gap: 0;
    padding-left: 0;
    padding-right: 0;
  }

  /* All the text steps aside. Grouped in one rule so a new label added to a row
     later is caught by the same fold rather than left jutting into the strip.
     The streak card's figure, headings and week strip go too, leaving the flame
     as the card's lone mark — the strip keeps icons, not numbers or words. */
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-label,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-copy,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-sub,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-chevron,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-shine,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-dot,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-flyout-chevron,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-group-label,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-day-value,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-day-headings,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-week,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-tile-copy {
    display: none;
  }

  /* But when a flyout panel is open, its labels must be readable.
     The panel is a sibling of the trigger, so we target it via the
     [data-sidebar-flyout].is-open state on the parent group. */
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-link-label,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-link-copy,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-link-sub,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-link-chevron,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-link-shine,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-link-dot,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-flyout-chevron,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-group-label,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-day-value,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-day-headings,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-week,
  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-tile-copy {
    display: inline-flex;
  }

  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-link {
    justify-content: flex-start;
    gap: 10px;
    padding-left: 12px;
    padding-right: 12px;
  }

  html[data-design="sigma"].is-sidebar-collapsed [data-sidebar-flyout].is-open .sidebar-flyout-panel .sidebar-flyout-links .sidebar-link {
    min-height: 38px;
  }

  /* ——— The rail floor: streak + settings stack and keep only their marks ———
     Two half-width cards cannot fit the strip, so the pair becomes one column
     and each card keeps the single thing that identifies it — the flame for the
     streak, the gear for settings — with the words gone. The marks scale up with
     the strip too: a 1.15rem-scale flame beside 1.4rem nav glyphs is the partial
     scale this rail has been bitten by before, so the floor rides the same
     enlargement as the list above it. */
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-foot-pair {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
  }

  /* The flame and the gear keep their proportion to each other, just larger:
     1.4/1.15 is the scale the nav glyphs just took, applied to the two marks that
     were sized for the old strip. The numeral is gone in the fold, so the flame
     is the streak card's only mark here and the gear is the settings card's —
     which is exactly why they have to grow with the strip rather than sit in it
     at the open rail's size. */
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-foot-pair .sidebar-day-flame {
    width: 23px;
    height: 28px;
  }

  html[data-design="sigma"].is-sidebar-collapsed .sidebar-foot-pair .sidebar-day-flame svg {
    width: 23px;
    height: 28px;
  }

  html[data-design="sigma"].is-sidebar-collapsed .sidebar-foot-pair .sidebar-tile-icon {
    width: 24px;
    height: 24px;
  }

  html[data-design="sigma"].is-sidebar-collapsed .sidebar-foot-pair .sidebar-tile-icon svg {
    width: 24px;
    height: 24px;
  }

  html[data-design="sigma"].is-sidebar-collapsed .sidebar-day {
    justify-content: center;
    align-items: center;
  }

  html[data-design="sigma"].is-sidebar-collapsed .sidebar-day-head {
    justify-content: center;
    margin-bottom: 0;
  }

  html[data-design="sigma"].is-sidebar-collapsed .sidebar-tile {
    justify-content: center;
  }

  /* The Unlock Unlimited promo row: in collapsed mode, centre the crown icon
     and hide the shine/label/sub/chevron (already handled above), but keep the
     brass tile background so it still reads as the premium CTA. */
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-promo {
    justify-content: center;
    gap: 0;
    padding-left: 0;
    padding-right: 0;
    width: 100%;
  }

  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-promo .sidebar-link-icon {
    width: 32px;
    height: 32px;
    padding: 0;
    margin: 0 auto;
    /* Nudged right onto the strip's optical centre so the emoji sits in line
       with the rest of the sidebar icons. */
    position: relative;
    left: 18px;
  }

  /* Keep the crown icon visible on hover/active/focus in collapsed mode.
     The icon's sapphire gradient background must not show through the SVG. */
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-promo:hover .sidebar-link-icon,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-promo:focus-visible .sidebar-link-icon,
  html[data-design="sigma"].is-sidebar-collapsed .sidebar-link-promo:active .sidebar-link-icon {
    transform: scale(1.06) rotate(-4deg);
    /* The resting glyph glow is switched off here and only here: from this
       state on, the icon is a badge carrying its own background, and a
       drop-shadow over a filled rectangle is a halo around a rectangle. The
       sapphire box-shadow below is already the light this state wants. */
    filter: none;
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.55),
      inset 0 -1px 0 rgba(0, 0, 0, 0.32),
      0 3px 10px rgba(0, 0, 0, 0.32),
      0 0 22px color-mix(in srgb, #4a7dff 65%, transparent);
    /* Explicitly preserve the sapphire gradient background so the crown never
       disappears on hover/focus/active — the link's background change must not bleed. */
    background:
      radial-gradient(ellipse 130% 100% at 50% 85%, color-mix(in srgb, #8ab4ff 55%, transparent), transparent 65%),
      linear-gradient(165deg, #0a1633 0%, #122a5c 30%, #2855b0 65%, #4a7dff 100%);
  }

  /* No hover colour shift on the gem's facet lines in collapsed mode. */
}

html[data-design="sigma"] .site-sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 2px 0;
  /* A slim, themed rail that stays out of the way until the pointer is over
     the nav. The default Chrome scrollbar is a wide grey slab and undoes the
     whole machined-surface treatment. */
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--gold) 34%, transparent) transparent;
  overscroll-behavior: contain;
}

/* The rail's rows.

   This element used to carry a `mask-image` that faded the top and bottom
   edges where a long menu met the boundaries. It does not any more, and the
   removal is deliberate rather than incidental.

   A `mask-image` makes an element a containing block for `position: fixed`
   descendants. With the mask here, every `.sidebar-flyout-panel` inside the nav
   stopped being positioned against the viewport and started being positioned
   against this box — so each panel was trapped inside the rail, clipped by its
   overflow, and painted underneath the page content it was supposed to sit
   over. Clicks landed on the page underneath instead: on /repertoire a flyout
   link resolved to the intro section, on /puzzles to a board square.

   Nothing needs the fade any more. The rail is four section rows plus the
   account block, which fits without scrolling at any realistic viewport, so
   there is no edge for a mask to soften. If the rail ever does grow long enough
   to scroll, the fade has to go somewhere that is not an ancestor of the
   panels — on a `::after` overlay on the rail, never on a container the panels
   descend from. */
html[data-design="sigma"] .sidebar-nav-scroll {
  display: flex;
  flex-direction: column;
  gap: var(--sidebar-group-gap);
  flex: 1 0 auto;
  padding: 4px 0;
  /* Deliberately no mask here. See the note above: a mask on this element —
     which is the panels' own ancestor — turns every flyout panel from
     viewport-positioned into rail-positioned, and they end up clipped and
     behind the page. */
}

/* ——— The entrance ———
   The rail's rows arrive one after another instead of all at once.

   This is the one piece of motion that runs without the pointer, so it is the
   one most worth keeping quiet. The stagger is small — the whole sequence lands
   inside half a second — because the rail is on screen for every page and
   anything longer becomes a wait the reader has to sit through on every
   navigation. It reads as the menu assembling, not as an intro.

   Two constraints, both learned the hard way here:

   · It targets the ROWS, never the group. The flyout panel is a SIBLING of the
     trigger inside `[data-sidebar-flyout]`, so a transform on the trigger does
     not touch the panel — but a transform on the GROUP would, because the group
     is the panel's ancestor. A group-level entrance animation would trap every
     panel inside the rail during the animation and break the hover system for
     as long as it played.

   · It never touches a panel row. `.sidebar-flyout-links .sidebar-link` also
     matches `.sidebar-link`, and animating those would fire a transform on rows
     the reader cannot see until the panel is already animating in.

   `backwards` fill, not `forwards`: before its delay elapses each row holds the
   `from` state, so the first card is never briefly visible at full opacity
   before the sequence starts. */
@keyframes sidebar-card-in {
  from {
    opacity: 0;
    transform: translateY(7px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-link,
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-group-links-inner > .sidebar-link,
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-flyout-trigger {
  animation: sidebar-card-in var(--sidebar-card-in) cubic-bezier(0.22, 1, 0.36, 1) backwards;
}

/* One step per group. The delays are set on the GROUP as a custom property and
   read by the rows inside it — a group can hold more than one row, and they
   should arrive together rather than as a second, nested stagger. */
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group:nth-child(1) {
  --sidebar-in-delay: 0ms;
}
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group:nth-child(2) {
  --sidebar-in-delay: 36ms;
}
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group:nth-child(3) {
  --sidebar-in-delay: 72ms;
}
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group:nth-child(4) {
  --sidebar-in-delay: 108ms;
}
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group:nth-child(5) {
  --sidebar-in-delay: 144ms;
}
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group:nth-child(6) {
  --sidebar-in-delay: 180ms;
}
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group:nth-child(7) {
  --sidebar-in-delay: 216ms;
}

html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-link,
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-group-links-inner > .sidebar-link,
html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-flyout-trigger {
  animation-delay: var(--sidebar-in-delay, 0ms);
}

html[data-design="sigma"] .site-sidebar-nav::-webkit-scrollbar {
  width: 8px;
}

html[data-design="sigma"] .site-sidebar-nav::-webkit-scrollbar-track {
  background: transparent;
}

html[data-design="sigma"] .site-sidebar-nav::-webkit-scrollbar-thumb {
  border: 2px solid transparent;
  border-radius: 999px;
  background-clip: content-box;
  background-color: color-mix(in srgb, var(--gold) 26%, transparent);
  transition: background-color 0.2s ease;
}

html[data-design="sigma"] .site-sidebar-nav:hover::-webkit-scrollbar-thumb,
html[data-design="sigma"] .site-sidebar-nav:focus-within::-webkit-scrollbar-thumb {
  background-color: color-mix(in srgb, var(--gold) 52%, transparent);
}

html[data-design="sigma"] .site-sidebar-nav:hover {
  scrollbar-color: color-mix(in srgb, var(--gold) 52%, transparent) transparent;
}

/* The rail's rows.

   44px is the floor, not an arbitrary number: it is the smallest a row can be
   and still be a comfortable pointer target on both a desktop and a laptop
   trackpad, so this is as short as a nav row is allowed to get. Everything
   else about the rail's size — the width, the glyph, the type — was reduced to
   suit it, which is the opposite of the previous state where a 50px row in a
   wide rail made every destination read as a card. */
html[data-design="sigma"] .sidebar-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 0 12px 0 13px;
  /* No border, no surface, no shadow. The row is invisible until the pointer
     arrives.

     This is the quiet-flush decision, and it is a real trade rather than a
     neutral one. A permanent edge gives the eye something to aim at while
     scanning a long column; without it, finding a row means reading it. What
     that buys is a rail that stops competing with the page it sits beside — the
     chrome disappears and only the words remain.

     The border stays declared as `1px solid transparent` rather than dropped to
     `0`, so the row's box is byte-identical to the card version and nothing
     shifts if this is ever reversed. Reserving the space costs nothing. */
  border: 1px solid transparent;
  border-radius: var(--radius-nav);
  color: var(--cream-dim);
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  background: transparent;
  box-shadow: none;
  transition:
    color 0.18s ease,
    background 0.18s ease;
}

html[data-design="sigma"] .sidebar-link:hover {
  color: var(--cream);
  /* A wash and nothing else. No edge to warm, because there is no edge; no
     surface to lift, because there is no surface; no raise, because a row with
     nothing to lift reads as a label floating off the page. On a flush row the
     wash is the entire response. */
  background: var(--hover-fill);
}

/* Keyboard focus needs to be obvious on a long list of identical rows. */
html[data-design="sigma"] .sidebar-link:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--om-brass) 68%, transparent);
  outline-offset: -2px;
  color: var(--cream);
}

/* The active row is marked by a slim accent bar on its leading edge, and the bar
   is BACK after the card experiment.

   It was removed when every row became a bordered card, for a good reason that
   no longer applies: inside a card's own rounded border, a bar read as a second
   competing frame, and the row looked like it had two edges. On a card the
   border IS the frame, so the border lit instead.

   The rows are flush again, so the card's frame is gone and so is the reason.
   With no resting edge anywhere in the rail, a bar is not a second frame — it is
   the only persistent mark in the column, which is what makes the current page
   findable in a scroll of identical grey words. This is the reason it worked the
   first time, and the reason it stopped working was the card, not the bar.

   2px, matching the 1.25 glyph stroke. It is inset 8px from each end rather than
   running the full height, so it reads as a marker pointing at the row rather
   than as a rail running down the side of the rail. */
html[data-design="sigma"] .sidebar-link[aria-current="page"] {
  color: var(--cream);
  background: var(--hover-fill);
  box-shadow: none;
}

html[data-design="sigma"] .sidebar-link[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  bottom: 8px;
  width: 2px;
  border-radius: 0 2px 2px 0;
  background: linear-gradient(180deg, var(--om-brass-bright), var(--om-brass));
}

html[data-design="sigma"] .sidebar-link-cta {
  color: var(--cream);
}

html[data-design="sigma"] .sidebar-link-cta .sidebar-link-label {
  color: var(--om-brass-bright);
}

/* The glyph takes its row's tint (declared below), not a fixed colour. The
   opacity floor is what lets a tinted glyph sit quietly at rest and still come
   forward on hover without the hue itself having to be loud. */
html[data-design="sigma"] .sidebar-link-icon {
  width: var(--sidebar-nav-icon);
  height: var(--sidebar-nav-icon);
  flex: 0 0 auto;
  color: var(--sidebar-row-tint, var(--cream-dim));
  opacity: 0.9;
  /* The glow, and why it is built this way.

     Two stacked drop-shadows rather than one: a tight core that lights the
     stroke itself and a wider bloom that fades into the rail behind it. One
     shadow is either a smear at the tight end or a haze at the wide end; the
     two-step falloff is the part that reads as light rather than blur, and it
     is the same shape the flame and the avatar frames use elsewhere on site.

     No colour is written here. The shadow is currentColor at partial alpha,
     so the halo IS the glyph's own tint: it walks the per-row ramp with the
     row, swaps with the theme, and a row nobody has tinted still glows in its
     label colour. A literal hex would be a second palette the rail does not
     have and tests would (rightly) reject.

     Kept faint at rest on purpose. The rail is a quiet flush column by
     design, and a resting glow that shouts would undo that; this is here to
     make the glyph read as lit rather than painted, and the hover below is
     where it actually flares. */
  filter:
    drop-shadow(0 0 3px color-mix(in srgb, currentColor 34%, transparent))
    drop-shadow(0 0 9px color-mix(in srgb, currentColor 16%, transparent));
  transition:
    opacity 0.18s ease,
    color 0.18s ease,
    filter 0.18s ease,
    transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}

/* The glyph lifts as the row is approached.

   It moves, not just brightens. A colour change alone is easy to miss on a row
   you are already reading, and this is the element that says "and there is a
   glyph for this thing" — nudging it draws the eye to the pairing. 1.05 on a
   1.15rem glyph is about a pixel of travel: enough to register, not enough to
   look like the icon is bouncing. */
html[data-design="sigma"] .sidebar-link:hover .sidebar-link-icon {
  opacity: 1;
  transform: scale(1.05);
}

/* A per-row icon tint.

   The rail's glyphs used to be one colour that brightened on hover, which is
   correct and completely invisible: nothing in the resting state distinguishes
   one destination from another except its word.

   These are tints, not a palette per row. Each is a mix of the accent and the
   warm streak family, so they stay inside the theme's own range — brass,
   copper, ember — and differ from each other by degree rather than by hue. A
   green row and a red row and a blue row would be louder than the words beside
   them, and on a dark rail six saturated colours read as a toy rather than as
   navigation.

   Set on the ROW, so the tint is a property of the destination and cascades to
   whatever markup that row happens to contain. `.sidebar-link-icon` and
   `.sidebar-tile-icon` both read it, and anything added to a row later picks it
   up without a second decision. */

html[data-design="sigma"] .sidebar-link {
  /* Row 1 of the tint set. Each row overrides this with the next step, so the
     rail walks the ramp top to bottom and returns to the accent for the
     promoted rows at the floor. */
  --sidebar-row-tint: color-mix(in srgb, var(--om-brass) 58%, var(--cream-dim));
}

html[data-design="sigma"] .sidebar-group:nth-child(2) .sidebar-flyout-trigger {
  --sidebar-row-tint: color-mix(in srgb, var(--streak-mid) 62%, var(--cream-dim));
}

html[data-design="sigma"] .sidebar-group:nth-child(3) .sidebar-flyout-trigger {
  --sidebar-row-tint: color-mix(in srgb, var(--streak-core) 58%, var(--cream-dim));
}

html[data-design="sigma"] .sidebar-group:nth-child(4) .sidebar-flyout-trigger {
  --sidebar-row-tint: color-mix(in srgb, var(--streak-edge) 46%, var(--cream-dim));
}

/* Hover lifts the row's own tint rather than jumping to a fixed accent, so the
   colour you saw at rest is recognisably the same colour that lit up. */
html[data-design="sigma"] .sidebar-link:hover .sidebar-link-icon,
html[data-design="sigma"] .sidebar-flyout-trigger:hover .sidebar-link-icon {
  color: color-mix(in srgb, var(--sidebar-row-tint) 45%, var(--om-brass-bright));
  /* The flare. Same two-step falloff as the rest state, roughly doubled in
     strength: the colour lifts toward the accent and the light lifts with it,
     so hover arrives as one event rather than a tint change and a glow change
     landing a beat apart. It rides currentColor again, so the flare keeps the
     row's own tint instead of snapping to a fixed accent. */
  filter:
    drop-shadow(0 0 4px color-mix(in srgb, currentColor 55%, transparent))
    drop-shadow(0 0 12px color-mix(in srgb, currentColor 30%, transparent));
}

html[data-design="sigma"] .sidebar-link[aria-current="page"] .sidebar-link-icon {
  color: var(--om-brass-bright);
  /* The current page stays lit at rest, not just tinted: it is the one glyph
     that has to be findable without a pointer anywhere near it, so it carries
     hover-strength light permanently, in the accent colour. */
  filter:
    drop-shadow(0 0 4px color-mix(in srgb, currentColor 52%, transparent))
    drop-shadow(0 0 13px color-mix(in srgb, currentColor 26%, transparent));
}

/* Keyboard focus lights the glyph exactly the way hover does, so tabbing down
   the rail reads the same as sweeping the pointer down it. The row's outline
   above says "this one is focused"; keeping the light identical to hover's
   means focus never looks like a second, different system. */
html[data-design="sigma"] .sidebar-link:focus-visible .sidebar-link-icon,
html[data-design="sigma"] .sidebar-flyout-trigger:focus-visible .sidebar-link-icon {
  filter:
    drop-shadow(0 0 4px color-mix(in srgb, currentColor 55%, transparent))
    drop-shadow(0 0 12px color-mix(in srgb, currentColor 30%, transparent));
}

/* The stroke weight, and the single biggest reason the rail reads as crafted
   rather than assembled.

   These glyphs are line art: a 24x24 grid stroked with round caps and joins,
   fill: none. At 1.5 the stroke was wide enough that at small sizes the closed
   shapes (the house, the folder grid) filled in their own counters and the
   shapes stopped being distinguishable from each other at a glance. At 1.25 the
   counters stay open, and the icons sit at the same optical weight as the
   0.95rem label beside them instead of competing with it.

   Driven by the token so it moves with the glyph size. */
html[data-design="sigma"] .sidebar-link-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: var(--sidebar-nav-stroke);
  stroke-linecap: round;
  stroke-linejoin: round;
}

html[data-design="sigma"] .sidebar-link-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The "you have not read the newest release" marker on the Changelog row.

   A pill with a word rather than a bare dot. The dot was right when the row was
   a line of text and the only thing competing with it was another line of text;
   now that every row is a bordered card, an 8px circle beside the label is the
   one element on the card that explains nothing. "New" says what it is at a
   glance, and it survives being seen out of the corner of the eye — which is
   how a release marker is actually noticed.

   The text is generated rather than written into the template, so the markup
   stays empty whether or not there is anything unread. That matters: the
   server renders this unconditionally, and a template-side "New" would sit in
   the DOM on every page load and be visible in the gap between paint and
   changelog_badge.js running.

   It sits after the label, which is flex: 1, so it is pinned to the card's
   right edge instead of sitting next to the word — the same slot the chevron
   uses on a section row, so the two read as one column of trailing marks.

   Off by default, on by a class rather than by the [hidden] attribute: the rule
   below sets `display`, and style_dark.css has no global [hidden] rule, so an
   attribute would lose to it and the badge could never be switched off. */
html[data-design="sigma"] .sidebar-link-dot {
  display: none;
  flex: 0 0 auto;
  padding: 2px 7px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--om-brass) 20%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--om-brass) 46%, transparent);
  color: var(--om-brass-bright);
  font-size: 0.58rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.5;
}

html[data-design="sigma"] .sidebar-link-dot::after {
  content: "New";
}

html[data-design="sigma"] .sidebar-link-dot.is-on {
  display: block;
}

/* The live pulse.

   A static badge tells you a release happened once, at the moment you looked.
   This row is the only one in the rail that is about something that CHANGES, so
   a marker that never moves is the wrong signal for it: every other row is a
   fixed destination, and this one is the only destination that is different
   tomorrow than it is today.

   A small dot before the word, breathing on a 2.6s cycle. Slow and shallow on
   purpose. A fast blink reads as an alert demanding attention, and the thing it
   announces is a changelog; what it needs to say is "still here, still unread",
   which is what a breath does and a strobe does not.

   It lives on `::before` rather than `::after` because `::after` carries the
   word, and an animated `box-shadow` would overwrite that pill's own border
   mid-cycle — an animation wins over a normal declaration, so the two would
   fight and the pill would flicker its outline.

   Only `box-shadow` and `opacity` are animated, and never a `transform`. This
   element sits inside the rail, and a transform on anything in that subtree
   risks becoming the containing block for the fixed flyout panels — the bug
   documented on .sidebar-nav-scroll, where a mask on the rail's scroller made
   every panel trap itself in the sidebar and stop receiving clicks. A glow does
   not need a transform to work. */
html[data-design="sigma"] .sidebar-link-dot.is-on::before {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-right: 5px;
  border-radius: 50%;
  background: var(--om-brass-bright);
  vertical-align: 1px;
  animation: sidebar-badge-breathe 2.6s ease-in-out infinite;
}

@keyframes sidebar-badge-breathe {
  0%,
  100% {
    opacity: 1;
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--om-brass-bright) 60%, transparent);
  }
  50% {
    opacity: 0.55;
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--om-brass-bright) 0%, transparent);
  }
}

/* A second, quieter pulse on the row's own edge while there is something
   unread, so the eye catches the card itself rather than only the badge on it.

   Scoped to `:has(.is-on)` so it stops the moment the release is read — the
   animation is the reminder, and a reminder that outlives its message is noise.

   Same reasoning as above for the properties: the resting box-shadow is
   restated in the keyframes, because a keyframe replaces the whole value rather
   than merging with it, and the top hairline that makes the card look raised
   would otherwise disappear for the whole cycle. */
html[data-design="sigma"] .site-sidebar-changelog:has(.sidebar-link-dot.is-on) {
  border-color: color-mix(in srgb, var(--om-brass) 52%, var(--line));
  animation: sidebar-changelog-edge 2.6s ease-in-out infinite;
}

@keyframes sidebar-changelog-edge {
  0%,
  100% {
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, var(--cream) 6%, transparent),
      0 0 0 0 color-mix(in srgb, var(--gold) 0%, transparent);
  }
  50% {
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, var(--cream) 6%, transparent),
      0 0 14px 0 color-mix(in srgb, var(--gold) 26%, transparent);
  }
}

/* A still badge under reduced motion. The state is carried entirely by the word
   and the lit border, so dropping the animation loses the emphasis but nothing
   that identifies it. */
@media (prefers-reduced-motion: reduce) {
  html[data-design="sigma"] .sidebar-link-dot.is-on::before,
  html[data-design="sigma"] .site-sidebar-changelog:has(.sidebar-link-dot.is-on) {
    animation: none;
  }
}

/* The rail's own motion, all of it, in one place.

   Two effects — the staggered entrance and the hover raise — and each is opt-out
   rather than opt-in. They are the difference between a rail that feels alive
   and one that feels like a list, but they are decoration over a functional
   menu, so a reader who has asked the OS to stop moving things has to actually
   get a still rail. */
@media (prefers-reduced-motion: reduce) {
  html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-link,
  html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-group-links-inner > .sidebar-link,
  html[data-design="sigma"] .sidebar-nav-scroll > .sidebar-group > .sidebar-flyout-trigger {
    animation: none;
  }
}

/* ——— The rail's floor: Changelog, then Sign in ————————————————————————————
   The Changelog row moved here from the nav, where it sat between Evaluation and
   Account looking exactly like a destination. It is not one — it is the only row
   that reports a CHANGE rather than being a place — so it belongs with the other
   utility controls at the foot, where a returning visitor's eye lands last.

   It sits directly above Sign in, which is the only relationship the markup
   implies: a signed-out visitor meets them stacked, "what's new" then "come in".
   For a signed-in reader the Sign in row is absent and this becomes the last
   thing above the streak and settings cards, which is also correct — it is the
   final item before the floor.

   No border of its own. `.site-sidebar-cta` below already draws the rule that
   separates this pair from the list above, and a second one here would fence off
   a single row for no reason. The gap is enough: these two are a pair, not a
   section. */
html[data-design="sigma"] .site-sidebar-changelog {
  flex: 0 0 auto;
  margin-top: var(--sidebar-group-gap);
}

/* A <button> that is a rail row rather than a navigation link — the Changelog
   panel has no page behind it, so there is nothing to navigate to.

   `.sidebar-link` already supplies the box, the type, and the icon pairing.
   What is left is the browser's own <button> styling leaking through, which is
   the same set of resets .sidebar-flyout-trigger carries: buttons default to
   their own font, to a centred label, and to a system button background.

   Not `.sidebar-link-button`, which was the settings control's class while it
   was a nav row. The name here says what it is — a button shaped like a row —
   so the next rail row that needs it can take it too. */
html[data-design="sigma"] .sidebar-row-button {
  width: 100%;
  background: transparent;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

html[data-design="sigma"] .site-sidebar-foot {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

html[data-design="sigma"] .sidebar-day {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 12px 12px 10px;
  border: 1px solid color-mix(in srgb, var(--streak-mid) 28%, var(--line));
  border-radius: 14px;
  text-decoration: none;
  color: inherit;
  background:
    radial-gradient(ellipse 70% 90% at 8% 80%, color-mix(in srgb, var(--streak-mid) 18%, transparent), transparent 55%),
    linear-gradient(135deg, color-mix(in srgb, var(--streak-core) 8%, var(--bg-3)), var(--bg-3));
  overflow: hidden;
  transition: border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}

html[data-design="sigma"] .sidebar-day::before {
  content: "";
  position: absolute;
  inset: auto -20% -40% auto;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--streak-edge) 14%, transparent);
  filter: blur(16px);
  pointer-events: none;
}

html[data-design="sigma"] .sidebar-day:hover {
  border-color: color-mix(in srgb, var(--streak-edge) 55%, var(--line));
  background:
    radial-gradient(ellipse 70% 90% at 8% 80%, color-mix(in srgb, var(--streak-mid) 26%, transparent), transparent 55%),
    linear-gradient(135deg, color-mix(in srgb, var(--streak-core) 12%, var(--bg-3)), var(--bg-3));
  box-shadow: 0 0 22px color-mix(in srgb, var(--streak-mid) 18%, transparent);
  transform: translateY(-1px);
}

html[data-design="sigma"] .sidebar-day-flame {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  width: 38px;
  height: 47px;
  display: grid;
  place-items: center;
  filter: drop-shadow(0 0 8px color-mix(in srgb, var(--streak-mid) 45%, transparent));
}

html[data-design="sigma"] .sidebar-day-flame svg {
  width: 32px;
  height: 41px;
}

html[data-design="sigma"] .sidebar-day-flame-outer {
  fill: var(--streak-core);
  animation: sidebar-flame-flicker 1.5s ease-in-out infinite;
  transform-origin: 50% 90%;
}

html[data-design="sigma"] .sidebar-day-flame-mid {
  fill: var(--streak-mid);
  animation: sidebar-flame-flicker 1.15s ease-in-out infinite reverse;
  transform-origin: 50% 90%;
}

html[data-design="sigma"] .sidebar-day-flame-core {
  fill: var(--streak-edge);
  animation: sidebar-flame-flicker 0.9s ease-in-out infinite;
  transform-origin: 50% 90%;
}

html[data-design="sigma"] .sidebar-day-kicker {
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--streak-ink);
}

html[data-design="sigma"] .sidebar-day-value {
  font-size: 1.24rem;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--cream);
}

/* ———— The week strip ————
   A labelled Mon–Sun row rather than seven anonymous pips.

   The pips could only say "3 of 7", which is not what anyone looks at a streak
   to find out. The two questions are "did I do anything today" and "which days
   are still open", and both need the day to be named.

   Each column is a label over a marker, so the weekday is readable at a glance
   and the marker carries the state. Three states, matching the practice
   dashboard's own vocabulary so the two cannot describe a week differently:
     · is-done   — practised, filled and lit
     · is-today  — a ring, so today is findable even when not yet practised
     · is-future — hollow and dimmed; the days you could still use

   Today is a ring rather than a fill on purpose. "Have I done today?" is the
   question, and a ring reads as "not yet" whether or not it is also done —
   whereas a fill would look identical to a finished day and leave the question
   unanswered. */
html[data-design="sigma"] .sidebar-week {
  display: grid;
  /* Seven equal columns. `1fr` rather than auto so every day gets the same
     width and the row cannot drift as labels differ in length. */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 3px;
}

/* Marker over label: the letter names the day, the shape above it carries the
   state. Letter-first would put the smallest text at the top of a short card
   and read as a footnote to the boxes. */
html[data-design="sigma"] .sidebar-week-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-width: 0;
}

/* The marker. A rounded square rather than a dot or a bar: at roughly 14px it
   has room for a visible hollow state AND a lit ring for today, which a 6px
   dot cannot hold both of. A bar was too thin to tell filled from empty. */
html[data-design="sigma"] .sidebar-week-day i {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  /* Big enough to hold a hollow state AND a lit ring at the same time. The
     first pass capped this at 16px inside a 1fr column of a half-width card,
     which is about 20px of available width — so the cap never bound and the
     real size came out smaller than intended. The cap is now generous enough
     to let the column decide, with a floor so the marker never collapses. */
  max-width: 20px;
  min-width: 13px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--streak-mid) 8%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--streak-edge) 20%, transparent);
  transition: background-color 0.2s ease, box-shadow 0.2s ease;
}

/* Practised: filled, and lifted slightly by its own glow. */
html[data-design="sigma"] .sidebar-week-day.is-done i {
  background: linear-gradient(160deg, var(--streak-edge), var(--streak-mid));
  box-shadow:
    0 0 10px color-mix(in srgb, var(--streak-mid) 60%, transparent),
    inset 0 1px 0 color-mix(in srgb, #fff 28%, transparent);
}

/* Today: a bright ring, findable whether or not it is practised. A fill would
   look identical to a finished day and leave "have I done today?" unanswered. */
html[data-design="sigma"] .sidebar-week-day.is-today i {
  box-shadow: inset 0 0 0 1.5px var(--streak-edge);
}

html[data-design="sigma"] .sidebar-week-day.is-today .sidebar-week-label {
  color: var(--cream);
  font-weight: 800;
}

/* Done AND today: fill and ring together, so neither state is lost. */
html[data-design="sigma"] .sidebar-week-day.is-done.is-today i {
  box-shadow:
    0 0 10px color-mix(in srgb, var(--streak-mid) 65%, transparent),
    inset 0 0 0 1.5px var(--streak-edge);
}

/* Still to come. Dimmed rather than hidden: an empty gap would read as a
   missing day, not a day not yet reached. */
html[data-design="sigma"] .sidebar-week-day.is-future {
  opacity: 0.45;
}

html[data-design="sigma"] .sidebar-week-day.is-future i {
  background: transparent;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--streak-edge) 18%, transparent);
}

/* The letter. A single initial — M T W T F S S — so the strip reads at a
   glance and never has to truncate. `text-transform: uppercase` is redundant
   on an already-capital initial, but it keeps the rule correct if a locale ever
   hands back a lowercase label. */
html[data-design="sigma"] .sidebar-week-label {
  font-size: 0.56rem;
  font-weight: 700;
  line-height: 1;
  color: var(--muted);
  text-transform: uppercase;
}

html[data-design="sigma"] .sidebar-day.is-hot .sidebar-day-flame {
  filter: drop-shadow(0 0 12px color-mix(in srgb, var(--streak-edge) 70%, transparent));
}

html[data-design="sigma"] .sidebar-day.is-blazing {
  border-color: color-mix(in srgb, var(--streak-edge) 60%, var(--line));
  box-shadow: 0 0 24px color-mix(in srgb, var(--streak-mid) 22%, transparent);
}

html[data-design="sigma"] .sidebar-day.is-blazing .sidebar-day-value {
  color: var(--streak-edge);
}

@keyframes sidebar-flame-flicker {
  0%, 100% { transform: scaleY(1) scaleX(1); opacity: 1; }
  40% { transform: scaleY(1.06) scaleX(0.96); opacity: 0.92; }
  70% { transform: scaleY(0.96) scaleX(1.04); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  html[data-design="sigma"] .sidebar-day-flame-outer,
  html[data-design="sigma"] .sidebar-day-flame-mid,
  html[data-design="sigma"] .sidebar-day-flame-core {
    animation: none;
  }
}

/* Mobile drawer */
html[data-design="sigma"] .sidebar-mobile-toggle {
  display: none;
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 140;
  width: 42px;
  height: 42px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  color: var(--cream);
  box-shadow: var(--panel-glow);
  cursor: pointer;
}

html[data-design="sigma"] .sidebar-mobile-toggle svg {
  width: 18px;
  height: 18px;
  margin: 0 auto;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
}

html[data-design="sigma"] .sidebar-backdrop {
  display: none;
}

@media (max-width: 980px) {
  html[data-design="sigma"] body {
    display: block;
  }

  html[data-design="sigma"] .sidebar-mobile-toggle {
    display: grid;
    place-items: center;
    top: max(12px, env(safe-area-inset-top, 0px));
    left: max(12px, env(safe-area-inset-left, 0px));
  }

  /* The rail is a drawer here, with no folded state — so the collapse toggle,
     which belongs to the fixed desktop rail, is hidden rather than left offering
     a fold that the drawer cannot perform. */
  html[data-design="sigma"] .sidebar-collapse-toggle {
    display: none;
  }

  html[data-design="sigma"] .site-sidebar {
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: min(var(--sidebar-w), 88vw);
    transform: translate3d(-105%, 0, 0);
    -webkit-transform: translate3d(-105%, 0, 0);
    transition: transform 0.22s ease;
    /* The drawer keeps its drop shadow and takes the rail's seam too: its right
       edge is the only boundary against the backdrop, so it glows the same way
       the desktop rail's does, from the same token. */
    box-shadow:
      0 24px 64px rgba(0, 0, 0, 0.45),
      1px 0 0 color-mix(in srgb, var(--glow-line) 34%, transparent),
      12px 0 30px -14px color-mix(in srgb, var(--glow-line) 85%, transparent);
    align-items: stretch;
    padding: 14px 12px max(12px, env(safe-area-inset-bottom, 0px));
    z-index: 120;
    overflow-y: auto;
  }

  html[data-design="sigma"] body.is-sidebar-open .site-sidebar {
    transform: translate3d(0, 0, 0);
    -webkit-transform: translate3d(0, 0, 0);
  }

  html[data-design="sigma"] .site-frame {
    margin-left: 0;
    width: 100%;
    max-width: 100%;
    overflow-x: hidden;
  }

  /* ——— The drawer has no "beside" ———
     A flyout hangs beside the rail, which assumes there is room beside it. The
     drawer is the rail at up to 88vw with a backdrop over the page, so a panel
     pinned to `calc(var(--sidebar-w) + 8px)` would sit off the right edge of a
     phone, or over the backdrop with the rail already covering the screen.

     Inside the drawer the section is therefore a plain disclosure: the panel
     drops into the rail's own flow, full width, under its trigger. The markup
     and theme.js are identical to desktop — the panel is already a sibling of
     its trigger, and theme.js positions it, so overriding both here is enough.
     Tapping the row is the way in (the hover path is skipped for touch in
     theme.js), which is why the trigger stays a button rather than becoming a
     link on phones only. */
  html[data-design="sigma"] .sidebar-flyout-panel {
    position: static;
    left: auto;
    width: auto;
    min-width: 0;
    margin: 2px 0 0;
    padding: 6px;
    border-radius: 10px;
    box-shadow: none;
    background: color-mix(in srgb, var(--bg-2) 88%, var(--bg));
    max-height: none;
    /* No horizontal travel here — there is nowhere to travel from. */
    animation: none;
  }

  /* Indented to read as belonging to the row above it, since there is no
     spatial gap to make the relationship.

     Kept in step with the panel rows above it. Left at the old 44px/0.95rem
     this became the one place in the rail where a phone drew its rows TALLER
     than a desktop did, which is the partial-scale failure this module exists
     to catch, just mirrored into the drawer.

     Only size and type, same as the desktop rule. This copy used to repeat the
     card-removal too, back when the rail's rows were cards and a phone drawing a
     bordered sub-item inside a static panel was a real risk. The rows are flush
     now, so there is nothing to repeat. */
  html[data-design="sigma"] .sidebar-flyout-links .sidebar-link {
    min-height: 40px;
    font-size: 0.9rem;
  }

  html[data-design="sigma"] .sidebar-flyout-chevron {
    transform: rotate(0deg);
  }

  html[data-design="sigma"] [data-sidebar-flyout].is-open > .sidebar-flyout-trigger .sidebar-flyout-chevron {
    transform: rotate(90deg);
  }

  html[data-design="sigma"] .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 115;
    background: rgba(0, 0, 0, 0.48);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
  }

  html[data-design="sigma"] body.is-sidebar-open .sidebar-backdrop {
    opacity: 1;
    pointer-events: auto;
  }

  /* The rail's floor goes back to full-width rows in the drawer.

     50/50 is right on the desktop rail, which is fixed and has room to spare.
     The drawer is `min(var(--sidebar-w), 88vw)`, and on a 390px phone that
     resolves to the rail's own 296px rather than to the viewport — the drawer is
     now narrower than the desktop rail on most phones. After the drawer's own
     12px padding and the pair's 6px gap, each card gets about 133px, and after
     the card's own 10px padding roughly 113px of content. That is not enough for
     a flame, a figure and a kicker, let alone a week strip: everything would
     clip its own text.

     Narrowing the rail therefore makes the drawer stack MORE necessary, not
     less — which is why this override is kept rather than dropped. The pair
     concept does not survive a narrower box. */
  html[data-design="sigma"] .sidebar-foot-pair {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
  }

  html[data-design="sigma"] .site-header--utility .site-header-inner {
    width: calc(100% - 24px);
    padding-left: 52px;
    min-height: 48px;
    flex-wrap: nowrap;
  }

  html[data-design="sigma"] .site-header-actions {
    padding: 0;
    border: 0;
    flex-wrap: nowrap;
    margin-left: auto;
  }

  html[data-design="sigma"] .header-sale {
    flex: 1 1 auto;
    max-width: none;
    gap: 8px;
    padding: 6px 8px;
  }

  html[data-design="sigma"] .header-sale-copy {
    font-size: 0.72rem;
  }

  html[data-design="sigma"] .header-sale-was {
    display: none;
  }

  html[data-design="sigma"] .header-sale-cta {
    padding: 4px 8px;
    font-size: 0.64rem;
  }

  /* Keep header theme pinned to the top bar — don't let Safari sticky
     + transparent chrome float Dark/Light over the training board. */
  html[data-design="sigma"] body.training-page .site-header--utility {
    position: sticky;
    top: 0;
    z-index: 130;
    display: block;
    background: var(--bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    contain: none;
    box-shadow: 0 1px 0 color-mix(in srgb, var(--line) 70%, transparent);
  }

  html[data-design="sigma"] body.training-page .site-header--utility .site-header-inner {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: flex-end;
    width: calc(100% - 24px);
    min-height: 48px;
    padding-top: max(6px, env(safe-area-inset-top, 0px));
    padding-bottom: 6px;
    padding-left: 52px;
  }

  html[data-design="sigma"] body.training-page .site-header-actions {
    display: flex;
    flex: 0 0 auto;
    width: auto;
    margin-left: auto;
    padding: 0;
    border: 0;
    flex-wrap: nowrap;
  }

  html[data-design="sigma"] body.training-page .header-theme {
    flex: 0 0 auto;
  }

  html[data-design="sigma"] body.training-page .header-sale {
    display: none;
  }

  html[data-design="sigma"] body.training-page .sidebar-mobile-toggle {
    top: max(12px, env(safe-area-inset-top, 0px));
    left: max(12px, env(safe-area-inset-left, 0px));
  }
}

@media (max-width: 640px) {
  /* On phones the full price copy wraps into a tall stack, which leaves the
     "Two plans" badge and "Compare" button floating out of alignment (most
     visibly on iOS Safari). Collapse the pill to badge + Compare so it stays a
     single tidy row; the linked features page still shows the full pricing. */
  html[data-design="sigma"] .header-sale {
    flex: 0 1 auto;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
  }

  html[data-design="sigma"] .header-sale-badge {
    display: none;
  }

  html[data-design="sigma"] .header-sale-copy {
    display: none;
  }

  html[data-design="sigma"] .header-sale-cta {
    margin-left: 0;
    padding: 3px 6px;
    font-size: 0.6rem;
  }
}

/* ——— Sidebar sections and lit destinations ——————————————————————————————
   The nav is split into labelled groups. Leaderboard, Unlimited and the
   practice streak card read as lit panels: a crisp opaque surface, a
   machined top light, and a restrained glow -- a tight kiss of light at
   the edge plus a short bloom. No wide haze and no neon outline, because
   a glowing green box reads cheap; the accent is spent on small, precise
   details instead.

   Every ordinary row is now a card too, for the reason set out on
   .sidebar-link above: a flush row only shows a background once the pointer
   arrives, which gives a reader scanning the rail nothing to aim at. These three
   are lit panels rather than plain cards, so they take the treatment further —
   an opaque surface, a ring and a glow — to say "this one does something else"
   against the quieter cards around it.

   The spacing tokens live on .sidebar-nav-scroll, the inner wrapper, because
   that is the element whose children are the groups. It used to be set on the
   nav itself, which no
   longer has group children directly. */

html[data-design="sigma"] .sidebar-group {
  display: flex;
  flex-direction: column;
  gap: var(--sidebar-row-gap);
}

html[data-design="sigma"] .sidebar-group + .sidebar-group {
  /* An increment on top of the row gap, so a section boundary is one step
     further apart than two ordinary neighbours. `calc` rather than the group
     token directly: applying the token here as well as on the scroller's gap
     would double it, which is what happened before — the two numbers were
     added together and the boundary landed at twice the intended distance.

     The separator hairline that used to live here is gone, and so is the reason
     it was removed. It was dropped when every row became a bordered card,
     because a hairline then ran between two edges instead of through empty space
     and read as a stray line under a stack of boxes. The rows are flush again, so
     a hairline would again be dividing through empty space — which is exactly
     what it was for. It stays gone: the step in spacing does the dividing, and a
     flush rail is calmer without a rule under every section. */
  padding-top: calc(var(--sidebar-group-gap) - var(--sidebar-row-gap));
}

/* The rows inside a group live in this wrapper column, so it carries the same
   row rhythm as the group itself. Every section in the rail holds exactly one
   row, which is why `.sidebar-group` alone never needed to reach past that —
   the Account section is the exception, holding two (Unlimited and Account).
   Without the gap on this wrapper those two sit flush against each other
   instead of one row's width apart. */
html[data-design="sigma"] .sidebar-group-links-inner {
  display: flex;
  flex-direction: column;
  gap: var(--sidebar-row-gap);
}

html[data-design="sigma"] .sidebar-group-label {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 4px;
  padding: 0 12px;
  color: var(--muted);
  font-size: 0.64rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.82;
}

/* A hairline that trails off after the label, so each group reads as a titled
   section rather than a bare uppercase word floating above the rows. */
html[data-design="sigma"] .sidebar-group-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--line) 85%, transparent), transparent);
}

/* Sign in sits alone on the floor of the rail, below the whole nav, so it
   reads as the page's primary action rather than the last row of a list. */
html[data-design="sigma"] .site-sidebar-cta {
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

/* Compact icon tiles for the emphasised rows. */
html[data-design="sigma"] .sidebar-link-lg .sidebar-link-icon,
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-icon,
html[data-design="sigma"] .sidebar-link-primary .sidebar-link-icon {
  width: 24px;
  height: 24px;
  padding: 4px;
  border-radius: 7px;
  box-sizing: border-box;
  opacity: 1;
}

/* The Unlimited rocket reads bigger than the rest of the rail. It is the one
   promoted call-to-action and the one glyph carrying live motion, so it earns a
   larger tile than the shared 24px above. overflow: visible on the svg lets the
   exhaust plume flicker past the tile's box instead of being clipped at 24px,
   which would slice the flame off mid-animation. */
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-icon {
  width: 30px;
  height: 30px;
  padding: 0;
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-icon svg {
  overflow: visible;
}

html[data-design="sigma"] .sidebar-link-lg .sidebar-link-icon {
  background: color-mix(in srgb, var(--cream) 7%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cream) 10%, transparent);
  color: var(--om-brass);
}

/* ———— Leaderboard: a clean elevated row ———— */
html[data-design="sigma"] .sidebar-link-lg {
  min-height: 40px;
  gap: 10px;
  padding: 0 10px;
  font-size: 0.88rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-card);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 5%, transparent), transparent 62%),
    var(--paper);
  color: var(--cream);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 8%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 0 5px color-mix(in srgb, var(--om-brass) 26%, transparent),
    0 0 16px color-mix(in srgb, var(--om-brass) 10%, transparent);
  transition: border-color 0.22s ease, background 0.22s ease, box-shadow 0.22s ease, transform 0.22s ease;
}

html[data-design="sigma"] .sidebar-link-lg:hover,
html[data-design="sigma"] .sidebar-link-lg:focus-visible {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--om-brass) 45%, var(--line-strong));
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 7%, transparent), transparent 62%),
    var(--paper);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--om-brass) 28%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 0 7px color-mix(in srgb, var(--om-brass) 44%, transparent),
    0 0 22px color-mix(in srgb, var(--om-brass) 16%, transparent);
}

/* ———— Unlimited: the upgrade card ————————————————————————————————————————
   The only row in the rail that has to sell something, so it is built like a
   small piece of jewellery rather than a bigger green box: a drawn gradient
   ring instead of a flat border, a solid brass tile with its own lit top
   edge, a gradient wordmark, a quiet value line, and a specular sweep that
   only fires on hover. Depth comes from stacked low-opacity light, never
   from a wide neon haze — that is what keeps it looking expensive. */

html[data-design="sigma"] .sidebar-link-promo {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 50px;
  gap: 10px;
  padding: 7px 10px;
  font-weight: 700;
  letter-spacing: -0.02em;
  border: 1px solid color-mix(in srgb, #7c3aed 26%, var(--line-strong));
  border-radius: var(--radius-card);
  background:
    radial-gradient(ellipse 100% 130% at 2% 0%, color-mix(in srgb, #7c3aed 20%, transparent), transparent 56%),
    radial-gradient(ellipse 90% 120% at 100% 100%, color-mix(in srgb, #7c3aed 9%, transparent), transparent 62%),
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 7%, transparent), transparent 58%),
    var(--paper);
  color: var(--cream);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 13%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.36),
    0 6px 18px rgba(0, 0, 0, 0.22);
  transition:
    border-color 0.24s ease,
    background 0.24s ease,
    box-shadow 0.24s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Water inside the box — a contained liquid effect with depth and flowing
   surface ripples. The soft-light blend mode lets it mix with the card's
   existing background so it reads as real water, not a flat overlay. */
html[data-design="sigma"] .sidebar-link-promo::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background:
    /* Depth gradient — darker at the bottom like a real body of water */
    linear-gradient(180deg,
      transparent 0%,
      color-mix(in srgb, #a855f7 4%, transparent) 40%,
      color-mix(in srgb, #5b21b6 12%, transparent) 100%),
    /* Surface ripples — horizontal bands that scroll like flowing water */
    repeating-linear-gradient(
      180deg,
      transparent 0px,
      transparent 16px,
      color-mix(in srgb, #c084fc 5%, transparent) 16px,
      color-mix(in srgb, #e9d5ff 3%, transparent) 20px,
      transparent 20px,
      transparent 32px
    );
  background-size: 100% 100%, 100% 200%;
  pointer-events: none;
  mix-blend-mode: soft-light;
  animation: water-ripple 3s linear infinite;
}

@keyframes water-ripple {
  0% { background-position: 0 0, 0 0; }
  100% { background-position: 0 0, 0 64px; }
}

/* The ring: a 1px gradient band painted with a mask, so the card gets a
   brushed-metal edge that is brightest where the light would hit it. */
html[data-design="sigma"] .sidebar-link-promo::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(
    150deg,
    color-mix(in srgb, #a855f7 92%, transparent) 0%,
    color-mix(in srgb, #7c3aed 42%, transparent) 26%,
    color-mix(in srgb, var(--cream) 12%, transparent) 52%,
    color-mix(in srgb, #7c3aed 54%, transparent) 74%,
    color-mix(in srgb, #a855f7 88%, transparent) 100%
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0.7;
  pointer-events: none;
  transition: opacity 0.24s ease;
}

/* If a browser can't composite the mask (the ring needs content-box minus
   border-box), drop the ring rather than letting it flood the card — the
   base 1px border stays and the card still reads correctly. */
@supports not ((mask-composite: exclude) or (-webkit-mask-composite: xor)) {
  html[data-design="sigma"] .sidebar-link-promo::after {
    display: none;
  }
}

/* Specular sweep, clipped to the card. */
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-shine {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    115deg,
    transparent 32%,
    color-mix(in srgb, #a855f7 42%, rgba(255, 255, 255, 0.6)) 48%,
    transparent 62%
  );
  transform: translateX(-135%);
  transition: transform 0.85s cubic-bezier(0.22, 1, 0.36, 1);
}

html[data-design="sigma"] .sidebar-link-promo:hover .sidebar-link-shine,
html[data-design="sigma"] .sidebar-link-promo:focus-visible .sidebar-link-shine {
  transform: translateX(135%);
}

/* A solid brass tile with a lit top edge — far richer than a translucent
   wash. The rocket is drawn on it in ink as line art (see the rules below), so
   the brass gradient reads through the body instead of the glyph being a solid
   black shape. color: #0b1405 is what currentColor resolves to for those
   strokes, which is what keeps the outline legible on the bright brass. */
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-icon {
  position: relative;
  z-index: 1;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 9px;
  color: #b8d6ff;
  background:
    radial-gradient(ellipse 130% 100% at 50% 85%, color-mix(in srgb, #8ab4ff 40%, transparent), transparent 65%),
    linear-gradient(165deg, #0a1633 0%, #122a5c 30%, #2855b0 65%, #4a7dff 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 -1px 0 rgba(0, 0, 0, 0.3),
    0 2px 6px rgba(0, 0, 0, 0.3),
    0 0 12px color-mix(in srgb, #2855b0 50%, transparent);
  transition:
    box-shadow 0.24s ease,
    transform 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}

/* The rocket is deliberately the simplest possible silhouette — a pointed nose
   cone, a round porthole, a straight body with two side fins and a flame — so
   it reads as "rocket" at a glance. It is line art, not a filled mass: the same
   strong ink stroke all the way round, no fill, so the brass gradient tile reads
   through it. The stroke is heavy on purpose; at 30px a hairline outline turns
   to mush, and a bold border is what makes the shape legible.

   The body also rides the thrust: a couple of pixels of vertical bob, timed to
   the flame, so the whole thing reads as under power rather than a static badge
   with a blinking tail. */
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket,
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-fin {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket,
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-fin,
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-detail {
  animation: om-rocket-bob 1.5s ease-in-out infinite;
}

@keyframes om-rocket-bob {
  0%,
  100% {
    transform: translateY(0px) rotate(0deg);
  }
  33% {
    transform: translateY(-1.5px) rotate(-1.5deg);
  }
  66% {
    transform: translateY(-0.5px) rotate(1.5deg);
  }
}

/* The porthole: the same ink outline as the body, a touch lighter so it still
   reads as a detail rather than a second hull. It warms to deep bronze on
   hover — the one part of the outline that responds to the pointer, so the
   window is what catches the eye as the row activates. A literal, not a token:
   the rail's gold tokens are green, and a green porthole on the brass tile
   would read as a defect rather than a highlight. */
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-detail {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  transition: stroke 0.24s ease;
}

/* No hover colour shift — the gem's facet lines keep their light-blue
   ink so the cut reads clearly against the sapphire tile at all times. */

/* The glowing thruster. Three stacked parts, all sharing one flicker so they
   read as a single flame rather than three separate blobs:

   - .rocket-glow   a blurred radial halo behind the plume (the "glowing" part),
   - .rocket-flame  the warm body of the fire,
   - .rocket-flame-core  a white-hot core drawn on top for heat.

   transform-box: fill-box + transform-origin at the top means every part grows
   out of the nozzle (the top of its own box) rather than the middle of the SVG,
   so the plume lengthens and shortens instead of swelling in place. */
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-flame {
  transform-box: fill-box;
  transform-origin: 50% 0%;
  animation: om-rocket-thrust 0.4s ease-in-out infinite, om-rocket-bob 0.9s ease-in-out infinite;
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-flame-core {
  transform-box: fill-box;
  transform-origin: 50% 0%;
  animation: om-rocket-thrust-core 0.35s ease-in-out infinite, om-rocket-bob 0.9s ease-in-out infinite;
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-flame {
  fill: url(#om-flame);
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-flame-core {
  fill: url(#om-flame-core);
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-glow {
  fill: url(#om-flame-glow);
  filter: url(#om-glow-blur);
  transform-box: fill-box;
  transform-origin: 50% 30%;
  animation: om-rocket-glow 0.5s ease-in-out infinite, om-rocket-bob 0.9s ease-in-out infinite;
}

/* Smooth, overlapping combustion cycle — the outer flame flickers with a
   wider, slower beat while the inner core runs faster and hotter. ScaleY
   carries the plume length (it grows from the nozzle), scaleX keeps the
   fire from collapsing into a spike, and opacity dims between beats so it
   reads as real combustion rather than an elastic band. */
@keyframes om-rocket-thrust {
  0% {
    transform: scale(1.04, 1.25);
    opacity: 1;
  }
  18% {
    transform: scale(0.9, 0.82);
    opacity: 0.6;
  }
  35% {
    transform: scale(1.06, 1.3);
    opacity: 0.95;
  }
  55% {
    transform: scale(0.88, 0.78);
    opacity: 0.55;
  }
  78% {
    transform: scale(1.02, 1.15);
    opacity: 0.85;
  }
  100% {
    transform: scale(1.04, 1.25);
    opacity: 1;
  }
}

/* Hotter, faster core — runs at a slightly different frequency so the inner
   and outer flame mix organically instead of pulsing in lockstep. */
@keyframes om-rocket-thrust-core {
  0% {
    transform: scale(1.06, 1.35);
    opacity: 1;
  }
  22% {
    transform: scale(0.88, 0.78);
    opacity: 0.65;
  }
  48% {
    transform: scale(1.08, 1.32);
    opacity: 1;
  }
  70% {
    transform: scale(0.85, 0.72);
    opacity: 0.5;
  }
  88% {
    transform: scale(1.04, 1.22);
    opacity: 0.85;
  }
  100% {
    transform: scale(1.06, 1.35);
    opacity: 1;
  }
}

/* The glow breathes more slowly than the thrust and never fully drops out,
   so the exhaust haze is always present even on the dim beat — a thruster
   that stopped glowing between stutters would read as dead, not flickering. */
@keyframes om-rocket-glow {
  0%,
  100% {
    transform: scale(1);
    opacity: 0.8;
  }
  25% {
    transform: scale(1.16);
    opacity: 1;
  }
  55% {
    transform: scale(0.94);
    opacity: 0.65;
  }
  78% {
    transform: scale(1.12);
    opacity: 0.9;
  }
}

html[data-design="sigma"] .sidebar-link-promo:hover .sidebar-link-icon,
html[data-design="sigma"] .sidebar-link-promo:focus-visible .sidebar-link-icon,
html[data-design="sigma"] .sidebar-link-promo:active .sidebar-link-icon {
  transform: scale(1.06) rotate(-4deg);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 rgba(0, 0, 0, 0.32),
    0 3px 10px rgba(0, 0, 0, 0.32),
    0 0 22px color-mix(in srgb, #4a7dff 65%, transparent);
  /* Explicitly preserve the sapphire gradient background so the crown never
     disappears on hover/focus/active — the link's background change must not bleed. */
  background:
    radial-gradient(ellipse 130% 100% at 50% 85%, color-mix(in srgb, #8ab4ff 55%, transparent), transparent 65%),
    linear-gradient(165deg, #0a1633 0%, #122a5c 30%, #2855b0 65%, #4a7dff 100%);
}

/* The crest is ink knocked out of the tile, so its colour is the tile's own
   contrast, not the row tint. The generic rules above light a glyph on
   hover/current by painting it the accent — and for this tile the accent IS
   the same green as its gradient, so the crown is repainted the tile's own
   colour and vanishes, leaving a solid green square. The ink is pinned here,
   after those rules, so hover, focus, press and the current-page marker all
   keep the mark. */
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-icon,
html[data-design="sigma"] .sidebar-link-promo:hover .sidebar-link-icon,
html[data-design="sigma"] .sidebar-link-promo:focus-visible .sidebar-link-icon,
html[data-design="sigma"] .sidebar-link-promo:active .sidebar-link-icon,
html[data-design="sigma"] .sidebar-link-promo[aria-current="page"] .sidebar-link-icon {
  color: #b8d6ff;
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-copy {
  position: relative;
  z-index: 1;
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
  gap: 1px;
}

/* Gradient wordmark: cream on the left, signal purple on the right. */
html[data-design="sigma"] .sidebar-link-promo .sidebar-link-label {
  flex: 0 0 auto;
  font-size: 0.95rem;
  font-weight: 800;
  letter-spacing: -0.025em;
  background: linear-gradient(98deg, var(--cream) 0%, var(--cream) 42%, #a855f7 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-sub {
  color: var(--muted);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 0.24s ease;
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-chevron {
  position: relative;
  z-index: 1;
  display: grid;
  flex: 0 0 auto;
  place-items: center;
  width: 15px;
  height: 15px;
  color: color-mix(in srgb, var(--om-brass-bright) 62%, var(--muted));
  transition:
    color 0.24s ease,
    transform 0.24s cubic-bezier(0.22, 1, 0.36, 1);
}

html[data-design="sigma"] .sidebar-link-promo .sidebar-link-chevron svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

html[data-design="sigma"] .sidebar-link-promo:hover,
html[data-design="sigma"] .sidebar-link-promo:focus-visible {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, #a855f7 52%, var(--line-strong));
  background:
    radial-gradient(ellipse 100% 130% at 2% 0%, color-mix(in srgb, #7c3aed 32%, transparent), transparent 56%),
    radial-gradient(ellipse 90% 120% at 100% 100%, color-mix(in srgb, #7c3aed 16%, transparent), transparent 62%),
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 11%, transparent), transparent 58%),
    var(--paper);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 20%, transparent),
    0 2px 6px rgba(0, 0, 0, 0.38),
    0 12px 28px rgba(0, 0, 0, 0.28);
}

html[data-design="sigma"] .sidebar-link-promo:hover::after,
html[data-design="sigma"] .sidebar-link-promo:focus-visible::after {
  opacity: 1;
}

html[data-design="sigma"] .sidebar-link-promo:hover .sidebar-link-chevron,
html[data-design="sigma"] .sidebar-link-promo:focus-visible .sidebar-link-chevron {
  color: #a855f7;
  transform: translateX(2px);
}

html[data-design="sigma"] .sidebar-link-promo:hover .sidebar-link-sub,
html[data-design="sigma"] .sidebar-link-promo:focus-visible .sidebar-link-sub {
  color: color-mix(in srgb, #a855f7 42%, var(--cream-dim));
}

html[data-design="sigma"] .sidebar-link-promo:focus-visible {
  outline: 2px solid color-mix(in srgb, #7c3aed 72%, transparent);
  outline-offset: -2px;
}

html[data-design="sigma"] .sidebar-link-promo:active {
  transform: translateY(1px) scale(0.994);
}

/* ———— Practice streak: same structure, in the shell's cobalt ———— */
html[data-design="sigma"] .sidebar-day {
  border-color: color-mix(in srgb, var(--streak-mid) 28%, var(--line-strong));
  border-radius: var(--radius-card);
  background:
    radial-gradient(ellipse 120% 150% at 8% 100%, color-mix(in srgb, var(--streak-mid) 18%, transparent), transparent 60%),
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 5%, transparent), transparent 62%),
    var(--paper);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--streak-edge) 30%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.32),
    0 0 5px color-mix(in srgb, var(--streak-mid) 36%, transparent),
    0 0 18px color-mix(in srgb, var(--streak-core) 16%, transparent);
  transition: border-color 0.22s ease, background 0.22s ease, box-shadow 0.22s ease, transform 0.22s ease;
}

html[data-design="sigma"] .sidebar-day:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--streak-edge) 50%, var(--line-strong));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--streak-edge) 44%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.32),
    0 0 8px color-mix(in srgb, var(--streak-mid) 52%, transparent),
    0 0 26px color-mix(in srgb, var(--streak-core) 22%, transparent);
}

html[data-design="sigma"] .sidebar-day.is-blazing {
  border-color: color-mix(in srgb, var(--streak-edge) 58%, var(--line-strong));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--streak-edge) 48%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.32),
    0 0 10px color-mix(in srgb, var(--streak-mid) 58%, transparent),
    0 0 30px color-mix(in srgb, var(--streak-core) 26%, transparent);
}

/* ———— The rail's floor: streak and settings, side by side ————
   Two cards in one 50/50 row. Both shrink, and that is the point: each is now
   half the rail's width, so the full-width treatment (34px flame, 1.2rem value,
   12px padding) left each card mostly empty inside its own box. The pair reads
   as a single control strip rather than one card that swallowed the other.

   Both are children of a grid with equal tracks rather than flex-grow, so they
   are genuinely 50/50 — a long label on one side cannot squeeze the other. */
html[data-design="sigma"] .sidebar-foot-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  align-items: stretch;
}

/* Both cards fill the row's height, so the pair reads as one strip. The streak
   card is taller than the settings tile by design — it carries a week — so
   without this the tile floats centred in a taller box and the two look
   unrelated rather than paired. */
html[data-design="sigma"] .sidebar-foot-pair > * {
  height: 100%;
}

/* The streak card in its narrower home. Padding and the gap come down so the
   flame and the copy still fit the same column. */
html[data-design="sigma"] .sidebar-foot-pair .sidebar-day {
  /* Column, not row. The streak figure and its headings sit on one line at the
     top, and the week strip runs the full width beneath them — which is the
     only arrangement that lets seven equal columns breathe in a half-width
     card. Side by side, the week had roughly 60px to divide seven ways.

     Vertical centring so the figure sits on the card's optical middle rather
     than floating in the top third, with the week strip as a base. `gap` is
     0 because the figure block and the strip each own their own internal
     spacing, and a flex gap on top of that double-counts into a cramped row. */
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 0;
  padding: 10px 10px 10px;
  min-width: 0;
}

/* The flame's own box, shrunk for the pair.

   The base rule is a fixed 38x47 sized for a full-width card where the flame was
   the whole left column. In a half-width card beside a large figure that box
   became the loudest thing in the card and pushed the number and the headings
   into each other — the glow is sized off this box too, so leaving it large
   meant a 20px glyph inside a 47px slot. */
html[data-design="sigma"] .sidebar-foot-pair .sidebar-day-flame {
  /* Kept just under the numeral's cap height. At 30px against a 1.9rem figure
     the flame box was exactly as tall as the digit, and even though the glyph
     inside it is smaller, the two read as competing for the same line rather
     than the flame qualifying the number. */
  width: 19px;
  height: 23px;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--streak-mid) 45%, transparent));
}

html[data-design="sigma"] .sidebar-foot-pair .sidebar-day-flame svg {
  width: 19px;
  height: 23px;
}

/* ———— The streak figure ————
   Flame and number as one unit, so the number is the loudest thing in the card
   and the flame reads as its qualifier rather than as a separate icon.

   The figure is sized off the card, not off the rail: --sidebar-nav-icon is a
   token for 50px nav rows and would be far too large here. */
html[data-design="sigma"] .sidebar-day-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
  /* The card is a column with gap 0, so the figure row and the week strip need
     their own separation. Without it the numeral's descender and the marker row
     sit close enough to read as one crowded block. */
  margin-bottom: 8px;
}

html[data-design="sigma"] .sidebar-day-figure {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

html[data-design="sigma"] .sidebar-foot-pair .sidebar-day-value {
  /* The number IS the card. It is set well above the rail's label scale on
     purpose: this is a figure to be read at a glance from the corner of your
     eye, not a caption. Sized off the card, not off --sidebar-nav-icon, which
     is a token for 50px nav rows and would be far too large here.

     The serif is the site's own --serif, and it is what keeps this from being a
     copy of the reference: the numeral is a text serif with real weight
     contrast rather than a geometric sans in a heavier weight. */
  font-family: var(--serif, Georgia, "Times New Roman", serif);
  font-size: 1.9rem;
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--streak-edge);
  text-shadow: 0 0 22px color-mix(in srgb, var(--streak-mid) 50%, transparent);
}

/* The headings sit opposite the figure, right-aligned, so the eye lands on the
   number first and the label second. Left-aligning them under the flame pushed
   the card's content into an L and left the right edge empty. */
html[data-design="sigma"] .sidebar-day-headings {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  min-width: 0;
  text-align: right;
}

html[data-design="sigma"] .sidebar-foot-pair .sidebar-day-kicker {
  font-size: 0.54rem;
  font-weight: 800;
  letter-spacing: 0.13em;
  line-height: 1;
  color: var(--cream-dim);
  white-space: nowrap;
}

/* The supporting line. This is the "what is this number" text the reference
   spells out, kept quiet so it does not compete with the figure. */
html[data-design="sigma"] .sidebar-day-sub {
  font-size: 0.54rem;
  line-height: 1;
  color: var(--muted);
  white-space: nowrap;
}

/* ———— The settings tile ————
   Deliberately NOT a .sidebar-link. That class is a full-width nav row: 44px
   tall, 0.95rem, 14px of left padding, meant to be scanned in a vertical list.
   Reusing it inside a half-width card is what left the row looking wrong — and
   because the rail's .sidebar-link rules are scoped to `html[data-design=
   "sigma"]` and reset the button's border/background/font but never its
   `color`, the button inherited the UA's default button text colour instead of
   `--cream-dim`. That is the greyed-out look, and it was a missing property
   rather than a colour choice.

   So this is its own component with every property stated: the text colour is
   set here explicitly, which is the actual fix. */
html[data-design="sigma"] .sidebar-tile {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 9px 9px 9px 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-card);
  /* The fix for the greyed-out row. Without an explicit `color`, a <button>
     takes the UA's buttontext and ignores the rail's --cream-dim. */
  color: var(--cream);  background:
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 5%, transparent), transparent 62%),
    var(--paper);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 6%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.32);
  transition: border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}

html[data-design="sigma"] .sidebar-tile:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--om-brass) 40%, var(--line-strong));
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--om-brass) 7%, transparent), transparent 62%),
    var(--paper);
}

html[data-design="sigma"] .sidebar-tile:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--om-brass) 68%, transparent);
  outline-offset: -2px;
}

html[data-design="sigma"] .sidebar-tile[aria-expanded="true"] {
  border-color: color-mix(in srgb, var(--om-brass) 50%, var(--line-strong));
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--om-brass) 12%, transparent), transparent 62%),
    var(--paper);
}

/* The glyph. Sized off the same idea as the flame beside it rather than the
   nav token, which is tuned for a 44px row and would be oversized here. */
html[data-design="sigma"] .sidebar-tile-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  color: var(--om-brass);
  /* The same light the nav glyphs carry, at the same rest strength, so the
     gear reads as a mark on the rail rather than a widget with its own
     effects. currentColor again: the halo is the brass the glyph is drawn in,
     so it follows the theme without a second declaration. */
  filter:
    drop-shadow(0 0 3px color-mix(in srgb, currentColor 34%, transparent))
    drop-shadow(0 0 9px color-mix(in srgb, currentColor 16%, transparent));
  transition: color 0.18s ease, filter 0.18s ease, transform 0.18s ease;
}

html[data-design="sigma"] .sidebar-tile:hover .sidebar-tile-icon {
  transform: rotate(35deg);
  filter:
    drop-shadow(0 0 4px color-mix(in srgb, currentColor 55%, transparent))
    drop-shadow(0 0 12px color-mix(in srgb, currentColor 30%, transparent));
}

/* Thinmed with everything else. The settings gear is the densest glyph on the
   rail — eight teeth around a ring — so it was the one that showed its weight
   most at small sizes; at 1.3 the teeth separate instead of merging into a
   solid cog. */
html[data-design="sigma"] .sidebar-tile-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

html[data-design="sigma"] .sidebar-tile-copy {
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 2px;
}

html[data-design="sigma"] .sidebar-tile-kicker {
  color: var(--muted);
  font-size: 0.56rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* The rail's section labels fade back; this is a control's own label, so it
     stays legible rather than matching them. */
  opacity: 1;
}

html[data-design="sigma"] .sidebar-tile-value {
  color: var(--cream);
  font-size: 0.88rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ———— Sign in: the primary action, in the brand's signal colour ———— */
html[data-design="sigma"] .sidebar-link-primary {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  min-height: 40px;
  justify-content: center;
  gap: 8px;
  padding: 0 14px;
  border: 1px solid color-mix(in srgb, var(--om-brass-bright) 72%, transparent);
  border-radius: var(--radius-card);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0) 62%),
    linear-gradient(180deg, var(--om-brass-bright), var(--om-brass));
  color: #0b1405;
  font-size: 0.98rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 6px 18px rgba(0, 0, 0, 0.2),
    0 0 8px color-mix(in srgb, var(--om-brass) 50%, transparent),
    0 0 24px color-mix(in srgb, var(--om-brass) 22%, transparent);
  transition:
    background 0.26s ease,
    box-shadow 0.26s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.26s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Specular sweep, clipped to the pill. */
html[data-design="sigma"] .sidebar-link-primary::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(115deg, transparent 34%, rgba(255, 255, 255, 0.5) 50%, transparent 66%);
  transform: translateX(-130%);
  transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

html[data-design="sigma"] .sidebar-link-primary:hover::after,
html[data-design="sigma"] .sidebar-link-primary:focus-visible::after {
  transform: translateX(130%);
}

html[data-design="sigma"] .sidebar-link-primary .sidebar-link-label {
  color: inherit;
  flex: 0 1 auto;
  font-size: 0.9rem;
  font-weight: 800;
}

html[data-design="sigma"] .sidebar-link-primary .sidebar-link-icon {
  color: inherit;
  background: rgba(11, 20, 5, 0.16);
  box-shadow: none;
}

html[data-design="sigma"] .sidebar-link-primary:hover,
html[data-design="sigma"] .sidebar-link-primary:focus-visible {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0) 62%),
    linear-gradient(180deg, #a3ff6e, var(--om-brass-bright));
  color: #0b1405;
  transform: translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 8px 22px rgba(0, 0, 0, 0.22),
    0 0 10px color-mix(in srgb, var(--om-brass) 65%, transparent),
    0 0 32px color-mix(in srgb, var(--om-brass) 30%, transparent);
}

html[data-design="sigma"] .sidebar-link-primary:active {
  transform: translateY(1px);
  box-shadow:
    inset 0 2px 4px rgba(11, 20, 5, 0.28),
    0 0 8px color-mix(in srgb, var(--om-brass) 40%, transparent);
}

/* Being ON Leaderboard or Unlimited keeps the crisp treatment rather than
   dropping to the base flat ring. */
html[data-design="sigma"] .sidebar-link-lg[aria-current="page"],
html[data-design="sigma"] .sidebar-link-promo[aria-current="page"] {
  border-color: color-mix(in srgb, #7c3aed 52%, var(--line-strong));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #7c3aed 34%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.3);
}

/* The promo keeps its jewellery when it is the current page: same layered
   depth, just with the ring fully lit. Placed after the shared rule above so
   it wins on the tie in specificity. */
html[data-design="sigma"] .sidebar-link-promo[aria-current="page"] {
  border-color: color-mix(in srgb, #a855f7 60%, var(--line-strong));
  background:
    radial-gradient(ellipse 100% 130% at 2% 0%, color-mix(in srgb, #7c3aed 27%, transparent), transparent 56%),
    radial-gradient(ellipse 90% 120% at 100% 100%, color-mix(in srgb, #7c3aed 13%, transparent), transparent 62%),
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 9%, transparent), transparent 58%),
    var(--paper);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 17%, transparent),
    0 2px 4px rgba(0, 0, 0, 0.36),
    0 10px 24px rgba(0, 0, 0, 0.26);
}

html[data-design="sigma"] .sidebar-link-promo[aria-current="page"]::after {
  opacity: 1;
}

/* More air above the streak card so the footer reads as its own section. */
html[data-design="sigma"] .site-sidebar-foot {
  padding-top: 16px;
}

@media (prefers-reduced-motion: reduce) {
  html[data-design="sigma"] .sidebar-link-lg:hover,
  html[data-design="sigma"] .sidebar-link-promo:hover,
  html[data-design="sigma"] .sidebar-link-promo:focus-visible,
  html[data-design="sigma"] .sidebar-link-promo:active,
  html[data-design="sigma"] .sidebar-link-promo:hover .sidebar-link-icon,
  html[data-design="sigma"] .sidebar-link-promo:focus-visible .sidebar-link-icon,
  html[data-design="sigma"] .sidebar-link-promo:hover .sidebar-link-chevron,
  html[data-design="sigma"] .sidebar-link-promo:focus-visible .sidebar-link-chevron,
  html[data-design="sigma"] .sidebar-day:hover,
  html[data-design="sigma"] .sidebar-tile:hover,
  html[data-design="sigma"] .sidebar-tile:hover .sidebar-tile-icon,
  html[data-design="sigma"] .sidebar-week-day i,
  html[data-design="sigma"] .sidebar-link-primary:hover,
  html[data-design="sigma"] .sidebar-link-primary:focus-visible,
  html[data-design="sigma"] .sidebar-link-primary:active {
    transform: none;
    transition: none;
  }

  html[data-design="sigma"] .sidebar-link-primary::after,
  html[data-design="sigma"] .sidebar-link-promo .sidebar-link-shine {
    display: none;
  }

  /* The gem motion is decorative looping animation, so it is the first
     thing to go under reduced-motion — the same courtesy the shine sweep and
     the hover lifts get above. The sapphire still reads as a gem, it just
     holds still. */
  html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket,
  html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-fin,
  html[data-design="sigma"] .sidebar-link-promo .sidebar-link-rocket-detail {
    animation: none;
  }
}

/* ——— Hover flyout sections ————————————————————————————————————————————
   Each section is ONE row in the rail, and hovering or focusing it opens a
   panel beside the rail holding that section's destinations. The rail does not
   grow, so the whole list stays short enough to take in at a glance — which is
   the point: a rail whose length depends on how many sections you expanded is a
   rail you have to re-read every time.

   Three structural rules, each fixing a way this has actually broken:

   1. The panel is positioned FIXED against the rail's right edge. It cannot be
      `position: absolute` inside the row: an absolutely positioned element is
      still clipped and scrolled by any ancestor with `overflow` set, and the
      rail is `overflow-y: auto`. Inside the rail, a panel taller than the
      visible portion scrolls with the rail instead of standing beside it, and on
      a short window it opens already cut off.

   2. The panel is a SIBLING of the trigger inside `[data-sidebar-flyout]`,
      never a child. A nested panel sits inside the element the pointer just
      left, so travelling toward it fires pointerleave on the row and the panel
      closes before the pointer arrives. Every nested flyout snaps shut for
      exactly this reason.

   3. `hidden` is the off state, and it is never transitioned away. It removes
      the panel from the accessibility tree and the tab order, which a panel
      merely faded out would not.

   theme.js sets `top` from the trigger's rect on every open, so the panel
   tracks whichever row is hovered. Without this script the panels stay `hidden`
   and navigation is never blocked — only the extras are unavailable. */

/* A section row. Every geometric property below is deliberately identical to
   .sidebar-link above — same min-height, gap, padding and type — and a test
   asserts they stay identical.

   This rule used to declare its own copy of the row's geometry, and the two
   copies drifted: the rail was narrowed and shortened, this stayed at the old
   values, and the section rows ended up visibly taller and heavier than the
   plain rows interleaved with them. The rail has two kinds of row and they must
   be indistinguishable in size, or the eye reads the interleaving as a mistake.

   `.sidebar-row-button` carries the same resets for the <button> form of this. */
html[data-design="sigma"] .sidebar-flyout-trigger {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  padding: 0 12px 0 13px;
  /* Flush, not a card — identical to .sidebar-link above, because the section
     rows and the destination rows sit interleaved in the same column and two
     treatments would read as a mistake. */
  border: 1px solid transparent;
  border-radius: var(--radius-nav);
  background: transparent;
  box-shadow: none;
  color: var(--cream-dim);
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  text-align: left;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition:
    color 0.18s ease,
    background 0.18s ease;
}

/* Matches .sidebar-link:hover exactly: a wash and nothing else. */
html[data-design="sigma"] .sidebar-flyout-trigger:hover {
  color: var(--cream);
  background: var(--hover-fill);
}

html[data-design="sigma"] .sidebar-flyout-trigger:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--om-brass) 68%, transparent);
  outline-offset: -2px;
  color: var(--cream);
}

/* The open row is marked with the same wash and the same leading bar as the
   current page, because it IS the same question: which one is active. One thing
   in this rail means "active", whether it was clicked or hovered.

   This one additionally keeps the bright leading edge flush against the row's
   full height rather than inset. That is the visual tether to the panel hanging
   off the right of the rail — the marker has to point at something outside the
   rail, so it reaches as far as it can in the direction the panel is in. */
html[data-design="sigma"] [data-sidebar-flyout].is-open > .sidebar-flyout-trigger {
  color: var(--cream);
  background: var(--hover-fill);
  box-shadow: none;
}

html[data-design="sigma"] [data-sidebar-flyout].is-open > .sidebar-flyout-trigger::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--om-brass-bright);
}

/* A chevron on the trailing edge, so the row reads as a disclosure rather than
   a link that happens to carry a folder icon. It rotates to point down while
   the panel is open, which is the standard "this is what opened me" signal.

   14px in a 44px row. It sits on the row's own baseline rhythm rather than
   floating in the extra space a 16px box left behind. */
html[data-design="sigma"] .sidebar-flyout-chevron {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  margin-left: auto;
  opacity: 0.55;
  transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.18s ease;
}

/* This was 2, which made the chevron the heaviest element in the rail — heavier
   than every destination icon beside it, and heavier than any line of type on
   the page. It is the smallest mark on the row, so it has to be the thinnest
   too.

   It reads at the same stroke as the icons rather than below them, and that is
   deliberate: the chevron is a simple open shape with no counters, so it already
   carries less visual mass than a filled glyph at an identical weight. Dropping
   it further would make it look like a rendering artefact rather than a
   deliberate mark.

   Reading the token rather than repeating the number is the point. Two literal
   strokes on the same row is two chances for them to disagree, and the
   disagreement is invisible in review and obvious on screen. */
html[data-design="sigma"] .sidebar-flyout-chevron svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: var(--sidebar-nav-stroke);
  stroke-linecap: round;
  stroke-linejoin: round;
}

html[data-design="sigma"] [data-sidebar-flyout].is-open > .sidebar-flyout-trigger .sidebar-flyout-chevron {
  transform: rotate(90deg);
  opacity: 1;
  color: var(--om-brass-bright);
}

/* ——— The panel ——— */
html[data-design="sigma"] .sidebar-flyout-panel {
  position: fixed;
  /* Flush against the rail's right edge, with no gap at all.

     The gap looked deliberate and was the whole problem. The rail is
     --sidebar-w wide with 14px of padding, so a row's box ends at
     --sidebar-w - 14px while the panel used to start at --sidebar-w + 8px.
     That left 22px of ordinary page content belonging to neither, which the
     pointer had to cross to get from the row to the panel — and crossing it
     fired `pointerleave` on the row, so the panel shut at the exact moment the
     pointer was halfway to it. It looked fine in a screenshot and was
     impossible to click.

     Sitting flush means the pointer never leaves the row on its way to the
     panel. The 150ms grace in theme.js is the second layer of the same
     defence: even a fast diagonal move that clips the corner cannot close it
     early. Reading --sidebar-w keeps the panel glued to the rail if the rail is
     ever widened. */
  left: var(--sidebar-w);
  /* Above the rail (120) and above the page content, but below the tour
     overlay (240) and the settings dialog, which are full-screen surfaces a
     flyout must never sit on top of. */
  z-index: 130;
  /* Narrower with the rail. 236px was sized to clear the rail's former width;
     at 296 the same panel overhangs the page by enough to cover a column of
     content behind it. 208px still fits the longest label in any section
     ("Opening Library", "Community Courses") with its glyph and breathing room. */
  min-width: 208px;
  padding: 8px;
  border: 1px solid var(--line-strong);
  /* Only the two corners away from the rail. Rounding all four would tuck the
     near edge in far enough to expose the page behind it, which is the very
     strip the pointer used to fall into — and a panel that appears to hover
     slightly off its row when it is bolted to it reads as a mistake. The rail
     side is squared off so the two read as one surface. */
  border-radius: 0 14px 14px 0;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 5%, transparent), transparent 60px),
    color-mix(in srgb, var(--panel) 94%, var(--bg-2));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 6%, transparent),
    0 24px 64px rgba(0, 0, 0, 0.5);
  /* A long section must not run off a short window. The links scroll inside
     the panel rather than the panel being clipped, so the last row is still
     reachable. */
  max-height: calc(100vh - 24px);
  overflow-y: auto;
  overscroll-behavior: contain;
  animation: sidebar-flyout-in 0.16s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes sidebar-flyout-in {
  from {
    opacity: 0;
    transform: translateX(-6px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* The section name repeated at the top of the panel. It sits outside the rail,
   so without this the reader has to remember which row they hovered; and for
   Community it is what separates "Community" (the section) from
   "Community Courses" (one of its links). */
html[data-design="sigma"] .sidebar-flyout-heading {
  margin: 0 0 6px;
  padding: 0 8px 6px;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.64rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

html[data-design="sigma"] .sidebar-flyout-links {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Panel rows keep the rail's label size but not its height: four rows at rail
   height is a 176px panel for four short words, which pushes the last one off a
   short screen.

   No card-removal here any more, and that is worth noting rather than leaving
   silent. This rule used to strip a border, a surface and a shadow off these
   rows so they would not be cards inside a bordered panel. The rail's own rows
   are flush now, so there is nothing left to strip — the rule is no longer
   protecting the panel from anything, and keeping three dead declarations would
   suggest the panel still needed defending against a treatment it no longer
   meets anywhere.

   Height and type are all this needs, and those two are checked against the
   drawer's copy so a phone cannot drift from a desktop. */
html[data-design="sigma"] .sidebar-flyout-links .sidebar-link {
  min-height: 38px;
  font-size: 0.9rem;
}

/* The panel's rows, not the rail's. Only the nudge is suppressed, and the rail
   no longer has one to suppress — this is kept as a statement of intent rather
   than left to be discovered: if a raise is ever reintroduced on the rail's rows,
   it must not come back inside a panel, where a travelling row reads as the
   panel shaking in place.

   The wash is all a panel row needs to show where the pointer is. */
html[data-design="sigma"] .sidebar-flyout-links .sidebar-link:hover {
  transform: none;
  background: var(--hover-fill);
}

/* The rail's sheen is gone, so panel rows no longer need to opt out of it. This
   rule used to sit here; what it protected against — a travelling highlight
   inside a panel that is itself animating in — cannot happen now that the
   highlight itself no longer exists. */

@media (prefers-reduced-motion: reduce) {
  html[data-design="sigma"] .sidebar-flyout-chevron {
    transition: none;
  }

  /* The fold is movement too, so a reader who asked the OS to hold still gets
     the rail changing width in one step rather than easing across. Same for the
     page sliding with it and the chevron's flip. */
  html[data-design="sigma"] .site-sidebar,
  html[data-design="sigma"] .site-frame,
  html[data-design="sigma"] .sidebar-collapse-toggle svg {
    transition: none;
  }

  /* The panel still appears; it just does not travel. */
  html[data-design="sigma"] .sidebar-flyout-panel {
    animation: none;
  }

  /* The nav rows settle into place rather than sliding. */
  html[data-design="sigma"] .sidebar-link,
  html[data-design="sigma"] .sidebar-link-icon,
  html[data-design="sigma"] .sidebar-tile-icon {
    transition: none;
  }

  /* The glyph still scales on hover, and that is the one piece of motion a
     flush rail keeps: with no card to lift, the icon's response is what tells
     the reader the row registered the pointer at all. So the scale stops here,
     and only the scale — the row's own wash and colour change are not motion
     and stay. */
  html[data-design="sigma"] .sidebar-link:hover .sidebar-link-icon,
  html[data-design="sigma"] .sidebar-flyout-trigger:hover .sidebar-link-icon {
    transform: none;
  }
}
@media (max-width: 980px) {
  /* Override the base .sidebar-flyout-panel rule which comes later in the file
     and would otherwise win the cascade, leaving the panel position: fixed
     and off the right edge of the phone screen. */
  html[data-design="sigma"] .sidebar-flyout-panel {
    position: static !important;
    left: auto !important;
    width: auto !important;
    min-width: 0 !important;
    margin: 2px 0 0;
    padding: 6px;
    border-radius: 10px;
    box-shadow: none;
    background: color-mix(in srgb, var(--bg-2) 88%, var(--bg));
    max-height: none;
    animation: none;
    z-index: auto;
    border: 0;
  }
}