/* ============================================================
   PENTAGON brand system

   Fonts: Medium (headers) · Space Grotesk (body) · Space Mono (footer)
   Colors: Void Black #0d1212 · Plaster White #fffef3 · Yellow Beam #ffc60b (VIP only)
   ============================================================ */

@font-face {
  font-family: 'Medium';
  src: url('/static/fonts/Medium.otf') format('opentype');
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-Light.ttf') format('truetype');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-Medium.ttf') format('truetype');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-SemiBold.ttf') format('truetype');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Grotesk';
  src: url('/static/fonts/SpaceGrotesk-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Mono';
  src: url('/static/fonts/SpaceMono-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Space Mono';
  src: url('/static/fonts/SpaceMono-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ============================================================
   Theme tokens

   Dark is the default and lives on :root. Light — "inverted paper" —
   swaps the same two brand colours: Plaster White becomes the ground,
   Void Black the ink.

   The resolved scheme is stamped onto <html data-theme> by the inline
   script in base.html before first paint, so there is never a flash and
   the light rules only ever need one selector. Without JS the site
   stays dark, which is the brand's default face.
   ============================================================ */

:root {
  color-scheme: dark;

  --bg: #0d1212;
  --bg-raise: #121818;
  /* Warm off-black used by the About tiles' gold-leaning panels. */
  --bg-warm: #1a1510;
  --card-bg: rgba(255, 254, 243, 0.022);
  --text: #fffef3;
  --text-dim: #c8c6b8;
  --muted: #8a887c;
  --faint: #3e4240;

  --line: rgba(255, 254, 243, 0.12);
  --line-soft: rgba(255, 254, 243, 0.06);
  --line-strong: rgba(255, 254, 243, 0.32);

  --vip: #ffc60b;
  --red: #ff5a4d;
  --green: #48d18a;
  --blue: #6f9dff;

  /* --ink is whatever reads on a --text-coloured fill, so the pairing
     `background: var(--text); color: var(--ink)` inverts with the theme. */
  --ink: #000;
  /* Recessed panel — darker than the page in dark, lighter in light. */
  --well: #000;
  /* Translucent surfaces that sit over content. */
  --scrim: rgba(0, 0, 0, 0.72);
  --scrim-solid: rgba(0, 0, 0, 0.95);
  --shadow: rgba(0, 0, 0, 0.45);

  /* Four graded washes for hover states and panel tints. Flat white at
     low alpha vanishes on paper, so these flip to ink in light mode. */
  --wash-1: rgba(255, 255, 255, 0.025);
  --wash-2: rgba(255, 255, 255, 0.042);
  --wash-3: rgba(255, 255, 255, 0.065);
  --wash-4: rgba(255, 255, 255, 0.1);

  /* The fixed background stack: ruled grid, grain, vignette. */
  --bg-rule: rgba(255, 255, 255, 0.028);
  --bg-grain-opacity: 0.16;
  --bg-vignette: rgba(0, 0, 0, 0.75);
  /* Read by bg.js for the canvas matrix. */
  --bg-canvas-ink: 255, 255, 255;
  /* The page ground as bare channels, so overlays can compose their own
     alpha: rgba(var(--ground-rgb), 0.55). Used by the scrims that sit on
     photographs — flyers, product shots — which have to darken in dark
     mode and lighten in light mode to keep --text legible on top. */
  --ground-rgb: 13, 18, 18;

  --radius: 0px;
  --font-display: 'Medium', 'Space Grotesk', sans-serif;
  --font-body: 'Space Grotesk', sans-serif;
  --font-mono: 'Space Mono', ui-monospace, monospace;

  --gut: clamp(18px, 4vw, 56px);   /* page gutter */
  --nav-h: 78px;
}

/* ---------- Light — inverted paper ---------- */
:root[data-theme="light"] {
  color-scheme: light;

  --bg: #fffef3;
  --bg-raise: #f6f4e4;
  --bg-warm: #f5eeda;
  --card-bg: rgba(13, 18, 18, 0.022);
  --text: #0d1212;
  --text-dim: #39413f;
  /* --muted carries the small mono labels, and many of them sit on --well
     rather than on the page, so it is tuned against the darker of the two:
     5.1:1 on --well, 5.8:1 on --bg. */
  --muted: #5f6662;
  /* Decorative hairline tone, never load-bearing text — deliberately at
     about the same 1.9:1 as its Void Black counterpart. */
  --faint: #b6bab3;

  --line: rgba(13, 18, 18, 0.16);
  --line-soft: rgba(13, 18, 18, 0.08);
  --line-strong: rgba(13, 18, 18, 0.4);

  /* Yellow Beam is a signal colour, not a legible one on paper — it drops
     to roughly 1.5:1 against #fffef3. These are the darkest versions that
     still read as the same hue. Small solid marks (dots, bars) keep their
     punch because they carry no text. */
  --vip: #8a6400;
  --red: #c1352a;
  --green: #157245;
  --blue: #2f5fd0;

  --ink: #fffef3;
  --well: #f1efdf;
  --scrim: rgba(255, 254, 243, 0.78);
  --scrim-solid: rgba(255, 254, 243, 0.97);
  --shadow: rgba(13, 18, 18, 0.16);

  --wash-1: rgba(13, 18, 18, 0.035);
  --wash-2: rgba(13, 18, 18, 0.055);
  --wash-3: rgba(13, 18, 18, 0.08);
  --wash-4: rgba(13, 18, 18, 0.13);

  --bg-rule: rgba(13, 18, 18, 0.045);
  --bg-grain-opacity: 0.07;
  --bg-vignette: rgba(13, 18, 18, 0.1);
  --bg-canvas-ink: 13, 18, 18;
  --ground-rgb: 255, 254, 243;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

/* The UA's `[hidden] { display: none }` loses to any author `display`
   rule of equal specificity, so `el.hidden = true` silently fails on
   anything styled as grid/flex — event cards, story buttons. Restate it
   here so hiding by attribute works everywhere. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.6;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

.vip-badge,
.vip-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--vip);
  font-family: var(--font-mono);
  font-size: 0.56rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.vip-name { color: var(--vip); }
.is-vip .nav-profile-name,
.is-vip .account-name { color: var(--vip); }

a { color: inherit; text-decoration: none; }
main { flex: 1; position: relative; z-index: 1; }
::selection { background: var(--text); color: var(--ink); }

.container {
  max-width: 1440px;
  width: 100%;
  margin: 0 auto;
  padding: clamp(28px, 5vw, 64px) var(--gut) 0;
}

/* ---------- Backgrounds — canvas matrix + grain + vignette ---------- */
.bg-grid {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}
/* Fine ruled grid — the Swiss substrate under everything. */
.bg-rules {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--bg-rule) 1px, transparent 1px),
    linear-gradient(to bottom, var(--bg-rule) 1px, transparent 1px);
  background-size: 96px 96px;
  mask-image: radial-gradient(120% 90% at 50% 30%, #000 25%, transparent 85%);
  -webkit-mask-image: radial-gradient(120% 90% at 50% 30%, #000 25%, transparent 85%);
}
/* Film grain — 1 tiny inline SVG, no network cost. */
.bg-grain {
  position: fixed;
  inset: -50%;
  z-index: 0;
  pointer-events: none;
  opacity: var(--bg-grain-opacity);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  animation: grain 6s steps(6) infinite;
}
@keyframes grain {
  0%, 100% { transform: translate(0, 0); }
  16% { transform: translate(-3%, -4%); }
  33% { transform: translate(2%, -2%); }
  50% { transform: translate(-2%, 3%); }
  66% { transform: translate(3%, 2%); }
  83% { transform: translate(-1%, -3%); }
}
.bg-vignette {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(115% 80% at 50% 40%, transparent 40%, var(--bg-vignette) 100%);
}

/* ---------- Header — hairline rule, wordmark, index ----------
   Scroll-scrubbed brand: --nav-p is 0 at the top of the page (hero logo
   alone, ~3×) and 1 once the member has scrolled ~120px (compact mark +
   spawned PENTAGON). Driven by a passive scroll listener in base.html —
   not a one-shot trigger, so scrubbing up/down plays the morph both ways. */
.nav {
  --nav-p: 0;
  position: sticky;
  top: 0;
  z-index: 90;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 18px;
  height: var(--nav-h);
  /* Clear the viewport / notch edge — the hero mark was kissing the top. */
  padding: max(10px, env(safe-area-inset-top, 0px)) var(--gut) 0;
  box-sizing: border-box;
  /* Transparent over the hero; scrim + blur + rule fade in with --nav-p. */
  background: color-mix(in srgb, var(--scrim) calc(var(--nav-p) * 100%), transparent);
  backdrop-filter: blur(calc(var(--nav-p) * 20px)) saturate(0);
  -webkit-backdrop-filter: blur(calc(var(--nav-p) * 20px)) saturate(0);
  border-bottom: 1px solid color-mix(in srgb, var(--line) calc(var(--nav-p) * 100%), transparent);
  overflow: visible;
}
.nav-side {
  display: flex;
  align-items: center;
  min-width: 0;
  gap: 16px;
}
.nav-side-left { justify-content: flex-start; }
.nav-side-right { justify-content: flex-end; }

.nav-cart {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  color: var(--text); border: 1px solid var(--line);
  transition: border-color 0.2s, color 0.2s;
}
.nav-cart:hover { border-color: var(--text); }
.nav-cart-n {
  position: absolute; top: -6px; right: -6px;
  min-width: 18px; height: 18px; padding: 0 5px;
  display: grid; place-items: center;
  background: var(--vip); color: #000;
  font-family: var(--font-mono); font-size: 0.58rem;
  font-variant-numeric: tabular-nums; line-height: 1;
}

.nav-meta {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}
.nav-meta .dot {
  display: inline-block;
  width: 5px; height: 5px;
  background: var(--green);
  margin-right: 7px;
  vertical-align: middle;
  animation: live-pulse 2.4s ease-in-out infinite;
}
@keyframes live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* Header techno tuner — Yellow Beam live control on the left. */
.nav-techno {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 34px;
  padding: 0 12px 0 10px;
  border: 1px solid color-mix(in srgb, var(--vip) 45%, var(--line));
  background: color-mix(in srgb, var(--vip) 10%, transparent);
  color: var(--vip);
  font-family: var(--font-mono);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s, color 0.2s, box-shadow 0.25s;
  -webkit-tap-highlight-color: transparent;
}
.nav-techno:hover {
  background: color-mix(in srgb, var(--vip) 18%, transparent);
  border-color: var(--vip);
  color: var(--vip);
}
.nav-techno.is-on {
  background: var(--vip);
  border-color: var(--vip);
  color: var(--bg);
  box-shadow: 0 0 22px color-mix(in srgb, var(--vip) 35%, transparent);
}
.nav-techno-wave {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 12px;
}
.nav-techno-wave i {
  width: 2px;
  background: currentColor;
  height: 35%;
}
.nav-techno.is-on .nav-techno-wave i {
  animation: eq 0.85s ease-in-out infinite;
}
.nav-techno.is-on .nav-techno-wave i:nth-child(1) { height: 40%; animation-delay: -0.1s; }
.nav-techno.is-on .nav-techno-wave i:nth-child(2) { height: 90%; animation-delay: -0.4s; }
.nav-techno.is-on .nav-techno-wave i:nth-child(3) { height: 55%; animation-delay: -0.7s; }
.nav-techno.is-on .nav-techno-wave i:nth-child(4) { height: 75%; animation-delay: -0.25s; }
.nav-techno:not(.is-on) .nav-techno-wave i:nth-child(1) { height: 35%; }
.nav-techno:not(.is-on) .nav-techno-wave i:nth-child(2) { height: 70%; }
.nav-techno:not(.is-on) .nav-techno-wave i:nth-child(3) { height: 45%; }
.nav-techno:not(.is-on) .nav-techno-wave i:nth-child(4) { height: 60%; }
@media (max-width: 520px) {
  .nav-techno { padding: 0 10px; gap: 7px; }
  .nav-techno-label { letter-spacing: 0.12em; }
}

.brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(11px * var(--nav-p));
  grid-column: 2;
  overflow: visible;
}
/* Candle mark — the SVG's centre teardrop is the candle. Flame lights in
   that centre; the mark stays put (no downward travel). */
.brand-mark {
  position: relative;
  display: block;
  flex-shrink: 0;
  line-height: 0;
  overflow: visible;
  transform-origin: 50% 50%;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.brand:hover .brand-mark,
.brand:focus-visible .brand-mark,
html.is-candle-lit .brand-mark {
  transform: scale(1.06);
}

/* Soft VIP-yellow halo — one radial, opacity/scale only. Default
   transition is none so snuff is instant; lit state adds a slow ease-in. */
.brand-glow {
  position: absolute;
  left: 50%;
  top: 48%;
  z-index: 1;
  width: calc(22px * (3 - 2 * var(--nav-p)) * 1.9);
  height: calc(22px * (3 - 2 * var(--nav-p)) * 1.9);
  transform: translate(-50%, calc(-50% - 1px)) scale(0.55);
  pointer-events: none;
  opacity: 0;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    color-mix(in srgb, var(--vip) 55%, transparent) 0%,
    color-mix(in srgb, var(--vip) 18%, transparent) 42%,
    transparent 72%
  );
  transition: none;
}
html.is-candle-lit .brand-glow {
  opacity: 1;
  transform: translate(-50%, calc(-50% - 1px)) scale(1);
  transition:
    opacity 0.85s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.95s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Simple VIP-yellow flame in the candle cavity.
   Off → on: slow grow. On → off: instant (transition: none). */
.brand-flame {
  position: absolute;
  left: 50%;
  top: 48%;
  z-index: 2;
  width: calc(22px * (3 - 2 * var(--nav-p)) * 0.42);
  height: auto;
  aspect-ratio: 24 / 36;
  margin: 0;
  padding: 0;
  overflow: visible;
  pointer-events: none;
  transform: translate(-50%, calc(-50% - 1px)) scale(0.15);
  transform-origin: 50% 90%;
  opacity: 0;
  transition: none;
}
.brand-flame .bf-body,
.brand-flame .bf-core {
  transform-box: fill-box;
  transform-origin: 50% 100%;
}
html.is-candle-lit .brand-flame {
  opacity: 1;
  transform: translate(-50%, calc(-50% - 1px)) scale(1);
  transition:
    opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
  animation: bf-flicker 2s ease-in-out infinite;
}
html.is-candle-lit .brand-flame .bf-core {
  animation: bf-core 1.4s ease-in-out infinite alternate;
}

@keyframes bf-flicker {
  0%, 100% { transform: translate(-50%, calc(-50% - 1px)) scale(1) rotate(0deg); }
  33%      { transform: translate(-50%, calc(-50% - 1px)) scale(0.96, 1.04) rotate(-1deg); }
  66%      { transform: translate(-50%, calc(-50% - 1px)) scale(1.03, 0.97) rotate(1.2deg); }
}
@keyframes bf-core {
  from { transform: scale(0.92); opacity: 0.85; }
  to   { transform: scale(1.06); opacity: 1; }
}

/* Snuff smoke — two soft puffs rise briefly after extinguish. */
.brand-smoke {
  position: absolute;
  left: 50%;
  top: 42%;
  z-index: 3;
  width: calc(22px * (3 - 2 * var(--nav-p)) * 0.55);
  height: calc(22px * (3 - 2 * var(--nav-p)) * 0.9);
  transform: translate(-50%, -50%);
  pointer-events: none;
  overflow: visible;
}
.brand-smoke i {
  position: absolute;
  left: 50%;
  bottom: 10%;
  width: 55%;
  height: 55%;
  margin-left: -27.5%;
  border-radius: 50%;
  background: color-mix(in srgb, var(--text) 22%, transparent);
  opacity: 0;
  transform: translateY(0) scale(0.4);
}
.brand-smoke i:nth-child(2) {
  width: 40%;
  height: 40%;
  margin-left: -12%;
  left: 42%;
}
.brand-mark.is-snuffing .brand-smoke i {
  animation: bf-smoke 0.45s ease-out forwards;
}
.brand-mark.is-snuffing .brand-smoke i:nth-child(2) {
  animation-delay: 0.05s;
}
@keyframes bf-smoke {
  0%   { opacity: 0.45; transform: translateY(0) scale(0.35); }
  40%  { opacity: 0.28; transform: translateY(-40%) scale(0.75); }
  100% { opacity: 0; transform: translateY(-110%) scale(1.1); }
}

/* Painted as a mask fill so the mark follows data-theme (currentColor /
   --text), not the OS preference baked into logo.svg for favicons. */
.logo {
  display: block;
  width: 22px;
  height: 22px;
  background: var(--text);
  opacity: 0.95;
  mask: var(--mark) center / contain no-repeat;
  -webkit-mask: var(--mark) center / contain no-repeat;
  transition: none;
  filter: none;
}
/* Nav mark size is scrubbed via width/height. Flame is centred on the
   candle cavity — the mark itself no longer travels on hover. */
.nav .logo {
  position: relative;
  z-index: 1;
  width: calc(22px * (3 - 2 * var(--nav-p)));
  height: calc(22px * (3 - 2 * var(--nav-p)));
  flex-shrink: 0;
}
html.is-candle-lit .logo {
  background: color-mix(in srgb, var(--vip) 50%, var(--text));
  opacity: 1;
  filter: drop-shadow(0 0 8px color-mix(in srgb, var(--vip) 45%, transparent));
  transition:
    background 0.85s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.85s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.5s ease;
}

/* ---- Candle-lit theme wash ----
   Soft Yellow Beam wash at the top. Slow in, instant out (transition only
   while lit). Stays on brand yellow — no orange hue shift. */
@property --candle-warm {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}
html {
  --candle-warm: 0;
  transition: none;
}
html.is-candle-lit {
  --candle-warm: 1;
  transition: --candle-warm 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}
.candle-wash {
  position: fixed;
  inset: 0;
  z-index: 70;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(
    ellipse 65% 40% at 50% -8%,
    color-mix(in srgb, var(--vip) 18%, transparent),
    transparent 72%
  );
  transition: none;
}
html.is-candle-lit .candle-wash {
  opacity: 1;
  transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}
:root[data-theme="light"] .candle-wash {
  background: radial-gradient(
    ellipse 65% 40% at 50% -8%,
    color-mix(in srgb, var(--vip) 22%, transparent),
    transparent 72%
  );
}

/* Safety net for pages that still load logo.svg as an <img>. The file
   answers to prefers-color-scheme; when the member has overridden the
   theme those two disagree and the mark vanishes — invert closes the gap.
   Mask-based .logo spans above, and logo-ink.svg (QR), are untouched. */
@media (prefers-color-scheme: light) {
  :root[data-theme="dark"] img[src*="logo.svg"]:not(.keep-scheme) {
    filter: invert(1);
  }
}
@media (prefers-color-scheme: dark) {
  :root[data-theme="light"] img[src*="logo.svg"]:not(.keep-scheme) {
    filter: invert(1);
  }
}
.brand-word {
  display: inline-flex;
  align-items: baseline;
  overflow: hidden;
  /* Collapse the word so the lone hero logo stays dead-centre; the clip
     opens with --nav-p while each glyph spawns on its own curve. */
  max-width: calc(var(--nav-p) * 11em);
  font-family: var(--font-display);
  font-size: 0.98rem;
  letter-spacing: 0.06em;
  color: var(--text);
  white-space: nowrap;
}
.brand-ch {
  display: inline-block;
  font-style: normal;
  /* Each glyph arms after a staggered threshold of --nav-p, then ramps
     over ~0.12 of the scrub range — scrubbing backwards unsawns them. */
  opacity: clamp(0, calc((var(--nav-p) - (0.16 + var(--i) * 0.085)) / 0.12), 1);
  transform: translate3d(
    0,
    calc((1 - clamp(0, calc((var(--nav-p) - (0.16 + var(--i) * 0.085)) / 0.12), 1)) * 0.55em),
    0
  );
  filter: blur(
    calc((1 - clamp(0, calc((var(--nav-p) - (0.16 + var(--i) * 0.085)) / 0.12), 1)) * 5px)
  );
}

.nav-link {
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--muted);
  transition: color 0.18s;
}
.nav-link:hover { color: var(--text); }

.nav-profile { display: inline-flex; align-items: center; gap: 8px; color: var(--text-dim); max-width: 200px; }
.nav-profile::before { content: "→"; color: var(--muted); }
.nav-profile:hover { color: var(--text); }
.nav-profile-name {
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-burger {
  display: flex;
  align-items: center;
  background: none;
  border: none;
  color: var(--text);
  cursor: pointer;
  padding: 6px 0;
}
.nav-burger .burger-lines { display: flex; flex-direction: column; gap: 5px; width: 24px; }
.nav-burger .burger-lines span { display: block; height: 1px; width: 100%; background: currentColor; transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.2s; }
.nav-burger:hover .burger-lines span:nth-child(2) { transform: scaleX(0.6); transform-origin: left; }
.nav-burger[aria-expanded="true"] .burger-lines span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-burger[aria-expanded="true"] .burger-lines span:nth-child(2) { opacity: 0; }
.nav-burger[aria-expanded="true"] .burger-lines span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.hide-mobile { display: none !important; }
@media (min-width: 900px) { .hide-mobile { display: inline-flex !important; } }

/* ---------- Fullscreen menu — index list, chips, account, colophon ---------- */
.mobile-menu {
  position: fixed;
  inset: 0;
  /* Above the sticky nav, the player bar and the bottom nav — the menu is a
     full-screen surface, so nothing else may sit on top of it. */
  z-index: 150;
  display: flex;
  flex-direction: column;
  padding: calc(var(--nav-h) + 40px) var(--gut) 32px;
  background: var(--well);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-6px);
  transition: opacity 0.32s cubic-bezier(0.22, 1, 0.36, 1), transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
  overflow-y: auto;
}
.mobile-menu.open { opacity: 1; pointer-events: auto; transform: none; }
.menu-close {
  position: fixed;
  top: 18px; right: var(--gut);
  background: none;
  border: none;
  color: var(--text);
  cursor: pointer;
  padding: 8px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s, transform 0.3s;
}
.mobile-menu.open .menu-close { opacity: 1; pointer-events: auto; }
.menu-close:hover { transform: rotate(90deg); }

.menu-section { width: 100%; max-width: 860px; margin: 0 auto; }
.menu-section-title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.28em;
  color: var(--muted);
  margin-bottom: 14px;
}
.menu-section-title::after { content: ""; flex: 1; height: 1px; background: var(--line-soft); }

/* Section 0 — record, ladder and the next night */
.menu-stats-section { margin-bottom: 34px; }
.menu-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.m-stat { background: var(--well); padding: 14px 12px; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.m-stat b {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 5.4vw, 1.6rem);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.02em;
}
.m-stat i {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 0.5rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.menu-tier { margin-top: 14px; }
.menu-tier-top {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  font-family: var(--font-mono); font-size: 0.55rem;
  letter-spacing: 0.18em; text-transform: uppercase;
}
.menu-tier-name { color: var(--text); }
.menu-tier-goal { color: var(--muted); text-align: right; }
.menu-tier-bar { height: 2px; background: var(--line); margin-top: 9px; overflow: hidden; }
.menu-tier-bar span {
  display: block; height: 100%; background: var(--text);
  transition: width 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.menu-next {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  margin-top: 16px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  transition: border-color 0.25s, background 0.25s;
}
.menu-next:hover { border-color: var(--line-strong); background: var(--wash-1); }
.menu-next-lbl {
  grid-column: 1 / -1;
  font-family: var(--font-mono); font-size: 0.5rem;
  letter-spacing: 0.22em; text-transform: uppercase; color: var(--muted);
}
.menu-next-title {
  font-family: var(--font-display); font-size: 1.05rem;
  letter-spacing: -0.02em; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.menu-next-in {
  font-family: var(--font-mono); font-size: 0.6rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-dim);
  white-space: nowrap; align-self: center;
}

/* Section 1 — Navigate: big numbered index list */
.menu-nav { margin-bottom: 40px; }
.mobile-menu-list { display: flex; flex-direction: column; width: 100%; border-top: 1px solid var(--line-soft); }
.mobile-menu-list a {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 22px;
  padding: 15px 4px;
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 4.6vw, 2rem);
  letter-spacing: -0.015em;
  color: var(--text-dim);
  overflow: hidden;
  transition: padding-left 0.3s cubic-bezier(0.22, 1, 0.36, 1), color 0.2s;
}
.mobile-menu-list a .idx {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.12em;
  min-width: 2.4ch;
  transition: color 0.2s;
}
.mobile-menu-list a .arw {
  margin-left: auto;
  font-size: 0.9rem;
  color: var(--muted);
  opacity: 0;
  transform: translateX(-10px);
  transition: opacity 0.25s, transform 0.25s;
}
.mobile-menu-list a:hover, .mobile-menu-list a:focus-visible { padding-left: 20px; color: var(--text); }
.mobile-menu-list a:hover .idx, .mobile-menu-list a.active .idx { color: var(--text); }
.mobile-menu-list a:hover .arw { opacity: 1; transform: none; }
.mobile-menu-list a.active { color: var(--text); border-bottom-color: var(--line-strong); }

/* The members index is long — set it smaller and in two columns when
   there is room, so the whole menu still fits one screen. */
.menu-list-compact a { font-size: clamp(0.95rem, 2.6vw, 1.15rem); padding: 11px 4px; }
@media (min-width: 720px) {
  .menu-list-compact { display: grid; grid-template-columns: 1fr 1fr; column-gap: 32px; }
}

/* Section 2 — Quick actions: square chips */
.menu-chips { margin-bottom: 32px; }
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 11px 18px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text-dim);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  cursor: pointer;
  font-family: inherit;
  transition: border-color 0.2s, color 0.2s, background 0.2s;
}
.chip:hover { border-color: var(--text); color: var(--text); background: var(--wash-2); }
.chip-admin { border-color: var(--line-strong); color: var(--text); }

/* Section 3 — Account strip */
.menu-account { margin-top: auto; padding-top: 28px; }
.account-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 20px;
  border: 1px solid var(--line);
}
.account-info { min-width: 0; }
.account-name { font-weight: 700; font-size: 0.92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-id { font-size: 0.68rem; color: var(--muted); margin-top: 3px; font-family: var(--font-mono); letter-spacing: 0.08em; }
.account-card .btn { flex-shrink: 0; }

/* Section 4 — Colophon: legal line at the foot of the menu */
.menu-colophon {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  max-width: 860px;
  margin: 22px auto 0;
  padding-top: 18px;
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.menu-colophon a { color: var(--muted); transition: color 0.2s; }
.menu-colophon a:hover { color: var(--text); }

/* ---------- Buttons — sharp, flat, tracked ---------- */
.btn {
  position: relative;
  padding: 14px 28px;
  border-radius: 0;
  border: 1px solid transparent;
  cursor: pointer;
  font-weight: 700;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-family: inherit;
  transition: background 0.2s, color 0.2s, border-color 0.2s;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  overflow: hidden;
}
.btn:disabled { opacity: 0.35; cursor: not-allowed; }
.btn.small { padding: 9px 16px; font-size: 0.64rem; }

/* Primary: white block that inverts on hover. */
.btn-gold, .btn-red {
  background: var(--text);
  color: var(--ink);
  border-color: var(--text);
}
.btn-gold:hover:not(:disabled), .btn-red:hover:not(:disabled) { background: transparent; color: var(--text); }

.btn-ghost { background: transparent; border-color: var(--line); color: var(--text-dim); }
.btn-ghost:hover:not(:disabled) { border-color: var(--text); color: var(--text); }

.btn-green { background: transparent; border-color: rgba(72, 209, 138, 0.45); color: var(--green); }
.btn-green:hover:not(:disabled) { background: rgba(72, 209, 138, 0.1); }
.btn-danger { background: transparent; border-color: rgba(255, 90, 77, 0.45); color: var(--red); }
.btn-danger:hover:not(:disabled) { background: rgba(255, 90, 77, 0.1); }
.btn-primary { background: var(--text); color: var(--ink); border-color: var(--text); }
.btn-primary:hover:not(:disabled) { background: transparent; color: var(--text); }
.full-width { width: 100%; text-align: center; }

/* ---------- Cards — hairline panels, no rounding, no glow ---------- */
.card {
  position: relative;
  background: var(--card-bg);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--line);
  padding: 26px;
  border-radius: 0;
  margin-bottom: 18px;
  transition: border-color 0.25s, background 0.25s;
}
.card:hover { border-color: var(--line-strong); }
/* Corner ticks — a quiet technical flourish on hover. */
.card.spot::before,
.card.spot::after {
  content: "";
  position: absolute;
  width: 9px; height: 9px;
  border-color: var(--text);
  border-style: solid;
  opacity: 0;
  transition: opacity 0.28s;
  pointer-events: none;
}
.card.spot::before { top: -1px; left: -1px; border-width: 1px 0 0 1px; }
.card.spot::after { bottom: -1px; right: -1px; border-width: 0 1px 1px 0; }
.card.spot:hover::before, .card.spot:hover::after { opacity: 1; }

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; margin-top: 20px; }

.section-title {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 64px 0 4px;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.26em;
  color: var(--muted);
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.section-title .count { margin-left: auto; color: var(--faint); }

/* ---------- Forms ---------- */
input, select, textarea {
  background: var(--wash-1);
  border: 1px solid var(--line);
  color: var(--text);
  padding: 13px 15px;
  border-radius: 0;
  margin-bottom: 14px;
  width: 100%;
  font-family: inherit;
  font-size: 0.92rem;
  transition: border-color 0.2s, background 0.2s;
}
input::placeholder, textarea::placeholder { color: var(--faint); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--text);
  background: var(--wash-2);
}
label {
  display: block;
  margin-bottom: 7px;
  color: var(--muted);
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.16em;
}

/* ---------- Typography ---------- */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.26em;
  color: var(--muted);
  margin-bottom: 18px;
}
.eyebrow::after { content: ""; flex: 1; max-width: 90px; height: 1px; background: var(--line); }

.page-title {
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 9vw, 6.5rem);
  line-height: 0.9;
  letter-spacing: -0.035em;
  margin: 0 0 18px;
  text-align: left;
  text-transform: uppercase;
}
.page-title .icon { display: none; }
.page-sub {
  color: var(--text-dim);
  font-size: clamp(0.95rem, 1.6vw, 1.05rem);
  line-height: 1.65;
  margin-bottom: 34px;
  max-width: 58ch;
}
.muted { color: var(--muted); }

h1, h2, h3, h4 { letter-spacing: -0.02em; }

code {
  font-family: var(--font-mono);
  background: var(--wash-3);
  border-radius: 0;
  padding: 2px 7px;
  font-size: 0.88em;
}

/* Page header block used across member pages. */
.page-head {
  padding-bottom: 40px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--line);
}

/* Label-over-value chips under the page subtitle (Wallet, Shop, Music…).
   Without column flex the <em> label and number smash into one word. */
.head-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 34px;
  margin-top: 8px;
  min-width: 0;
}
.head-meta span {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-family: var(--font-display);
  font-size: clamp(1rem, 3.5vw, 1.3rem);
  font-variant-numeric: tabular-nums;
  min-width: 0;
  max-width: 100%;
}
.head-meta em {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted);
}

/* ---------- Badges ---------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 0;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  border: 1px solid var(--line);
  color: var(--text-dim);
}
.badge.green { color: var(--green); border-color: rgba(72, 209, 138, 0.4); }
.badge.red { color: var(--red); border-color: rgba(255, 90, 77, 0.4); }
.badge.blue { color: var(--blue); border-color: rgba(111, 157, 255, 0.4); }
.badge.gold { color: var(--text); border-color: var(--line-strong); }

/* ---------- Codes / QR ---------- */
.code-row { display: flex; align-items: center; gap: 8px; margin: 14px 0 0; flex-wrap: wrap; }
.code-label {
  font-family: var(--font-mono);
  font-size: 0.58rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted);
  flex-basis: 100%;
}
.ticket-code {
  font-family: var(--font-mono);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  background: var(--wash-2);
  border: 1px dashed var(--line-strong);
  border-radius: 0;
  padding: 9px 14px;
  color: var(--text);
  user-select: all;
}
.copy-btn {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--text-dim);
  border-radius: 0;
  padding: 9px 14px;
  cursor: pointer;
  font-weight: 700;
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-family: inherit;
  transition: border-color 0.2s, color 0.2s;
}
.copy-btn:hover { border-color: var(--text); color: var(--text); }
/* Stays white in both themes — scanners need dark modules on a light
   quiet zone, so this one surface does not follow the palette. The
   hairline keeps it from dissolving into the paper background. */
.qr-box { position: relative; background: #fff; padding: 12px; width: fit-content; margin: 18px 0 4px; border: 1px solid var(--line-soft); }
/* The mark sits in a white keep-out square so it never eats QR modules
   the decoder needs; level H absorbs the rest. */
.qr-mark {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 21%; height: auto;
  /* No filter: the source is logo-ink.svg, which is Void Black by
     definition. logo.svg follows the viewer's colour scheme, so inverting
     it here would hand back a white mark on the white keep-out square
     whenever the device is in light mode. */
  padding: 5px; background: #fff;
}

/* ---------- Ticket ----------
   Body + tear-off stub, split by a real perforation with punched notches.
   `.is-torn` pulls the two halves apart — the door scanner plays it when a
   code is accepted. */
.tkt {
  display: grid;
  grid-template-columns: 1fr auto auto;
  /* A ticket that spans a desktop column stops reading as a ticket. */
  max-width: 640px;
  border: 1px solid var(--line);
  background: linear-gradient(135deg, var(--wash-2), var(--wash-1));
  position: relative;
  overflow: hidden;
}
.tkt-main { padding: 22px 24px; min-width: 0; }
.tkt-brand {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-mono); font-size: 0.58rem;
  letter-spacing: 0.24em; text-transform: uppercase; color: var(--text);
  padding-bottom: 14px; border-bottom: 1px solid var(--line-soft); margin-bottom: 16px;
}
.tkt-brand img { height: 15px; opacity: 0.9; }
.tkt-serial { margin-left: auto; color: var(--muted); letter-spacing: 0.12em; }

.tkt-event {
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 3vw, 1.6rem);
  line-height: 1.02; letter-spacing: -0.03em;
  text-transform: uppercase; margin: 0 0 18px;
}

.tkt-rows { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 14px 18px; margin: 0 0 18px; }
.tkt-rows dt { font-family: var(--font-mono); font-size: 0.52rem; text-transform: uppercase; letter-spacing: 0.2em; color: var(--muted); margin-bottom: 5px; }
.tkt-rows dd { margin: 0; font-size: 0.86rem; font-weight: 600; overflow-wrap: anywhere; }

/* Decorative barcode — texture, not data. The QR on the stub is the data. */
.tkt-strip { display: flex; align-items: flex-end; gap: 2px; height: 26px; opacity: 0.5; }
.tkt-strip span { flex: 1; background: var(--text); height: 100%; }
.tkt-strip span:nth-child(3n) { height: 62%; }
.tkt-strip span:nth-child(4n) { height: 84%; opacity: 0.6; }
.tkt-strip span:nth-child(5n) { height: 45%; }
.tkt-strip span:nth-child(7n) { flex: 2; }

/* Perforation */
.tkt-perf { position: relative; width: 1px; background-image: linear-gradient(to bottom, var(--line-strong) 50%, transparent 0); background-size: 1px 9px; }
.tkt-notch {
  position: absolute; left: 50%; width: 15px; height: 15px;
  background: var(--bg); border: 1px solid var(--line);
  border-radius: 50%; transform: translate(-50%, -50%);
}
.tkt-notch.top { top: 0; }
.tkt-notch.bottom { top: 100%; }

/* Stub */
.tkt-stub {
  width: 172px; flex-shrink: 0;
  padding: 20px 18px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  background: var(--wash-1);
  text-align: center;
}
.tkt-stub .qr-box { margin: 0; padding: 9px; }
.tkt-code { font-family: var(--font-mono); font-size: 0.78rem; letter-spacing: 0.1em; background: none; padding: 0; color: var(--text); user-select: all; }
.tkt-copy {
  background: none; border: 1px solid var(--line); color: var(--muted);
  font-family: inherit; font-size: 0.54rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.16em; padding: 6px 12px; cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}
.tkt-copy:hover { border-color: var(--text); color: var(--text); }
.tkt-stub-label {
  font-family: var(--font-mono); font-size: 0.5rem;
  text-transform: uppercase; letter-spacing: 0.22em; color: var(--muted);
  margin-top: 2px;
}
.tkt-note { display: flex; flex-direction: column; align-items: center; gap: 12px; font-family: var(--font-mono); font-size: 0.56rem; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); line-height: 1.7; }
.tkt-spin { width: 22px; height: 22px; border: 1px solid var(--line-strong); border-top-color: var(--text); border-radius: 50%; animation: tkt-spin 1.1s linear infinite; }
@keyframes tkt-spin { to { transform: rotate(360deg); } }
.tkt-await { width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; border: 1px solid var(--red); color: var(--red); font-size: 0.7rem; }
.tkt-badge-mark { width: 26px; opacity: 0.6; }

/* State accents */
.tkt-paid { border-left: 2px solid var(--green); }
.tkt-pending { border-left: 2px solid var(--text); }
.tkt-awaiting { border-left: 2px solid var(--red); }
.tkt-badge { border-left: 2px solid var(--line-strong); }

/* The tear */
.tkt.is-torn .tkt-main,
.tkt.is-torn .tkt-stub,
.tkt.is-torn .tkt-perf { transition: transform 0.75s cubic-bezier(0.34, 1.3, 0.5, 1), opacity 0.5s ease; }
.tkt.is-torn { overflow: visible; border-color: transparent; background: none; }
.tkt.is-torn .tkt-main { transform: translateX(-13px) rotate(-1.1deg); }
.tkt.is-torn .tkt-stub { transform: translateX(15px) rotate(2.2deg); }
.tkt.is-torn .tkt-perf { opacity: 0; }

@media (max-width: 560px) {
  .tkt { grid-template-columns: 1fr; }
  .tkt-perf { width: auto; height: 1px; background-image: linear-gradient(to right, var(--line-strong) 50%, transparent 0); background-size: 9px 1px; }
  .tkt-notch { left: 0; top: 50%; }
  .tkt-notch.bottom { left: 100%; top: 50%; }
  .tkt-stub { width: auto; }
  .tkt.is-torn .tkt-main { transform: translateY(-10px) rotate(-0.6deg); }
  .tkt.is-torn .tkt-stub { transform: translateY(12px) rotate(1.2deg); }
}

@media (prefers-reduced-motion: reduce) {
  .tkt.is-torn .tkt-main, .tkt.is-torn .tkt-stub { transform: none; }
  .tkt-spin { animation: none; }
}

/* Marks a state the page is actively watching for a change. */
.live-dot {
  display: inline-block; width: 6px; height: 6px; margin-right: 7px;
  background: var(--text); vertical-align: middle;
  animation: live-pulse 1.8s ease-in-out infinite;
}

/* ---------- Stats ---------- */
.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  border: 1px solid var(--line);
  margin-bottom: 26px;
}
.stat {
  padding: 18px 16px;
  border-left: 1px solid var(--line);
  text-align: left;
  min-width: 0;           /* let the grid shrink cells instead of blowing out */
  overflow: hidden;
}
.stat:first-child { border-left: none; }
.stat .num {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 4.2vw, 1.9rem);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.stat .lbl {
  font-family: var(--font-mono);
  font-size: 0.56rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  margin-top: 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Money / IDs / long labels — never push a card wider than its column. */
.fit-num,
.wal-num,
.hub-bal-amount,
.menu-id-bal b,
.hub-tx-amt,
.hub-order-amt,
.wal-order-amt,
.wal-row-amt {
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
}
.page-title,
.hub-next-title,
.next-title,
.tier-name {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ---------- Sticky player ----------
   Floating glass strip above the bottom nav (mobile) / page edge (desktop).
   On phones it only rises while audio is actually playing, so idle sessions
   keep the full viewport. */
:root { --player-h: 0px; --bnav-h: 0px; }

.pl {
  position: fixed;
  left: 10px; right: 10px;
  bottom: calc(var(--bnav-h) + 10px);
  z-index: 96;
  overflow: hidden;
  background: color-mix(in srgb, var(--bg) 52%, transparent);
  backdrop-filter: blur(22px) saturate(1.35);
  -webkit-backdrop-filter: blur(22px) saturate(1.35);
  border: 1px solid var(--line);
  box-shadow:
    0 12px 40px var(--shadow),
    inset 0 1px 0 color-mix(in srgb, var(--text) 8%, transparent);
  transform: translateY(calc(100% + 24px));
  transition:
    transform 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    border-color 0.3s,
    box-shadow 0.3s;
}
.pl.open { transform: none; }
.pl.is-playing {
  border-color: color-mix(in srgb, var(--vip) 28%, var(--line));
  box-shadow:
    0 14px 44px var(--shadow),
    0 0 0 1px color-mix(in srgb, var(--vip) 10%, transparent),
    inset 0 1px 0 color-mix(in srgb, var(--text) 10%, transparent);
}

/* Ambient bars under the glass — sit behind the controls. */
.pl-viz {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 28px;
  display: flex;
  align-items: flex-end;
  justify-content: stretch;
  gap: 2px;
  padding: 0 8px 2px;
  opacity: 0.22;
  pointer-events: none;
  z-index: 0;
  mask-image: linear-gradient(to top, #000 20%, transparent 100%);
  -webkit-mask-image: linear-gradient(to top, #000 20%, transparent 100%);
}
.pl-viz i {
  flex: 1;
  min-width: 0;
  height: 20%;
  background: var(--text);
  transform-origin: bottom center;
  animation: pl-viz-idle 2.8s ease-in-out infinite;
}
.pl.is-playing .pl-viz { opacity: 0.38; }
.pl.is-playing .pl-viz i {
  background: var(--vip);
  animation-name: pl-viz-beat;
  animation-duration: 0.85s;
}
.pl-viz i:nth-child(3n)   { animation-delay: -0.15s; height: 35%; }
.pl-viz i:nth-child(3n+1) { animation-delay: -0.4s;  height: 55%; }
.pl-viz i:nth-child(3n+2) { animation-delay: -0.65s; height: 25%; }
.pl-viz i:nth-child(5n)   { animation-delay: -0.28s; }
.pl-viz i:nth-child(7n)   { animation-delay: -0.52s; }
@keyframes pl-viz-idle {
  0%, 100% { transform: scaleY(0.35); opacity: 0.5; }
  50%      { transform: scaleY(0.7);  opacity: 0.85; }
}
@keyframes pl-viz-beat {
  0%, 100% { transform: scaleY(0.3); }
  35%      { transform: scaleY(1); }
  60%      { transform: scaleY(0.55); }
}

.pl-seek {
  position: relative;
  height: 2px;
  background: var(--line-soft);
  cursor: pointer;
  z-index: 1;
}
.pl-seek:hover { height: 4px; }
.pl-seek-fill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--vip), var(--text));
  pointer-events: none;
}
.pl-seek-head {
  position: absolute; top: 50%; left: 0; width: 8px; height: 8px;
  background: var(--text); transform: translate(-50%, -50%) scale(0);
  transition: transform 0.2s; pointer-events: none;
}
.pl-seek:hover .pl-seek-head { transform: translate(-50%, -50%) scale(1); }
/* A stream has no scrub position to show. */
.pl.is-live .pl-seek { pointer-events: none; }
.pl.is-live .pl-seek-fill { width: 100%; opacity: 0.2; background: var(--vip); }

.pl-body {
  position: relative;
  z-index: 1;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 16px;
  padding: 10px 14px;
  max-width: 1440px; margin: 0 auto;
}
.pl-now {
  display: flex; align-items: center; gap: 12px; min-width: 0;
  background: none; border: none; color: inherit; font: inherit; text-align: left;
  cursor: pointer; padding: 0;
}
.pl-art {
  position: relative; width: 36px; height: 36px; flex-shrink: 0;
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 40%, transparent);
  display: flex; align-items: center; justify-content: center;
}
.pl-art-mark {
  display: block; width: 18px; height: 18px; opacity: 0.9;
  background: var(--text);
  mask: var(--mark) center / contain no-repeat;
  -webkit-mask: var(--mark) center / contain no-repeat;
}
.pl-eq { position: absolute; inset: 0; display: none; align-items: flex-end; justify-content: center; gap: 2px; padding: 8px; }
.pl.is-playing .pl-eq { display: flex; }
.pl.is-playing .pl-art-mark { opacity: 0.12; }
.pl-eq i { width: 2px; background: var(--vip); animation: eq 0.9s ease-in-out infinite; }
.pl-eq i:nth-child(1) { height: 40%; animation-delay: -0.1s; }
.pl-eq i:nth-child(2) { height: 85%; animation-delay: -0.4s; }
.pl-eq i:nth-child(3) { height: 55%; animation-delay: -0.7s; }
.pl-eq i:nth-child(4) { height: 70%; animation-delay: -0.25s; }
@keyframes eq { 0%, 100% { transform: scaleY(0.35); } 50% { transform: scaleY(1); } }

.pl-meta { min-width: 0; }
.pl-title { font-weight: 700; font-size: 0.84rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-artist { font-family: var(--font-mono); font-size: 0.5rem; text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted); margin-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pl-controls { display: flex; align-items: center; gap: 4px; }
.pl-btn {
  width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid transparent; color: var(--text-dim);
  cursor: pointer; transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.pl-btn:hover { color: var(--text); }
.pl-main {
  border-color: color-mix(in srgb, var(--text) 35%, transparent);
  background: color-mix(in srgb, var(--text) 92%, transparent);
  color: var(--ink);
  width: 40px; height: 40px;
}
.pl-main:hover { background: transparent; color: var(--text); border-color: var(--text); }
.i-pause, .pl .i-off, .pb .i-off { display: none; }
.pl.is-playing .i-play, .pb.is-playing .i-play { display: none; }
.pl.is-playing .i-pause, .pb.is-playing .i-pause { display: flex; }
.pl.is-muted .i-on, .pb.is-muted .i-on { display: none; }
.pl.is-muted .i-off, .pb.is-muted .i-off { display: flex; }

.pl-right { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
.pl-time { font-family: var(--font-mono); font-size: 0.54rem; letter-spacing: 0.1em; color: var(--muted); white-space: nowrap; }
.pl-time b { color: var(--text); font-weight: 400; }
.pl-time i { font-style: normal; }
.pl-live { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.2em; color: var(--red); white-space: nowrap; }
.pl-vol-range { width: 80px; margin: 0; padding: 0; background: none; border: none; accent-color: var(--text); }

/* ---------- Player-Black fullscreen ---------- */
.pb {
  position: fixed; inset: 0; z-index: 200;
  display: grid;
  grid-template-columns: 1fr minmax(240px, 320px);
  grid-template-rows: auto 1fr;
  background: var(--bg);
  color: var(--text);
  opacity: 0; pointer-events: none;
  transition: opacity 0.35s ease;
}
.pb.open { opacity: 1; pointer-events: auto; }
.pb[hidden] { display: none !important; }
body.pb-open { overflow: hidden; }

.pb-bg {
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(80% 60% at 30% 20%, var(--wash-3), transparent 60%),
    radial-gradient(70% 50% at 80% 80%, rgba(255,198,11,0.04), transparent 55%),
    var(--bg);
  transition: opacity 0.5s;
}
.pb.open .pb-bg {
  animation: pbHue 14s ease-in-out infinite alternate;
}
@keyframes pbHue {
  from { filter: hue-rotate(0deg); }
  to { filter: hue-rotate(18deg); }
}
.pb-viz {
  position: absolute; left: 0; right: 320px; bottom: 0; height: 40%;
  z-index: 1; width: calc(100% - 320px); pointer-events: none; opacity: 0.85;
  transition: opacity 0.4s ease;
}

/* Pages wrapper: on wide screens this is just a transparent passthrough —
   .pb-page-now / .pb-page-viz / .pb-page-queue take the same grid cells the
   unwrapped elements used to occupy. Below 860px it becomes a horizontal,
   swipeable, scroll-snapped strip (see the max-width media query). */
.pb-pages { display: contents; }
.pb-page-now {
  position: relative; grid-column: 1; grid-row: 2; min-height: 0;
}
.pb-page-viz {
  position: relative; grid-column: 1; grid-row: 2; min-height: 0;
  pointer-events: none;
}
.pb-page-viz > * { pointer-events: auto; }
.pb-viz-label { display: none; }
.pb-page-viz .pb-viz-bar {
  position: absolute; left: 50%; bottom: 28px; transform: translateX(-50%);
}
.pb-page-queue {
  grid-column: 2; grid-row: 2; min-height: 0; display: flex;
}
.pb-page-queue .pb-queue { flex: 1; min-height: 0; }

.pb-dots { display: none; }

.pb-top {
  position: relative; z-index: 2;
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 16px;
  padding: 18px var(--gut);
  border-bottom: 1px solid var(--line);
}
.pb-brand {
  font-family: var(--font-display);
  font-size: 1.05rem; letter-spacing: 0.04em; text-transform: uppercase;
}
.pb-mode {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 0.56rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--muted);
}
.pb-stage {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 28px; padding: 40px var(--gut) 60px; text-align: center;
}
.pb-mark {
  position: relative; width: min(42vw, 220px); height: min(42vw, 220px);
  border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
}
.pb-mark-glyph {
  display: block; width: 42%; height: 42%; opacity: 0.9; transition: opacity 0.3s;
  background: var(--text);
  mask: var(--mark) center / contain no-repeat;
  -webkit-mask: var(--mark) center / contain no-repeat;
}
.pb-eq { position: absolute; inset: 18%; display: none; align-items: flex-end; justify-content: center; gap: 5px; }
.pb.is-playing .pb-eq { display: flex; }
.pb.is-playing .pb-mark-glyph { opacity: 0.1; }
.pb-eq i { width: 4px; background: var(--text); animation: eq 0.9s ease-in-out infinite; }
.pb-eq i:nth-child(1) { height: 35%; animation-delay: -0.1s; }
.pb-eq i:nth-child(2) { height: 70%; animation-delay: -0.35s; }
.pb-eq i:nth-child(3) { height: 95%; animation-delay: -0.55s; }
.pb-eq i:nth-child(4) { height: 55%; animation-delay: -0.2s; }
.pb-eq i:nth-child(5) { height: 80%; animation-delay: -0.7s; }

.pb-meta { max-width: 36rem; }
.pb-live { font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.22em; color: var(--red); margin-bottom: 10px; }
.pb-title {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 5vw, 3.4rem);
  letter-spacing: -0.03em; line-height: 1.05; margin: 0 0 12px;
  text-transform: uppercase;
}
.pb-artist {
  font-family: var(--font-mono); font-size: 0.72rem;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--muted); margin: 0;
}
.pb-seek-wrap { width: min(520px, 100%); }
.pb-seek { height: 6px; }
.pb-times {
  display: flex; justify-content: space-between; margin-top: 10px;
  font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.12em; color: var(--muted);
}
.pb-controls { display: flex; align-items: center; gap: 14px; }
.pb-main { width: 64px; height: 64px; }
.pb-controls .pl-btn.on { color: var(--text); border-color: var(--line-strong); }
.pb-vol-row { display: flex; align-items: center; gap: 12px; width: min(360px, 100%); }
.pb-vol { flex: 1; width: auto; }
.pb-sleep {
  background: transparent; border: 1px solid var(--line); color: var(--muted);
  font-family: var(--font-mono); font-size: 0.52rem; letter-spacing: 0.12em;
  text-transform: uppercase; padding: 8px 10px; cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.pb-sleep:hover { color: var(--text); border-color: var(--line-strong); }
.pb-sleep:focus { outline: 1px solid var(--line-strong); color: var(--text); }
.pb-sleep.on {
  color: var(--bg); background: var(--text); border-color: var(--text);
}

.pb-viz-bar {
  display: flex; flex-wrap: wrap; gap: 14px 22px; justify-content: center;
  width: min(560px, 100%); margin-top: 4px;
}
.pb-viz-group { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.pb-chip {
  background: none; border: 1px solid var(--line); color: var(--muted);
  font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.14em;
  text-transform: uppercase; padding: 8px 11px; cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background 0.2s, transform 0.2s;
}
.pb-chip:hover { color: var(--text); border-color: var(--line-strong); }
.pb-chip.on {
  color: var(--bg); background: var(--pb-viz, var(--text)); border-color: var(--pb-viz, var(--text));
}
.pb-swatch {
  width: 22px; height: 22px; border: 1px solid var(--line); cursor: pointer;
  background: var(--sw); padding: 0; transition: transform 0.2s, box-shadow 0.2s;
}
.pb-swatch:hover { transform: scale(1.08); }
.pb-swatch.on { box-shadow: 0 0 0 2px var(--bg), 0 0 0 3px var(--sw); }

.pb-title.pb-pop { animation: pbPop 0.45s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes pbPop {
  from { opacity: 0; transform: translateY(12px); filter: blur(4px); }
  to { opacity: 1; transform: none; filter: none; }
}
.pb.is-playing .pb-mark {
  animation: pbPulse 2.8s ease-in-out infinite;
}
@keyframes pbPulse {
  0%, 100% { transform: scale(1); border-color: var(--line); }
  50% { transform: scale(1.03); border-color: var(--pb-viz, var(--line-strong)); }
}

.pb-queue {
  position: relative; z-index: 2;
  border-left: 1px solid var(--line);
  display: flex; flex-direction: column;
  background: var(--scrim-solid);
  overflow: hidden;
}
.pb-q-tabs { display: flex; border-bottom: 1px solid var(--line); }
.pb-q-tab {
  flex: 1; padding: 14px 10px; background: none; border: none;
  color: var(--muted); cursor: pointer; font-family: var(--font-mono);
  font-size: 0.56rem; letter-spacing: 0.18em; text-transform: uppercase;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
}
.pb-q-tab .c {
  font-size: 0.5rem; opacity: 0.7; min-width: 1.2em;
}
.pb-q-tab.on { color: var(--text); box-shadow: inset 0 -2px 0 var(--text); }
.pb-filters {
  display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 12px;
  border-bottom: 1px solid var(--line-soft);
}
.pb-filters .pb-chip { padding: 6px 9px; }
.pb-q-list { overflow-y: auto; flex: 1; padding: 8px 0; }
.pb-q-item {
  display: grid; grid-template-columns: 36px 1fr auto; gap: 2px 10px;
  width: 100%; padding: 12px 16px; background: none; border: none;
  color: inherit; text-align: left; cursor: pointer; font: inherit;
  transition: background 0.2s, transform 0.2s;
}
.pb-q-item:hover { background: var(--wash-2); }
.pb-q-item.on { background: var(--wash-3); }
.pb-q-item .n { grid-row: span 2; font-family: var(--font-mono); font-size: 0.58rem; color: var(--muted); align-self: center; }
.pb-q-item .t { font-size: 0.88rem; font-weight: 600; grid-column: 2; }
.pb-q-item .a { font-family: var(--font-mono); font-size: 0.52rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); grid-column: 2; }
.pb-q-item .tag {
  grid-row: span 2; align-self: center;
  font-family: var(--font-mono); font-size: 0.48rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted); border: 1px solid var(--line); padding: 4px 6px;
}
.pb-q-item.playing .n { color: var(--pb-viz, var(--text)); }
.pb-q-empty { padding: 24px 16px; color: var(--muted); font-size: 0.85rem; line-height: 1.6; }
.pb-q-empty a { color: var(--text); border-bottom: 1px solid var(--line); }
.pb.is-live .pb-seek { pointer-events: none; }
.pb.is-live .pb-seek .pl-seek-fill { width: 100%; opacity: 0.16; }

@media (max-width: 860px) {
  .pb {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr auto;
    height: 100dvh;
  }

  /* Canvas becomes a full-bleed backdrop behind every page — dim by
     default, and turned up bright by JS while the Visuals page is active. */
  .pb-viz { left: 0; right: 0; width: 100%; height: 100%; opacity: 0.28; }
  .pb.pb-viz-active .pb-viz { opacity: 0.95; }

  /* The three pages become a horizontal, snap-scrolling strip. */
  .pb-pages {
    display: flex;
    grid-column: 1; grid-row: 2;
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none; min-height: 0;
  }
  .pb-pages::-webkit-scrollbar { display: none; }

  .pb-page-now, .pb-page-viz, .pb-page-queue {
    grid-column: auto; grid-row: auto;
    flex: 0 0 100%; width: 100%; min-height: 0;
    scroll-snap-align: start; scroll-snap-stop: always;
    display: flex; flex-direction: column;
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    opacity: 0.45; transform: scale(0.96);
    transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .pb-page.in-view, .pb-page-now.in-view, .pb-page-viz.in-view, .pb-page-queue.in-view {
    opacity: 1; transform: none;
  }

  .pb-page-now {
    justify-content: center; align-items: center;
    padding: 6px var(--gut) 22px;
  }
  .pb-stage { padding: 0; gap: 20px; width: 100%; }
  .pb-mark { width: min(56vw, 260px); height: min(56vw, 260px); }

  .pb-page-viz {
    pointer-events: auto;
    justify-content: space-between; align-items: center;
    padding: 20px var(--gut) calc(28px + env(safe-area-inset-bottom, 0px));
  }
  .pb-viz-label {
    display: block; width: 100%; text-align: center;
    font-family: var(--font-mono); font-size: 0.6rem;
    letter-spacing: 0.28em; text-transform: uppercase; color: var(--muted);
    padding-top: 6px;
  }
  .pb-page-viz .pb-viz-bar { position: static; transform: none; }

  .pb-page-queue { padding: 0; }
  .pb-queue {
    border-left: none; border-top: none; background: var(--bg);
    width: 100%; flex: 1;
  }

  /* Page dots */
  .pb-dots {
    grid-column: 1; grid-row: 3;
    display: flex; justify-content: center; align-items: center; gap: 9px;
    padding: 14px 0 calc(14px + env(safe-area-inset-bottom, 0px));
    position: relative; z-index: 2;
  }
  .pb-dot {
    width: 6px; height: 6px; border-radius: 50%; padding: 0; border: none;
    background: var(--line-strong); cursor: pointer;
    transition: width 0.3s cubic-bezier(0.22, 1, 0.36, 1), background 0.3s;
  }
  .pb-dot.on { width: 22px; border-radius: 3px; background: var(--text); }

  /* One-time swipe hint on the now-playing page. */
  .pb-page-now::after {
    content: '‹ swipe for visuals & queue ›';
    position: absolute; bottom: 4px; left: 0; right: 0; text-align: center;
    font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.14em;
    text-transform: uppercase; color: var(--muted); opacity: 0;
    animation: pbSwipeHint 4s ease 1.2s 2;
    pointer-events: none;
  }
  .pb.pb-swiped .pb-page-now::after { display: none; }
  @keyframes pbSwipeHint {
    0%, 100% { opacity: 0; transform: translateY(2px); }
    15%, 40% { opacity: 0.8; transform: translateY(0); }
  }
}
@media (max-width: 860px) and (prefers-reduced-motion: reduce) {
  .pb-page-now, .pb-page-viz, .pb-page-queue { transition: none; opacity: 1; transform: none; }
  .pb-page-now::after { animation: none; display: none; }
}

/* ---------- Bottom nav — mobile and the Telegram mini app ---------- */
.bnav {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 97;
  display: none;
  align-items: stretch;
  background: var(--scrim-solid);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border-top: 1px solid var(--line);
  /* Clear the iOS home indicator and Telegram's own bottom chrome. */
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.bnav-i {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  padding: 10px 4px;
  background: none; border: none; cursor: pointer;
  font-family: inherit; color: var(--muted);
  transition: color 0.2s;
}
.bnav-i span {
  font-family: var(--font-mono); font-size: 0.5rem;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.bnav-i:hover, .bnav-i.on { color: var(--text); }
.bnav-i.on { box-shadow: inset 0 2px 0 var(--text); }

/* The mark, raised out of the bar and centred. */
/* No plate behind it any more: the bare mark, coloured exactly like the
   icons either side, so the bar reads as one row of five glyphs rather
   than a white tile with navigation around it. */
.bnav-mark {
  position: relative;
  flex: 0 0 auto;
  width: 54px; height: 54px;
  margin: -8px 6px 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer;
  color: var(--muted);
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), color 0.2s;
}
/* The mark is painted as a mask fill, which is what lets it inherit
   `currentColor` and follow the theme without a second asset. */
.bnav-mark-glyph {
  display: block;
  /* Sibling icons are 19px; 6% larger would be invisible at that scale, so
     the mark sits ~58% above them (30px) — same muted colour, more presence. */
  width: 30px; height: 30px;
  background: currentColor;
  mask: var(--mark) center / contain no-repeat;
  -webkit-mask: var(--mark) center / contain no-repeat;
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.bnav-mark:hover, .bnav-mark.on { color: var(--text); }
.bnav-mark.on { filter: drop-shadow(0 0 10px var(--wash-4)); }
.bnav-mark:active { transform: scale(0.94); }

/* Locked, for visitors who have not been approved. Deliberately still
   visible and still the same shape — it is a door, not an absence. */
.bnav-mark.is-locked {
  color: var(--faint);
  cursor: not-allowed;
  opacity: 1;
}
.bnav-mark.is-locked .bnav-mark-glyph { transform: scale(0.92); }
.bnav-mark.is-locked:active { transform: none; }
.bnav-lock {
  position: absolute;
  right: 6px; bottom: 6px;
  display: flex; align-items: center; justify-content: center;
  width: 17px; height: 17px;
  color: var(--bg);
  background: var(--muted);
  border-radius: 50%;
}
@media (prefers-reduced-motion: reduce) {
  .bnav-mark, .bnav-mark-glyph { transition: none; }
}

@media (max-width: 900px) {
  .bnav { display: flex; }
  :root { --bnav-h: 62px; }
  /* Keep the footer and page tail clear of the fixed furniture. */
  body { padding-bottom: calc(var(--bnav-h) + env(safe-area-inset-bottom, 0px)); }
  /* Compact floating strip only while audio is live — idle stays clear. */
  body.has-player { padding-bottom: calc(var(--bnav-h) + env(safe-area-inset-bottom, 0px)); }
  body:has(.pl.open.is-playing) {
    padding-bottom: calc(var(--bnav-h) + 68px + env(safe-area-inset-bottom, 0px));
  }
  .pl {
    left: 8px; right: 8px;
    bottom: calc(var(--bnav-h) + env(safe-area-inset-bottom, 0px) + 8px);
  }
  /* Hide when cued but not playing — reclaim the screen. */
  .pl.open:not(.is-playing) {
    transform: translateY(calc(100% + 28px));
    pointer-events: none;
  }
  .pl.open.is-playing { transform: none; pointer-events: auto; }

  .pl-body {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px;
    padding: 8px 10px 10px;
  }
  .pl-controls { gap: 0; }
  .pl-controls #plPrev,
  .pl-controls #plNext { display: none; }
  .pl-right {
    display: none;
  }
  /* Fullscreen still reachable by tapping the now-playing row. */
  .pl-main { width: 38px; height: 38px; }
  .pl-art { width: 32px; height: 32px; }
  .pl-art-mark { width: 16px; height: 16px; }
  .pl-title { font-size: 0.78rem; }
  .pl-viz { height: 22px; opacity: 0.28; }
  .pl.is-playing .pl-viz { opacity: 0.45; }
}
@media (min-width: 901px) {
  body.has-player { padding-bottom: 86px; }
  .pl {
    left: 18px; right: 18px;
    bottom: 16px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .pl { transition: none; }
  .pl-eq i, .pl-viz i { animation: none !important; }
}

/* ---------- Toasts ---------- */
.toasts {
  position: fixed;
  top: calc(var(--nav-h) + 14px);
  right: var(--gut);
  /* Top of the stack: the player and the menu both raise toasts, so they
     have to clear the fullscreen player (200) and the menu (150). */
  z-index: 260;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 240px;
  max-width: 360px;
  padding: 14px 16px;
  border-radius: 0;
  background: var(--well);
  border: 1px solid var(--line);
  border-left: 2px solid var(--text);
  font-size: 0.84rem;
  font-weight: 500;
  animation: toast-in 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}
.toast.success { border-left-color: var(--green); }
.toast.error { border-left-color: var(--red); }
.toast.accent { border-left-color: var(--text); }
.toast.leaving { animation: toast-out 0.25s ease forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateX(20px); } }
.flash { display: none; }

/* ---------- Tables ---------- */
table { border-collapse: collapse; width: 100%; }
th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--muted);
  padding: 12px;
  border-bottom: 1px solid var(--line);
  font-weight: 600;
}
td { padding: 13px 12px; border-bottom: 1px solid var(--line-soft); font-size: 0.88rem; }
tr:hover td { background: var(--wash-1); }

/* ---------- Marquee ticker ---------- */
.ticker {
  position: relative;
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 12px 0;
  user-select: none;
}
.ticker-track {
  display: flex;
  gap: 40px;
  width: max-content;
  animation: ticker 38s linear infinite;
}
.ticker:hover .ticker-track { animation-play-state: paused; }
.ticker span {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.26em;
  color: var(--muted);
  white-space: nowrap;
}
.ticker span::after { content: "◆"; margin-left: 40px; color: var(--faint); }
@keyframes ticker { to { transform: translateX(-50%); } }

/* ---------- Reveal / split text ----------
   Scoped to .js so content is visible by default. Without this gate a
   failed script — or an observer that never fires because the page was
   opened at an anchor mid-document — leaves the page permanently blank. */
.reveal { transition: opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1), transform 0.8s cubic-bezier(0.22, 1, 0.36, 1); }
.js .reveal { opacity: 0; transform: translateY(22px); }
.js .reveal.in { opacity: 1; transform: none; }
.reveal.d1 { transition-delay: 0.07s; }
.reveal.d2 { transition-delay: 0.14s; }
.reveal.d3 { transition-delay: 0.21s; }

[data-split] .ch {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.5em);
  filter: blur(5px);
  animation: ch-in 0.7s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  animation-delay: calc(var(--i) * 45ms + 120ms);
}
@keyframes ch-in { to { opacity: 1; transform: none; filter: blur(0); } }

.blur-in { opacity: 0; filter: blur(8px); animation: blur-in 1s cubic-bezier(0.22, 1, 0.36, 1) forwards; }
.blur-in.late { animation-delay: 0.5s; }
.blur-in.later { animation-delay: 0.9s; }
@keyframes blur-in { to { opacity: 1; filter: blur(0); } }

/* ---------- Site footer ---------- */
.site-footer {
  position: relative;
  z-index: 1;
  margin-top: 120px;
  border-top: 1px solid var(--line);
  padding: 56px var(--gut) 0;
  /* Pin the mega wordmark to the bottom of the viewport on tall desktops. */
  display: flex;
  flex-direction: column;
  min-height: min(72vh, 820px);
}
.footer-inner {
  max-width: 1440px;
  margin: 0 auto;
  width: 100%;
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 40px;
}
.footer-brand .logo { width: 26px; height: 26px; margin-bottom: 16px; }
.footer-brand p { color: var(--muted); font-size: 0.85rem; max-width: 34ch; margin: 0; }
.footer-col h4 {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--muted);
  margin: 0 0 14px;
}
.footer-col a {
  display: block;
  font-size: 0.85rem;
  color: var(--text-dim);
  padding: 5px 0;
  transition: color 0.2s, padding-left 0.25s;
}
.footer-col a:hover { color: var(--text); padding-left: 6px; }

/* Oversized outlined wordmark, flush to the base of the page. */
.mega-footer {
  position: relative;
  overflow: hidden;
  padding: 10vh var(--gut) 0;
  margin-top: auto;
  user-select: none;
  pointer-events: none;
  container-type: inline-size;
}
.mega-text {
  display: block;
  text-align: left;
  font-family: var(--font-display);
  /* Bigger than before — fills nearly the full content width. */
  font-size: min(calc(100cqi / 7.55), 280px);
  line-height: 0.72;
  letter-spacing: -0.03em;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--line-strong);
  transform: translateY(18%);
  opacity: 0.55;
  transition: transform 0.1s linear, opacity 0.1s linear;
  will-change: transform, opacity;
  /* Nudge left so the trailing N isn't cramped against the edge. */
  margin-left: calc(var(--gut) * -0.55);
  margin-bottom: -0.12em;
}
.footer-legal {
  position: relative;
  z-index: 1;
  max-width: 1440px;
  margin: 0 auto;
  width: 100%;
  padding: 18px var(--gut) 22px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.footer-legal a { color: var(--muted); transition: color 0.2s; }
.footer-legal a:hover { color: var(--text); }

/* Soft page transitions — chrome (player, bnav, nav) never leave. */
main.container {
  transition: opacity 0.22s ease, transform 0.28s cubic-bezier(0.22, 1, 0.36, 1), filter 0.22s ease;
}
main.container.page-leave {
  opacity: 0;
  transform: translateY(10px);
  filter: blur(4px);
  pointer-events: none;
}
main.container.page-enter {
  animation: page-enter 0.38s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes page-enter {
  from { opacity: 0; transform: translateY(14px); filter: blur(6px); }
  to   { opacity: 1; transform: none; filter: none; }
}
body.is-navigating { cursor: progress; }
@media (prefers-reduced-motion: reduce) {
  main.container { transition: none; }
  main.container.page-leave,
  main.container.page-enter { animation: none; filter: none; transform: none; opacity: 1; }
}

/* ---------- Modal ---------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--scrim);
  opacity: 0;
  pointer-events: none;
  /* A closed modal must be genuinely gone, not merely transparent.
     `visibility` takes it out of the accessibility tree and lets the
     browser stop compositing it — left visible, the blur below was a
     full-viewport filter layer live on every page, which is what made
     opening it stutter on phones. Delayed on the way out so the fade
     still plays. */
  visibility: hidden;
  transition: opacity 0.25s, visibility 0s linear 0.25s;
  padding: 20px;
}
.modal-backdrop.open {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: opacity 0.25s, visibility 0s;
  /* Only blur while it is actually up. */
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.modal-card {
  position: relative;
  background: var(--well);
  border: 1px solid var(--line);
  border-radius: 0;
  padding: 40px 34px 30px;
  width: 100%;
  max-width: 380px;
  text-align: left;
  /* Tall sheets have to scroll rather than run off the top and bottom of a
     short viewport — on a phone in landscape the install steps were simply
     unreachable. */
  max-height: calc(100dvh - 40px);
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: translateY(12px);
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.modal-backdrop.open .modal-card { transform: none; }
.modal-close {
  position: absolute;
  top: 14px; right: 16px;
  z-index: 2;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 1.5rem;
  cursor: pointer;
  line-height: 1;
  transition: color 0.2s, transform 0.3s;
}
.modal-close:hover { color: var(--text); transform: rotate(90deg); }
.modal-card .full-width { width: 100%; }

/* Get-app modal — brand-led install sheet */
.app-modal {
  max-width: 400px;
  padding: 0 0 22px;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% -10%, var(--wash-3), transparent 55%),
    linear-gradient(180deg, var(--bg-raise) 0%, var(--well) 42%);
}
.app-modal-stage {
  position: relative;
  height: 168px;
  margin-bottom: 22px;
  border-bottom: 1px solid var(--line);
  display: grid;
  place-items: center;
  overflow: hidden;
  background:
    linear-gradient(var(--bg-rule) 1px, transparent 1px),
    linear-gradient(90deg, var(--bg-rule) 1px, transparent 1px);
  background-size: 28px 28px;
}
.app-modal-scan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    transparent 0%,
    var(--wash-3) 50%,
    transparent 100%
  );
  background-size: 100% 40%;
  animation: app-scan 3.6s ease-in-out infinite;
}
.app-modal-phone {
  position: relative;
  z-index: 1;
  width: 92px;
  height: 118px;
  border: 1px solid var(--line-strong);
  background: var(--well);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  box-shadow: 0 18px 40px var(--shadow);
  animation: app-phone-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.app-modal-phone::before {
  content: '';
  position: absolute;
  top: 8px;
  width: 28px;
  height: 3px;
  background: var(--line);
}
.app-modal-phone img {
  width: 44px;
  height: 44px;
  border: 1px solid var(--line);
}
.app-modal-mark {
  font-family: var(--font-mono);
  font-size: 0.48rem;
  letter-spacing: 0.22em;
  color: var(--text-dim);
}
.app-modal-corners {
  position: absolute;
  inset: 14px;
  pointer-events: none;
}
.app-modal-corners i {
  position: absolute;
  width: 10px;
  height: 10px;
  border-color: var(--text-dim);
  border-style: solid;
  opacity: 0.55;
}
.app-modal-corners .tl { top: 0; left: 0; border-width: 1px 0 0 1px; }
.app-modal-corners .tr { top: 0; right: 0; border-width: 1px 1px 0 0; }
.app-modal-corners .bl { bottom: 0; left: 0; border-width: 0 0 1px 1px; }
.app-modal-corners .br { bottom: 0; right: 0; border-width: 0 1px 1px 0; }

.app-modal-eyebrow,
.app-modal h3,
.app-modal-lede,
.app-modal-access,
.app-modal #installBtn,
.app-modal .install-steps,
.app-modal-foot {
  margin-left: 28px;
  margin-right: 28px;
}
.app-modal-eyebrow {
  margin-top: 0;
  margin-bottom: 10px;
  font-family: var(--font-mono);
  font-size: 0.56rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  animation: app-rise 0.45s 0.08s both;
}
.app-modal h3 {
  margin: 0 0 12px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.7rem, 6vw, 2.05rem);
  line-height: 0.95;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  color: var(--text);
  animation: app-rise 0.5s 0.14s both;
}
.app-modal h3 em {
  display: block;
  font-style: normal;
  color: transparent;
  -webkit-text-stroke: 1px var(--line-strong);
}
.app-modal-lede {
  margin: 0 0 20px;
  font-size: 0.88rem;
  line-height: 1.65;
  color: var(--text-dim);
  max-width: 34ch;
  animation: app-rise 0.5s 0.2s both;
}
.app-modal-access {
  list-style: none;
  margin: 0 28px 22px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border: 1px solid var(--line);
  animation: app-rise 0.5s 0.26s both;
}
.app-modal-access li {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 10px;
  font-family: var(--font-display);
  font-size: 0.78rem;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--text);
  border-right: 1px solid var(--line-soft);
}
.app-modal-access li:last-child { border-right: none; }
.app-modal-access span {
  font-family: var(--font-mono);
  font-size: 0.5rem;
  letter-spacing: 0.16em;
  color: var(--muted);
}
.app-modal #installBtn {
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
  animation: app-rise 0.5s 0.3s both;
}
.app-modal #installBtn i {
  font-style: normal;
  transition: transform 0.25s;
}
.app-modal #installBtn:hover i { transform: translateX(3px); }

/* Update sheet — same card as Get App; phone glyph spins to signal a new build. */
.app-modal-phone.is-update img {
  animation: update-mark-spin 2.8s linear infinite;
}
@keyframes update-mark-spin {
  to { transform: rotate(360deg); }
}
.update-modal #updateBtn {
  justify-content: space-between;
  gap: 12px;
  margin-left: 28px;
  margin-right: 28px;
  margin-bottom: 8px;
  animation: none;
}
.update-modal #updateBtn i {
  font-style: normal;
  transition: transform 0.25s;
}
.update-modal #updateBtn:hover i { transform: translateX(3px); }
.modal-backdrop.open .update-modal #updateBtn { animation: app-rise 0.5s 0.3s both; }

/* Full-screen apply veil — between Update tap and the same-URL reload. */
.update-veil {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  background:
    radial-gradient(ellipse 55% 40% at 50% 42%, color-mix(in srgb, var(--vip) 10%, transparent), transparent 70%),
    var(--bg);
  overflow: hidden;
}
.update-veil[hidden] { display: none !important; }
html.is-updating, html.is-updating body { overflow: hidden; }
.update-veil-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, var(--bg-rule) 1px, transparent 1px),
    linear-gradient(to bottom, var(--bg-rule) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(70% 60% at 50% 50%, #000 10%, transparent 80%);
  -webkit-mask-image: radial-gradient(70% 60% at 50% 50%, #000 10%, transparent 80%);
  animation: boot-grid-in 0.7s ease both;
}
.update-veil-core {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}
.update-veil-mark {
  display: block;
  width: 64px;
  height: 64px;
  background: var(--text);
  mask: var(--mark) center / contain no-repeat;
  -webkit-mask: var(--mark) center / contain no-repeat;
  animation: update-veil-spin 1.1s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes update-veil-spin {
  0%   { transform: rotate(0deg) scale(0.92); }
  50%  { transform: rotate(180deg) scale(1.04); }
  100% { transform: rotate(360deg) scale(0.92); }
}
.update-veil-word {
  display: flex;
  gap: 0.04em;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 5vw, 1.85rem);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text);
}
.update-veil-word i {
  font-style: normal;
  opacity: 0;
  transform: translateY(0.4em);
  filter: blur(6px);
  animation: update-letter-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  animation-delay: calc(0.08s + var(--i) * 0.05s);
}
@keyframes update-letter-in {
  to { opacity: 1; transform: none; filter: none; }
}
.update-veil-bar {
  width: min(220px, 55vw);
  height: 2px;
  background: var(--line-soft);
  overflow: hidden;
}
.update-veil-bar span {
  display: block;
  height: 100%;
  width: 40%;
  background: var(--text);
  animation: update-veil-bar 0.9s ease-in-out infinite;
}
@keyframes update-veil-bar {
  0%   { transform: translateX(-120%); }
  100% { transform: translateX(320%); }
}
.update-veil-foot {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.52rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  animation: app-rise 0.45s 0.35s both;
}

.install-steps {
  text-align: left;
  margin-top: 4px;
  margin-bottom: 4px;
  animation: app-rise 0.5s 0.3s both;
}
.install-steps[hidden] { display: none !important; }
.install-steps .step {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--muted);
  font-size: 0.84rem;
}
.install-steps .step:last-child { border-bottom: none; }
.install-steps .step span {
  width: 24px; height: 24px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.68rem;
}
.install-steps .step strong { color: var(--text); font-weight: 600; }

.app-modal-foot {
  margin-top: 18px;
  margin-bottom: 0;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-size: 0.52rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  animation: app-rise 0.5s 0.34s both;
}

@keyframes app-scan {
  0%, 100% { transform: translateY(-70%); opacity: 0.35; }
  50% { transform: translateY(70%); opacity: 0.9; }
}
@keyframes app-phone-in {
  from { opacity: 0; transform: translateY(18px) scale(0.96); }
  to { opacity: 1; transform: none; }
}
@keyframes app-rise {
  from { opacity: 0; transform: translateY(10px); filter: blur(4px); }
  to { opacity: 1; transform: none; filter: none; }
}

@media (prefers-reduced-motion: reduce) {
  .app-modal-scan,
  .app-modal-phone,
  .app-modal-eyebrow,
  .app-modal h3,
  .app-modal-lede,
  .app-modal-access,
  .app-modal #installBtn,
  .app-modal .install-steps,
  .app-modal-foot,
  .update-modal #updateBtn,
  .app-modal-phone.is-update img,
  .update-veil-mark,
  .update-veil-word i,
  .update-veil-bar span,
  .update-veil-foot {
    animation: none !important;
  }
  .update-veil-word i { opacity: 1; transform: none; filter: none; }
}

[dir="rtl"] { direction: rtl; }
[dir="ltr"] { direction: ltr; }

@media (max-width: 900px) {
  .footer-inner { grid-template-columns: 1fr; gap: 20px; }
  .footer-brand { grid-column: 1 / -1; }
  /* App-like: drop the link columns on phones — bottom nav owns navigation. */
  .footer-col { display: none; }
  .site-footer {
    min-height: 0;
    margin-top: 64px;
    padding-top: 28px;
  }
  .footer-brand p { display: none; }
  .footer-brand .logo { margin-bottom: 0; opacity: 0.55; }
  .mega-footer { padding-top: 4vh; margin-top: 20px; }
  .mega-text {
    font-size: min(calc(100cqi / 7.2), 120px);
    -webkit-text-stroke-width: 1px;
    opacity: 0.7;
    transform: none;
  }
  /* Mobile: wordmark only — copyright lives elsewhere / is redundant. */
  .footer-legal { display: none; }
}
@media (max-width: 640px) {
  body { font-size: 14.5px; }
  .toasts { left: var(--gut); right: var(--gut); }
  .toast { max-width: none; width: 100%; }
  .grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .reveal, [data-split] .ch, .blur-in {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    animation: none !important;
    transition: none !important;
  }
  .mega-text { transform: none !important; opacity: 1 !important; }
  .ticker-track, .bg-grain { animation: none !important; }
  /* Skip the scrub morph — land on the compact brand immediately. */
  .nav {
    --nav-p: 1 !important;
  }
  .brand-ch {
    filter: none !important;
    transform: none !important;
    opacity: 1 !important;
  }
  .brand-flame,
  .brand-glow,
  .brand-flame .bf-core,
  .brand-mark.is-snuffing .brand-smoke i {
    animation: none !important;
  }
  html.is-candle-lit .brand-flame {
    opacity: 1;
    transform: translate(-50%, calc(-50% - 1px)) scale(1);
  }
  html.is-candle-lit .brand-glow {
    opacity: 1;
    transform: translate(-50%, calc(-50% - 1px)) scale(1);
  }
}

/* ---------- Boot splash ----------
   Shown once per tab, armed by the head script before first paint.

   The whole sequence — including the lift at the end — is CSS animation
   with `forwards` fill. Script only removes the element early and plays
   the chord; if scripting fails outright the splash still clears itself,
   so it can never become a locked screen over a working page. */
.boot {
  position: fixed;
  inset: 0;
  /* Above every other fixed surface: menu (150) and fullscreen player (200). */
  z-index: 9999;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 26px;
  background:
    radial-gradient(ellipse 55% 40% at 50% 42%, color-mix(in srgb, var(--vip) 8%, transparent), transparent 70%),
    var(--bg);
  overflow: hidden;
  animation: boot-lift 0.55s cubic-bezier(0.65, 0, 0.35, 1) 1.5s forwards;
}
.booting .boot { display: flex; }
/* Nothing behind the splash may scroll while it is up. */
.booting body { overflow: hidden; }
/* Removed by script the moment the splash is done. */
.boot.is-gone { display: none !important; }

.boot-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, var(--bg-rule) 1px, transparent 1px),
    linear-gradient(to bottom, var(--bg-rule) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(70% 60% at 50% 50%, #000 10%, transparent 80%);
  -webkit-mask-image: radial-gradient(70% 60% at 50% 50%, #000 10%, transparent 80%);
  animation: boot-grid-in 1.4s ease both;
}
@keyframes boot-grid-in {
  from { opacity: 0; transform: scale(1.12); }
  to   { opacity: 1; transform: none; }
}

.boot-core {
  position: relative;
  display: grid;
  place-items: center;
  width: 120px;
  height: 120px;
}
.boot-mark {
  width: 64px;
  height: 64px;
  background: var(--text);
  mask: var(--mark) center / contain no-repeat;
  -webkit-mask: var(--mark) center / contain no-repeat;
  animation: boot-mark 1.1s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes boot-mark {
  0%   { opacity: 0; transform: scale(0.72) rotate(-18deg); filter: blur(12px); }
  55%  { opacity: 1; transform: scale(1.06) rotate(4deg); filter: blur(0); }
  100% { opacity: 1; transform: scale(1) rotate(0deg); filter: blur(0); }
}
/* A single arc sweeping the mark — the only moving part, so it reads as
   "working" rather than as decoration. */
.boot-ring {
  position: absolute;
  inset: 0;
  border: 1px solid var(--line-soft);
  border-top-color: var(--vip);
  border-radius: 50%;
  box-shadow: 0 0 28px color-mix(in srgb, var(--vip) 22%, transparent);
  animation: boot-spin 1s linear infinite, boot-fade-in 0.5s ease both;
}
@keyframes boot-spin { to { transform: rotate(360deg); } }
@keyframes boot-fade-in { from { opacity: 0; } to { opacity: 1; } }

.boot-word {
  display: flex;
  gap: 0.42em;
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 4.6vw, 1.6rem);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text);
}
.boot-word i {
  font-style: normal;
  opacity: 0;
  transform: translateY(10px);
  filter: blur(6px);
  animation: boot-letter 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  /* Each glyph one beat behind the last. */
  animation-delay: calc(0.24s + var(--i) * 0.055s);
}
@keyframes boot-letter {
  to { opacity: 1; transform: none; filter: blur(0); }
}

.boot-bar {
  width: min(190px, 42vw);
  height: 1px;
  background: var(--line);
  overflow: hidden;
}
.boot-bar span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--text);
  transform-origin: left center;
  animation: boot-progress 1.35s cubic-bezier(0.5, 0, 0.2, 1) both;
}
@keyframes boot-progress {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.boot-foot {
  font-family: var(--font-mono);
  font-size: 0.5rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
  animation: boot-fade-in 0.6s 0.7s both;
}

@keyframes boot-lift {
  to { opacity: 0; transform: translateY(-2%); visibility: hidden; pointer-events: none; }
}

/* The splash is opt-in motion by definition — the head script never arms
   it under reduced motion, and this is the belt to that braces. */
@media (prefers-reduced-motion: reduce) {
  .boot { display: none !important; }
}

/* ---------- Menu identity card ----------
   The menu used to open on a wall of statistics. It opens on the member
   now: who they are, what tier they hold, and what is in the wallet. */
.menu-id { margin-bottom: 26px; }
.menu-id-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  background: linear-gradient(135deg, var(--wash-2), transparent 60%);
}
/* VIP is a gold edge on the whole card, not just a chip in the corner. */
.menu-id-card.is-vip {
  border-color: color-mix(in srgb, var(--vip) 45%, transparent);
  background: linear-gradient(135deg, color-mix(in srgb, var(--vip) 10%, transparent), transparent 62%);
}
.menu-id-mark {
  width: 34px; height: 34px;
  background: var(--text);
  mask: var(--mark) center / contain no-repeat;
  -webkit-mask: var(--mark) center / contain no-repeat;
}
.menu-id-card.is-vip .menu-id-mark { background: var(--vip); }
.menu-id-body { min-width: 0; }
.menu-id-name {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  font-family: var(--font-display);
  font-size: 1.1rem;
  letter-spacing: -0.02em;
  color: var(--text);
}
.menu-id-meta {
  display: flex; gap: 12px; flex-wrap: wrap;
  margin-top: 5px;
  font-family: var(--font-mono);
  font-size: 0.52rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.menu-id-admin { color: var(--text-dim); }

.menu-id-bal {
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
  padding-left: 16px;
  border-left: 1px solid var(--line-soft);
  transition: opacity 0.2s;
  min-width: 0;
  max-width: 42%;
}
.menu-id-bal:hover { opacity: 0.72; }
.menu-id-bal em {
  font-style: normal; font-family: var(--font-mono);
  font-size: 0.46rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--muted);
}
.menu-id-bal b {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(0.85rem, 3.6vw, 1.15rem); letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; color: var(--text);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;
}
.menu-id-bal i {
  font-style: normal; font-family: var(--font-mono);
  font-size: 0.44rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--vip);
}

/* The badge itself — a filled plate, so VIP reads at a glance rather than
   as another line of small mono type. */
.vip-plate {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 8px;
  background: var(--vip);
  color: var(--bg);
  font-family: var(--font-mono);
  font-size: 0.48rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
}
.vip-plate svg { stroke-width: 2.5; }

@media (max-width: 560px) {
  .menu-id-card { grid-template-columns: auto minmax(0, 1fr); }
  .menu-id-bal {
    grid-column: 1 / -1;
    align-items: flex-start;
    padding: 12px 0 0;
    border-left: none;
    border-top: 1px solid var(--line-soft);
  }
  .menu-id-bal b { font-size: 1.3rem; }
}

/* ---------- Get-app modal: open-scoped motion and small screens ----------
   The entrance animations above are declared on the elements themselves,
   so they ran once at page load — while the modal was still invisible —
   and had long finished by the time anyone opened it. Opening therefore
   snapped straight to the final frame, and the infinite scan line ran
   behind a closed sheet for the life of the page.

   Gating animation-name on `.open` fixes both: `none` while closed means
   the name changes on open, which is what makes an animation restart. */
.app-modal-scan,
.app-modal-phone,
.app-modal-eyebrow,
.app-modal h3,
.app-modal-lede,
.app-modal-access,
.app-modal #installBtn,
.app-modal .install-steps,
.app-modal-foot,
.update-modal #updateBtn {
  animation: none;
}
.modal-backdrop.open .app-modal-scan   { animation: app-scan 3.6s ease-in-out infinite; }
.modal-backdrop.open .app-modal-phone  { animation: app-phone-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both; }
.modal-backdrop.open .app-modal-eyebrow{ animation: app-rise 0.45s 0.08s both; }
.modal-backdrop.open .app-modal h3     { animation: app-rise 0.5s 0.14s both; }
.modal-backdrop.open .app-modal-lede   { animation: app-rise 0.5s 0.2s both; }
.modal-backdrop.open .app-modal-access { animation: app-rise 0.5s 0.26s both; }
.modal-backdrop.open .app-modal #installBtn    { animation: app-rise 0.5s 0.3s both; }
.modal-backdrop.open .app-modal .install-steps { animation: app-rise 0.5s 0.3s both; }
.modal-backdrop.open .app-modal-foot   { animation: app-rise 0.5s 0.34s both; }
.modal-backdrop.open .update-modal #updateBtn  { animation: app-rise 0.5s 0.3s both; }
.modal-backdrop.open .app-modal-phone.is-update img {
  animation: update-mark-spin 2.8s linear infinite;
}

/* The 6-second auto-dismiss, made visible. A sheet that vanishes on its
   own with no warning reads as a glitch; a countdown reads as intent. */
.app-modal-timer {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--line-soft);
  overflow: hidden;
}
.app-modal-timer span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--text);
  transform-origin: right center;
  transform: scaleX(0);
}
.modal-backdrop.open .app-modal-timer span {
  animation: app-timer 6s linear forwards;
}
/* Paused while the member is actually reading it. */
.modal-backdrop.is-held .app-modal-timer span { animation-play-state: paused; }
@keyframes app-timer {
  from { transform: scaleX(1); }
  to   { transform: scaleX(0); }
}

/* ---- Small screens ----
   The sheet was laid out for 400px and hard-coded 28px side margins, which
   on a 360px phone left the three-column feature grid about 30px per cell
   and pushed the card wider than the viewport. */
@media (max-width: 420px) {
  .app-modal { max-width: 100%; }
  .app-modal-eyebrow,
  .app-modal h3,
  .app-modal-lede,
  .app-modal #installBtn,
  .app-modal .install-steps,
  .app-modal-foot,
  .update-modal #updateBtn {
    margin-left: 18px;
    margin-right: 18px;
  }
  .app-modal-access { margin-left: 18px; margin-right: 18px; }
  .app-modal-stage { height: 132px; margin-bottom: 18px; }
  .app-modal-phone { width: 76px; height: 98px; }
  .app-modal-phone img { width: 36px; height: 36px; }
  .app-modal-lede { max-width: none; }
}
/* Short viewports — a phone in landscape, or a small window. The stage is
   the first thing to go: it is decoration, and the install steps are not. */
@media (max-height: 640px) {
  .app-modal-stage { height: 96px; }
  .app-modal h3 { font-size: 1.4rem; }
  .app-modal-lede { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .modal-backdrop.open .app-modal-timer span { animation: none; transform: scaleX(0); }
}
