/* ==========================================================================
   SKYY ENT — Premium Artist Theme
   Dark, cinematic, music-player inspired. Built on Bootstrap 5.

   Every color, font, radius, shadow and spacing step is a CSS variable so the
   admin theme settings can override the whole design from one <style> block.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. DESIGN TOKENS
   -------------------------------------------------------------------------- */
/* Palette taken from the 29 Skyy Ent logo: molten gold and ember orange over
   obsidian black. Kept to roughly 70% black/charcoal, 20% white/gray and 10%
   fire, so the result reads premium music rather than gaming or horror. */
:root {
  /* Surfaces — black glass. The page is near-pure black so the frosted
     panels above it have something to be lighter than. */
  --c-bg:            #050505;
  --c-bg-2:          #0A0A0A;
  --c-card:          #101010;
  --c-card-hover:    #171717;
  --c-elevated:      #1C1C1C;

  /* Glass */
  --c-glass:         rgba(255, 255, 255, 0.045);
  --c-glass-2:       rgba(255, 255, 255, 0.075);
  --c-glass-line:    rgba(255, 255, 255, 0.12);
  --c-glass-hi:      rgba(255, 255, 255, 0.30);

  /* UI accent — MONOCHROME on purpose. Everything interactive resolves
     through these, which is what makes the interface greyscale without
     touching the sixty-odd rules that reference them. */
  --c-primary:       #FFFFFF;
  --c-primary-soft:  #E8E8E8;
  --c-primary-dark:  #C2C2C2;
  --c-accent:        #DCDCDC;
  --c-accent-2:      #8C8C8C;

  /* Fire — the accent, and ONLY for: the logo, the burning headline, the
     primary call to action and the active nav item. Anything else reaching
     for these is drifting off the monochrome direction. */
  --c-fire:          #FF5A1F;
  --c-fire-gold:     #FFB000;
  --c-fire-red:      #A91B0D;
  --grad-fire:       linear-gradient(135deg, #FFB000 0%, #FF5A1F 48%, #A91B0D 100%);
  --grad-fire-hv:    linear-gradient(135deg, #FFC33D 0%, #FF7A45 48%, #C42410 100%);

  /* Text */
  --c-text:          #FFFFFF;
  --c-muted:         #A8A8A8;
  --c-dim:           #6E6E6E;

  /* Lines */
  --c-border:        rgba(255, 255, 255, 0.12);
  --c-border-strong: rgba(255, 255, 255, 0.22);
  --c-border-soft:   rgba(255, 255, 255, 0.06);

  /* Status — semantic, not brand, so these keep their meaning. */
  --c-success:       #22C55E;
  --c-warning:       #E0B341;
  --c-error:         #EF4444;
  --c-info:          #BFBFBF;

  /* Gradients — silver, for UI surfaces and highlights */
  --grad-primary:    linear-gradient(135deg, #FFFFFF 0%, #D4D4D4 48%, #9C9C9C 100%);
  --grad-primary-hv: linear-gradient(135deg, #FFFFFF 0%, #E8E8E8 48%, #B8B8B8 100%);
  --grad-cool:       linear-gradient(135deg, var(--c-accent) 0%, var(--c-primary) 100%);
  --grad-text:       linear-gradient(120deg, #FFFFFF 0%, #DCDCDC 45%, #9E9E9E 100%);
  --grad-line:       linear-gradient(90deg, transparent, rgba(255,255,255,0.45), rgba(255,255,255,0.85), transparent);

  /* Typography */
  --font-display: 'Space Grotesk', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-mono:    ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  --fs-xs:   0.75rem;    /* 12px */
  --fs-sm:   0.875rem;   /* 14px */
  --fs-base: 1rem;       /* 16px */
  --fs-lg:   1.125rem;   /* 18px */
  --fs-xl:   1.375rem;   /* 22px */
  --fs-2xl:  1.75rem;    /* 28px */
  --fs-3xl:  2.25rem;    /* 36px */
  --fs-4xl:  3rem;       /* 48px */
  --fs-hero: clamp(2.75rem, 11vw, 8.5rem);
  --fs-section: clamp(1.75rem, 4.2vw, 3rem);

  --lh-tight: 1.1;
  --lh-snug:  1.35;
  --lh-body:  1.7;

  --fw-normal: 400;
  --fw-medium: 500;
  --fw-semi:   600;
  --fw-bold:   700;

  /* Spacing scale */
  --s-1:  0.25rem;
  --s-2:  0.5rem;
  --s-3:  0.75rem;
  --s-4:  1rem;
  --s-5:  1.5rem;
  --s-6:  2rem;
  --s-7:  2.5rem;
  --s-8:  3rem;
  --s-9:  4rem;
  --s-10: 5rem;
  --s-section: clamp(3.5rem, 8vw, 7rem);

  /* Radii */
  --r-xs:   6px;
  --r-sm:   10px;
  --r-md:   14px;
  --r-lg:   18px;
  --r-xl:   24px;
  --r-2xl:  32px;
  --r-pill: 999px;

  /* Shadows */
  --sh-sm:    0 1px 2px rgba(0, 0, 0, 0.4);
  --sh-md:    0 6px 20px rgba(0, 0, 0, 0.35);
  --sh-lg:    0 18px 48px rgba(0, 0, 0, 0.45);
  --sh-xl:    0 32px 80px rgba(0, 0, 0, 0.55);
  --sh-glow:  0 10px 40px -12px rgba(255, 255, 255, 0.20);
  --sh-fire:  0 10px 40px -12px rgba(255, 90, 31, 0.55);
  --sh-glow-accent: 0 10px 40px -12px rgba(255, 255, 255, 0.16);
  --sh-inset: inset 0 1px 0 rgba(255, 255, 255, 0.06);

  /* Motion */
  --t-fast:  140ms cubic-bezier(0.4, 0, 0.2, 1);
  --t-base:  240ms cubic-bezier(0.4, 0, 0.2, 1);
  --t-slow:  420ms cubic-bezier(0.16, 1, 0.3, 1);

  /* Layout */
  --w-max:      1280px;
  --w-narrow:   820px;
  --w-prose:    68ch;
  /* The brand is a three-line stacked mark, so the bar is sized to show all
     three lines rather than the mark being shrunk to fit a thin bar. It scales
     with the viewport so the logo is never cropped or squeezed at any width.
     `--brand-inset` is the breathing room above and below it. */
  --header-h:     clamp(76px, 4.6vw, 92px);
  --brand-inset:  14px;
  --z-header:   1030;
  --z-drawer:   1045;
  --z-modal:    1055;
  --z-toast:    1080;

  /* Glass */
  --glass-bg:     rgba(22, 22, 33, 0.72);
  --glass-border: rgba(255, 255, 255, 0.10);
  --glass-blur:   blur(20px) saturate(135%);
}

/* --------------------------------------------------------------------------
   2. RESET & BASE
   -------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  font-weight: var(--fw-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;         /* belt and braces against horizontal scroll */
  text-rendering: optimizeLegibility;
}

/* Ambient lighting behind the whole page — very subtle, never distracting. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(1100px 620px at 12% -8%,  rgba(255, 255, 255, 0.055), transparent 62%),
    radial-gradient(900px  520px at 92% 8%,   rgba(255, 255, 255, 0.038), transparent 60%),
    radial-gradient(800px  500px at 50% 108%, rgba(255, 255, 255, 0.030), transparent 62%);
}

main { position: relative; z-index: 1; }

img, svg, video, canvas, iframe {
  max-width: 100%;
  height: auto;
  display: block;
}

/* Inline icons must not be squeezed by their container.
   `max-width: 100%` lets an SVG shrink on the main axis, but a browser only
   derives an aspect-ratio from the width/height attributes for <img> — never
   for inline <svg>. So a squeezed icon keeps the full height from its
   attribute while losing width, and every circle in it is drawn as an ellipse.
   Refusing to shrink is what keeps icons circular; they are 12-26px, so they
   never had any business absorbing the layout's overflow anyway. */
svg { flex-shrink: 0; }

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  letter-spacing: -0.022em;
  margin: 0 0 var(--s-4);
  color: var(--c-text);
  text-wrap: balance;
}

h1 { font-size: clamp(2rem, 5.5vw, var(--fs-4xl)); }
h2 { font-size: var(--fs-section); }
h3 { font-size: clamp(1.25rem, 2.6vw, var(--fs-2xl)); }
h4 { font-size: var(--fs-xl); }
h5 { font-size: var(--fs-lg); }
h6 { font-size: var(--fs-base); letter-spacing: 0.04em; text-transform: uppercase; }

p { margin: 0 0 var(--s-4); }
p:last-child { margin-bottom: 0; }

a {
  color: var(--c-accent-2);
  text-decoration: none;
  transition: color var(--t-fast);
}
a:hover { color: var(--c-accent); }

ul, ol { margin: 0 0 var(--s-4); padding-left: 1.35rem; }
li + li { margin-top: var(--s-2); }

hr {
  border: 0;
  height: 1px;
  background: var(--c-border);
  margin: var(--s-6) 0;
  opacity: 1;
}

small { font-size: var(--fs-sm); }
strong, b { font-weight: var(--fw-semi); }

code, kbd, pre { font-family: var(--font-mono); font-size: 0.9em; }
code {
  background: rgba(255, 255, 255, 0.06);
  padding: 0.15em 0.45em;
  border-radius: var(--r-xs);
  color: #E8E8E8;
}

blockquote {
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  border-left: 3px solid var(--c-primary);
  background: rgba(255, 255, 255, 0.042);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  color: var(--c-text);
  font-size: var(--fs-lg);
}

/* The highlight takes the page ground as its text colour, not white. With
   --c-primary repainted to #FFFFFF for the monochrome UI, `color: #fff` made
   selected text white on white — invisible. This pairing measures 20.4:1. */
::selection { background: var(--c-primary); color: var(--c-bg); }
::-moz-selection { background: var(--c-primary); color: var(--c-bg); }

/* Scrollbars */
* { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.18) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--c-bg-2); }
::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.14);
  border-radius: var(--r-pill);
  border: 2px solid var(--c-bg-2);
}
::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.24); }

/* --------------------------------------------------------------------------
   3. ACCESSIBILITY
   -------------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  left: var(--s-4);
  top: -100px;
  z-index: 2000;
  padding: var(--s-3) var(--s-5);
  background: var(--c-primary);
  color: #fff;
  border-radius: var(--r-sm);
  font-weight: var(--fw-semi);
  transition: top var(--t-fast);
}
.skip-link:focus { top: var(--s-4); color: #fff; }

:focus-visible {
  outline: 2px solid var(--c-accent-2);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}
:focus:not(:focus-visible) { outline: none; }

.visually-hidden,
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
}

/* --------------------------------------------------------------------------
   4. LAYOUT
   -------------------------------------------------------------------------- */
.container,
.container-xl {
  width: 100%;
  max-width: var(--w-max);
  margin-inline: auto;
  padding-inline: var(--s-4);
}
@media (min-width: 768px)  { .container, .container-xl { padding-inline: var(--s-6); } }
@media (min-width: 1280px) { .container, .container-xl { padding-inline: var(--s-7); } }

.container-narrow {
  width: 100%;
  max-width: var(--w-narrow);
  margin-inline: auto;
  padding-inline: var(--s-4);
}

.section { padding-block: var(--s-section); position: relative; }
.section--tight { padding-block: clamp(2.5rem, 5vw, 4rem); }
.section--alt { background: var(--c-bg-2); }
.section--bordered { border-top: 1px solid var(--c-border-soft); }

/* Prose blocks never stretch across a wide monitor. */
.prose { max-width: var(--w-prose); }
.prose p, .prose li { color: var(--c-muted); font-size: var(--fs-lg); }
.prose h2, .prose h3 { color: var(--c-text); margin-top: var(--s-7); }
.prose h2:first-child, .prose h3:first-child { margin-top: 0; }
.prose img { border-radius: var(--r-lg); margin-block: var(--s-5); }
.prose a { color: var(--c-accent-2); text-decoration: underline; text-underline-offset: 3px; }
.prose iframe { max-width: 100%; border-radius: var(--r-md); }

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-7);
}
.section-head__text { min-width: 0; flex: 1 1 320px; }
.section-head h2 { margin-bottom: var(--s-2); }
.section-head p { color: var(--c-muted); margin: 0; max-width: 60ch; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-accent-2);
  margin-bottom: var(--s-3);
  /* An inline-flex box sizes to max-content and will not shrink, so a long
     tracked-out eyebrow ("INDEPENDENT RECORD LABEL — ATLANTA, GEORGIA") was
     wider than a phone screen. Because body carries overflow-x: hidden that
     never showed as a scrollbar — it silently widened the layout and pushed the
     header's cart and menu buttons off the right edge. It has to be allowed to
     wrap. */
  flex-wrap: wrap;
  max-width: 100%;
}
@media (max-width: 480px) {
  .eyebrow { letter-spacing: 0.1em; }
}
.eyebrow::before {
  content: '';
  width: 28px;
  height: 2px;
  background: var(--grad-primary);
  border-radius: var(--r-pill);
}

.text-gradient {
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

.text-muted-2 { color: var(--c-muted) !important; }
.text-dim     { color: var(--c-dim) !important; }

/* Reveal-on-scroll */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--t-slow), transform var(--t-slow);
  will-change: opacity, transform;
}
.reveal.is-visible { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   5. BUTTONS
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   BUTTONS — dimensional

   Every button is a physical key: a face, a solid coloured edge beneath it
   giving it thickness, a lit top bevel and an ambient shadow on the page.
   Pressing one moves the face down by exactly the edge thickness and collapses
   the edge to nothing, so the button genuinely travels rather than just
   changing colour.

   Each variant only has to set `--btn-edge` — the depth mechanics are shared,
   which is what keeps a gold button, a danger button and an outline button
   feeling like the same physical object.
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: transparent;
  --btn-color: var(--c-text);
  --btn-border: var(--c-border-strong);

  /* Depth of the key. Larger buttons get a thicker edge further down. */
  --btn-depth: 3px;
  /* Colour of that edge — the side of the key catching no light. */
  --btn-edge: rgba(0, 0, 0, 0.55);
  /* How far the ambient shadow falls on the page behind it. */
  --btn-cast: rgba(0, 0, 0, 0.45);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 46px;
  padding: 0.7rem 1.5rem;
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
  letter-spacing: 0.015em;
  line-height: 1.2;
  text-align: center;
  border-radius: var(--r-pill);
  border: 1px solid var(--btn-border);
  background: var(--btn-bg);
  color: var(--btn-color);
  cursor: pointer;
  text-decoration: none;
  max-width: 100%;
  white-space: nowrap;

  position: relative;
  transform: translateY(0);
  box-shadow:
    /* the solid edge that gives the key its thickness */
    0 var(--btn-depth) 0 0 var(--btn-edge),
    /* ambient cast on the page */
    0 calc(var(--btn-depth) + 5px) 14px -5px var(--btn-cast),
    /* lit top bevel and shaded bottom lip, inside the face */
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -1px 0 rgba(0, 0, 0, 0.20);

  transition: transform var(--t-fast), box-shadow var(--t-fast),
              background-color var(--t-base), border-color var(--t-base), color var(--t-base);
}

/* Hover lifts the key and lengthens both the edge and its cast shadow. */
.btn:hover {
  transform: translateY(-2px);
  color: var(--btn-color);
  box-shadow:
    0 calc(var(--btn-depth) + 2px) 0 0 var(--btn-edge),
    0 calc(var(--btn-depth) + 10px) 22px -6px var(--btn-cast),
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    inset 0 -1px 0 rgba(0, 0, 0, 0.20);
}

/* Press travels the full depth and flattens the edge — the button is now
   sitting on the surface rather than standing above it. */
.btn:active {
  transform: translateY(var(--btn-depth));
  box-shadow:
    0 0 0 0 var(--btn-edge),
    0 1px 3px -1px var(--btn-cast),
    inset 0 2px 5px rgba(0, 0, 0, 0.28);
}

.btn:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
}

.btn:disabled,
.btn.disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none !important;
}

/* The primary key is molten: its edge is the lava red the gradient ends on, so
   the side reads as the same material cooled rather than a generic dark band.
   The cast picks up ember, which is where the old glow now lives. */
/* Permitted fire accent 3 of 4: the primary call to action. On a greyscale
   page this is the only warm control, which is exactly why it pulls the eye. */
.btn-primary {
  --btn-bg: var(--grad-fire);
  --btn-color: #FFFFFF;
  --btn-border: transparent;
  --btn-edge: #7A1408;
  --btn-cast: rgba(255, 90, 31, 0.45);
  background-image: var(--grad-fire);
}
.btn-primary:hover {
  background-image: var(--grad-fire-hv);
  color: #fff;
}

.btn-accent {
  --btn-bg: var(--c-accent);
  --btn-color: #0A0A0A;
  --btn-border: transparent;
  --btn-edge: #8E8E8E;
  --btn-cast: rgba(255, 255, 255, 0.28);
}
.btn-accent:hover { background: #FFFFFF; color: #0A0A0A; }

/* Outline keys are hollow, so their edge is the dark of the page showing
   through rather than a colour of their own. */
.btn-outline,
.btn-outline-light {
  --btn-bg: rgba(255, 255, 255, 0.03);
  --btn-color: var(--c-text);
  --btn-border: var(--c-border-strong);
  --btn-edge: rgba(0, 0, 0, 0.6);
  --btn-cast: rgba(0, 0, 0, 0.5);
  backdrop-filter: var(--glass-blur);
}
.btn-outline:hover,
.btn-outline-light:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: rgba(255, 255, 255, 0.32);
}

/* Ghost buttons are text, not objects. A permanent slab under a text link
   reads as broken, so this one only gains its edge once it is hovered — and it
   still presses, so it belongs to the same family. */
.btn-ghost {
  --btn-bg: transparent;
  --btn-border: transparent;
  --btn-color: var(--c-muted);
  --btn-depth: 2px;
  --btn-edge: transparent;
  --btn-cast: transparent;
  padding-inline: var(--s-3);
  box-shadow: none;
}
.btn-ghost:hover {
  color: var(--c-text);
  background: rgba(255, 255, 255, 0.06);
  --btn-edge: rgba(0, 0, 0, 0.45);
  --btn-cast: rgba(0, 0, 0, 0.35);
  box-shadow:
    0 var(--btn-depth) 0 0 var(--btn-edge),
    0 calc(var(--btn-depth) + 6px) 14px -6px var(--btn-cast);
}

/* A platform button should identify the platform, not shout louder than the
   artist. Full Spotify green next to the ember CTA gave the hero two competing
   primaries and a third colour family; the green now lives only in the glyph,
   where it still reads instantly as Spotify, and the control itself matches
   every other secondary button on the site. */
.btn-spotify {
  --btn-bg: linear-gradient(160deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.035));
  --btn-color: var(--c-text);
  --btn-border: rgba(255, 255, 255, 0.18);
  --btn-edge: #0B0B0B;
  --btn-cast: rgba(0, 0, 0, 0.55);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.035));
  backdrop-filter: blur(14px) saturate(130%);
  -webkit-backdrop-filter: blur(14px) saturate(130%);
}
.btn-spotify svg { color: #1ED760; }
.btn-spotify:hover {
  --btn-border: rgba(255, 255, 255, 0.34);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0.06));
  color: var(--c-text);
}

.btn-danger {
  --btn-bg: var(--c-error);
  --btn-color: #fff;
  --btn-border: transparent;
  --btn-edge: #7F1D1D;
  --btn-cast: rgba(239, 68, 68, 0.35);
}
.btn-danger:hover { --btn-bg: #DC2626; color: #fff; }

.btn-success {
  --btn-bg: var(--c-success);
  --btn-color: #fff;
  --btn-border: transparent;
  --btn-edge: #14532D;
  --btn-cast: rgba(34, 197, 94, 0.32);
}
.btn-success:hover { --btn-bg: #16A34A; color: #fff; }

/* ---------------------------------------------------------------------------
   Bootstrap ships its own `.btn` and is loaded before this file. Its
   `.btn:focus-visible` rule sets `outline: 0` and a blue focus box-shadow, and
   at (0,2,0) it is MORE specific than our variant classes — so on keyboard
   focus a button lost its depth, lost its focus ring and gained a blue halo,
   regardless of load order.

   Restating the state here at equal specificity, later in the cascade, puts the
   button back: brand-coloured ring, depth intact, colours unchanged.
   --------------------------------------------------------------------------- */
.btn:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
  color: var(--btn-color);
  background: var(--btn-bg);
  border-color: var(--btn-border);
  box-shadow:
    0 var(--btn-depth) 0 0 var(--btn-edge),
    0 calc(var(--btn-depth) + 5px) 14px -5px var(--btn-cast),
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -1px 0 rgba(0, 0, 0, 0.20);
}
/* The gradient lives on background-image, which the shorthand above resets. */
.btn-primary:focus-visible { background-image: var(--grad-primary); }
.btn-ghost:focus-visible   { box-shadow: none; }
/* Pressing while focused must still read as pressed, not as focused. */
.btn:focus-visible:active {
  box-shadow:
    0 0 0 0 var(--btn-edge),
    0 1px 3px -1px var(--btn-cast),
    inset 0 2px 5px rgba(0, 0, 0, 0.28);
}

/* Depth scales with the key: a small button with a 3px edge looks clumsy, a
   large one with the same edge looks flat. */
.btn-sm  { --btn-depth: 2px; min-height: 38px; padding: 0.45rem 1.05rem; font-size: var(--fs-xs); }
.btn-lg  { --btn-depth: 4px; min-height: 56px; padding: 0.95rem 2.1rem; font-size: var(--fs-base); }
.btn-block, .btn-full { width: 100%; }

.btn-icon {
  min-height: 44px;
  min-width: 44px;
  padding: 0;
  border-radius: 50%;
}

.btn-group-inline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}

/* --- Buttons: responsive and input-aware ------------------------------------

   Three separate problems, each with its own trigger:

   1. On touch there is no hover, but a tapped button keeps the :hover state
      until you tap elsewhere — so it stays lifted and looks stuck. Hover
      effects are therefore given only to devices that can actually hover.
   2. `white-space: nowrap` keeps labels tidy but a long one ("Reject
      non-essential") cannot fit on a 320px screen, so wrapping is allowed once
      the viewport is genuinely narrow.
   3. A 38px small button is below the 44px minimum touch target, which is fine
      with a mouse and not fine with a thumb.
   ------------------------------------------------------------------------- */
@media (hover: none) {
  .btn:hover {
    transform: translateY(0);
    box-shadow:
      0 var(--btn-depth) 0 0 var(--btn-edge),
      0 calc(var(--btn-depth) + 5px) 14px -5px var(--btn-cast),
      inset 0 1px 0 rgba(255, 255, 255, 0.16),
      inset 0 -1px 0 rgba(0, 0, 0, 0.20);
  }
  .btn-ghost:hover { box-shadow: none; }
}

/* Coarse pointers get a full-size target regardless of the visual size class. */
@media (pointer: coarse) {
  .btn-sm { min-height: 44px; padding-block: 0.6rem; }
  .btn-icon, .icon-btn { min-height: 44px; min-width: 44px; }
}

@media (max-width: 400px) {
  .btn {
    white-space: normal;
    text-wrap: balance;
    padding-inline: 1.1rem;
  }
  .btn-lg { padding-inline: 1.3rem; font-size: var(--fs-sm); }
}

/* With motion reduced the key still changes state on press — it just does not
   travel. Removing the feedback entirely would be worse than the animation. */
@media (prefers-reduced-motion: reduce) {
  .btn,
  .btn:hover,
  .btn:active { transform: none !important; }
  .btn:active {
    box-shadow:
      0 0 0 0 var(--btn-edge),
      inset 0 2px 5px rgba(0, 0, 0, 0.28);
  }
}

/* --------------------------------------------------------------------------
   6. CARDS
   -------------------------------------------------------------------------- */
.card,
.s-card {
  position: relative;
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-md), var(--sh-inset);
  overflow: hidden;
  transition: transform var(--t-base), border-color var(--t-base), box-shadow var(--t-base);
  color: var(--c-text);
}
.s-card--hover:hover,
a.s-card:hover {
  transform: translateY(-4px);
  border-color: var(--c-border-strong);
  box-shadow: var(--sh-lg);
}
.s-card__body { padding: var(--s-5); }
.s-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-semi);
  margin: 0 0 var(--s-2);
  line-height: var(--lh-snug);
}
.s-card__meta {
  font-size: var(--fs-xs);
  color: var(--c-dim);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: var(--s-2);
}
.s-card__text { color: var(--c-muted); font-size: var(--fs-sm); margin: 0; }

.glass {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
}

/* Media thumbnail with a fixed aspect ratio — prevents layout shift. */
.media-thumb {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--c-bg-2);
  overflow: hidden;
}
.media-thumb--wide  { aspect-ratio: 16 / 9; }
.media-thumb--photo { aspect-ratio: 4 / 5; }
.media-thumb--poster{ aspect-ratio: 3 / 4; }
.media-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--t-slow);
}
.s-card--hover:hover .media-thumb img,
a.s-card:hover .media-thumb img { transform: scale(1.05); }

.media-thumb__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(7,7,7,0) 45%, rgba(7,7,7,0.88) 100%);
  opacity: 0;
  transition: opacity var(--t-base);
}
.s-card:hover .media-thumb__overlay { opacity: 1; }

/* --------------------------------------------------------------------------
   7. GRIDS
   -------------------------------------------------------------------------- */
.grid { display: grid; gap: var(--s-5); }
.grid--2 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); }
.grid--products { grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr)); }
/* auto-FIT, not auto-fill: the home page preview shows only two photographs,
   and auto-fill would lay down empty 210px phantom tracks beside them, stranding
   both at the left of a mostly empty row. auto-fit collapses those empty tracks
   so the two stretch across. With a full gallery the two behave identically. */
.grid--gallery  { grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); gap: var(--s-3); }

@media (max-width: 575.98px) {
  .grid--products { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
  .grid--gallery  { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid--3, .grid--4 { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 359.98px) {
  .grid--products { grid-template-columns: minmax(0, 1fr); }
}

.split {
  display: grid;
  gap: clamp(var(--s-6), 5vw, var(--s-9));
  align-items: center;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 992px) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .split--60-40 { grid-template-columns: 1.5fr 1fr; }
  .split--40-60 { grid-template-columns: 1fr 1.5fr; }
}

/* --------------------------------------------------------------------------
   8. HEADER & NAVIGATION
   -------------------------------------------------------------------------- */
/* A machined rail across the top of the page rather than a coloured strip.
   The depth comes from three things reading together: a bright bevel along the
   top edge where light catches, a dark line along the bottom where it falls
   away, and a cast shadow onto the header beneath it. Take away any one and it
   flattens back into a band of colour. */
.announcement-bar {
  position: relative;
  z-index: calc(var(--z-header) + 1);
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0.155) 0%,
    rgba(255, 255, 255, 0.072) 46%,
    rgba(255, 255, 255, 0.028) 74%,
    rgba(0, 0, 0, 0.30) 100%);
  backdrop-filter: blur(16px) saturate(135%);
  -webkit-backdrop-filter: blur(16px) saturate(135%);
  border: 0;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.36),
    inset 0 -1px 0 rgba(0, 0, 0, 0.55),
    0 7px 20px -9px rgba(0, 0, 0, 0.95);
  color: #fff;
  font-size: 0.72rem;
  font-weight: var(--fw-semi);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-align: center;
  padding: 0.62rem calc(var(--s-4) + 34px);
}

/* The light that sells the curve. One soft specular band travelling slowly
   across the rail — slow enough to register as a surface catching light rather
   than as an animation demanding attention. */
.announcement-bar::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(104deg,
    transparent 24%,
    rgba(255, 255, 255, 0.16) 46%,
    rgba(255, 255, 255, 0.26) 50%,
    rgba(255, 255, 255, 0.16) 54%,
    transparent 76%);
  background-size: 230% 100%;
  background-repeat: no-repeat;
  animation: rail-sheen 8.5s linear infinite;
}
@keyframes rail-sheen {
  from { background-position: 210% 0; }
  to   { background-position: -70% 0; }
}

/* The link carries its own rule rather than a browser underline, so it can sit
   off the baseline and grow on hover instead of switching on and off. */
.announcement-bar a {
  position: relative;
  color: #fff;
  text-decoration: none;
  padding-bottom: 2px;
  background-image: linear-gradient(90deg, rgba(255,255,255,0.85), rgba(255,255,255,0.85));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 1px;
  transition: background-size var(--t-base), color var(--t-fast);
}
.announcement-bar a:hover {
  color: #fff;
  background-size: 100% 2px;
}

/* A recessed disc, so the control belongs to the same physical object. */
.announcement-bar__close {
  position: absolute;
  right: var(--s-3);
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.28);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.72;
  transition: opacity var(--t-fast), background-color var(--t-fast),
              border-color var(--t-fast), transform var(--t-fast);
}
.announcement-bar__close:hover {
  opacity: 1;
  background: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.40);
  transform: translateY(-50%) scale(1.06);
}
.announcement-bar__close:active { transform: translateY(-50%) scale(0.94); }

/* Tracked-out uppercase needs room; a phone has none. Tighten the tracking and
   let the line wrap rather than shrinking the type to unreadable. */
@media (max-width: 600px) {
  .announcement-bar {
    letter-spacing: 0.08em;
    font-size: 0.66rem;
    padding: 0.55rem calc(var(--s-3) + 30px);
    line-height: 1.5;
  }
  .announcement-bar::after { animation: none; }
}

@media (prefers-reduced-motion: reduce) {
  .announcement-bar::after { animation: none; }
}

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color var(--t-base), border-color var(--t-base), backdrop-filter var(--t-base);
}
/* Once the page moves, the bar tightens and settles onto glass. The condense
   is deliberately small: --header-h is overridden on the header only, so the
   row and the mark shrink together while the hero — which is not a descendant
   and so still reads the :root value — keeps its layout and nothing jumps. */
.site-header.is-solid {
  --header-h: 68px;
  background: rgba(7, 7, 7, 0.72);
  backdrop-filter: blur(22px) saturate(165%);
  -webkit-backdrop-filter: blur(22px) saturate(165%);
  border-bottom-color: transparent;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.05), 0 18px 40px -28px rgba(0, 0, 0, 0.9);
}
/* A hairline that carries the brand rather than a flat grey rule: strongest
   under the centre of the bar and dissolving toward both edges. */
.site-header.is-solid::after,
.site-header--solid::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%, rgba(255, 255, 255, 0.132) 22%, rgba(255, 255, 255, 0.252) 50%,
    rgba(255, 255, 255, 0.132) 78%, transparent 100%);
  pointer-events: none;
}
/* Pages without a hero always show the solid header. */
.site-header--solid {
  background: rgba(7, 7, 7, 0.88);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom-color: var(--c-border);
}

.site-header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--s-4);
  min-height: var(--header-h);
  /* Without this the children refuse to shrink below their content width and
     the header becomes the widest thing on the page. */
  min-width: 0;
  transition: min-height var(--t-base);
}
.site-header__inner > .brand   { grid-column: 1; justify-self: start; }
.site-header__inner > .nav-primary   { grid-column: 2; }
.site-header__inner > .header-actions { grid-column: 3; justify-self: end; }

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 3.2vw, 1.35rem);
  font-weight: var(--fw-bold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-text);
  /* The site name is admin-editable and can be long ("29 Skyy Entertainment"
     rather than a single word). It must be allowed to shrink, or the header
     pushes the whole page wider than the viewport on a phone. */
  min-width: 0;
  flex-shrink: 1;
}
.brand:hover { color: var(--c-text); }

/* The supplied 29 Skyy Ent artwork is a three-line stacked wordmark inside a
   square. At header height all three lines turn to mud, so the header uses only
   the "29" from the top line beside the name set in the display face, and the
   complete mark is kept for the footer, sign-in screens and email where it has
   room. The glow is deliberately tight: a wide halo bleeds into the black bar
   and makes the fire read as a much larger share of the header than it is. */
.brand__logo,
.brand__mark-img {
  width: auto;
  max-width: 100%;
  object-fit: contain;
  filter: drop-shadow(0 1px 5px rgba(255, 90, 31, 0.30));
}

/* The "29" alone. Kept for anywhere a compact square icon is wanted. */
.brand__mark-img { height: clamp(38px, 4.5vw, 44px); }

/* The full stacked mark. It is near-square rather than a wide horizontal
   lockup, so it is sized against the header height and takes very little
   horizontal room — which is what lets the whole thing show at every width
   instead of being cropped or truncated. */
.brand__logo {
  height: calc(var(--header-h) - var(--brand-inset, 26px));
  max-height: 100%;
  transition: height var(--t-base);
}
.site-footer .brand__logo { height: clamp(76px, 12vw, 104px); }
.auth-shell .brand__logo  { height: clamp(84px, 16vw, 116px); }

.brand img:not(.brand__logo):not(.brand__mark-img) { max-height: 42px; width: auto; }
.brand > span:not(.brand__mark) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* Once the primary nav appears there is a fixed layout to respect, so the name
   keeps its full width; truncation is a small-screen behavior only. */
@media (min-width: 1024px) {
  .brand { flex-shrink: 0; }
  .brand > span:not(.brand__mark) { overflow: visible; text-overflow: clip; }
}

/* Below this the header cannot hold the mark, the full name and the cart and
   menu buttons at once — the name wins the space and pushes the buttons off the
   screen. The mark carries the brand on its own here, and the name stays in the
   accessibility tree rather than being removed, so the link is still announced
   as "29 Skyy Entertainment — home". */
/* On a phone the bar carries only three buttons, so the mark can have more of
   the height than it gets on desktop where a full nav shares the row. */
@media (max-width: 640px) {
  .brand__mark-img { height: 34px; }
}
@media (max-width: 420px) {
  .brand { gap: var(--s-2); }
  .brand__mark { width: 32px; height: 32px; font-size: 0.95rem; }
  .brand__mark-img { height: 32px; }
}
.brand__mark {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--grad-primary);
  font-size: 1.05rem;
  color: #fff;
  box-shadow: var(--sh-glow);
}

@media (max-width: 767.98px) {
  .site-header__inner {
    grid-template-columns: auto 1fr auto;
    gap: var(--s-2);
  }

  .brand {
    max-width: 100%;
    letter-spacing: 0.08em;
  }

  .brand > span:not(.brand__mark) {
    max-width: clamp(120px, 38vw, 170px);
  }

  .header-actions {
    gap: var(--s-2);
  }

  .icon-btn {
    width: 40px;
    height: 40px;
  }
}

@media (max-width: 479.98px) {
  .site-header__inner {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  .brand {
    font-size: clamp(0.75rem, 4vw, 0.95rem);
    letter-spacing: 0.06em;
  }

  .brand > span:not(.brand__mark) {
    max-width: clamp(92px, 30vw, 130px);
  }

  .header-actions {
    gap: 0.125rem;
  }

  .icon-btn {
    width: 38px;
    height: 38px;
  }
}

.nav-primary { display: none; --nav-pad-x: 0.9rem; }
@media (min-width: 1024px) { .nav-primary { display: block; } }
/* Tighter links buy the ~90px that makes the full bar fit a 1024px laptop. */
@media (min-width: 1024px) and (max-width: 1199.98px) {
  .nav-primary { --nav-pad-x: 0.5rem; }
  .nav-primary ul { gap: 0; }
}

.nav-primary ul {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav-primary li { margin: 0; }
.nav-primary a {
  position: relative;
  display: block;
  padding: 0.6rem var(--nav-pad-x);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--c-muted);
  border-radius: var(--r-sm);
  transition: color var(--t-fast), background-color var(--t-fast);
}
.nav-primary a:hover { color: var(--c-text); background: rgba(255, 255, 255, 0.05); }

/* The page you are on is the one that is alight.
   Two parts: a heat bloom rising off the link, and a burning rule beneath it
   whose gradient travels, so the fire reads as running along the line rather
   than sitting still. */
.nav-primary a.active {
  color: var(--c-text);
  text-shadow: 0 0 14px rgba(255, 122, 46, 0.55), 0 0 30px rgba(255, 90, 31, 0.28);
}
.nav-primary a.active::after {
  content: '';
  position: absolute;
  left: var(--nav-pad-x); right: var(--nav-pad-x); bottom: 0.28rem;
  height: 2px;
  border-radius: var(--r-pill);
  /* Repeated so the travelling gradient has no visible seam when it loops. */
  background: linear-gradient(90deg,
    #8C1E06 0%, #FF5A1F 18%, #FFB000 34%, #FFF3D0 50%,
    #FFB000 66%, #FF5A1F 82%, #8C1E06 100%);
  background-size: 220% 100%;
  box-shadow: 0 0 10px rgba(255, 122, 46, 0.75), 0 0 22px rgba(255, 90, 31, 0.45);
  animation: nav-fire-run 2.8s linear infinite;
}
/* A soft ember pooling under the active link. */
.nav-primary a.active::before {
  content: '';
  position: absolute;
  left: 50%; bottom: -2px;
  width: 72%; height: 14px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at center,
    rgba(255, 122, 46, 0.45) 0%, rgba(255, 90, 31, 0.18) 45%, transparent 72%);
  filter: blur(3px);
  pointer-events: none;
  animation: nav-fire-breathe 2.2s ease-in-out infinite alternate;
}

@keyframes nav-fire-run {
  from { background-position: 0% 50%; }
  to   { background-position: 220% 50%; }
}
@keyframes nav-fire-breathe {
  from { opacity: 0.45; transform: translateX(-50%) scaleY(0.85); }
  to   { opacity: 0.95; transform: translateX(-50%) scaleY(1.25); }
}

/* Same idea in the mobile drawer, where the marker is a dot rather than a rule. */
.mobile-drawer nav a.active {
  text-shadow: 0 0 12px rgba(255, 122, 46, 0.5);
}

@media (prefers-reduced-motion: reduce) {
  .nav-primary a.active::after,
  .nav-primary a.active::before { animation: none; }
}

.header-actions {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  flex-shrink: 0;
}
/* Header icons sit on a dark bar and are used constantly, so they get the same
   press physics as the buttons but only take on depth once hovered — a row of
   permanently raised discs would compete with the logo. */
.icon-btn {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 44px; height: 44px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid transparent;
  background: transparent;
  color: var(--c-muted);
  cursor: pointer;
  transform: translateY(0);
  transition: color var(--t-fast), background-color var(--t-fast),
              border-color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}
.icon-btn:hover {
  color: var(--c-text);
  background: rgba(255, 255, 255, 0.07);
  border-color: var(--c-border);
  transform: translateY(-2px);
  box-shadow:
    0 2px 0 0 rgba(0, 0, 0, 0.5),
    0 8px 16px -6px rgba(0, 0, 0, 0.55),
    inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.icon-btn:active {
  transform: translateY(1px);
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.35);
}
.icon-btn:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}
@media (hover: none) {
  .icon-btn:hover { transform: none; box-shadow: none; }
}
@media (prefers-reduced-motion: reduce) {
  .icon-btn, .icon-btn:hover, .icon-btn:active { transform: none !important; }
}
.icon-btn svg { width: 20px; height: 20px; }

.icon-btn__badge {
  position: absolute;
  top: 4px; right: 2px;
  min-width: 19px; height: 19px;
  padding: 0 5px;
  display: grid; place-items: center;
  font-size: 10px;
  font-weight: var(--fw-bold);
  line-height: 1;
  color: #fff;
  background: var(--c-accent);
  border-radius: var(--r-pill);
  border: 2px solid var(--c-bg);
}
.icon-btn__badge[hidden] { display: none; }

.nav-toggle { display: inline-grid; }
@media (min-width: 1024px) { .nav-toggle { display: none; } }

.nav-toggle__bars { width: 20px; height: 14px; position: relative; }
.nav-toggle__bars span {
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--t-base), opacity var(--t-fast);
}
.nav-toggle__bars span:nth-child(1) { top: 0; }
.nav-toggle__bars span:nth-child(2) { top: 6px; }
.nav-toggle__bars span:nth-child(3) { top: 12px; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Mobile slide-out drawer */
.drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-drawer) - 1);
  background: rgba(7, 7, 7, 0.72);
  backdrop-filter: blur(4px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-base), visibility var(--t-base);
}
.drawer-backdrop.is-open { opacity: 1; visibility: visible; }

.mobile-drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: min(400px, 100vw);
  max-width: 100%;
  z-index: var(--z-drawer);
  background: var(--c-bg-2);
  border-left: 1px solid var(--c-border);
  box-shadow: var(--sh-xl);
  transform: translateX(100%);
  transition: transform var(--t-slow);
  display: flex;
  flex-direction: column;
  overscroll-behavior: contain;
}
.mobile-drawer.is-open { transform: none; }

.mobile-drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--c-border);
  min-height: var(--header-h);
}
.mobile-drawer__head .brand {
  min-width: 0;
  flex: 1;
  font-size: clamp(0.9rem, 3.2vw, 1.05rem);
  letter-spacing: 0.08em;
}
.mobile-drawer__head .brand > span:not(.brand__mark) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mobile-drawer__body {
  flex: 1;
  overflow-y: auto;
  padding: var(--s-4) var(--s-5) var(--s-8);
  -webkit-overflow-scrolling: touch;
}
.mobile-drawer nav ul { list-style: none; margin: 0 0 var(--s-6); padding: 0; }
.mobile-drawer nav li { margin: 0; border-bottom: 1px solid var(--c-border-soft); }
.mobile-drawer nav a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 56px;
  padding: var(--s-3) 0;
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 3.8vw, 1.35rem);
  font-weight: var(--fw-semi);
  color: var(--c-text);
}
.mobile-drawer nav a:hover,
.mobile-drawer nav a.active { color: var(--c-accent); }
.mobile-drawer nav a.active::after { content: '●'; font-size: 0.55rem; color: var(--c-accent); }

.drawer-section-label {
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-dim);
  margin: var(--s-5) 0 var(--s-3);
}

body.drawer-open { overflow: hidden; }

/* Search overlay */
.search-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  background: rgba(7, 7, 7, 0.94);
  backdrop-filter: var(--glass-blur);
  display: grid;
  place-items: start center;
  padding: clamp(var(--s-8), 14vh, 10rem) var(--s-4) var(--s-6);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-base), visibility var(--t-base);
}
.search-overlay.is-open { opacity: 1; visibility: visible; }
.search-overlay__inner { width: 100%; max-width: 680px; }
.search-overlay input[type="search"] {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 2px solid var(--c-border-strong);
  color: var(--c-text);
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5vw, 2.5rem);
  padding: var(--s-3) 0;
}
.search-overlay input[type="search"]:focus {
  outline: none;
  border-bottom-color: var(--c-accent);
}
.search-overlay input::placeholder { color: var(--c-dim); }

/* --------------------------------------------------------------------------
   9. HERO
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  /* The cap matters more than the vh. Content is bottom-anchored, so any height
     the hero reserves beyond what the content needs does not pad the bottom —
     it piles up ABOVE the content as an empty band directly under the header.
     A 900px cap was taller than this hero ever needs (727-884px depending on
     how the copy wraps), so on any viewport that is tall relative to its width
     — tablets in portrait, a tall desktop window — the surplus showed as a
     dead zone under the nav. Capping just under the content's natural height
     lets the content set the height in every case. */
  min-height: min(94vh, 740px);
  margin-top: calc(var(--header-h) * -1);
  padding-top: calc(var(--header-h) + var(--s-8));
  padding-bottom: var(--s-9);
  overflow: hidden;
  isolation: isolate;
}
@media (max-width: 767.98px) {
  /* Same reasoning as above: a bare vh leaves a dead band on tall viewports. */
  .hero { min-height: min(86vh, 740px); padding-bottom: var(--s-7); align-items: flex-end; }
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.hero__media img,
.hero__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
  /* Hero artwork is supplied by the client and will not always be shot in
     brand colors. A light warm grade pulls whatever is uploaded towards the
     ember palette so the top of the page stays on-brand. */
  filter: saturate(0.72) sepia(0.18) contrast(1.04);
}

.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(7,7,7,0.64) 0%, rgba(7,7,7,0.32) 35%, rgba(7,7,7,0.93) 88%, var(--c-bg) 100%),
    linear-gradient(100deg, rgba(7,7,7,0.88) 0%, rgba(7,7,7,0.34) 58%, transparent 100%),
    /* Ember wash, kept faint — this is the 10% fire in the 70/20/10 split. */
    linear-gradient(120deg, rgba(255, 255, 255, 0.12) 0%, transparent 45%, rgba(255, 255, 255, 0.084) 100%);
}

/* Slow-drifting light — decorative only. */
.hero__glow {
  position: absolute;
  z-index: -1;
  width: 52vmax; height: 52vmax;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0.42;
  pointer-events: none;
}
.hero__glow--1 { top: -18%; right: -12%; background: radial-gradient(circle, rgba(255, 255, 255, 0.33), transparent 68%); animation: drift 22s ease-in-out infinite alternate; }
.hero__glow--2 { bottom: -22%; left: -14%; background: radial-gradient(circle, rgba(255, 255, 255, 0.24), transparent 68%); animation: drift 28s ease-in-out infinite alternate-reverse; }

@keyframes drift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(4%, 5%, 0) scale(1.12); }
}

.hero__content { position: relative; max-width: 780px; }

.hero__name {
  font-size: var(--fs-hero);
  line-height: 0.88;
  letter-spacing: -0.045em;
  /* Head-room for the flames. Without it the plume rises into the eyebrow
     above and, because it blends additively, washes that line out. */
  margin: 0.30em 0 var(--s-4);
  text-transform: uppercase;
  text-wrap: nowrap;

  /* Additive fire only reads as fire over something dark — added to the teal
     in a hero photograph it turns olive. This soft vignette gives the flames a
     near-black ground to burn against, and doubles as contrast for the text.
     It is padded and offset so the shape stays invisible against the hero. */
  position: relative;
  isolation: isolate;
}
.hero__name::before {
  content: '';
  position: absolute;
  inset: -0.45em -1.5em -0.35em -1.2em;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 62% 68% at 34% 55%,
    rgba(7, 7, 7, 0.88) 0%, rgba(7, 7, 7, 0.62) 42%, rgba(7, 7, 7, 0.22) 68%, transparent 82%);
}
@media (max-width: 480px) { .hero__name { text-wrap: balance; letter-spacing: -0.03em; } }

.hero__tagline {
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 2.6vw, 1.6rem);
  font-weight: var(--fw-medium);
  color: var(--c-text);
  margin-bottom: var(--s-4);
  line-height: var(--lh-snug);
}
.hero__intro {
  font-size: var(--fs-lg);
  color: var(--c-muted);
  max-width: 56ch;
  margin-bottom: var(--s-6);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-bottom: var(--s-6);
}
@media (max-width: 575.98px) {
  .hero__actions { flex-direction: column; align-items: stretch; }
  .hero__actions .btn { width: 100%; }
}

.hero__socials { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }

.social-link {
  display: inline-grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 1px solid var(--c-border-strong);
  background: rgba(255, 255, 255, 0.04);
  color: var(--c-muted);
  backdrop-filter: var(--glass-blur);
  transition: all var(--t-base);
}
.social-link:hover {
  color: #fff;
  background: var(--grad-primary);
  border-color: transparent;
  transform: translateY(-3px);
  box-shadow: var(--sh-glow);
}
.social-link svg { width: 19px; height: 19px; }

.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: var(--s-5);
  transform: translateX(-50%);
  display: grid;
  place-items: center;
  gap: var(--s-2);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--c-dim);
}
.scroll-cue__line {
  width: 1px; height: 40px;
  background: linear-gradient(180deg, var(--c-accent), transparent);
  animation: cue 2.2s ease-in-out infinite;
}
@keyframes cue { 0%,100% { opacity: 0.25; transform: scaleY(0.55); } 50% { opacity: 1; transform: scaleY(1); } }
@media (max-width: 767.98px) { .scroll-cue { display: none; } }

/* Page hero for interior pages */
.page-hero {
  position: relative;
  padding-top: calc(var(--header-h) + clamp(2.5rem, 7vw, 5rem));
  padding-bottom: clamp(2.5rem, 6vw, 4rem);
  border-bottom: 1px solid var(--c-border-soft);
  overflow: hidden;
}
.page-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(900px 380px at 20% 0%, rgba(255, 255, 255, 0.102), transparent 65%);
}
.page-hero h1 { margin-bottom: var(--s-3); }
.page-hero p  { color: var(--c-muted); max-width: 62ch; margin: 0; font-size: var(--fs-lg); }

/* --------------------------------------------------------------------------
   10. BREADCRUMBS
   -------------------------------------------------------------------------- */
.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  list-style: none;
  margin: 0 0 var(--s-5);
  padding: 0;
  font-size: var(--fs-xs);
  color: var(--c-dim);
}
.breadcrumbs li { margin: 0; display: flex; align-items: center; gap: var(--s-2); }
.breadcrumbs li + li::before { content: '/'; color: var(--c-dim); opacity: 0.5; }
.breadcrumbs a { color: var(--c-muted); }
.breadcrumbs a:hover { color: var(--c-accent-2); }
.breadcrumbs [aria-current="page"] { color: var(--c-text); }

/* --------------------------------------------------------------------------
   11. FORMS
   -------------------------------------------------------------------------- */
.form-group,
.field { margin-bottom: var(--s-4); }

.form-label,
.field label {
  display: block;
  margin-bottom: var(--s-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--c-text);
}
.form-label .req,
.field label .req { color: var(--c-accent); margin-left: 2px; }

.form-control,
.form-select,
input[type="text"], input[type="email"], input[type="password"], input[type="tel"],
input[type="number"], input[type="url"], input[type="search"], input[type="date"],
input[type="time"], input[type="datetime-local"], select, textarea {
  display: block;
  width: 100%;
  min-height: 48px;
  padding: 0.7rem 1rem;
  font-family: var(--font-body);
  font-size: var(--fs-base);  /* 16px stops iOS zooming on focus */
  line-height: 1.4;
  color: var(--c-text);
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  transition: border-color var(--t-fast), box-shadow var(--t-fast), background-color var(--t-fast);
  appearance: none;
}
textarea { min-height: 130px; resize: vertical; }

.form-control:focus,
.form-select:focus,
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--c-primary-soft);
  background: rgba(255, 255, 255, 0.06);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.132);
}

::placeholder { color: var(--c-dim); opacity: 1; }

select,
.form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23A3A3A3'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.9rem center;
  background-size: 15px;
  padding-right: 2.5rem;
}
select option { background: var(--c-bg-2); color: var(--c-text); }

.form-control.is-invalid,
.field.has-error .form-control,
input.is-invalid, select.is-invalid, textarea.is-invalid {
  border-color: var(--c-error);
}
.form-control.is-invalid:focus,
input.is-invalid:focus { box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.22); }

.field-error,
.invalid-feedback {
  display: block;
  margin-top: var(--s-2);
  font-size: var(--fs-sm);
  color: #FCA5A5;
}
.field-hint,
.form-text {
  display: block;
  margin-top: var(--s-2);
  font-size: var(--fs-sm);
  color: var(--c-dim);
}

/* Checkboxes & radios with a 44px touch target */
.check {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  min-height: 44px;
  padding: var(--s-2) 0;
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--c-muted);
  line-height: 1.5;
}
.check input[type="checkbox"],
.check input[type="radio"] {
  flex-shrink: 0;
  width: 20px; height: 20px;
  min-height: 20px;
  margin: 2px 0 0;
  padding: 0;
  accent-color: var(--c-primary);
  cursor: pointer;
}
.check a { text-decoration: underline; text-underline-offset: 2px; }

.form-row {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 640px) {
  .form-row--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .form-row--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .form-row--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 900px) {
  .form-row--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.input-group { display: flex; gap: var(--s-2); }
.input-group .form-control { flex: 1; }

/* Quantity stepper */
.qty {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--c-border);
  border-radius: var(--r-pill);
  overflow: hidden;
  background: rgba(255, 255, 255, 0.035);
}
.qty button {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  background: none;
  border: 0;
  color: var(--c-text);
  font-size: 1.1rem;
  cursor: pointer;
  transition: background-color var(--t-fast);
}
.qty button:hover:not(:disabled) { background: rgba(255, 255, 255, 0.08); }
.qty button:disabled { opacity: 0.35; cursor: not-allowed; }
.qty input {
  width: 52px;
  min-height: 44px;
  text-align: center;
  border: 0;
  background: none;
  color: var(--c-text);
  font-weight: var(--fw-semi);
  padding: 0;
  border-radius: 0;
  -moz-appearance: textfield;
}
.qty input::-webkit-outer-spin-button,
.qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty input:focus { box-shadow: none; background: none; }

/* Option pills (size / color selection) */
.option-set { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.option-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-width: 52px;
  min-height: 44px;
  padding: 0.5rem 1rem;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.03);
  color: var(--c-text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  cursor: pointer;
  transition: all var(--t-fast);
}
.option-pill:hover:not(.is-disabled) { border-color: var(--c-primary-soft); background: rgba(255, 255, 255, 0.072); }
.option-pill.is-selected {
  border-color: var(--c-primary);
  background: rgba(255, 255, 255, 0.144);
  box-shadow: 0 0 0 1px var(--c-primary);
}
.option-pill.is-disabled {
  opacity: 0.35;
  cursor: not-allowed;
  text-decoration: line-through;
}
.option-pill__swatch {
  width: 18px; height: 18px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   12. ALERTS, BADGES, TOASTS
   -------------------------------------------------------------------------- */
.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-radius: var(--r-md);
  border: 1px solid var(--c-border);
  background: var(--c-card);
  color: var(--c-text);
  font-size: var(--fs-sm);
  margin-bottom: var(--s-4);
  line-height: 1.55;
}
.alert__icon { flex-shrink: 0; margin-top: 1px; }
.alert__body { flex: 1; min-width: 0; }
.alert a { color: inherit; text-decoration: underline; }

.alert-success { border-color: rgba(34, 197, 94, 0.4);  background: rgba(34, 197, 94, 0.10);  color: #BBF7D0; }
.alert-error,
.alert-danger  { border-color: rgba(239, 68, 68, 0.4);  background: rgba(239, 68, 68, 0.10);  color: #FECACA; }
.alert-warning { border-color: rgba(245, 158, 11, 0.4); background: rgba(245, 158, 11, 0.10); color: #FDE68A; }
.alert-info    { border-color: rgba(255, 122, 69, 0.40); background: rgba(255, 122, 69, 0.10); color: #DCDCDC; }

.badge,
.s-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: 0.3rem 0.7rem;
  font-size: 11px;
  font-weight: var(--fw-semi);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-radius: var(--r-pill);
  border: 1px solid var(--c-border);
  background: rgba(255, 255, 255, 0.06);
  color: var(--c-muted);
  line-height: 1.35;
  white-space: nowrap;
}
.badge-primary { background: rgba(255, 255, 255, 0.132); border-color: rgba(255, 255, 255, 0.27); color: #FFFFFF; }
.badge-success { background: rgba(34, 197, 94, 0.18);  border-color: rgba(34,197,94,0.42);  color: #BBF7D0; }
.badge-warning { background: rgba(255, 255, 255, 0.12); border-color: rgba(255,255,255,0.30); color: #FFFFFF; }
.badge-danger  { background: rgba(239, 68, 68, 0.18);  border-color: rgba(239,68,68,0.42);  color: #FECACA; }
.badge-info    { background: rgba(255, 255, 255, 0.08); border-color: rgba(255,255,255,0.22); color: #E4E4E4; }
.badge-muted   { background: rgba(255,255,255,0.06);   border-color: var(--c-border);       color: var(--c-muted); }
.badge-sale    { background: var(--c-accent); border-color: transparent; color: #0A0A0A; }

.badge-float {
  position: absolute;
  top: var(--s-3);
  left: var(--s-3);
  z-index: 2;
}
.badge-float--right { left: auto; right: var(--s-3); }

/* Toasts */
.toast-stack {
  position: fixed;
  right: var(--s-4);
  bottom: var(--s-4);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  max-width: min(380px, calc(100vw - 2rem));
  pointer-events: none;
}
.toast-item {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-4);
  border-radius: var(--r-md);
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--c-border-strong);
  box-shadow: var(--sh-lg);
  color: var(--c-text);
  font-size: var(--fs-sm);
  pointer-events: auto;
  animation: toastIn var(--t-base) ease-out;
}
.toast-item--success { border-left: 3px solid var(--c-success); }
.toast-item--error   { border-left: 3px solid var(--c-error); }
.toast-item--info    { border-left: 3px solid var(--c-info); }
.toast-item.is-leaving { animation: toastOut var(--t-base) forwards; }

@keyframes toastIn  { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes toastOut { to   { opacity: 0; transform: translateY(14px); } }

@media (max-width: 575.98px) {
  .toast-stack { left: var(--s-3); right: var(--s-3); bottom: var(--s-3); max-width: none; }
}

/* --------------------------------------------------------------------------
   13. MUSIC COMPONENTS
   -------------------------------------------------------------------------- */
.track-row {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid transparent;
  transition: background-color var(--t-fast), border-color var(--t-fast);
}
.track-row:hover { background: rgba(255, 255, 255, 0.04); border-color: var(--c-border); }
.track-row__index {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--c-dim);
  text-align: center;
}
.track-row__art {
  width: 52px; height: 52px;
  border-radius: var(--r-xs);
  object-fit: cover;
  flex-shrink: 0;
}
.track-row__main { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }
.track-row__title {
  font-weight: var(--fw-semi);
  color: var(--c-text);
  margin: 0;
  font-size: var(--fs-base);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.track-row__sub {
  font-size: var(--fs-sm);
  color: var(--c-muted);
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.track-row__actions { display: flex; align-items: center; gap: var(--s-2); }
.track-row__time { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--c-dim); }

@media (max-width: 575.98px) {
  .track-row { grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-3); padding: var(--s-2); }
  .track-row__index { display: none; }
  .track-row__time  { display: none; }
}

.play-btn {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 0;
  background: var(--grad-primary);
  color: #fff;
  cursor: pointer;
  flex-shrink: 0;
  box-shadow: var(--sh-glow);
  transition: transform var(--t-fast), box-shadow var(--t-base);
}
.play-btn:hover { transform: scale(1.08); }
.play-btn svg { width: 16px; height: 16px; margin-left: 2px; }

.play-btn--overlay {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(0.85);
  opacity: 0;
  transition: opacity var(--t-base), transform var(--t-base);
  z-index: 3;
}
.s-card:hover .play-btn--overlay,
.media-thumb:hover .play-btn--overlay {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* Audio player for authorized preview uploads */
.audio-player {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-4);
  border-radius: var(--r-lg);
  background: var(--c-card);
  border: 1px solid var(--c-border);
}
.audio-player__art {
  width: 64px; height: 64px;
  border-radius: var(--r-sm);
  object-fit: cover;
  flex-shrink: 0;
}
.audio-player__body { flex: 1; min-width: 0; }
.audio-player__title { font-weight: var(--fw-semi); margin: 0 0 var(--s-1); }
.audio-player__meta  { font-size: var(--fs-xs); color: var(--c-dim); margin: 0 0 var(--s-3); }

.audio-progress {
  position: relative;
  height: 6px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.10);
  cursor: pointer;
  overflow: hidden;
}
.audio-progress__bar {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  border-radius: var(--r-pill);
  background: var(--grad-primary);
  transition: width 100ms linear;
}
.audio-times {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--c-dim);
  margin-top: var(--s-2);
}

@media (max-width: 480px) {
  .audio-player { flex-direction: column; align-items: stretch; text-align: left; }
  .audio-player__art { width: 100%; height: 180px; }
}

/* Spotify embeds */
.spotify-embed {
  position: relative;
  width: 100%;
  border-radius: 12px;
  overflow: hidden;
  background: var(--c-bg-2);
  min-height: var(--embed-height, 152px);
}
.spotify-embed iframe {
  display: block;
  width: 100%;
  height: var(--embed-height, 152px);
  border: 0;
  border-radius: 12px;
}
.spotify-embed--lazy {
  display: grid;
  place-items: center;
  border: 1px solid var(--c-border);
  background:
    radial-gradient(circle at 30% 20%, rgba(29, 185, 84, 0.16), transparent 60%),
    var(--c-card);
}
.spotify-embed__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  padding: 0.75rem 1.4rem;
  min-height: 46px;
  border: 0;
  border-radius: var(--r-pill);
  background: #1DB954;
  color: #fff;
  font-weight: var(--fw-semi);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: transform var(--t-fast), background-color var(--t-fast);
}
.spotify-embed__trigger:hover { background: #1ED760; transform: translateY(-2px); }
.spotify-embed__icon { display: grid; place-items: center; }

/* Video embeds */
.video-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #000;
}
.video-embed iframe,
.video-embed video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.video-card__play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(7, 7, 7, 0.28);
  transition: background-color var(--t-base);
  z-index: 2;
  border: 0;
  width: 100%;
  cursor: pointer;
}
.video-card__play:hover { background: rgba(7, 7, 7, 0.12); }
.video-card__play span {
  width: 62px; height: 62px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--grad-primary);
  box-shadow: var(--sh-glow);
  color: #fff;
  transition: transform var(--t-base);
}
.video-card__play:hover span { transform: scale(1.1); }
.video-card__duration {
  position: absolute;
  right: var(--s-3);
  bottom: var(--s-3);
  z-index: 3;
  padding: 0.2rem 0.5rem;
  border-radius: var(--r-xs);
  background: rgba(7, 7, 7, 0.82);
  font-family: var(--font-mono);
  font-size: 11px;
  color: #fff;
}

/* --------------------------------------------------------------------------
   14. PRODUCT COMPONENTS
   -------------------------------------------------------------------------- */
.product-card { display: flex; flex-direction: column; height: 100%; }
.product-card__body {
  padding: var(--s-4);
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  flex: 1;
}
.product-card__cat {
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-dim);
}
.product-card__name {
  font-family: var(--font-display);
  font-size: var(--fs-base);
  font-weight: var(--fw-semi);
  line-height: var(--lh-snug);
  margin: 0;
  color: var(--c-text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.product-card__foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  padding-top: var(--s-2);
  flex-wrap: wrap;
}

.price { display: inline-flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap; }
.price__now {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  color: var(--c-text);
}
.price__was {
  font-size: var(--fs-sm);
  color: var(--c-dim);
  text-decoration: line-through;
}
.price__tax { font-size: 11px; color: var(--c-dim); }
.price--lg .price__now { font-size: clamp(1.6rem, 3.5vw, 2.1rem); }

.wish-btn {
  position: absolute;
  top: var(--s-3);
  right: var(--s-3);
  z-index: 3;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--c-border);
  background: rgba(7, 7, 7, 0.68);
  backdrop-filter: blur(8px);
  color: var(--c-muted);
  cursor: pointer;
  transition: all var(--t-fast);
}
.wish-btn:hover { color: var(--c-accent); border-color: var(--c-accent); transform: scale(1.08); }
.wish-btn.is-active { color: var(--c-accent); border-color: var(--c-accent); background: rgba(255, 255, 255, 0.12); }
.wish-btn.is-active svg { fill: currentColor; }

.stock-note { font-size: var(--fs-xs); display: inline-flex; align-items: center; gap: var(--s-2); }
.stock-note::before {
  content: '';
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.stock-note--in    { color: var(--c-success); }
.stock-note--low   { color: var(--c-warning); }
.stock-note--out   { color: var(--c-error); }

/* Product gallery */
.product-gallery { display: grid; gap: var(--s-3); }
.product-gallery__main {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--c-bg-2);
  border: 1px solid var(--c-border);
  cursor: zoom-in;
}
.product-gallery__main img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--t-slow);
}
.product-gallery__main.is-zoomed img { transform: scale(1.9); cursor: zoom-out; }

.product-gallery__thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: var(--s-2);
}
.product-gallery__thumb {
  aspect-ratio: 1 / 1;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 2px solid transparent;
  background: var(--c-bg-2);
  cursor: pointer;
  padding: 0;
  transition: border-color var(--t-fast);
}
.product-gallery__thumb img { width: 100%; height: 100%; object-fit: cover; }
.product-gallery__thumb.is-active { border-color: var(--c-primary); }

/* Ratings */
.stars { display: inline-flex; gap: 2px; color: #FFFFFF; }
.stars svg { width: 15px; height: 15px; }
.stars--muted { color: var(--c-dim); }
.rating-bar {
  height: 7px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.09);
  overflow: hidden;
}
.rating-bar__fill { height: 100%; background: rgba(255,255,255,0.85); border-radius: var(--r-pill); }

/* --------------------------------------------------------------------------
   15. SHOP LAYOUT & FILTERS
   -------------------------------------------------------------------------- */
.shop-layout {
  display: grid;
  gap: var(--s-6);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 992px) {
  .shop-layout { grid-template-columns: 268px minmax(0, 1fr); gap: var(--s-7); }
}

.filter-panel {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  padding: var(--s-5);
}
@media (min-width: 992px) {
  .filter-panel { position: sticky; top: calc(var(--header-h) + var(--s-4)); max-height: calc(100vh - var(--header-h) - 2rem); overflow-y: auto; }
}

.filter-group { padding-block: var(--s-4); border-bottom: 1px solid var(--c-border-soft); }
.filter-group:first-child { padding-top: 0; }
.filter-group:last-child  { border-bottom: 0; padding-bottom: 0; }
.filter-group__title {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--c-dim);
  margin-bottom: var(--s-3);
}
.filter-list { list-style: none; margin: 0; padding: 0; }
.filter-list li { margin: 0; }
.filter-list a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  min-height: 40px;
  padding: var(--s-2) 0;
  font-size: var(--fs-sm);
  color: var(--c-muted);
}
.filter-list a:hover { color: var(--c-text); }
.filter-list a.is-active { color: var(--c-accent); font-weight: var(--fw-medium); }
.filter-list .count { font-size: 11px; color: var(--c-dim); }

.filter-chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 38px;
  padding: 0.35rem 0.85rem;
  border-radius: var(--r-pill);
  border: 1px solid var(--c-border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--c-muted);
  font-size: var(--fs-sm);
  transition: all var(--t-fast);
  cursor: pointer;
}
.chip:hover { color: var(--c-text); border-color: var(--c-border-strong); }
.chip.is-active { background: rgba(255, 255, 255, 0.132); border-color: var(--c-primary); color: #FFFFFF; }
.chip__remove { font-size: 1rem; line-height: 1; opacity: 0.7; }

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin-bottom: var(--s-5);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--c-border-soft);
}
.toolbar__count { font-size: var(--fs-sm); color: var(--c-muted); }
.toolbar__actions { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.toolbar select { min-width: 170px; min-height: 44px; }

.filter-toggle { display: inline-flex; }
@media (min-width: 992px) { .filter-toggle { display: none; } }

/* Mobile filter drawer */
.filter-drawer {
  position: fixed;
  inset: auto 0 0 0;
  z-index: var(--z-drawer);
  max-height: 88vh;
  background: var(--c-bg-2);
  border-top: 1px solid var(--c-border);
  border-radius: var(--r-2xl) var(--r-2xl) 0 0;
  box-shadow: var(--sh-xl);
  transform: translateY(100%);
  transition: transform var(--t-slow);
  display: flex;
  flex-direction: column;
}
.filter-drawer.is-open { transform: none; }
.filter-drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--c-border);
}
.filter-drawer__body { flex: 1; overflow-y: auto; padding: var(--s-4) var(--s-5); }
.filter-drawer__foot {
  padding: var(--s-4) var(--s-5);
  border-top: 1px solid var(--c-border);
  display: flex;
  gap: var(--s-3);
  padding-bottom: max(var(--s-4), env(safe-area-inset-bottom));
}
@media (min-width: 992px) { .filter-drawer { display: none; } }

/* --------------------------------------------------------------------------
   16. CART & CHECKOUT
   -------------------------------------------------------------------------- */
.cart-layout {
  display: grid;
  gap: var(--s-6);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 992px) {
  .cart-layout { grid-template-columns: minmax(0, 1fr) 380px; gap: var(--s-7); }
}

.cart-line {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: var(--s-4);
  padding: var(--s-4) 0;
  border-bottom: 1px solid var(--c-border-soft);
}
.cart-line:last-child { border-bottom: 0; }
.cart-line__img {
  width: 96px; height: 96px;
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--c-bg-2);
}
.cart-line__body {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  justify-content: space-between;
  align-items: flex-start;
}
.cart-line__info { min-width: 0; flex: 1 1 200px; }
.cart-line__name { font-weight: var(--fw-semi); margin: 0 0 var(--s-1); font-size: var(--fs-base); }
.cart-line__variant { font-size: var(--fs-sm); color: var(--c-muted); margin: 0 0 var(--s-2); }
.cart-line__controls { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.cart-line__total { font-family: var(--font-display); font-weight: var(--fw-bold); font-size: var(--fs-lg); white-space: nowrap; }

@media (max-width: 575.98px) {
  .cart-line { grid-template-columns: 76px minmax(0, 1fr); gap: var(--s-3); }
  .cart-line__img { width: 76px; height: 76px; }
}

.summary-card {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  padding: var(--s-5);
}
@media (min-width: 992px) {
  .summary-card { position: sticky; top: calc(var(--header-h) + var(--s-4)); }
}

.summary-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  padding-block: var(--s-2);
  font-size: var(--fs-sm);
  color: var(--c-muted);
}
.summary-row span:last-child { color: var(--c-text); font-weight: var(--fw-medium); white-space: nowrap; }
.summary-row--discount span:last-child { color: var(--c-success); }
.summary-row--total {
  margin-top: var(--s-3);
  padding-top: var(--s-4);
  border-top: 1px solid var(--c-border);
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  color: var(--c-text);
}
.summary-row--total span:last-child { font-size: var(--fs-2xl); }

.free-ship-meter { margin-bottom: var(--s-4); }
.free-ship-meter__track {
  height: 6px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.09);
  overflow: hidden;
  margin-top: var(--s-2);
}
.free-ship-meter__fill {
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--grad-primary);
  transition: width var(--t-slow);
}

.checkout-layout {
  display: grid;
  gap: var(--s-6);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 992px) {
  .checkout-layout { grid-template-columns: minmax(0, 1fr) 400px; gap: var(--s-8); }
}

.checkout-section {
  padding-bottom: var(--s-6);
  margin-bottom: var(--s-6);
  border-bottom: 1px solid var(--c-border-soft);
}
.checkout-section:last-child { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }
.checkout-section__title {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  margin-bottom: var(--s-5);
}
.checkout-section__num {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--grad-primary);
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  flex-shrink: 0;
}

.ship-option {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  cursor: pointer;
  margin-bottom: var(--s-3);
  transition: all var(--t-fast);
  min-height: 44px;
}
.ship-option:hover { border-color: var(--c-border-strong); background: rgba(255,255,255,0.03); }
.ship-option.is-selected { border-color: var(--c-primary); background: rgba(255, 255, 255, 0.06); }
.ship-option input { margin-top: 3px; flex-shrink: 0; accent-color: var(--c-primary); width: 20px; height: 20px; }
.ship-option__body { flex: 1; min-width: 0; }
.ship-option__name { font-weight: var(--fw-semi); font-size: var(--fs-sm); margin: 0 0 2px; }
.ship-option__desc { font-size: var(--fs-xs); color: var(--c-muted); margin: 0; }
.ship-option__price { font-weight: var(--fw-bold); white-space: nowrap; }

/* Sticky mobile action bar */
.sticky-actions {
  position: sticky;
  bottom: 0;
  z-index: 20;
  margin: var(--s-5) calc(var(--s-4) * -1) 0;
  padding: var(--s-3) var(--s-4);
  padding-bottom: max(var(--s-3), env(safe-area-inset-bottom));
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--c-border);
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.sticky-actions .btn { flex: 1; }
@media (min-width: 992px) { .sticky-actions { display: none; } }

.trust-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  align-items: center;
  justify-content: center;
  padding-top: var(--s-4);
  margin-top: var(--s-4);
  border-top: 1px solid var(--c-border-soft);
  font-size: var(--fs-xs);
  color: var(--c-dim);
}
.trust-row span { display: inline-flex; align-items: center; gap: var(--s-2); }

/* --------------------------------------------------------------------------
   17. MEMBERSHIP
   -------------------------------------------------------------------------- */
.plan-grid {
  display: grid;
  gap: var(--s-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  align-items: stretch;
}

.plan-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--s-6);
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-xl);
  transition: transform var(--t-base), border-color var(--t-base), box-shadow var(--t-base);
}
.plan-card:hover { transform: translateY(-5px); border-color: var(--c-border-strong); box-shadow: var(--sh-lg); }
.plan-card--featured {
  border-color: transparent;
  background:
    linear-gradient(var(--c-card), var(--c-card)) padding-box,
    var(--grad-primary) border-box;
  border: 1px solid transparent;
  box-shadow: var(--sh-glow);
}
.plan-card__flag {
  position: absolute;
  top: -13px;
  left: 50%;
  transform: translateX(-50%);
  padding: 0.32rem 1rem;
  border-radius: var(--r-pill);
  background: var(--grad-primary);
  color: #fff;
  font-size: 11px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  white-space: nowrap;
}
.plan-card__name { font-family: var(--font-display); font-size: var(--fs-xl); margin: 0 0 var(--s-2); }
.plan-card__tagline { font-size: var(--fs-sm); color: var(--c-muted); margin: 0 0 var(--s-5); }
.plan-card__price { display: flex; align-items: baseline; gap: var(--s-2); margin-bottom: var(--s-1); }
.plan-card__amount { font-family: var(--font-display); font-size: clamp(2.2rem, 5.5vw, 3rem); font-weight: var(--fw-bold); line-height: 1; }
.plan-card__period { color: var(--c-muted); font-size: var(--fs-sm); }
.plan-card__save { font-size: var(--fs-xs); color: var(--c-success); margin-bottom: var(--s-5); min-height: 1.2em; }
.plan-card__benefits { list-style: none; margin: 0 0 var(--s-6); padding: 0; flex: 1; }
.plan-card__benefits li {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding-block: var(--s-2);
  font-size: var(--fs-sm);
  color: var(--c-muted);
  margin: 0;
  line-height: 1.5;
}
.plan-card__benefits svg { flex-shrink: 0; margin-top: 3px; color: var(--c-success); width: 16px; height: 16px; }

.billing-toggle {
  display: inline-flex;
  padding: 4px;
  border-radius: var(--r-pill);
  background: var(--c-card);
  border: 1px solid var(--c-border);
  margin-bottom: var(--s-7);
}
.billing-toggle button {
  min-height: 42px;
  padding: 0.5rem 1.4rem;
  border: 0;
  border-radius: var(--r-pill);
  background: none;
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
  cursor: pointer;
  transition: all var(--t-base);
  white-space: nowrap;
}
.billing-toggle button.is-active {
  background: var(--grad-primary);
  color: #fff;
  box-shadow: var(--sh-glow);
}

/* A locked card has to sell the thing it is hiding.
   The veil covers the ARTWORK ONLY. Covering the whole card — which is what an
   `inset: 0` veil does — blurred the title and the excerpt too, turning the
   grid into six identical grey boxes and removing the only thing that actually
   persuades anyone to subscribe: knowing what is behind the lock. The art is
   obscured, the words stay crisp. */
.locked-card { position: relative; overflow: hidden; }

.locked-card__art { position: relative; overflow: hidden; }
.locked-card__art img {
  filter: blur(7px) saturate(0.55) brightness(0.5);
  transform: scale(1.12);       /* hides the soft edge blur leaves behind */
}
.locked-card__seal {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--s-2);
  background: linear-gradient(180deg, rgba(6, 5, 4, 0.35), rgba(6, 5, 4, 0.72));
}
/* The lock sits on its own glass disc so it reads as hardware on the artwork
   rather than an icon floating in a smudge. */
.locked-card__seal-disc {
  display: grid;
  place-items: center;
  width: 52px; height: 52px;
  border-radius: 50%;
  background: linear-gradient(160deg, rgba(255,255,255,0.16), rgba(255,255,255,0.05));
  border: 1px solid rgba(255, 255, 255, 0.24);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.30), 0 10px 24px -10px rgba(0,0,0,0.9);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.locked-card__seal-disc svg { width: 22px; height: 22px; color: var(--c-text); }
.locked-card__seal-label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-text);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.8);
  margin: 0;
}
/* The whole card is the target, so the grid needs no row of repeated buttons —
   six identical CTAs was the single cheapest-looking thing on the page. */
.locked-card--link { cursor: pointer; transition: transform var(--t-base), border-color var(--t-base), box-shadow var(--t-base); }
.locked-card--link:hover { transform: translateY(-4px); }
.locked-card--link:hover .locked-card__art img { filter: blur(5px) saturate(0.7) brightness(0.62); }
.locked-card--link:hover .locked-card__seal-disc { border-color: rgba(255,255,255,0.42); }
.locked-card > .locked-card__link { position: absolute; inset: 0; z-index: 5; }
.locked-card__link span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

@media (max-width: 700px) {
  .locked-card__seal-disc { backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* --------------------------------------------------------------------------
   18. TABLES
   -------------------------------------------------------------------------- */
.table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--r-lg);
  border: 1px solid var(--c-border);
  background: var(--c-card);
}
.s-table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.s-table th,
.s-table td {
  padding: var(--s-3) var(--s-4);
  text-align: left;
  vertical-align: middle;
  border-bottom: 1px solid var(--c-border-soft);
}
.s-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--c-bg-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-dim);
  white-space: nowrap;
}
.s-table tbody tr { transition: background-color var(--t-fast); }
.s-table tbody tr:hover { background: rgba(255, 255, 255, 0.028); }
.s-table tbody tr:last-child td { border-bottom: 0; }
.s-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Card-style rows on small screens */
@media (max-width: 767.98px) {
  .table-cards .s-table { min-width: 0; }
  .table-cards thead { display: none; }
  .table-cards tbody tr {
    display: block;
    padding: var(--s-4);
    border-bottom: 1px solid var(--c-border);
  }
  .table-cards tbody td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s-4);
    padding: var(--s-2) 0;
    border: 0;
    text-align: right;
  }
  .table-cards tbody td::before {
    content: attr(data-label);
    flex-shrink: 0;
    font-size: var(--fs-xs);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--c-dim);
    text-align: left;
  }
  .table-cards tbody td:first-child { padding-top: 0; }
  .table-cards tbody td.td-full {
    display: block;
    text-align: left;
    padding-bottom: var(--s-3);
  }
  .table-cards tbody td.td-full::before { display: block; margin-bottom: var(--s-1); }
}

/* --------------------------------------------------------------------------
   19. PAGINATION
   -------------------------------------------------------------------------- */
.pagination-nav { margin-top: var(--s-7); }
.pagination {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-2);
  list-style: none;
  margin: 0;
  padding: 0;
}
.pagination li { margin: 0; }
.page-link {
  display: grid;
  place-items: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--s-2);
  border-radius: var(--r-sm);
  border: 1px solid var(--c-border);
  background: var(--c-card);
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  transition: all var(--t-fast);
}
a.page-link:hover { color: var(--c-text); border-color: var(--c-border-strong); background: var(--c-card-hover); }
.page-item.active .page-link {
  background: var(--grad-primary);
  border-color: transparent;
  color: #fff;
  box-shadow: var(--sh-glow);
}
.page-item.disabled .page-link { opacity: 0.35; cursor: not-allowed; }

/* --------------------------------------------------------------------------
   20. MODALS & LIGHTBOX
   -------------------------------------------------------------------------- */
.s-modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: var(--s-4);
  background: rgba(7, 7, 7, 0.90);
  backdrop-filter: blur(10px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-base), visibility var(--t-base);
}
.s-modal.is-open { opacity: 1; visibility: visible; }
.s-modal__panel {
  position: relative;
  width: 100%;
  max-width: 800px;
  max-height: 90vh;
  overflow-y: auto;
  background: var(--c-card);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-xl);
  transform: translateY(16px) scale(0.985);
  transition: transform var(--t-base);
}
.s-modal.is-open .s-modal__panel { transform: none; }
.s-modal__panel--wide  { max-width: 1100px; }
.s-modal__panel--plain { background: transparent; border: 0; box-shadow: none; max-width: min(1200px, 94vw); overflow: visible; }
.s-modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-5);
  border-bottom: 1px solid var(--c-border);
}
.s-modal__body { padding: var(--s-5); }
.s-modal__close {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--c-border);
  background: rgba(255, 255, 255, 0.05);
  color: var(--c-text);
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color var(--t-fast);
}
.s-modal__close:hover { background: rgba(255, 255, 255, 0.12); }

.lightbox__figure { margin: 0; text-align: center; }
.lightbox__figure img {
  max-height: 78vh;
  width: auto;
  margin-inline: auto;
  border-radius: var(--r-md);
  box-shadow: var(--sh-xl);
}
.lightbox__caption {
  margin-top: var(--s-4);
  color: var(--c-muted);
  font-size: var(--fs-sm);
}
.lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 52px; height: 52px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--c-border-strong);
  background: rgba(7, 7, 7, 0.72);
  backdrop-filter: blur(8px);
  color: #fff;
  cursor: pointer;
  z-index: 5;
}
.lightbox__nav:hover { background: rgba(7, 7, 7, 0.95); }
.lightbox__nav--prev { left: -8px; }
.lightbox__nav--next { right: -8px; }
@media (max-width: 767.98px) {
  .lightbox__nav { width: 44px; height: 44px; }
  .lightbox__nav--prev { left: 4px; }
  .lightbox__nav--next { right: 4px; }
}

/* --------------------------------------------------------------------------
   21. TIMELINE, STATS, MISC
   -------------------------------------------------------------------------- */
.timeline { position: relative; padding-left: var(--s-6); }
.timeline::before {
  content: '';
  position: absolute;
  left: 7px; top: 8px; bottom: 8px;
  width: 2px;
  background: linear-gradient(180deg, var(--c-primary), var(--c-accent), transparent);
  border-radius: var(--r-pill);
}
.timeline__item { position: relative; padding-bottom: var(--s-6); }
.timeline__item:last-child { padding-bottom: 0; }
.timeline__item::before {
  content: '';
  position: absolute;
  left: calc(var(--s-6) * -1 + 1px);
  top: 7px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--c-bg);
  border: 3px solid var(--c-primary);
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.084);
}
.timeline__year {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  color: var(--c-accent-2);
  margin-bottom: var(--s-1);
}
.timeline__title { font-family: var(--font-display); font-size: var(--fs-lg); margin: 0 0 var(--s-1); }
.timeline__text { color: var(--c-muted); font-size: var(--fs-sm); margin: 0; }

.stat-grid {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
}
.stat-card {
  padding: var(--s-5);
  border-radius: var(--r-lg);
  background: var(--c-card);
  border: 1px solid var(--c-border);
}
.stat-card__label {
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--c-dim);
  margin-bottom: var(--s-2);
}
.stat-card__value {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 3.4vw, 2rem);
  font-weight: var(--fw-bold);
  line-height: 1.1;
  margin: 0;
}
.stat-card__meta { font-size: var(--fs-xs); color: var(--c-muted); margin-top: var(--s-2); }

.empty-state {
  padding: clamp(var(--s-7), 9vw, var(--s-10)) var(--s-5);
  text-align: center;
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--r-xl);
  background: rgba(255, 255, 255, 0.015);
}
.empty-state__icon {
  width: 62px; height: 62px;
  margin: 0 auto var(--s-4);
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.084);
  color: var(--c-primary-soft);
}
.empty-state h3 { margin-bottom: var(--s-2); }
.empty-state p  { color: var(--c-muted); max-width: 44ch; margin-inline: auto; margin-bottom: var(--s-5); }

.divider-glow {
  height: 1px;
  border: 0;
  background: var(--grad-line);
  opacity: 0.55;
  margin: 0;
}

.countdown { display: flex; gap: var(--s-3); flex-wrap: wrap; }
.countdown__unit {
  min-width: 74px;
  padding: var(--s-3);
  text-align: center;
  border-radius: var(--r-md);
  background: var(--c-card);
  border: 1px solid var(--c-border);
}
.countdown__num {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 3.6vw, 1.9rem);
  font-weight: var(--fw-bold);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.countdown__label {
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-dim);
  margin-top: var(--s-1);
}

/* Event rows */
.event-row {
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr) auto;
  gap: var(--s-4);
  align-items: center;
  padding: var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--c-border);
  background: var(--c-card);
  margin-bottom: var(--s-3);
  transition: border-color var(--t-base), transform var(--t-base);
}
.event-row:hover { border-color: var(--c-border-strong); transform: translateX(3px); }
.event-row__date {
  text-align: center;
  padding: var(--s-2);
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.084);
  border: 1px solid rgba(255, 255, 255, 0.168);
}
.event-row__day   { font-family: var(--font-display); font-size: var(--fs-xl); font-weight: var(--fw-bold); line-height: 1; }
.event-row__month { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--c-accent-2); margin-top: 2px; }
.event-row__info { min-width: 0; }
.event-row__name { font-family: var(--font-display); font-size: var(--fs-lg); margin: 0 0 var(--s-1); }
.event-row__venue { font-size: var(--fs-sm); color: var(--c-muted); margin: 0; }
.event-row__actions { display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap; justify-content: flex-end; }

@media (max-width: 767.98px) {
  .event-row { grid-template-columns: 64px minmax(0, 1fr); }
  .event-row__actions { grid-column: 1 / -1; justify-content: flex-start; }
  .event-row__actions .btn { flex: 1; min-width: 130px; }
}

/* --------------------------------------------------------------------------
   22. FOOTER
   -------------------------------------------------------------------------- */
.site-footer {
  position: relative;
  z-index: 1;
  margin-top: var(--s-section);
  background: var(--c-bg-2);
  border-top: 1px solid var(--c-border);
  padding-top: var(--s-8);
}

/* A single ember hairline across the top edge. It is the only fire in the
   footer's chrome, which is what keeps the section inside the 10% share the
   brand allows while still marking where the page ends. */
.site-footer::before {
  content: '';
  position: absolute;
  top: -1px; left: 0; right: 0;
  height: 1px;
  background: var(--grad-line);
  opacity: 0.7;
  pointer-events: none;
}
.footer-grid {
  display: grid;
  gap: var(--s-6);
  grid-template-columns: minmax(0, 1fr);
  padding-bottom: var(--s-7);
}
@media (min-width: 640px)  { .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .footer-grid { grid-template-columns: 1.6fr 1fr 1fr 1.4fr; gap: var(--s-7); } }

/* Column headings were set in --c-dim, which sits close enough to the footer
   ground that they read as disabled text rather than as headings. Lifted to
   --c-muted and given a short ember rule, which also gives the four columns a
   shared baseline to hang from. */
.footer-col h4,
.footer-contact h4 {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-muted);
  margin-bottom: var(--s-4);
  padding-bottom: var(--s-2);
  position: relative;
}
.footer-col h4::after,
.footer-contact h4::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 26px; height: 2px;
  border-radius: 2px;
  background: var(--grad-primary);
  opacity: 0.85;
}
.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li { margin: 0; }
.footer-col li a {
  display: block;
  padding: 0.42rem 0;
  font-size: var(--fs-sm);
  color: var(--c-muted);
  min-height: 32px;
}
.footer-col li a:hover { color: var(--c-accent-2); }
.footer-col p { font-size: var(--fs-sm); color: var(--c-muted); }

/* Contact routes, grouped rather than left as loose paragraphs. */
.footer-contact { margin-top: var(--s-6); }
.footer-contact ul { list-style: none; margin: 0; padding: 0; }
.footer-contact li {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: 0.3rem 0;
  font-size: var(--fs-sm);
  color: var(--c-muted);
  min-height: 34px;
}
.footer-contact__icon {
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 1px solid var(--c-border);
  color: var(--c-accent);
}
.footer-contact a { color: var(--c-muted); overflow-wrap: anywhere; }
.footer-contact a:hover { color: var(--c-text); }

/* Reassurance strip. Deliberately quiet — it is a row of facts, not a banner. */
.footer-trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding-block: var(--s-5);
  border-top: 1px solid var(--c-border-soft);
}
.footer-trust__list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-6);
  margin: 0; padding: 0;
  font-size: var(--fs-xs);
  color: var(--c-muted);
}
.footer-trust__list li {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}
.footer-trust__icon { color: var(--c-accent); flex-shrink: 0; display: inline-flex; }
.footer-trust__list a { color: var(--c-muted); text-decoration: underline; text-underline-offset: 2px; }
.footer-trust__list a:hover { color: var(--c-accent); }

.back-to-top {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 0.5rem 0.9rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--c-border);
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-muted);
  flex-shrink: 0;
  transition: color var(--t-fast), border-color var(--t-fast), background-color var(--t-fast);
}
.back-to-top svg { transform: rotate(-90deg); }
.back-to-top:hover {
  color: var(--c-text);
  border-color: var(--c-primary);
  background: rgba(255, 255, 255, 0.06);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding-block: var(--s-5);
  border-top: 1px solid var(--c-border-soft);
  font-size: var(--fs-xs);
  color: var(--c-dim);
}
.footer-bottom a { color: var(--c-muted); }
.footer-bottom a:hover { color: var(--c-accent-2); }
.footer-legal { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); }

.newsletter-form { display: flex; gap: var(--s-2); flex-wrap: wrap; }

/* Scoped to the email field on purpose. `.newsletter-form input` also matched
   the consent checkbox, which then grew to a 190px flex basis and squeezed the
   consent text into a narrow column beside it. */
.newsletter-form input[type="email"] { flex: 1 1 190px; min-width: 0; }

.newsletter-form__consent {
  flex: 1 1 100%;
  align-items: flex-start;
  gap: var(--s-3);
}
.newsletter-form__consent input[type="checkbox"] { flex: 0 0 auto; }
.newsletter-form__consent span { flex: 1 1 auto; min-width: 0; }

@media (max-width: 420px) {
  /* nowrap matters as much as the direction here. The base rule sets
     flex-wrap:wrap for the ROW layout, where it drops the consent line below
     the field and button. Once the direction is column, wrapping no longer
     means "next row" — it means NEXT COLUMN, so the consent label jumps to the
     right of the button and out of the card entirely. */
  .newsletter-form { flex-direction: column; align-items: stretch; flex-wrap: nowrap; }
  .newsletter-form .btn { width: 100%; }
  .newsletter-form__consent { flex-direction: row; }
  /* `flex: 1 1 190px` above is a WIDTH basis written for the row layout. Once
     the form becomes a column that basis applies to the main axis, which is
     now height — giving a 190px-tall email box on every phone, and taller
     still wherever the form can grow. Height goes back to the control size. */
  .newsletter-form input[type="email"] { flex: 0 0 auto; }
}

/* --------------------------------------------------------------------------
   23. COOKIE BANNER
   -------------------------------------------------------------------------- */
.cookie-banner {
  position: fixed;
  left: var(--s-4);
  right: var(--s-4);
  bottom: var(--s-4);
  z-index: var(--z-toast);
  max-width: 760px;
  margin-inline: auto;
  padding: var(--s-5);
  border-radius: var(--r-xl);
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--c-border-strong);
  box-shadow: var(--sh-xl);
  transform: translateY(calc(100% + 2rem));
  transition: transform var(--t-slow);
}
.cookie-banner.is-visible { transform: none; }
.cookie-banner__title { font-family: var(--font-display); font-size: var(--fs-lg); margin: 0 0 var(--s-2); }
.cookie-banner__text  { font-size: var(--fs-sm); color: var(--c-muted); margin: 0 0 var(--s-4); }
.cookie-banner__actions { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.cookie-banner__actions .btn { flex: 1 1 auto; }
@media (max-width: 575.98px) {
  .cookie-banner { left: var(--s-2); right: var(--s-2); bottom: var(--s-2); padding: var(--s-4); }
  .cookie-banner__actions .btn { flex: 1 1 100%; }
}

.consent-toggle {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--c-border);
  margin-bottom: var(--s-3);
}
.consent-toggle__body { flex: 1; min-width: 0; }
.consent-toggle__title { font-weight: var(--fw-semi); font-size: var(--fs-sm); margin: 0 0 var(--s-1); }
.consent-toggle__desc  { font-size: var(--fs-xs); color: var(--c-muted); margin: 0; }

.switch { position: relative; width: 50px; height: 28px; flex-shrink: 0; }
.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; z-index: 2; }
.switch__track {
  position: absolute;
  inset: 0;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.14);
  transition: background-color var(--t-base);
}
.switch__track::after {
  content: '';
  position: absolute;
  top: 3px; left: 3px;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: #fff;
  transition: transform var(--t-base);
}
.switch input:checked ~ .switch__track { background: var(--c-primary); }
.switch input:checked ~ .switch__track::after { transform: translateX(22px); }
.switch input:disabled ~ .switch__track { opacity: 0.5; }
.switch input:focus-visible ~ .switch__track { outline: 2px solid var(--c-accent-2); outline-offset: 2px; }

/* --------------------------------------------------------------------------
   24. AUTH & ACCOUNT
   -------------------------------------------------------------------------- */
.auth-shell {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: calc(var(--header-h) + var(--s-6)) var(--s-4) var(--s-8);
}
.auth-card {
  width: 100%;
  max-width: 460px;
  padding: clamp(var(--s-5), 5vw, var(--s-7));
  border-radius: var(--r-xl);
  background: var(--c-card);
  border: 1px solid var(--c-border);
  box-shadow: var(--sh-lg);
}
.auth-card--wide { max-width: 620px; }
.auth-card__head { text-align: center; margin-bottom: var(--s-6); }
.auth-card__head h1 { font-size: var(--fs-2xl); margin-bottom: var(--s-2); }
.auth-card__head p  { color: var(--c-muted); font-size: var(--fs-sm); margin: 0; }
.auth-foot {
  margin-top: var(--s-5);
  padding-top: var(--s-5);
  border-top: 1px solid var(--c-border-soft);
  text-align: center;
  font-size: var(--fs-sm);
  color: var(--c-muted);
}

.account-layout {
  display: grid;
  gap: var(--s-6);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 992px) {
  .account-layout { grid-template-columns: 250px minmax(0, 1fr); gap: var(--s-7); }
}

.account-nav {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  padding: var(--s-3);
}
@media (min-width: 992px) { .account-nav { position: sticky; top: calc(var(--header-h) + var(--s-4)); } }

.account-nav ul { list-style: none; margin: 0; padding: 0; }
.account-nav li { margin: 0; }
.account-nav a {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 46px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--c-muted);
  transition: all var(--t-fast);
}
.account-nav a:hover { color: var(--c-text); background: rgba(255, 255, 255, 0.05); }
.account-nav a.is-active { color: #fff; background: var(--grad-primary); box-shadow: var(--sh-glow); }
.account-nav svg { width: 17px; height: 17px; flex-shrink: 0; }

@media (max-width: 991.98px) {
  .account-nav ul { display: flex; overflow-x: auto; gap: var(--s-2); padding-bottom: var(--s-1); }
  .account-nav a { white-space: nowrap; }
}

.panel {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  padding: clamp(var(--s-4), 3vw, var(--s-6));
  margin-bottom: var(--s-5);
}
.panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin-bottom: var(--s-5);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--c-border-soft);
}
.panel__title { font-family: var(--font-display); font-size: var(--fs-xl); margin: 0; }

.order-progress {
  display: flex;
  gap: var(--s-2);
  margin-bottom: var(--s-5);
  overflow-x: auto;
  padding-bottom: var(--s-2);
}
.order-progress__step {
  flex: 1;
  min-width: 96px;
  text-align: center;
  font-size: var(--fs-xs);
  color: var(--c-dim);
}
.order-progress__dot {
  width: 100%;
  height: 4px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.10);
  margin-bottom: var(--s-2);
}
.order-progress__step.is-done .order-progress__dot { background: var(--grad-primary); }
.order-progress__step.is-done { color: var(--c-text); }

/* --------------------------------------------------------------------------
   25. UTILITIES
   -------------------------------------------------------------------------- */
.stack     { display: flex; flex-direction: column; gap: var(--s-4); }
.stack-sm  { display: flex; flex-direction: column; gap: var(--s-2); }
.row-flex  { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); flex-wrap: wrap; }
.push-right{ margin-left: auto; }
.text-center { text-align: center; }
.text-right  { text-align: right; }
.nowrap    { white-space: nowrap; }
.truncate  { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clamp-2   { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.clamp-3   { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.full-w    { width: 100%; }
.mt-0 { margin-top: 0 !important; }
.mb-0 { margin-bottom: 0 !important; }
.mt-4 { margin-top: var(--s-4); }
.mt-5 { margin-top: var(--s-5); }
.mt-6 { margin-top: var(--s-6); }
.mb-4 { margin-bottom: var(--s-4); }
.mb-5 { margin-bottom: var(--s-5); }
.mb-6 { margin-bottom: var(--s-6); }
.fs-sm { font-size: var(--fs-sm); }
.fs-xs { font-size: var(--fs-xs); }
/* A utility that hides below a breakpoint must not dictate the display type
   above it. `display: initial` computes to `inline`, which beat .icon-btn's
   `inline-grid` on the two header buttons carrying this class — `place-items:
   center` then had nothing to center, and the icon dropped to the text
   baseline, riding 11px above the middle of its 44px circle. Scoping the rule
   to the small breakpoint leaves each element's own display intact. */
@media (max-width: 575.98px) { .hide-sm { display: none !important; } }
@media (min-width: 576px)    { .only-sm { display: none; } }
.print-only { display: none; }

/* --------------------------------------------------------------------------
   26. PRINT
   -------------------------------------------------------------------------- */
@media print {
  body { background: #fff; color: #000; }
  body::before { display: none; }
  .site-header, .site-footer, .cookie-banner, .toast-stack, .sticky-actions,
  .no-print, .btn, .mobile-drawer, .drawer-backdrop, .announcement-bar { display: none !important; }
  .print-only { display: block; }
  .panel, .s-card, .card { border: 1px solid #ccc; box-shadow: none; background: #fff; color: #000; }
  a { color: #000; text-decoration: underline; }
  .s-table th, .s-table td { border-color: #ccc; color: #000; }
  .s-table thead th { background: #f2f2f2; }
}

/* California requires the privacy-choices link to be clear and conspicuous, so
   it is tinted rather than sitting anonymously in the legal row. */
.footer-legal__privacy {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  color: var(--c-accent);
}
.footer-legal__privacy:hover { color: var(--c-primary); }
.footer-legal__privacy svg { flex-shrink: 0; }

/* Every legal template ships with a banner saying it still needs a lawyer's
   eye. It is loud on purpose — it has to be impossible to publish by accident,
   and it is meant to be deleted once the page has actually been reviewed. */
.legal-review-banner {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-sm);
  border: 1px dashed var(--c-accent);
  background: rgba(255, 255, 255, 0.054);
  color: #DCDCDC;
  font-size: var(--fs-sm);
}

/* Legal pages use tables for rate cards and cookie categories. */
.legal-body table,
.prose table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--s-5) 0;
  font-size: var(--fs-sm);
}
.legal-body th,
.legal-body td,
.prose th,
.prose td {
  padding: var(--s-3);
  border-bottom: 1px solid var(--c-border);
  text-align: left;
  vertical-align: top;
}
.legal-body th,
.prose th {
  color: var(--c-text);
  font-weight: var(--fw-bold);
  border-bottom-color: var(--c-border-strong);
}

/* ==========================================================================
   BURNING HEADLINE

   The word is genuinely on fire, built from six stacked layers:

     1. a solid extrusion, so the letters have thickness
     2. a molten fill that flows, like metal still cooling
     3. base heat sitting on the glyphs        (.ignite::before)
     4. the main flame body rising off them    (.ignite__fire::before)
     5. tall flame tongues                     (.ignite__fire::after)
     6. flickering tips, highest and coolest   (.ignite__tips::before)

   Every flame layer is a copy of the word pushed around by the turbulence
   filters in partials/fire-filter.php. Blur alone would only be a glow — it is
   the displacement that makes an edge lick and curl. Each layer runs at its own
   height, speed and temperature so they never move in lockstep.

   All copies come from data-text and are aria-hidden, so the heading is still
   announced exactly once.
   ========================================================================== */
.ignite {
  position: relative;
  display: inline-block;
  /* Deliberately NOT isolated: the flame layers blend additively and need the
     dark scrim behind the heading as their ground. Isolating here would make
     them blend against nothing, and orange added to gold with no dark
     underneath comes out khaki. Containment happens on .hero__name. */

  background: linear-gradient(178deg,
    #FFFDF6 0%, #FFEFC2 14%, #FFC53D 34%, #FF8A2B 56%, #EF4A10 78%, #A82408 100%);
  background-size: 100% 280%;
  background-position: 50% 78%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;

  /* Extrusion. text-shadow paints from the glyph outline even when the fill is
     transparent, so the depth sits behind the molten surface. */
  text-shadow:
    0 1px 0 #C4360C, 0 2px 0 #B02F0A, 0 3px 0 #9A2708,
    0 4px 0 #842006, 0 5px 0 #6E1905, 0 6px 0 #581304,
    0 7px 1px rgba(0, 0, 0, 0.4),
    0 0 30px rgba(255, 90, 31, 0.45),
    0 0 70px rgba(255, 122, 46, 0.28);

  animation: ignite-molten 11s ease-in-out infinite;
}

/* The two flame carriers sit exactly over the word and contribute nothing to
   layout — they exist only to give the fire four more pseudo-elements. */
.ignite__fire,
.ignite__tips {
  position: absolute;
  left: 0; top: 0;
  width: 100%; height: 100%;
  pointer-events: none;
}

/* Shared flame behaviour. Painted as solid coloured glyphs, NOT with
   background-clip: text — an SVG filter establishes its own rendering context
   and the text clip does not survive it, so a gradient fill would paint as a
   rectangle. Solid colour is what the displacement map wants anyway. */
.ignite::before,
.ignite::after,
.ignite__fire::before,
.ignite__fire::after,
.ignite__tips::before {
  content: attr(data-text);
  position: absolute;
  left: 0; top: 0;
  width: 100%;
  pointer-events: none;
  text-shadow: none;
  background: none;
  /* Additive, because fire is emitted light: it adds to what is behind it
     rather than averaging with it, which is what stops the plume going grey. */
  mix-blend-mode: plus-lighter;
  will-change: transform, opacity;
}

/* --- The rise ------------------------------------------------------------
   Fire travels. Each flame layer is born at the glyph, rises, thins and dies
   out above it, then restarts — a `linear` loop with no `alternate`, because
   alternate runs the motion backwards on the return and reads as pulsing in
   place rather than burning upward.

   Each layer is born ON the line of the text — translateY is 0 at 0% — then
   climbs and dies out above it. Nothing is drawn below the words: an earlier
   version started the travel BELOW the baseline (translateY +0.30em) so the
   flame swept up through the glyphs, but that put visible fire under the line,
   which is not what a burning word looks like. Paired with transform-origin at
   the baseline, every layer now grows and travels upward only.

   Four layers share one cycle with staggered delays, so at any instant there
   is flame at every height and the fire looks continuous rather than like one
   puff repeating. Opacity starts and ends at zero, which is what hides the
   loop point — but the fades are kept SHORT and the plateau long. A peaked
   opacity hump makes each layer bright in the middle and dead at both ends,
   and with four different periods those humps beat against each other into a
   visible global flicker. A long plateau keeps the total output steady while
   the individual tongues still travel.
   ------------------------------------------------------------------------- */
@keyframes ignite-rise {
  0%   { opacity: 0;    transform: translateY(0)       scale(0.99, 0.88); }
  7%   { opacity: 0.52; transform: translateY(-0.06em) scale(1,    0.96); }
  40%  { opacity: 0.50; transform: translateY(-0.22em) scale(1.02, 1.16); }
  72%  { opacity: 0.44; transform: translateY(-0.42em) scale(1.04, 1.40); }
  92%  { opacity: 0.20; transform: translateY(-0.58em) scale(1.05, 1.62); }
  100% { opacity: 0;    transform: translateY(-0.68em) scale(1.06, 1.74); }
}

/* Base heat sits on the glyphs and only breathes — it is the bed the flames
   rise out of, so it does not travel with them. */
.ignite::before {
  color: #FFC24D; -webkit-text-fill-color: #FFC24D;
  filter: url(#flame-embers);
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,0.28) 0%, rgba(0,0,0,0.82) 46%, #000 80%, rgba(0,0,0,0.35) 94%, transparent 100%);
          mask-image: linear-gradient(to bottom, rgba(0,0,0,0.28) 0%, rgba(0,0,0,0.82) 46%, #000 80%, rgba(0,0,0,0.35) 94%, transparent 100%);
  opacity: 0.32;
  z-index: 1;
  animation: ignite-base 2.4s ease-in-out infinite alternate;
}

/* The four rising layers. Same keyframes, different speed, delay and heat, so
   they never stack into a single visible pulse. */
.ignite::after,
.ignite__fire::before,
.ignite__fire::after,
.ignite__tips::before {
  animation-name: ignite-rise;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  /* Anchor the growth to the baseline. scaleY from the default centre origin
     lowers the bottom edge as much as it raises the top, which puts flame
     below the letters no matter where the travel starts. 92% is the baseline
     rather than the box bottom, which sits in the descender space. */
  transform-origin: 50% 92%;
  -webkit-mask-image: linear-gradient(to top, transparent 4%, rgba(0,0,0,0.55) 20%, #000 36%, rgba(0,0,0,0.75) 54%, transparent 76%);
          mask-image: linear-gradient(to top, transparent 4%, rgba(0,0,0,0.55) 20%, #000 36%, rgba(0,0,0,0.75) 54%, transparent 76%);
}

.ignite::after {
  color: #FF8A18; -webkit-text-fill-color: #FF8A18;
  filter: url(#flame-churn) saturate(1.3);
  z-index: 2;
  animation-duration: 2.7s;
  animation-delay: 0s;
}
.ignite__fire::before {
  color: #FF7412; -webkit-text-fill-color: #FF7412;
  filter: url(#flame-churn) saturate(1.4);
  z-index: 3;
  animation-duration: 3.5s;
  animation-delay: -1.2s;      /* negative delay starts it mid-cycle */
}
.ignite__fire::after {
  color: #FF5A0A; -webkit-text-fill-color: #FF5A0A;
  filter: url(#flame-wisp) saturate(1.45);
  z-index: 4;
  animation-duration: 2.3s;
  animation-delay: -2.0s;
}
.ignite__tips::before {
  color: #F0430A; -webkit-text-fill-color: #F0430A;
  filter: url(#flame-wisp) saturate(1.5);
  z-index: 5;
  animation-duration: 4.1s;
  animation-delay: -3.1s;
}

@keyframes ignite-base {
  from { opacity: 0.22; transform: translateY(0)       scaleY(1); }
  to   { opacity: 0.40; transform: translateY(-0.02em) scaleY(1.04); }
}
@keyframes ignite-molten {
  0%, 100% { background-position: 50% 78%; }
  50%      { background-position: 50% 44%; }
}

/* The filters are expensive on a headline this large. Phones keep the molten
   fill, the extrusion and one flame layer; the rest are dropped. */
@media (max-width: 700px) {
  .ignite__fire::after,
  .ignite__tips::before { display: none; }
  /* Two layers instead of four, and the cheaper embers filter for the upper
     one. Swapping to a plain blur here would drop the SMIL churn and leave a
     soft glow that rises without ever looking like it is burning. */
  .ignite__fire::before { filter: url(#flame-embers) saturate(1.4); }
}

@media (prefers-reduced-motion: reduce) {
  .ignite,
  .ignite::before, .ignite::after,
  .ignite__fire::before, .ignite__fire::after,
  .ignite__tips::before { animation: none; }
  /* The rising layers take their opacity from the keyframes, so with the
     animation off they would otherwise sit at a fully opaque 1 and blow the
     headline out. Pin them to a mid-cycle strength. */
  .ignite::after { opacity: 0.48; }
  .ignite__fire::before { opacity: 0.4; }
  .ignite__fire::after,
  .ignite__tips::before { opacity: 0.28; }
  .ignite::before { opacity: 0.3; }
}

/* Hidden, but still RENDERED. A display:none or zero-sized SVG may have its
   SMIL animation stopped by the browser, which freezes the turbulence and
   leaves the flames standing perfectly still. */
.fire-defs {
  position: absolute;
  width: 1px; height: 1px;
  top: 0; left: 0;
  opacity: 0.01;
  pointer-events: none;
  clip-path: inset(50%);
}

/* ==========================================================================
   PRODUCT CARDS — dimensional

   The grid is the shop's whole storefront, so the cards are treated as
   physical objects rather than rectangles: they sit in 3D space, tilt towards
   the pointer, catch a light sweep as they move, and lift off the page on
   approach. The tilt is driven by two custom properties that a small script
   updates from the pointer position.

   Everything is built so the card is still completely usable with the effects
   off — on touch, with reduced motion, or if the script never runs.
   ========================================================================== */
.grid--products,
.product-grid {
  /* The shared perspective is what makes neighbouring cards feel like they are
     in one space rather than each having its own private vanishing point. */
  perspective: 1400px;
  perspective-origin: 50% 40%;
}

.product-card {
  --tilt-x: 0deg;
  --tilt-y: 0deg;
  --lift: 0px;
  --glare-x: 50%;
  --glare-y: 50%;

  position: relative;
  transform-style: preserve-3d;
  transform:
    perspective(1400px)
    rotateX(var(--tilt-x))
    rotateY(var(--tilt-y))
    translateY(var(--lift))
    translateZ(0);
  transition: transform 260ms cubic-bezier(.22, .61, .36, 1),
              box-shadow 260ms ease,
              border-color 260ms ease;
  will-change: transform;
}

.product-card:hover,
.product-card:focus-within {
  --lift: -6px;
  border-color: rgba(255, 255, 255, 0.228);
  box-shadow:
    0 26px 50px -22px rgba(0, 0, 0, 0.85),
    0 10px 22px -14px rgba(255, 255, 255, 0.27),
    0 0 0 1px rgba(255, 255, 255, 0.084) inset;
  z-index: 2;
}

.product-card__media {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  transform: translateZ(28px);      /* the image sits proud of the card face */
  background:
    radial-gradient(ellipse 70% 60% at 50% 42%,
      rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.03) 45%, transparent 72%),
    linear-gradient(180deg, #17161A 0%, #101013 100%);
}
.product-card__media img {
  transition: transform 520ms cubic-bezier(.22, .61, .36, 1), filter 320ms ease;
}
.product-card:hover .product-card__media img {
  transform: scale(1.07);
  filter: saturate(1.08) contrast(1.03);
}

/* A light sweep that tracks the pointer, so the card reads as a surface
   catching a light rather than a flat swatch. */
.product-card__sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 260ms ease;
  background: radial-gradient(
    420px circle at var(--glare-x) var(--glare-y),
    rgba(255, 210, 150, 0.20) 0%,
    rgba(255, 255, 255, 0.06) 32%,
    transparent 62%);
  mix-blend-mode: screen;
}
.product-card:hover .product-card__sheen { opacity: 1; }

/* Text and controls sit forward of the image so the card has real depth
   rather than everything living on one plane. */
.product-card__body { transform: translateZ(18px); }
.product-card__name { transform: translateZ(6px); }

/* Badges float highest — they are the first thing the eye should catch. */
.product-card .badge-float {
  transform: translateZ(46px);
  box-shadow: 0 6px 14px -6px rgba(0, 0, 0, 0.7);
}
.product-card .wish-btn { transform: translateZ(46px); }

/* Quick add. Hidden until the card is approached on pointer devices so the
   grid stays calm, always visible on touch where there is no hover. */
.product-card__action {
  margin-top: var(--s-3);
  transform: translateZ(24px);
}
/* Deliberately always visible rather than revealed on hover. A hover-only buy
   button is invisible to the shopper at the moment they are deciding, and
   invisible entirely on touch. It brightens on approach instead. */
.product-card__action .btn { opacity: 0.88; transition: opacity 200ms ease; }
.product-card:hover .product-card__action .btn,
.product-card:focus-within .product-card__action .btn { opacity: 1; }

/* Touch devices get the lift but never the tilt — there is no pointer to
   track, and a card that stays tilted after a tap looks broken. */
@media (hover: none) {
  .product-card { transform: none; }
  .product-card:hover { --lift: 0px; transform: none; }
  .product-card__sheen { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .product-card,
  .product-card__media img,
  .product-card__action { transition: none; }
  .product-card { transform: none !important; }
  .product-card__sheen { display: none; }
}

/* ==========================================================================
   SHOP STOREFRONT HEADER
   ========================================================================== */
/* Tighter than the default page hero, but the top padding must still clear
   the fixed header — shortening it with padding-block alone would slide the
   breadcrumb underneath the nav. */
.page-hero--shop {
  padding-top: calc(var(--header-h) + clamp(1.1rem, 3vw, 2.1rem));
  padding-bottom: clamp(1.8rem, 4vw, 2.8rem);
}

.shop-hero {
  display: grid;
  gap: var(--s-6);
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
}
@media (min-width: 992px) {
  .shop-hero { grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.9fr); gap: var(--s-8); }
}

/* The reasons to buy, sitting where the hero used to be empty. */
.shop-hero__assurances {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  gap: var(--s-2);
}
@media (min-width: 560px) and (max-width: 991.98px) {
  .shop-hero__assurances { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.shop-hero__assurances li {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: linear-gradient(180deg, rgba(255,255,255,0.035) 0%, rgba(255,255,255,0.012) 100%);
  /* A shallow version of the button edge, so these read as the same material
     as the rest of the storefront rather than as flat boxes. */
  box-shadow: 0 2px 0 0 rgba(0,0,0,0.45), 0 8px 18px -12px rgba(0,0,0,0.6);
}
.shop-hero__assurances strong {
  display: block;
  font-size: var(--fs-sm);
  color: var(--c-text);
  line-height: 1.3;
}
.shop-hero__assurances span span,
.shop-hero__assurances li > span:last-child > span {
  display: block;
  font-size: var(--fs-xs);
  color: var(--c-muted);
  margin-top: 2px;
}
.shop-hero__icon {
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 36px; height: 36px;
  border-radius: 50%;
  color: var(--c-accent);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.144);
}

/* --------------------------------------------------------------------------
   RESPONSIVE SAFETY NET

   Two classes of element were found overflowing narrow viewports by an
   element-level audit rather than by eye:

   1. Badges are inline-flex, which sizes to max-content and will not shrink.
      A long one — "Free US shipping on orders over $75.00" — was 142px wider
      than a 320px screen and simply ran off the edge. Same failure the hero
      eyebrow had.

   2. Form controls with an intrinsic minimum width. Chrome gives date, number
      and similar inputs a built-in minimum that ignores its container, so a
      date field overflowed the booking form at 320px.
   -------------------------------------------------------------------------- */
.badge,
.s-badge {
  flex-wrap: wrap;
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
}
/* Floating badges over product imagery stay on one line — they are short by
   design and wrapping them inside a card corner looks broken. */
.badge-float { white-space: nowrap; overflow-wrap: normal; }

input,
select,
textarea {
  max-width: 100%;
  min-width: 0;
}


/* --------------------------------------------------------------------------
   EXCLUSIVE CONTENT PAYWALL
   The public face of /exclusive. It has to do one job: make the price feel
   small next to the catalogue sitting behind the lock.
   -------------------------------------------------------------------------- */
.page-hero--paywall .page-hero__lead {
  max-width: 62ch;
  font-size: var(--fs-lg);
  color: var(--c-text);
}

.paywall-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: var(--s-6) 0 var(--s-5);
}
.paywall-price__from,
.paywall-price__period { font-size: var(--fs-sm); color: var(--c-muted); }
.paywall-price__amount {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 6vw, 3.6rem);
  font-weight: var(--fw-bold);
  line-height: 1;
  background: var(--grad-primary);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* ==========================================================================
   3D GLASS
   --------------------------------------------------------------------------
   The surfaces stop being flat fills and become panes: a translucent pane
   catching light at its top edge, sitting in shadow, with the page visible
   through it.

   Three things together are what read as glass rather than "a dark box with
   a border":

     1. A gradient fill, not a flat one. Real glass is brighter where it faces
        the light, so the fill runs light at the top-left to nearly nothing at
        the bottom-right.
     2. Two inset shadows. A bright hairline on the top edge is the lit rim; a
        dark hairline on the bottom edge is the shaded one. Without the pair
        the pane has no thickness and just looks tinted.
     3. A cast shadow with a large negative spread, so the panel floats above
        the page instead of being welded to it.

   backdrop-filter is what makes it actually transparent — the ambient wash on
   body::before and the hero art genuinely show through and blur.
   ========================================================================== */

:root {
  --glass-fill:  linear-gradient(157deg,
                   rgba(255, 255, 255, 0.085) 0%,
                   rgba(255, 255, 255, 0.042) 38%,
                   rgba(255, 255, 255, 0.022) 100%);
  --glass-edge:  inset 0 1px 0 rgba(255, 255, 255, 0.22),
                 inset 0 -1px 0 rgba(0, 0, 0, 0.45);
  --glass-cast:  0 22px 48px -24px rgba(0, 0, 0, 0.95),
                 0 4px 12px -6px rgba(0, 0, 0, 0.6);
  --glass-cast-hi: 0 34px 70px -28px rgba(0, 0, 0, 1),
                   0 8px 20px -8px rgba(0, 0, 0, 0.7);
}

.s-card,
.plan-card,
.product-card,
.summary-card,
.empty-state,
.toolbar,
.filter-panel,
.alert,
.locked-card,
.account-nav,
.stat-card,
.a-card {
  background: var(--glass-fill);
  background-color: rgba(255, 255, 255, 0.012);
  backdrop-filter: blur(18px) saturate(130%);
  -webkit-backdrop-filter: blur(18px) saturate(130%);
  border: 1px solid var(--c-glass-line);
  box-shadow: var(--glass-edge), var(--glass-cast);
}

/* The specular streak. One soft diagonal band across the upper third — the
   reflection of a light source the page does not have to actually contain. */
.s-card::before,
.plan-card::before,
.summary-card::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 55%;
  border-radius: inherit;
  background: linear-gradient(163deg,
    rgba(255, 255, 255, 0.10) 0%,
    rgba(255, 255, 255, 0.035) 42%,
    transparent 78%);
  pointer-events: none;
  z-index: 0;
}
/* Content has to sit above the sheen or the sheen washes the text out. */
.s-card > *,
.plan-card > *,
.summary-card > * { position: relative; z-index: 1; }

/* Lift on hover: the pane rises, its rim brightens and its shadow deepens and
   spreads, which is what sells the height rather than the movement alone. */
.s-card--hover:hover,
.plan-card:hover,
.product-card:hover {
  border-color: var(--c-glass-hi);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.32),
    inset 0 -1px 0 rgba(0, 0, 0, 0.5),
    var(--glass-cast-hi);
}

/* The featured plan is the pane closest to the viewer. */
.plan-card--featured {
  background: linear-gradient(157deg,
    rgba(255, 255, 255, 0.13) 0%,
    rgba(255, 255, 255, 0.055) 40%,
    rgba(255, 255, 255, 0.025) 100%);
  border-color: rgba(255, 255, 255, 0.26);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.34),
    inset 0 -1px 0 rgba(0, 0, 0, 0.5),
    var(--glass-cast-hi);
}

/* Small controls get the same treatment at a smaller scale. Chips and pills
   are the elements most likely to look pasted-on if they stay flat while
   everything around them turns to glass. */
.chip,
.option-pill,
.s-badge,
.badge,
.icon-btn,
.billing-toggle {
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.028));
  backdrop-filter: blur(12px) saturate(125%);
  -webkit-backdrop-filter: blur(12px) saturate(125%);
  border: 1px solid var(--c-glass-line);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 2px 8px -4px rgba(0, 0, 0, 0.7);
}
.chip:hover,
.option-pill:hover,
.icon-btn:hover {
  border-color: var(--c-glass-hi);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.26), 0 6px 16px -6px rgba(0, 0, 0, 0.8);
}
.chip.is-active,
.option-pill.is-selected {
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.20), rgba(255, 255, 255, 0.08));
  border-color: rgba(255, 255, 255, 0.38);
  color: var(--c-text);
}

/* Fields are recessed rather than raised — light falls INTO them, which is
   the inverse of the panels and is what makes them read as inputs. */
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
select,
textarea {
  background: rgba(0, 0, 0, 0.32);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--c-glass-line);
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.55), inset 0 -1px 0 rgba(255, 255, 255, 0.07);
}
input:focus,
select:focus,
textarea:focus {
  border-color: rgba(255, 255, 255, 0.42);
  box-shadow:
    inset 0 2px 5px rgba(0, 0, 0, 0.55),
    0 0 0 3px rgba(255, 255, 255, 0.10);
}

/* Alternating sections become a faint pane the width of the page, so the
   rhythm of the page is glass on black rather than grey on black. */
.section--alt {
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0.035) 0%,
    rgba(255, 255, 255, 0.012) 100%);
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

/* The drawer and footer are the two largest panes. */
.mobile-drawer {
  background: rgba(8, 8, 8, 0.82);
  backdrop-filter: blur(26px) saturate(140%);
  -webkit-backdrop-filter: blur(26px) saturate(140%);
  border-left: 1px solid var(--c-glass-line);
}
.site-footer {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.035) 0%, rgba(255, 255, 255, 0.008) 100%);
  border-top: 1px solid var(--c-glass-line);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* backdrop-filter forces its own compositing layer, and a dozen of them on a
   long page costs real frames on a phone. The panes keep their fill, edges and
   shadow — everything that reads as glass in a screenshot — and give up only
   the live blur, which is the expensive part and the least visible. */
@media (max-width: 700px) {
  .s-card, .plan-card, .product-card, .summary-card, .empty-state, .toolbar,
  .filter-panel, .alert, .locked-card, .account-nav, .stat-card, .a-card,
  .chip, .option-pill, .s-badge, .badge, .icon-btn, .billing-toggle,
  .site-footer, input, select, textarea {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .s-card, .plan-card, .product-card, .summary-card, .locked-card {
    background-color: rgba(18, 18, 18, 0.92);
  }
}

/* Hero photography is desaturated to sit inside the monochrome scheme — a
   full-colour photograph behind a greyscale interface reads as a mistake.
   It is not taken all the way to zero: a trace of the original colour keeps
   the image from going flat, and the contrast lift puts back the punch that
   desaturating always costs.

   Deliberately scoped to editorial art only. Product photography stays in
   full colour, because a customer choosing merchandise has to see what colour
   the garment actually is. */
.hero__media img,
.hero__media video,
.page-hero__media img {
  filter: grayscale(0.88) contrast(1.08) brightness(0.94);
}

/* The mark in the admin sidebar and the mobile drawer. Both previously showed
   the first letter of the site name in a gradient square next to the name in
   text — a stand-in, not the brand. They now carry the complete artwork, sized
   against their own bar rather than the site header's. */
.brand--sidebar .brand__logo,
.brand--drawer .brand__logo {
  height: clamp(46px, 9vw, 58px);
  width: auto;
  max-width: 100%;
}
.brand--sidebar,
.brand--drawer { gap: 0; min-width: 0; }

/* --------------------------------------------------------------------------
   HERO ARRIVAL
   The headline is not simply there when the page loads — it arrives, and then
   it catches fire. Characters rise and settle one after another, and only once
   they have landed do the tall flame layers build on top.

   The order matters: fire before the letters have arrived looks like a render
   glitch, whereas fire that catches after them reads as ignition.

   Nothing here uses filter or opacity on .ignite itself. Both create a
   stacking context, which would isolate the flame layers from the dark scrim
   they blend against and turn the plume khaki. The animation stays on the
   characters and on the two flame carrier spans instead.
   -------------------------------------------------------------------------- */
.ignite__ch {
  display: inline-block;
  /* `backwards` holds the 0% frame during the stagger delay, so a character
     waiting its turn is invisible rather than popping in at full size. */
  animation: hero-char-in 0.72s cubic-bezier(0.16, 0.84, 0.32, 1) backwards;
  animation-delay: calc(var(--i, 0) * 42ms);
}
@keyframes hero-char-in {
  from { opacity: 0; transform: translate3d(0, 0.44em, 0) scale(0.94); }
  to   { opacity: 1; transform: none; }
}

/* Gating the flames is not as simple as fading the two carrier spans, because
   two of the four layers are pseudo-elements on .ignite itself and draw the
   WHOLE word from data-text. Left alone they paint the finished headline in
   flame at frame one, so the letters appear to arrive into something that has
   already arrived — measured, full-width ink was on screen at 0.15s.

   `visibility` is the tool for this. It inherits, so it reaches pseudo-elements
   that cannot be wrapped; a child may override it back to visible, which is how
   the letters stay unaffected; and unlike opacity or filter it creates no
   stacking context, so the additive blend against the dark scrim survives.
   steps(1, end) holds `hidden` for the whole duration and then flips once. */
.ignite {
  /* Both, listed together: the shorthand replaces whatever came before, so
     declaring flame-gate on its own would silently kill the molten fill. */
  animation:
    ignite-molten 11s ease-in-out infinite,
    flame-gate 0.62s steps(1, end) backwards;
}
@keyframes flame-gate {
  from { visibility: hidden; }
  to   { visibility: visible; }
}
.ignite__ch { visibility: visible; }

/* Once the gate opens the tall layers come up rather than snapping on. This
   multiplies with the opacity their own pseudo-elements animate, so the
   continuous burn underneath is untouched. */
.ignite__fire,
.ignite__tips {
  animation: hero-flames-in 1.1s ease-out 0.62s backwards;
}
@keyframes hero-flames-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .ignite,
  .ignite__ch,
  .ignite__fire,
  .ignite__tips { animation: none; visibility: visible; }
}

/* --------------------------------------------------------------------------
   ARTIST CARD — ROTATING SHOTS
   With more than one photo the card cross-fades through them on its own.

   Pure CSS, no JavaScript: every image runs the same keyframe track and is
   offset by a delay of its own index, so they hand over in order and can never
   drift out of step the way a JS timer can if one image decodes late.

   The keyframes have to be written per photo-count. A keyframe stop must be a
   literal percentage — `calc(100% / var(--n))` is not valid there — and the
   fraction of the cycle each photo holds is exactly 1/count. Two through six
   covers any realistic gallery; beyond that it falls back to the 6-photo
   timing, which simply holds each shot a little longer than its slot.
   -------------------------------------------------------------------------- */
.artist-shots { position: relative; display: block; overflow: hidden; }

.artist-shots--rotating .artist-shots__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  animation-duration: var(--shot-cycle, 11s);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-delay: calc(var(--n, 0) * var(--shot-cycle, 11s) / var(--shot-count, 3));
}
/* The first photo stays in flow so the card keeps its natural height; the rest
   stack on top of it. */
.artist-shots--rotating .artist-shots__img:first-child { position: relative; }

.artist-shots--rotating { --shot-name: artist-shot-3; }
.artist-shots--rotating .artist-shots__img { animation-name: var(--shot-name); }
.artist-shots--n2 { --shot-name: artist-shot-2; }
.artist-shots--n3 { --shot-name: artist-shot-3; }
.artist-shots--n4 { --shot-name: artist-shot-4; }
.artist-shots--n5 { --shot-name: artist-shot-5; }
.artist-shots--n6 { --shot-name: artist-shot-6; }

/* Hold, then hand over. An even cross-fade across the whole slot reads as a
   slideshow that never settles; holding still for most of the slot and trading
   only at the end reads as a photograph that happens to change. */
@keyframes artist-shot-2 { 0%, 44% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes artist-shot-3 { 0%, 27% { opacity: 1; } 33%, 100% { opacity: 0; } }
@keyframes artist-shot-4 { 0%, 19% { opacity: 1; } 25%, 100% { opacity: 0; } }
@keyframes artist-shot-5 { 0%, 14% { opacity: 1; } 20%, 100% { opacity: 0; } }
@keyframes artist-shot-6 { 0%, 11% { opacity: 1; } 16%, 100% { opacity: 0; } }

/* A quiet marker row, so a changing photo reads as intentional. */
.artist-shots__dots {
  position: absolute;
  left: 50%; bottom: 0.7rem;
  transform: translateX(-50%);
  display: flex;
  gap: 5px;
  z-index: 3;
  pointer-events: none;
}
.artist-shots__dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
  opacity: 0.35;
  animation-name: artist-dot;
  animation-duration: var(--shot-cycle, 11s);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-delay: calc(var(--n, 0) * var(--shot-cycle, 11s) / var(--shot-count, 3));
}
.artist-shots--n2 .artist-shots__dot { animation-name: artist-dot-2; }
.artist-shots--n4 .artist-shots__dot { animation-name: artist-dot-4; }
.artist-shots--n5 .artist-shots__dot { animation-name: artist-dot-5; }
.artist-shots--n6 .artist-shots__dot { animation-name: artist-dot-6; }
@keyframes artist-dot   { 0%, 30% { opacity: 1; } 34%, 100% { opacity: 0.35; } }
@keyframes artist-dot-2 { 0%, 47% { opacity: 1; } 51%, 100% { opacity: 0.35; } }
@keyframes artist-dot-4 { 0%, 22% { opacity: 1; } 26%, 100% { opacity: 0.35; } }
@keyframes artist-dot-5 { 0%, 17% { opacity: 1; } 21%, 100% { opacity: 0.35; } }
@keyframes artist-dot-6 { 0%, 14% { opacity: 1; } 17%, 100% { opacity: 0.35; } }

@media (prefers-reduced-motion: reduce) {
  .artist-shots--rotating .artist-shots__img { animation: none; opacity: 0; }
  .artist-shots--rotating .artist-shots__img:first-child { opacity: 1; }
  .artist-shots__dot { animation: none; }
  .artist-shots__dot:first-child { opacity: 1; }
}

/* Gallery thumbnails on the artist edit screen. */
.artist-photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: var(--s-2);
  margin-bottom: var(--s-3);
}
.artist-photo-grid__item {
  position: relative;
  margin: 0;
  aspect-ratio: 1;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--c-border);
}
.artist-photo-grid__item img { width: 100%; height: 100%; object-fit: cover; }
.artist-photo-grid__remove {
  position: absolute;
  top: 4px; right: 4px;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.66);
  color: #fff;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}
.artist-photo-grid__remove:hover { background: var(--c-error); border-color: transparent; }

/* --------------------------------------------------------------------------
   ARTIST PLATE — the state before photography arrives
   A signed artist with no photo yet should look deliberate. A generic grey
   placeholder reads as a broken image; a monogram plate reads as a design
   choice, and it disappears the moment a real photo is uploaded.
   -------------------------------------------------------------------------- */
.artist-shots--plate {
  position: relative;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background:
    radial-gradient(120% 90% at 30% 12%, rgba(255, 255, 255, 0.085), transparent 62%),
    linear-gradient(168deg, #14120F 0%, #0B0A09 58%, #060504 100%);
  overflow: hidden;
}
/* A single raking highlight across the plate, so it reads as a surface with a
   direction to it rather than a flat swatch. */
.artist-shots--plate::before {
  content: '';
  position: absolute;
  inset: -30% -10% auto -10%;
  height: 70%;
  background: linear-gradient(168deg, rgba(255, 255, 255, 0.07), transparent 70%);
  transform: rotate(-8deg);
  pointer-events: none;
}
.artist-plate {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0.55rem;
  text-align: center;
  padding: var(--s-4);
}
.artist-plate__initials {
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 7vw, 3.9rem);
  font-weight: var(--fw-bold);
  line-height: 1;
  letter-spacing: 0.02em;
  /* The one place fire is allowed on this card — it ties the plate to the
     mark and the headline rather than leaving it a grey box. */
  background: var(--grad-fire);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  filter: drop-shadow(0 3px 14px rgba(255, 90, 31, 0.30));
}
.artist-plate__label {
  font-size: 0.62rem;
  font-weight: var(--fw-semi);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--c-muted);
}
/* The hover overlay would only muddy a plate that has no photograph under it. */
.artist-shots--plate .media-thumb__overlay { display: none; }

/* --------------------------------------------------------------------------
   ARTIST SOCIAL RAIL — official platform colours, on 3D buttons
   The one place on the site where brand colours other than our own are
   allowed: a listener scanning for "where do I hear this" recognises Spotify
   green and Apple red faster than any label we could write.

   Depth is built the same way as the site's other 3D buttons — a solid edge
   underneath standing for the button's thickness, plus a coloured cast beneath
   that. Pressing collapses the edge and drops the button by the same amount,
   so it travels exactly as far as it is thick.
   -------------------------------------------------------------------------- */
.social-rail {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.social-btn {
  --sb-depth: 3px;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.58rem 1.05rem;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
  background: var(--sb-bg, #1a1a1a);
  box-shadow:
    0 var(--sb-depth) 0 var(--sb-edge, #000),
    0 calc(var(--sb-depth) + 5px) 16px -6px var(--sb-cast, rgba(0,0,0,0.7)),
    inset 0 1px 0 rgba(255, 255, 255, 0.22);
  transform: translateY(0);
  transition: transform var(--t-fast), box-shadow var(--t-fast), filter var(--t-fast);
}
.social-btn:hover {
  color: #fff;
  filter: brightness(1.08);
  transform: translateY(-1px);
  box-shadow:
    0 calc(var(--sb-depth) + 1px) 0 var(--sb-edge, #000),
    0 calc(var(--sb-depth) + 9px) 22px -6px var(--sb-cast, rgba(0,0,0,0.7)),
    inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.social-btn:active {
  transform: translateY(var(--sb-depth));
  box-shadow:
    0 0 0 var(--sb-edge, #000),
    0 2px 6px -3px var(--sb-cast, rgba(0,0,0,0.7)),
    inset 0 1px 0 rgba(255, 255, 255, 0.16);
}
.social-btn__icon { display: inline-grid; place-items: center; }
.social-btn__icon svg { width: 18px; height: 18px; }

/* Official platform colours. The edge is a darkened version of each brand
   colour rather than plain black, so the side of the button still reads as
   the same material as its face. */
.social-btn--spotify    { --sb-bg: #1DB954; --sb-edge: #0E6B2F; --sb-cast: rgba(29,185,84,0.40); }
.social-btn--apple      { --sb-bg: #FA243C; --sb-edge: #93101F; --sb-cast: rgba(250,36,60,0.38); }
.social-btn--youtube    { --sb-bg: #FF0000; --sb-edge: #8E0000; --sb-cast: rgba(255,0,0,0.34); }
.social-btn--soundcloud { --sb-bg: linear-gradient(180deg, #FF7700, #FF3300);
                          --sb-edge: #932700; --sb-cast: rgba(255,85,0,0.38); }
.social-btn--instagram  { --sb-bg: linear-gradient(45deg, #F58529 0%, #DD2A7B 45%, #8134AF 70%, #515BD4 100%);
                          --sb-edge: #5A2170; --sb-cast: rgba(221,42,123,0.40); }
.social-btn--facebook   { --sb-bg: #1877F2; --sb-edge: #0A4795; --sb-cast: rgba(24,119,242,0.38); }

/* TikTok and X are black brands. On a black page a black button would vanish,
   so they take the treatment those brands themselves use on dark backgrounds:
   near-black with a light rim, and TikTok keeps its cyan/red signature in the
   cast rather than losing its identity entirely. */
.social-btn--tiktok {
  --sb-bg: #121212; --sb-edge: #000; --sb-cast: rgba(37,244,238,0.30);
  border-color: rgba(255, 255, 255, 0.28);
}
.social-btn--tiktok:hover { --sb-cast: rgba(254,44,85,0.38); }
.social-btn--x {
  --sb-bg: #121212; --sb-edge: #000; --sb-cast: rgba(255,255,255,0.16);
  border-color: rgba(255, 255, 255, 0.28);
}

@media (max-width: 480px) {
  /* Eight labelled pills will not fit a phone. The glyphs carry the meaning,
     and each button keeps a 44px target. */
  .social-btn__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .social-btn { padding: 0.72rem; min-width: 44px; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .social-btn, .social-btn:hover, .social-btn:active { transform: none; transition: none; }
}

/* Custom links share the social rail's shape but stay in the site's own
   palette — they are the label's links, not a platform's, so borrowing a
   brand colour for them would be misleading. */
.social-btn--custom {
  --sb-bg: linear-gradient(160deg, rgba(255,255,255,0.14), rgba(255,255,255,0.05));
  --sb-edge: #000;
  --sb-cast: rgba(0, 0, 0, 0.7);
  border-color: rgba(255, 255, 255, 0.22);
  color: var(--c-text);
}
.social-btn--custom:hover { border-color: rgba(255, 255, 255, 0.42); color: var(--c-text); }

/* Custom-link editor rows on the artist form. */
.admin-link-row {
  display: grid;
  grid-template-columns: 1fr 1.5fr auto;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
}
@media (max-width: 700px) { .admin-link-row { grid-template-columns: 1fr; } }
.admin-link-list { list-style: none; margin: 0 0 var(--s-3); padding: 0; }
.admin-link-list li {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 0.5rem 0.65rem;
  margin-bottom: 6px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.04);
}
.admin-link-list__label { font-weight: var(--fw-semi); white-space: nowrap; }
.admin-link-list__url {
  flex: 1; min-width: 0;
  font-size: var(--fs-xs);
  color: var(--c-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.admin-link-list__remove {
  flex-shrink: 0;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border: 1px solid rgba(255,255,255,0.2);
  border-radius: 50%;
  background: rgba(0,0,0,0.4);
  color: #fff; cursor: pointer; line-height: 1;
}
.admin-link-list__remove:hover { background: var(--c-error); border-color: transparent; }

/* --------------------------------------------------------------------------
   FOOTER SOCIAL — official platform colours
   The glyph carries the brand colour at rest and the whole disc fills with it
   on hover. Filling nine discs permanently would put more colour in the footer
   than anywhere else on a monochrome site; colouring only the glyph keeps them
   recognisable at a glance while the row still reads as one quiet unit.
   -------------------------------------------------------------------------- */
.social-link--spotify    { color: #1DB954; }
.social-link--apple      { color: #FA243C; }
.social-link--youtube    { color: #FF0000; }
.social-link--soundcloud { color: #FF5500; }
.social-link--instagram  { color: #E1306C; }
.social-link--facebook   { color: #1877F2; }
.social-link--bandcamp   { color: #629AA9; }
/* TikTok and X are black brands — invisible on this page — so they keep the
   near-white the rest of the footer text uses. */
.social-link--tiktok,
.social-link--x          { color: var(--c-text); }

/* Hover fills the disc with the platform's colour and lifts it. The shared
   .social-link:hover rule sets a gradient background, so each of these has to
   override background-image, not just background-color. */
.social-link[class*="social-link--"]:hover {
  color: #fff;
  background-image: none;
  transform: translateY(-3px);
}
.social-link--spotify:hover    { background-color: #1DB954; box-shadow: 0 8px 22px -8px rgba(29,185,84,0.85); }
.social-link--apple:hover      { background-color: #FA243C; box-shadow: 0 8px 22px -8px rgba(250,36,60,0.85); }
.social-link--youtube:hover    { background-color: #FF0000; box-shadow: 0 8px 22px -8px rgba(255,0,0,0.75); }
.social-link--soundcloud:hover { background-color: #FF5500; box-shadow: 0 8px 22px -8px rgba(255,85,0,0.85); }
.social-link--instagram:hover  {
  background-image: linear-gradient(45deg, #F58529 0%, #DD2A7B 45%, #8134AF 70%, #515BD4 100%);
  box-shadow: 0 8px 22px -8px rgba(221,42,123,0.85);
}
.social-link--facebook:hover   { background-color: #1877F2; box-shadow: 0 8px 22px -8px rgba(24,119,242,0.85); }
.social-link--bandcamp:hover   { background-color: #629AA9; box-shadow: 0 8px 22px -8px rgba(98,154,169,0.85); }
.social-link--tiktok:hover,
.social-link--x:hover          { background-color: #1A1A1A; border-color: rgba(255,255,255,0.45); }

@media (prefers-reduced-motion: reduce) {
  .social-link:hover { transform: none; }
}

/* Build credit. Quiet by design — present and clickable, without competing
   with the label's own copyright line above it. */
.footer-credit {
  font-size: 11px;
  color: var(--c-dim);
  letter-spacing: 0.02em;
}
.footer-credit a {
  color: var(--c-muted);
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, 0.18);
  transition: color var(--t-fast), border-color var(--t-fast);
}
.footer-credit a:hover { color: var(--c-text); border-bottom-color: rgba(255, 255, 255, 0.5); }

/* --------------------------------------------------------------------------
   CONTRAST REPAIR — white text on what became a white surface
   These rules were written when --grad-primary and --c-primary were the fire
   palette, so white text on them read fine. The monochrome repaint made both
   near-white, and every one of them turned into white-on-white: the checkout
   step numbers, the cart count, the "Most popular" flag, even the keyboard
   skip link, all invisible.

   Two treatments, chosen by what the element is for:
     - Attention and brand moments take the fire gradient and keep white text.
       These are the places colour carries meaning — a step you are on, a
       basket that has something in it, a play control.
     - Neutral UI state stays silver and switches to near-black text, because
       an active page number does not need to shout.
   -------------------------------------------------------------------------- */

/* Fire — where the colour means something */
.checkout-section__num,
.plan-card__flag,
.play-btn,
.video-card__play span,
.icon-btn__badge {
  background: var(--grad-fire);
  background-image: var(--grad-fire);
  color: #fff;
}
.icon-btn__badge { box-shadow: 0 2px 8px -2px rgba(255, 90, 31, 0.7); }
.play-btn,
.video-card__play span { box-shadow: 0 8px 24px -10px rgba(255, 90, 31, 0.75); }

/* Silver — neutral state, dark text for contrast */
.brand__mark,
.billing-toggle button.is-active,
.page-item.active .page-link,
.account-nav a.is-active,
.skip-link {
  color: #0A0A0A;
}

/* Footer link icons. Small, muted and fixed-width so the labels stay on one
   optical column — an icon that changes width per glyph would leave the text
   ragged down the list. The icon warms to the brand accent on hover while the
   label goes white, so the row reads as one target rather than two. */
.footer-link {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}
.footer-link__icon {
  display: inline-grid;
  place-items: center;
  width: 16px;
  flex-shrink: 0;
  color: var(--c-dim);
  transition: color var(--t-fast), transform var(--t-fast);
}
.footer-link__icon svg { width: 14px; height: 14px; }
.footer-link:hover .footer-link__icon { color: var(--c-fire); transform: translateX(1px); }

@media (prefers-reduced-motion: reduce) {
  .footer-link:hover .footer-link__icon { transform: none; }
}

/* ==========================================================================
   CART DRAWER — opens from the right on add-to-cart
   An addition, not a replacement: /cart remains a full page, and with
   JavaScript off the add form posts and redirects there exactly as before.
   ========================================================================== */
.cart-drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-drawer) - 1);
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity var(--t-base);
}
.cart-drawer-backdrop.is-open { opacity: 1; }

.cart-drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  z-index: var(--z-drawer);
  width: min(420px, 92vw);
  display: flex;
  flex-direction: column;
  background: rgba(10, 9, 8, 0.94);
  backdrop-filter: blur(26px) saturate(140%);
  -webkit-backdrop-filter: blur(26px) saturate(140%);
  border-left: 1px solid var(--c-glass-line);
  box-shadow: -24px 0 60px -30px rgba(0, 0, 0, 1);
  transform: translateX(100%);
  transition: transform var(--t-base);
}
.cart-drawer.is-open { transform: none; }

.cart-drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--c-border);
}
.cart-drawer__title {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0;
  font-size: var(--fs-lg);
}
.cart-drawer__count {
  font-size: var(--fs-xs);
  color: var(--c-muted);
  font-weight: var(--fw-normal);
}
.cart-drawer__body {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--s-4) var(--s-5);
}
.cart-drawer__empty { color: var(--c-muted); text-align: center; padding: var(--s-8) 0; }

.cart-line {
  display: grid;
  grid-template-columns: 64px 1fr auto;
  gap: var(--s-3);
  align-items: start;
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--c-border-soft);
}
.cart-line__img {
  width: 64px; height: 64px;
  object-fit: cover;
  border-radius: var(--r-sm);
  border: 1px solid var(--c-border);
}
.cart-line__name { font-weight: var(--fw-semi); font-size: var(--fs-sm); margin: 0 0 2px; }
.cart-line__meta { font-size: var(--fs-xs); color: var(--c-muted); margin: 0; }
.cart-line__price { font-weight: var(--fw-semi); font-size: var(--fs-sm); white-space: nowrap; }

.cart-drawer__foot {
  padding: var(--s-4) var(--s-5) var(--s-5);
  border-top: 1px solid var(--c-border);
  background: rgba(255, 255, 255, 0.03);
}
.cart-drawer__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: var(--fs-lg);
  margin-bottom: var(--s-2);
}
.cart-drawer__note { font-size: var(--fs-xs); color: var(--c-dim); margin: 0 0 var(--s-4); }

/* ==========================================================================
   PAGE JUMP — top / bottom
   ========================================================================== */
.page-jump {
  position: fixed;
  right: clamp(0.75rem, 2vw, 1.4rem);
  bottom: clamp(0.75rem, 2vw, 1.4rem);
  z-index: calc(var(--z-header) - 1);
  display: flex;
  flex-direction: column;
  gap: 6px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--t-base), transform var(--t-base);
  pointer-events: none;
}
.page-jump.is-visible { opacity: 1; transform: none; pointer-events: auto; }
.page-jump__btn {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--c-glass-line);
  background: linear-gradient(160deg, rgba(255,255,255,0.12), rgba(255,255,255,0.04));
  backdrop-filter: blur(14px) saturate(130%);
  -webkit-backdrop-filter: blur(14px) saturate(130%);
  color: var(--c-text);
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 6px 18px -8px rgba(0,0,0,0.9);
  transition: transform var(--t-fast), border-color var(--t-fast), background-color var(--t-fast);
}
.page-jump__btn:hover { border-color: var(--c-glass-hi); transform: translateY(-2px); }
.page-jump__btn:active { transform: translateY(1px); }
/* One arrow glyph, rotated — no second icon to keep in sync. */
[data-page-jump-up] svg   { transform: rotate(-90deg); }
[data-page-jump-down] svg { transform: rotate(90deg); }
/* The buttons sit where a phone's thumb rests; keep them clear of the footer. */
@media (max-width: 600px) { .page-jump { bottom: 1rem; } }

@media (prefers-reduced-motion: reduce) {
  .cart-drawer, .cart-drawer-backdrop, .page-jump, .page-jump__btn { transition: none; }
  .page-jump__btn:hover, .page-jump__btn:active { transform: none; }
}

/* --------------------------------------------------------------------------
   AUTOFILL
   Chrome paints autofilled fields with its own near-white background and black
   text, which on a dark form makes address and ZIP lines read as black on
   black once the surrounding style reasserts itself. The background cannot be
   set directly — the browser overrides it — so a very large inset shadow is
   used to cover the field instead, and -webkit-text-fill-color is what
   actually controls the glyph colour here (plain `color` is ignored).

   The absurd transition delay is the standard trick to defeat the yellow flash
   Chrome animates in on autofill: the animation never reaches its first frame.
   -------------------------------------------------------------------------- */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active,
select:-webkit-autofill,
select:-webkit-autofill:hover,
select:-webkit-autofill:focus,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--c-text) !important;
  caret-color: var(--c-text);
  -webkit-box-shadow: 0 0 0 1000px #121110 inset !important;
          box-shadow: 0 0 0 1000px #121110 inset !important;
  border-color: var(--c-glass-line);
  transition: background-color 100000s ease-in-out 0s;
}

/* Belt and braces for the same symptom without autofill: any field that
   inherits a light colour from a parent still has to draw light-on-dark. */
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]),
select,
textarea {
  color: var(--c-text);
}
input::placeholder, textarea::placeholder { color: var(--c-dim); opacity: 1; }
/* Native pickers render their popup in the OS theme; tell them we are dark so
   the calendar and select lists are not black-on-black either. */
input, select, textarea { color-scheme: dark; }

/* --------------------------------------------------------------------------
   CARD GRIDS ON PHONES — two up, not one
   grid--3 and grid--4 auto-fill from a 280px/240px minimum. On a 390px phone
   neither minimum fits twice, so the grid collapsed to a single column and
   every track and release card rendered ~360px wide — one enormous card per
   row, and a list you had to scroll forever to read.

   Below 600px the column count is stated outright instead of derived from a
   minimum width. minmax(0, 1fr) rather than 1fr is what stops a long title
   from pushing its column wider than the screen: the auto minimum of a grid
   track is its content, and 0 overrides that.
   -------------------------------------------------------------------------- */
@media (max-width: 599.98px) {
  .grid--3,
  .grid--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s-3);
  }
  /* Two-up leaves roughly 165px per card, so the type has to come down with
     it or the titles wrap to four lines. */
  .grid--3 .s-card__title,
  .grid--4 .s-card__title { font-size: var(--fs-sm); }
  .grid--3 .s-card__meta,
  .grid--4 .s-card__meta { font-size: 11px; }
  .grid--3 .s-card__body,
  .grid--4 .s-card__body { padding: var(--s-3); }
}

/* --------------------------------------------------------------------------
   ACTIVE / SELECTED STATES
   The glass treatment gave these a translucent white fill and kept near-white
   text on top. Over a dark section that is just about readable; over a glass
   card the two translucent whites compound and the label disappears into its
   own background — the "white on white" active button.

   Selected state now reads as selected at a glance: the brand gradient with
   white text, the same language as the primary button. Colour here is doing a
   job — telling you which filter is on — rather than decorating.
   -------------------------------------------------------------------------- */
.chip.is-active,
.option-pill.is-selected,
.filter-chips .chip.is-active {
  background: var(--grad-fire);
  background-image: var(--grad-fire);
  border-color: transparent;
  color: #FFFFFF;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28),
              0 6px 16px -8px rgba(255, 90, 31, 0.75);
}
.chip.is-active:hover,
.option-pill.is-selected:hover {
  background-image: var(--grad-fire-hv);
  border-color: transparent;
  color: #FFFFFF;
}
/* The swatch inside a selected colour pill must stay its own colour — it is
   showing you the product colour, not the selection state. */
.option-pill.is-selected .option-pill__swatch { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85); }

/* --------------------------------------------------------------------------
   TOUCH TARGETS
   Two controls sat below a comfortable finger size: the announcement bar's
   close disc (26px) and the filter chips (37-38px).

   The fix expands the TOUCHABLE area without changing the drawn size. A
   pseudo-element stretched past the button's edges is what the finger actually
   hits, so the close disc still reads as a small quiet control and the chips
   keep their compact row — but both become comfortable to tap.

   Growing the visual size instead would have made the announcement bar taller
   on every page and pushed the chip row into wrapping on a phone, which is a
   worse outcome than the problem.
   -------------------------------------------------------------------------- */
/* .chip only. The close disc is ALREADY position:absolute (it is pinned to the
   right of the bar) and is therefore already a containing block for its own
   ::after. Including it here re-declared position at equal specificity but
   later in the file, which won — dropping the button out of absolute
   positioning into normal flow, where it rendered below the text at the left
   edge and made the bar a line taller on phones. */
.chip {
  position: relative;
}
.announcement-bar__close::after,
.chip::after {
  content: '';
  position: absolute;
  /* Pulls the hit area out to at least 44px in both directions. */
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
  /* Invisible, and never intercepts anything the button itself does not. */
  background: transparent;
}

/* Coarse pointers only need the larger target; a mouse is precise enough that
   overlapping invisible boxes would just make neighbouring chips harder to hit. */
@media (hover: hover) and (pointer: fine) {
  .chip::after { display: none; }
}

/* ==========================================================================
   EMBER LINE — the softer burn, for the line above the footer
   A deliberate echo of the hero headline at the other end of the page, sized
   and tuned for a section heading rather than a display headline.

   Three things had to change rather than simply reusing .ignite:

   1. SCALE. feDisplacementMap's `scale` is in absolute pixels. The hero's
      20-34px displacement is right for 64-136px type and would tear a 28px
      heading apart, so this uses the -sm filters at roughly a third of that.

   2. NO ARRIVAL. The hero's flame-gate and hero-char-in fire on page load with
      fixed delays. Down here they would finish long before anyone scrolled
      this far, so the line would simply be there — the animation would be
      wasted work. This variant keeps only the continuous burn.

   3. ITS OWN GROUND. .ignite is deliberately NOT isolated and carries no
      backdrop: the hero's containment and near-black scrim live on .hero__name.
      Reusing .ignite without an equivalent container means the additive
      plus-lighter layers blend against whatever happens to be behind them.
      .ember-line below is that container.
   ========================================================================== */
.ember-line {
  position: relative;
  isolation: isolate;
  display: inline-block;
  /* Head-room, or the plume rises into the line above and — because it blends
     additively — washes that line out. */
  margin: 0.34em 0 0.16em;
  line-height: 1.05;
}
/* The dark ground the flames burn against. The footer region is already near
   black, but .site-footer paints a translucent white glass gradient and is
   itself a stacking context, so the body's black is NOT what these layers
   would otherwise blend with. This supplies it explicitly. */
.ember-line::before {
  content: '';
  position: absolute;
  inset: -0.5em -1.1em -0.35em -0.9em;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 78% 86% at 42% 56%,
    rgba(6, 5, 4, 0.58) 0%, rgba(6, 5, 4, 0.34) 38%, rgba(6, 5, 4, 0.12) 62%, transparent 80%);
}

/* The molten fill, same ramp as the hero so the two read as one family.

   NOTE the longhand. `background:` is a shorthand and resets background-clip to
   border-box, which silently destroys the `background-clip: text` set on the
   base .ignite rule — the gradient then paints the whole box and the line
   renders as a solid orange bar with the glyphs showing only as text-shadow
   extrusion. Same trap the animation shorthand carries just below. */
.ember-line .ignite {
  background-image: linear-gradient(178deg,
    #FFFDF6 0%, #FFEFC2 16%, #FFC53D 38%, #FF8A2B 60%, #EF4A10 80%, #A82408 100%);
  background-size: 100% 240%;
  background-position: 50% 72%;
  /* Shallower extrusion than the hero — at this size the hero's 6-step ramp
     reads as a smudge rather than depth. */
  text-shadow:
    0 1px 0 #C4360C, 0 2px 0 #A82C08, 0 3px 0 #852106,
    0 4px 1px rgba(0, 0, 0, 0.45),
    0 0 18px rgba(255, 90, 31, 0.40);
  /* Only the molten pan — no flame-gate, so no arrival to wait for. */
  animation: ignite-molten 11s ease-in-out infinite;
  /* The flame layers are pseudo-elements painting attr(data-text) on a single
     line. If the .ignite__ch spans wrap, those layers cannot wrap with them and
     the whole string gets painted across a partial line — it reads as the text
     duplicated. .ignite__ch is inline-block, so a break can land between any
     two characters; nowrap is what keeps glyphs and flames in register. The
     heading size clamps instead of wrapping. */
  white-space: nowrap;
}

/* Two flame layers instead of four: a bed of heat and one rising body. At this
   size the hero's tall tongues and tips overlap into a single bright smear
   rather than reading as separate flames. */
.ember-line .ignite::before {
  filter: url(#flame-embers-sm);
  opacity: 0.34;
}
.ember-line .ignite::after {
  filter: url(#flame-churn-sm) saturate(1.3);
  animation-duration: 2.1s;
}
.ember-line .ignite__fire::before {
  filter: url(#flame-churn-sm) saturate(1.4);
  animation-duration: 2.6s;
}

/* Flames break off the TOP of the glyphs rather than sitting over them.
   The hero masks each flame layer across the full height of the text, which
   works when the text is 96px tall and the layers have room to separate. At
   28px those same masks stack three additive orange layers over glyphs barely
   20px tall: plus-lighter saturates, the counters fill in, and the whole line
   renders as a solid orange bar with the letters lost inside it — measured, not
   assumed. Re-masking so each layer fades out before it reaches the glyph body
   keeps the molten fill readable and puts the fire where it belongs. */
.ember-line .ignite::before,
.ember-line .ignite::after,
.ember-line .ignite__fire::before {
  -webkit-mask-image: linear-gradient(to top, transparent 54%, rgba(0,0,0,0.38) 67%, rgba(0,0,0,0.92) 81%, transparent 99%);
          mask-image: linear-gradient(to top, transparent 54%, rgba(0,0,0,0.38) 67%, rgba(0,0,0,0.92) 81%, transparent 99%);
}
/* Held well below the hero: additive layers over small type reach solid fast. */
.ember-line .ignite::before       { opacity: 0.26; }
.ember-line .ignite::after        { opacity: 0.78; }
.ember-line .ignite__fire::before { opacity: 0.64; }
/* The two highest layers are dropped entirely here. */
.ember-line .ignite__fire::after,
.ember-line .ignite__tips::before { display: none; }

/* Shorter travel — the hero's flames climb 0.52em, which at this size would
   throw them clear of the heading and into the paragraph above it. */
.ember-line .ignite::after,
.ember-line .ignite__fire::before {
  animation-name: ember-rise;
}
@keyframes ember-rise {
  0%   { opacity: 0;    transform: translateY(0.18em)  scale(0.99, 0.90); }
  9%   { opacity: 0.48; transform: translateY(0.13em)  scale(1,    0.98); }
  46%  { opacity: 0.44; transform: translateY(0.01em)  scale(1.02, 1.14); }
  76%  { opacity: 0.30; transform: translateY(-0.13em) scale(1.03, 1.30); }
  100% { opacity: 0;    transform: translateY(-0.26em) scale(1.05, 1.44); }
}

@media (max-width: 700px) {
  /* One flame layer on phones. The turbulence filters are the expensive part
     and this is decorative, at the bottom of the page. */
  .ember-line .ignite__fire::before { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .ember-line .ignite,
  .ember-line .ignite::before,
  .ember-line .ignite::after,
  .ember-line .ignite__fire::before { animation: none; }
  .ember-line .ignite::after { opacity: 0.42; }
  .ember-line .ignite__fire::before { opacity: 0.3; }
}

/* --------------------------------------------------------------------------
   NOTE DRIFT — ambient music glyphs rising through the hero

   Each note is a FULL-HEIGHT COLUMN with the glyph pinned to its bottom, not a
   small box positioned near the floor. That is deliberate: percentages inside
   `translate` resolve against the transformed element's OWN border box, so a
   26px note asked to travel -120% moves 31px and never crosses the section.
   Sizing the animated element to the layer instead makes those same
   percentages mean what they read as — a share of the hero's height.

   Two nested animations rather than one. The column carries the vertical rise
   and the fade; the glyph inside carries a lateral sway on its own, shorter,
   non-dividing period. One keyframe set doing both draws a straight diagonal,
   which reads as a slide transition rather than as something adrift; two
   periods that do not divide into each other never repeat the same path.

   z-index -1 puts the layer above the hero scrim and glows (also -1, and this
   partial is mounted after them, so later DOM order wins) while staying behind
   .hero__content, which is positioned and therefore paints above all of them.

   Only transform and opacity animate, so the whole layer stays on the
   compositor and costs no layout or paint while it runs.
   -------------------------------------------------------------------------- */
.note-drift {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: -1;
}
.note-drift__n {
  position: absolute;
  left: var(--x);
  bottom: 0;
  width: var(--sz);
  height: 100%;
  color: var(--col);
  opacity: 0;
  will-change: transform, opacity;
  animation: note-rise var(--dur) linear var(--delay) infinite;
}
.note-drift__n svg {
  position: absolute;
  left: 0;
  bottom: 0;
  width: var(--sz);
  height: var(--sz);
  /* A small bloom, so a note reads as something catching light in the room
     rather than as a flat sticker. Kept tight — a wide halo at this opacity
     turns the field into haze and the glyph stops being legible as a note. */
  filter: drop-shadow(0 0 5px var(--glow));
  animation: note-sway calc(var(--dur) * 0.41) ease-in-out var(--delay) infinite alternate;
}
@keyframes note-rise {
  0%   { transform: translate3d(0, 16%, 0);   opacity: 0; }
  14%  { opacity: var(--op); }
  76%  { opacity: var(--op); }
  100% { transform: translate3d(0, -104%, 0); opacity: 0; }
}
@keyframes note-sway {
  from { transform: translateX(calc(var(--drift) * -0.5)) rotate(calc(var(--rot) * -1)); }
  to   { transform: translateX(var(--drift)) rotate(var(--rot)); }
}

/* A phone shows the nearer half. Nine notes across 390px reads as clutter
   behind the headline rather than as atmosphere. */
@media (max-width: 700px) {
  .note-drift__n--extra { display: none; }
}

/* Motion is the whole point of this layer, so with motion suppressed it holds
   the notes still at low alpha rather than animating them in place. */
@media (prefers-reduced-motion: reduce) {
  .note-drift__n,
  .note-drift__n svg { animation: none; }
  .note-drift__n { opacity: calc(var(--op) * 0.8); transform: translate3d(0, -55%, 0); }
}

/* A short band — a page hero rather than the full home hero — takes the same
   sparser field a phone gets. Eighteen notes crossing 250px reads as clutter;
   the same seven read as atmosphere. */
.note-drift--compact .note-drift__n--extra { display: none; }

/* --------------------------------------------------------------------------
   SPLIT — MATCHED CARD PAIR

   .split defaults to align-items:center, which is correct for its usual job of
   setting a block of text beside an image: the two have unrelated heights and
   centring is what keeps them optically level.

   It is wrong when both children are cards. The shorter card then hovers in
   the middle of the taller one, sharing neither top nor bottom edge, and the
   row reads as two panels that happen to be near each other rather than as one
   band. Stretching makes them a matched pair, and centring the content inside
   the shorter one keeps it from sitting in the top corner of its new height.
   -------------------------------------------------------------------------- */
.split--cards { align-items: stretch; }
.split--cards > .s-card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* The taller card fills naturally, so centring is a no-op there; it only
     takes effect on whichever card has room to spare. */
}
/* Stacked on a phone there is no pair to match, so height equalising would
   just add dead space inside whichever card has less to say. */
@media (max-width: 767.98px) {
  .split--cards > .s-card { justify-content: flex-start; }
}

/* A section hosting the drifting notes. .section is already position:relative,
   but that alone is not enough: .note-drift sits at z-index -1, and without a
   stacking context here a negative-z child paints BEHIND its own section's
   background — which for .section--alt is opaque, so the notes would vanish.
   isolation:isolate creates that context with no other layout effect, putting
   the layer above the section background and below the section's content. */
.section--notes { isolation: isolate; }

/* The home page gallery is a TEASER for /gallery, not the gallery itself.
   .grid--gallery tracks are `1fr`, so with only two photographs each one
   stretches to roughly 600px on a desktop — a pair of slabs that outweighs
   every other section on the page. Capping the row keeps them small and
   left-aligned under the section heading, which is where the eye already is.
   The full /gallery page keeps the stretching tracks, where many items make
   them the right call. */
.grid--gallery-sm {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  max-width: 620px;
}

/* --------------------------------------------------------------------------
   MOBILE REPAIRS — MERCH STORE

   1. A badge carries its own type scale, but `.page-hero p` (0,1,1) is more
      specific than `.badge` (0,1,0), so the intro-copy size won and the free
      shipping pill rendered at 18px uppercase instead of 11px. At that size it
      spans the full width of a phone, wraps onto two lines, and the 13px truck
      icon is left stranded beside a two-line block. Restoring the badge's own
      size puts it back on one line and the icon back beside its text.
   -------------------------------------------------------------------------- */
/* Written as p.badge rather than .page-hero p.badge so it also outranks
   `.prose p`, which sets the same large prose size and would inflate a badge
   in exactly the same way. Both offenders are (0,1,1); so is this, and it
   comes later in the file. Eight views put a badge inside .page-hero, so this
   was site-wide rather than a Merch Store problem. */
p.badge,
p.s-badge {
  font-size: 11px;
  /* Those prose rules also set a 62ch measure; a pill sizes to its content. */
  max-width: 100%;
}

/* 2. Product cards sit two to a row below 600px, leaving roughly 140px of
      content width. The default pill padding plus the leading icon pushes
      "Choose options" past that, so it wrapped onto a second line inside a
      45px-tall button. Tighter side padding lets the label sit on one line
      without shrinking the tap target. */
@media (max-width: 600px) {
  .product-card .btn,
  .product-card .btn-sm {
    padding-inline: var(--s-2);
    gap: 0.3rem;
  }
  .product-card .btn { font-size: 11.5px; }
}
