/* ==========================================================================
   NYROX Design System
   A minimal, premium design system for a phone-case brand fulfilled via
   Printify. Warm neutral base, single copper accent, generous whitespace.
   ========================================================================== */

:root {
  /* ---- Color tokens (oklch: consistent lightness/chroma, hue varies) ---- */
  --bg:            oklch(98.2% 0.006 85);   /* warm bone white, page bg */
  --surface:       oklch(100% 0    0);       /* pure white, cards/panels */
  --surface-sunken:oklch(95.5% 0.008 85);   /* soft warm grey, section bg */
  --border:        oklch(89% 0.010 85);
  --border-strong: oklch(80% 0.014 85);

  --ink:           oklch(19% 0.014 80);      /* primary text, warm near-black */
  --ink-muted:     oklch(45% 0.014 80);      /* secondary text */
  --ink-faint:     oklch(52% 0.012 80);      /* tertiary text: dark enough to clear 4.5:1 on --surface */

  --accent:        oklch(58% 0.135 45);      /* copper/clay — primary brand color */
  --accent-strong: oklch(48% 0.135 45);      /* hover/active state */
  --accent-soft:   oklch(93% 0.03  50);      /* tinted backgrounds, badges */
  --accent-ink:    oklch(99% 0.006 85);      /* text on accent */

  --success:       oklch(55% 0.11 150);
  --success-soft:  oklch(94% 0.03 150);
  --danger:        oklch(52% 0.16 28);

  /* The footer is deliberately dark in BOTH themes, so it needs its own fixed values —
     riding on --ink would flip it to near-white the moment dark mode kicked in. */
  --footer-bg:     oklch(14% 0.014 80);
  --footer-text:   oklch(90% 0.010 85);
  --footer-muted:  oklch(70% 0.012 85);
  --footer-border: oklch(30% 0.012 85);

  /* ---- Type scale ---- */
  --font-display: 'Fraunces', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
  --font-body:    'Public Sans', -apple-system, 'Segoe UI', sans-serif;

  --text-xs:   0.75rem;
  --text-sm:   0.875rem;
  --text-base: 1rem;
  --text-lg:   1.125rem;
  --text-xl:   1.375rem;
  --text-2xl:  1.875rem;
  --text-3xl:  2.5rem;
  --text-4xl:  3.5rem;
  --text-5xl:  4.75rem;

  /* ---- Spacing scale ---- */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;
  --sp-9: 6rem;
  --sp-10: 8rem;

  /* ---- Misc ---- */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 14px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --container: 1240px;

  --shadow-sm: 0 1px 2px oklch(19% 0.014 80 / 0.06);
  --shadow-md: 0 8px 24px oklch(19% 0.014 80 / 0.08);
  --shadow-lg: 0 24px 64px oklch(19% 0.014 80 / 0.14);
}

/* ---------------------------- Reset ---------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent-strong); }
button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }
button { cursor: pointer; }
ul { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.1;
  margin: 0;
  letter-spacing: -0.01em;
}
p { margin: 0; }

.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--sp-6);
}
@media (max-width: 640px) {
  .container { padding-inline: var(--sp-4); }
}

.eyebrow {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-strong);
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ---------------------------- Logo ----------------------------
   Drawn vector lockup (case-shell mark + custom NYROX letterforms). The ink half follows
   currentColor so it inverts for dark mode and the dark footer without a second copy of the
   artwork; only the accent is pinned to a palette token. */
.logo {
  display: inline-flex;
  align-items: center;
  color: var(--ink);
  /* the artwork is only ~23px tall, which made "back to home" — the single most-tapped link
     on any site — a 23px-high target. The box grows, the logo does not. */
  min-height: 44px;
}
.logo-lockup { height: 27px; width: auto; display: block; flex-shrink: 0; }
.logo-lockup-mark { height: 30px; }
@media (max-width: 420px) { .logo-lockup { height: 23px; } }

/* ---------------------------- Buttons ---------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 0.85rem 1.6rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.02em;
  min-height: 44px;
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease),
              color 0.2s var(--ease), transform 0.15s var(--ease);
}
.btn:active { transform: scale(0.97); }

.btn-primary {
  background: var(--ink);
  color: var(--bg);
}
.btn-primary:hover { background: var(--accent-strong); color: var(--accent-ink); }

.btn-accent {
  background: var(--accent);
  color: var(--accent-ink);
}
.btn-accent:hover { background: var(--accent-strong); }

.btn-outline {
  background: transparent;
  border-color: var(--border-strong);
  color: var(--ink);
}
.btn-outline:hover { border-color: var(--ink); background: var(--surface-sunken); }

.btn-ghost {
  background: transparent;
  color: var(--ink-muted);
  padding-inline: var(--sp-2);
}
.btn-ghost:hover { color: var(--ink); }

.btn-block { width: 100%; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* Icon buttons (cart, search, menu) */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  /* without these two a <button> keeps the browser's default grey fill and border, which
     read as solid light discs in the dark header */
  background: none;
  border: none;
  color: var(--ink);
  transition: background-color 0.2s var(--ease);
  position: relative;
}
.icon-btn:hover { background: var(--surface-sunken); color: var(--ink); }
.icon-btn svg { width: 20px; height: 20px; }
.icon-btn .badge {
  position: absolute; top: 2px; right: 2px;
  background: var(--accent); color: var(--accent-ink);
  font-size: 10px; font-weight: 700;
  width: 16px; height: 16px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}

/* ---------------------------- Header / Nav ---------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in oklch, var(--bg) 85%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s var(--ease);
}
.site-header.is-scrolled { border-bottom-color: var(--border); }

.nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: var(--sp-4);
}
.nav-links {
  display: flex;
  align-items: center;
  gap: var(--sp-6);
}
.nav-links a {
  position: relative;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink-muted);
  padding-block: var(--sp-2);
  transition: color 0.2s var(--ease);
}
/* The rule is drawn as a pseudo-element that scales from the centre, so moving between
   items reads as the underline travelling rather than one blinking off and another on. */
.nav-links a::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--accent); border-radius: 2px;
  transform: scaleX(0); transform-origin: center;
  transition: transform 0.28s var(--ease);
}
.nav-links a:hover { color: var(--ink); }
.nav-links a:hover::after { transform: scaleX(0.55); }
.nav-links a.is-active { color: var(--ink); font-weight: 600; }
.nav-links a.is-active::after { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) { .nav-links a::after { transition: none; } }
.nav-actions { display: flex; align-items: center; gap: var(--sp-1); }
.nav-menu-btn { display: none; }

@media (max-width: 860px) {
  .nav-links { display: none; }
  .nav-menu-btn { display: inline-flex; }
}

/* ---------------------------- Hero ---------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  padding-block: var(--sp-10) var(--sp-9);
  background: var(--bg);
}
.hero::before {
  content: "";
  position: absolute;
  top: -20%; right: -10%;
  width: 60%; aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, var(--accent-soft), transparent 70%);
  opacity: 0.9;
  z-index: 0;
}
.hero-inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: var(--sp-8);
  align-items: center;
}
.hero-eyebrow { margin-bottom: var(--sp-4); }
.hero h1 {
  font-size: clamp(2.5rem, 5vw, var(--text-5xl));
  max-width: 14ch;
}
.hero-sub {
  margin-top: var(--sp-5);
  max-width: 42ch;
  color: var(--ink-muted);
  font-size: var(--text-lg);
}
.hero-actions {
  margin-top: var(--sp-6);
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.hero-trust {
  margin-top: var(--sp-7);
  display: flex;
  gap: var(--sp-6);
  color: var(--ink-muted);
  font-size: var(--text-sm);
}
.hero-trust strong { color: var(--ink); font-family: var(--font-display); font-size: var(--text-xl); display: block; }

.hero-visual {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-lg);
  background: linear-gradient(150deg, color-mix(in oklch, var(--surface-sunken) 82%, var(--accent-soft)), var(--surface-sunken) 62%);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}
.hero-visual img { width: 100%; height: 100%; object-fit: cover; }

/* A single centred outline read as an empty placeholder box. Three cases at different depths
   show the actual range instead, so the panel reads as a shelf rather than a frame around nothing. */
.hero-stack { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.hero-stack::after {
  content: ""; position: absolute; width: 62%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in oklch, var(--accent) 30%, transparent), transparent 68%);
  filter: blur(6px);
  /* purely decorative — without this it sits over the phones and eats their clicks */
  pointer-events: none;
}
/* all three phones are links now, so all three need the pointer and a visible focus ring —
   previously only the front one looked clickable, and it was the only one that was */
.hero-case { position: absolute; transition: transform 0.6s var(--ease), opacity 0.3s var(--ease), filter 0.3s var(--ease); background: none; border: none; padding: 0; line-height: 0; cursor: pointer; border-radius: 22px; }
.hero-case:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; }
/* the back two are dimmed to sit behind the front one; hovering brings the colour back so
   it is obvious each is its own destination — without reordering them, which reads as a
   glitch rather than as feedback */
.hero-case-back:hover, .hero-case-mid:hover { opacity: 0.95; filter: saturate(1); }
.hero-case svg { display: block; height: auto; }
.hero-case-back  { width: 40%; transform: translateX(-46%) rotate(-13deg); opacity: 0.5; filter: saturate(0.68); }
.hero-case-mid   { width: 42%; transform: translateX(42%) rotate(11deg);  opacity: 0.72; filter: saturate(0.88); }
.hero-case-front { width: 50%; transform: translateY(-1%); cursor: pointer; filter: drop-shadow(0 18px 32px oklch(19% 0.014 80 / 0.28)); }
.hero-visual:hover .hero-case-back  { transform: translateX(-52%) rotate(-16deg); }
.hero-visual:hover .hero-case-mid   { transform: translateX(48%) rotate(14deg); }
.hero-visual:hover .hero-case-front { transform: translateY(-4%) scale(1.02); }
@media (prefers-reduced-motion: reduce) { .hero-case { transition: none; } }
.hero-visual .placeholder-note {
  color: var(--ink-faint); font-size: var(--text-sm); text-align: center; padding: var(--sp-6);
}

@media (max-width: 860px) {
  .hero-inner { grid-template-columns: 1fr; }
  /* The image used to be ordered above the copy, so a phone opened on a case illustration
     and the headline started roughly 600px down — the pitch was below the fold on the device
     most visitors arrive on. Copy first, picture after. */
  .hero-visual { order: 0; aspect-ratio: 4/3; }
  .hero-inner { gap: var(--sp-6); }
  .hero-case-front { width: 34%; }
  .hero-case-back { width: 27%; }
  .hero-case-mid { width: 28%; }
}

/* ---------------------------- Sections ---------------------------- */
.section { padding-block: var(--sp-9); }
/* 96px above and below reads as generous on a 900px desktop window; on a 390px phone the
   same figure is roughly a quarter of the screen in empty space between every section, and
   it was making the home page 8.7 screens long against 5.7 on desktop. The proportion, not
   the pixel value, is what should carry across. */
@media (max-width: 640px) {
  .section { padding-block: var(--sp-8); }
}
.section-sunken { background: var(--surface-sunken); }
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-5);
  margin-bottom: var(--sp-7);
}
.section-head h2 { font-size: var(--text-3xl); }
.section-head p { color: var(--ink-muted); margin-top: var(--sp-2); }

/* Value props / trust strip */
.value-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-6);
}
.value-card {
  padding: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color 0.25s var(--ease), transform 0.25s var(--ease);
}
.value-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.value-card .icon { width: 28px; height: 28px; color: var(--accent); margin-bottom: var(--sp-4); }
.value-card h3 { font-size: var(--text-lg); font-family: var(--font-body); font-weight: 600; }
.value-card p { color: var(--ink-muted); margin-top: var(--sp-2); font-size: var(--text-sm); }

@media (max-width: 780px) {
  .value-grid { grid-template-columns: 1fr; }
}

/* ---------------------------- Product Grid / Cards ---------------------------- */
/* Three across, not four. With a four-design catalogue plus the custom-design tile, a
   four-column grid put one lonely card on a second row and left three empty slots — worse
   than the gap it was meant to fill. Three columns makes 3 + 2, fills the space far more
   evenly, and gives each piece of artwork noticeably more room, which matters when the
   artwork IS the product. Revisit this once there are enough designs to fill four. */
.product-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-5);
}
@media (max-width: 780px)  { .product-grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); } }

.product-card { display: block; }
.product-card-media {
  position: relative;
  aspect-ratio: 1 / 1.15;
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  overflow: hidden;
  margin-bottom: var(--sp-3);
  display: flex; align-items: center; justify-content: center;
  transition: box-shadow 0.3s var(--ease), background-color 0.3s var(--ease);
}
/* The case art is the product, so it gets the hover response — a slight lift and grow. */
.product-card-media .case-art { transition: transform 0.45s var(--ease); }
.product-card:hover .product-card-media {
  box-shadow: var(--shadow-md);
  background: color-mix(in oklch, var(--surface-sunken) 88%, var(--accent-soft));
}
.product-card:hover .product-card-media .case-art { transform: translateY(-6px) scale(1.045); }
.product-card-title { transition: color 0.2s var(--ease); }
.product-card:hover .product-card-title { color: var(--accent-strong); }
.product-card-media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 0.5s var(--ease);
}
.product-card:hover .product-card-media img { transform: scale(1.05); }
.product-card-badge {
  position: absolute; z-index: 2; top: var(--sp-3); left: var(--sp-3);
  background: var(--surface); color: var(--ink);
  font-size: var(--text-xs); font-weight: 600;
  padding: 0.25rem 0.6rem; border-radius: 999px;
  box-shadow: var(--shadow-sm);
}
.product-card-quick {
  position: absolute; z-index: 2; left: var(--sp-3); right: var(--sp-3); bottom: var(--sp-3);
  opacity: 0; transform: translateY(6px);
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
}
.product-card:hover .product-card-quick { opacity: 1; transform: translateY(0); }
.product-card-title { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.product-card-meta { font-size: var(--text-sm); color: var(--ink-muted); margin-top: 2px; }
.product-card-price { font-weight: 600; }

/* ---------------------------- Shop layout / Sidebar ---------------------------- */
.shop-layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: var(--sp-8);
  align-items: start;
}
@media (max-width: 900px) {
  .shop-layout { grid-template-columns: 1fr; }
}

.filter-sidebar {
  position: sticky;
  top: 96px;
  border-right: 1px solid var(--border);
  padding-right: var(--sp-6);
}
@media (max-width: 900px) {
  .filter-sidebar { position: static; border-right: none; padding-right: 0; padding-bottom: var(--sp-5); border-bottom: 1px solid var(--border); }
}

.filter-group { padding-block: var(--sp-5); border-bottom: 1px solid var(--border); }
.filter-group:first-child { padding-top: 0; }
.filter-group:last-child { border-bottom: none; }

.filter-title {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--text-sm); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--ink); margin-bottom: var(--sp-3);
}
.filter-title svg { width: 15px; height: 15px; color: var(--accent); }

.filter-option {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-2);
  margin-inline: calc(var(--sp-2) * -1);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--ink-muted);
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}
.filter-option:hover { background: var(--surface-sunken); color: var(--ink); }
.filter-option.is-active { color: var(--ink); font-weight: 600; background: var(--accent-soft); }
.filter-option .count { margin-left: auto; color: var(--ink-faint); font-size: var(--text-xs); }

.filter-checkbox {
  width: 16px; height: 16px; border-radius: 4px;
  border: 1.5px solid var(--border-strong);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease);
}
/* The tick only had a size rule inside .is-active, so unselected boxes fell back to the
   SVG's intrinsic size and rendered a visible tick — every case-type filter looked already
   selected on page load. Hide it explicitly when the option is off. */
.filter-checkbox svg { display: none; }
.filter-option.is-active .filter-checkbox { background: var(--ink); border-color: var(--ink); }
.filter-option.is-active .filter-checkbox svg { display: block; width: 10px; height: 10px; color: var(--bg); }
.filter-option:hover .filter-checkbox { border-color: var(--ink); }
.filter-option:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); }

/* Case type is a pick-one that reprices the grid, not a filter that narrows it. Round
   controls say "choose one of these"; square ticks say "narrow the results", which is what
   the phone-model list above actually does. Different jobs should not look identical. */
.filter-radios .filter-checkbox { border-radius: 50%; }
.filter-radios .filter-option.is-active .filter-checkbox { background: var(--accent); border-color: var(--accent); }
.filter-radios .filter-option.is-active .filter-checkbox svg { color: var(--accent-ink); }
.filter-note { font-size: var(--text-xs); color: var(--ink-faint); margin: calc(var(--sp-2) * -1) 0 var(--sp-3); line-height: 1.5; }

/* Shown when a model filter leaves nothing — a grid that silently empties reads as broken. */
.shop-empty { margin-top: var(--sp-6); color: var(--ink-muted); font-size: var(--text-sm); line-height: 1.6; }
.shop-empty button {
  background: none; border: none; padding: 0; font: inherit; color: var(--ink);
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.shop-empty a { color: var(--accent-strong); text-decoration: underline; text-underline-offset: 2px; }

.shop-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  margin-bottom: var(--sp-6);
  padding-bottom: var(--sp-5);
  border-bottom: 1px solid var(--border);
  font-size: var(--text-sm); color: var(--ink-muted);
}
/* The sort control used to carry these as inline styles at 14px. iOS Safari zooms the whole
   page in when you focus a form control smaller than 16px, and it does not zoom back out —
   so tapping "sort" left the visitor stranded at 1.15× with the layout overflowing. 16px is
   the threshold; the visual size is held down with padding instead. */
.sort-select {
  border: none; background: none; color: var(--ink-muted);
  font-size: 16px; padding: var(--sp-2) var(--sp-1);
  min-height: 44px; max-width: 100%;
}

/* ---------------------------- Product detail ---------------------------- */
.pdp-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-9);
  align-items: start;
}
@media (max-width: 900px) { .pdp-layout { grid-template-columns: 1fr; gap: var(--sp-6); } }

.pdp-gallery-main {
  position: relative;
  aspect-ratio: 1/1.1;
  border-radius: var(--radius-lg);
  background: linear-gradient(150deg, color-mix(in oklch, var(--surface-sunken) 84%, var(--accent-soft)), var(--surface-sunken) 65%);
  overflow: hidden;
  margin-bottom: var(--sp-3);
  display: flex; align-items: center; justify-content: center;
}
.pdp-gallery-main .case-art {
  filter: drop-shadow(0 16px 30px oklch(19% 0.014 80 / 0.22));
  transition: transform 0.5s var(--ease);
}
.pdp-gallery-main img { width: 100%; height: 100%; object-fit: cover; }
.pdp-gallery-thumbs { display: flex; gap: var(--sp-3); }
.pdp-thumb {
  width: 76px; height: 76px; border-radius: var(--radius-sm);
  background: var(--surface-sunken); overflow: hidden; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1.5px solid transparent; transition: border-color 0.2s var(--ease);
}
.pdp-thumb.is-active { border-color: var(--ink); }
.pdp-thumb img { width: 100%; height: 100%; object-fit: cover; }

.pdp-info .eyebrow { margin-bottom: var(--sp-2); }
.pdp-info h1 { font-size: var(--text-3xl); }
.pdp-price { font-size: var(--text-xl); font-weight: 600; margin-top: var(--sp-3); }
.pdp-desc { color: var(--ink-muted); margin-top: var(--sp-4); max-width: 52ch; }

.option-block { margin-top: var(--sp-6); }
.option-label {
  display: flex; justify-content: space-between;
  font-size: var(--text-sm); font-weight: 600; margin-bottom: var(--sp-3);
}
.option-label .selected-value { color: var(--ink-muted); font-weight: 400; }

.pill-group { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.pill {
  padding: 0.6rem 1rem;
  /* an explicit background and colour matter here: a <button> with neither falls back to the
     browser's default grey, which in dark mode sits light-on-light and is unreadable */
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: var(--text-sm);
  font-family: inherit;
  min-height: 40px;
  display: inline-flex; align-items: center;
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease), color 0.2s var(--ease);
}
.pill:hover { border-color: var(--ink); }
.pill.is-selected { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.pill.is-disabled { opacity: 0.35; text-decoration: line-through; pointer-events: none; }

.pdp-actions { display: flex; gap: var(--sp-3); margin-top: var(--sp-7); }

.pdp-fine-print {
  margin-top: var(--sp-6);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: var(--sp-3);
}
.fine-print-row { display: flex; gap: var(--sp-3); font-size: var(--text-sm); color: var(--ink-muted); }
.fine-print-row svg { width: 18px; height: 18px; color: var(--accent); flex-shrink: 0; margin-top: 1px; }

.accordion { border-top: 1px solid var(--border); }
.accordion-item { border-bottom: 1px solid var(--border); }
.accordion-trigger {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  padding-block: var(--sp-4); background: none; border: none; text-align: left;
  font-size: var(--text-base); font-weight: 600;
}
.accordion-trigger svg { width: 16px; height: 16px; transition: transform 0.25s var(--ease); }
.accordion-item.is-open .accordion-trigger svg { transform: rotate(45deg); }
.accordion-panel {
  max-height: 0; overflow: hidden; transition: max-height 0.3s var(--ease);
  color: var(--ink-muted); font-size: var(--text-sm);
}
.accordion-item.is-open .accordion-panel { max-height: 240px; padding-bottom: var(--sp-4); }

/* ---------------------------- Forms ---------------------------- */
.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field label { font-size: var(--text-sm); font-weight: 600; }
.field input, .field textarea, .field select {
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  min-height: 44px;
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px var(--accent-soft);
}
.field-row { display: flex; gap: var(--sp-3); }
/* flex items default to min-width:auto, so the two side-by-side fields refused to shrink
   below their inputs' intrinsic width and pushed the checkout page sideways on phones */
.field-row .field { flex: 1 1 0; min-width: 0; }
.field-row .field input { max-width: 100%; }
@media (max-width: 460px) { .field-row { flex-direction: column; gap: 0; } }

.newsletter-form { display: flex; gap: var(--sp-2); max-width: 420px; flex-wrap: wrap; }
/* Same trap as the checkout fields had: a flex item defaults to min-width:auto, so the input
   refused to shrink below its placeholder's intrinsic width and pushed the whole page sideways
   on a 320px screen. min-width:0 lets it shrink; the wrap is the fallback if it still can't. */
.newsletter-form input { flex: 1 1 12rem; min-width: 0; }
.newsletter-form .btn { flex: 0 0 auto; }
.form-note { font-size: var(--text-xs); color: var(--ink-faint); margin-top: var(--sp-2); }
.form-success { color: var(--success); font-size: var(--text-sm); font-weight: 600; display: none; }
.form-success.is-visible { display: block; }

/* ---------------------------- Footer ---------------------------- */
.site-footer { background: var(--footer-bg); color: var(--footer-text); padding-top: var(--sp-8); }
.footer-top {
  display: grid;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  gap: var(--sp-7);
  padding-bottom: var(--sp-8);
}
@media (max-width: 780px) {
  .footer-top { grid-template-columns: 1fr 1fr; }
}
.footer-brand .logo, .footer-brand .logo-lockup { color: var(--footer-text); }
.footer-brand p { color: var(--footer-muted); font-size: var(--text-sm); margin-top: var(--sp-4); max-width: 32ch; }
/* h3, not h4: the footer used to sit right after other h4s with no gap, but the legal pages'
   sections are h2 now — leaving this at h4 would have opened a new h2-to-h4 skip on exactly
   the two pages the fix was for. h3 also fits every other page, which already has real h3
   content (FAQ items, checkout sections) between the page's h2s and this footer. */
.footer-col h3 {
  font-family: var(--font-body); font-size: var(--text-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: oklch(70% 0.012 85); margin-bottom: var(--sp-4);
}
.footer-col ul { display: flex; flex-direction: column; gap: var(--sp-3); }
.footer-col a { font-size: var(--text-sm); color: var(--footer-text); transition: color 0.2s var(--ease); }
.footer-col a:hover { color: var(--accent); }
.footer-social { display: flex; gap: var(--sp-3); margin-top: var(--sp-5); }
.footer-social a {
  width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--footer-border);
  display: flex; align-items: center; justify-content: center;
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease);
}
.footer-social a:hover { border-color: var(--accent); background: color-mix(in oklch, var(--footer-bg) 70%, var(--accent)); }
.footer-social svg { width: 16px; height: 16px; }

.footer-bottom {
  border-top: 1px solid var(--footer-border);
  padding-block: var(--sp-5);
  display: flex; align-items: center; justify-content: space-between;
  font-size: var(--text-xs); color: var(--footer-muted);
  flex-wrap: wrap; gap: var(--sp-3);
}
.footer-legal { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
.footer-legal button {
  background: none; border: none; padding: 0; font: inherit; color: inherit;
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.footer-legal button:hover { color: var(--accent); }
.footer-brand p a { color: var(--footer-text); transition: color 0.2s var(--ease); }
.footer-brand p a:hover { color: var(--accent); }
.footer-col a[href^="tel:"], .footer-col a[href^="mailto:"] { color: var(--footer-text); }
.payment-icons { display: flex; gap: var(--sp-2); opacity: 0.8; }
.payment-icons svg { height: 18px; width: auto; }

/* ---------------------------- Cookie consent banner ---------------------------- */
.cookie-banner {
  position: fixed; left: var(--sp-4); right: var(--sp-4); bottom: var(--sp-4);
  z-index: 250; max-width: 520px; margin-inline: auto;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  padding: var(--sp-5); display: none;
}
.cookie-banner.is-open { display: block; }
.cookie-banner p { font-size: var(--text-sm); color: var(--ink-muted); margin: 0 0 var(--sp-4); }
.cookie-banner a.cookie-link { color: var(--ink); text-decoration: underline; }
.cookie-actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.cookie-actions .btn { flex: 1; min-width: 140px; }

/* ---------------------------- Demo-only notes ---------------------------- */
.demo-note { font-size: var(--text-xs); color: var(--ink-faint); text-align: left; margin-top: var(--sp-2); line-height: 1.5; }

/* ---------------------------- Field errors (checkout / forms) ---------------------------- */
.field-error { color: var(--danger); font-size: var(--text-xs); display: none; margin-top: -2px; }
.field.has-error input, .field.has-error textarea, .field.has-error select { border-color: var(--danger); }
.field.has-error .field-error { display: block; }

/* ---------------------------- Sticky buy bar (product page) ---------------------------- */
.buy-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 150;
  background: color-mix(in oklch, var(--bg) 94%, transparent); backdrop-filter: blur(10px);
  border-top: 1px solid var(--border); box-shadow: var(--shadow-lg);
  transform: translateY(100%); pointer-events: none;
  transition: transform 0.3s var(--ease);
}
.buy-bar.is-visible { transform: translateY(0); pointer-events: auto; }
.buy-bar-inner { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); padding-block: var(--sp-3); }
.buy-bar-info { display: flex; flex-direction: column; min-width: 0; }
.buy-bar-title { font-weight: 600; font-size: var(--text-sm); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.buy-bar-price { color: var(--ink-muted); font-size: var(--text-sm); }
.buy-bar .btn { flex-shrink: 0; }
@media (max-width: 480px) { .buy-bar-title { max-width: 45vw; } }

/* ---------------------------- Checkout / payment preview page ---------------------------- */
.breadcrumbs { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--text-xs); color: var(--ink-faint); margin-bottom: var(--sp-5); flex-wrap: wrap; }
/* 12px text gives a ~19px-high link. These are real navigation, not prose, so they get
   padding to clear the 24px minimum without changing how the trail looks. */
.breadcrumbs a { color: var(--ink-muted); display: inline-flex; align-items: center; min-height: 24px; padding-block: var(--sp-1); }
.breadcrumbs a:hover { color: var(--accent-strong); }
.breadcrumbs [aria-current="page"] { color: var(--ink); font-weight: 600; }
.checkout-layout { display: grid; grid-template-columns: 1.3fr 0.9fr; gap: var(--sp-9); align-items: start; }
/* Grid items default to min-width:auto, so the form refused to shrink below the
   intrinsic width of the disclaimer text and pushed the page sideways on phones. */
.checkout-layout > * { min-width: 0; }
.checkout-preview-note > span { min-width: 0; }
@media (max-width: 900px) { .checkout-layout { grid-template-columns: 1fr; gap: var(--sp-6); } }
.checkout-section { margin-bottom: var(--sp-7); }
.checkout-section-title { font-size: var(--text-lg); font-family: var(--font-body); font-weight: 600; margin-bottom: var(--sp-4); }
.checkout-section .field { margin-bottom: var(--sp-4); }
.checkout-preview-note {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  background: var(--accent-soft); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: var(--sp-4); margin-bottom: var(--sp-7); font-size: var(--text-sm); color: var(--ink);
}
.checkout-preview-note svg { width: 18px; height: 18px; color: var(--accent-strong); flex-shrink: 0; margin-top: 1px; }
.checkout-summary { background: var(--surface-sunken); border-radius: var(--radius-lg); padding: var(--sp-6); position: sticky; top: calc(var(--sp-6) + 72px); }
@media (max-width: 900px) { .checkout-summary { position: static; } }
.checkout-summary-item { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: var(--text-sm); padding-block: var(--sp-2); color: var(--ink-muted); }
.checkout-summary-item span:first-child { color: var(--ink); }
.checkout-summary-row { display: flex; justify-content: space-between; font-size: var(--text-sm); color: var(--ink-muted); padding-block: var(--sp-2); border-top: 1px solid var(--border); margin-top: var(--sp-2); }
.checkout-summary-total { font-weight: 700; color: var(--ink); font-size: var(--text-base); border-top: 1px solid var(--border-strong); margin-top: var(--sp-3); padding-top: var(--sp-3); }
.checkout-help { text-align: center; margin-top: var(--sp-4); font-size: var(--text-sm); color: var(--ink-muted); }
.checkout-success { display: none; background: var(--success-soft); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--sp-5); margin-bottom: var(--sp-6); }
.checkout-success.is-visible { display: block; }
.checkout-success h3 { font-size: var(--text-lg); margin-bottom: var(--sp-2); }
.checkout-success p { color: var(--ink-muted); font-size: var(--text-sm); }

/* ---------------------------- Legal content (Terms / Privacy) ---------------------------- */
.legal-body { font-size: var(--text-sm); color: var(--ink-muted); display: flex; flex-direction: column; gap: var(--sp-3); max-width: 72ch; }
/* the numbered sections are real headings in the page outline (h2, one level under the page's
   h1) rather than h4 chosen only for its smaller default size — a screen reader user jumping
   by heading level should not hit nothing between the title and eleven identically-deep items */
.legal-body h2 { color: var(--ink); font-size: var(--text-base); font-weight: 700; font-family: var(--font-body); margin-top: var(--sp-3); }
.legal-body a { color: var(--accent-strong); text-decoration: underline; text-underline-offset: 2px; }

/* ---------------------------- Mobile drawer ---------------------------- */
.drawer-overlay {
  position: fixed; inset: 0; background: oklch(19% 0.014 80 / 0.4);
  opacity: 0; pointer-events: none; transition: opacity 0.25s var(--ease);
  z-index: 200;
}
.drawer-overlay.is-open { opacity: 1; pointer-events: auto; }
.mobile-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(320px, 84vw);
  background: var(--bg); transform: translateX(100%);
  transition: transform 0.3s var(--ease); z-index: 201;
  padding: var(--sp-6); overflow-y: auto;
}
.mobile-drawer.is-open { transform: translateX(0); }
.mobile-drawer .nav-links { display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; margin-top: var(--sp-6); }
.drawer-head { display: flex; justify-content: space-between; align-items: center; }

/* ---------------------------- Utility ---------------------------- */
.text-center { text-align: center; }
.mt-0 { margin-top: 0 !important; }
.stack { display: flex; flex-direction: column; }
/* Note: scroll-reveal was deliberately dropped — it risked leaving
   below-the-fold content invisible if JS didn't run. Hover/press states
   above carry the motion instead. */


/* ---------------------------- Process sequence ----------------------------
   A genuine numbered sequence (design -> print -> ship), so the numerals carry real
   information rather than decoration: they get the accent and the display face to say so,
   with a connector between consecutive steps to make the order legible at a glance. */
.process-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-6); position: relative; }
.process-step { position: relative; padding-top: var(--sp-2); }
.process-step::after {
  content: ""; position: absolute; top: 34px; left: 62px;
  right: calc(10px - var(--sp-6)); height: 1px; background: var(--border-strong);
}
.process-step:last-child::after { display: none; }
.process-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; border-radius: 50%;
  background: var(--bg); border: 1px solid var(--border-strong);
  color: var(--accent-strong); font-family: var(--font-display);
  font-size: var(--text-xl); font-weight: 600; font-variant-numeric: tabular-nums;
  margin-bottom: var(--sp-4);
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.process-step:hover .process-num { border-color: var(--accent); background: var(--accent-soft); }
.process-step h3 { font-size: var(--text-xl); }
.process-step p { color: var(--ink-muted); margin-top: var(--sp-2); font-size: var(--text-sm); max-width: 34ch; }
@media (max-width: 760px) {
  .process-grid { grid-template-columns: 1fr; gap: var(--sp-7); }
  .process-step::after { display: none; }
}

/* The one place the accent owns a whole surface, so the page has a warm stopping point
   between the process story and the FAQ instead of another plain panel. */
.section-accent {
  background: linear-gradient(120deg, var(--accent-soft), color-mix(in oklch, var(--accent-soft) 45%, var(--surface-sunken)));
}

/* Drawn stand-in artwork for each design — real Printify mockups replace these later, but
   until then every product needs to look like a different product, not the same grey outline. */
.case-art { display: block; }

/* Secondary "read later" links — plain text + chevron, so they never compete with a primary .btn */
.link-chevron {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  background: none; border: none; padding-block: 0.5rem;
  font-size: var(--text-sm); font-weight: 600; color: var(--ink-muted);
  transition: color 0.2s var(--ease);
}
.link-chevron svg { width: 14px; height: 14px; transition: transform 0.2s var(--ease); flex-shrink: 0; }
.link-chevron:hover { color: var(--ink); }
.link-chevron:hover svg { transform: translateX(3px); }

/* ---------------------------- Scroll reveal ----------------------------
   The markup already carried .fade-up on ten elements but no rule ever defined it, so it was
   a dead class doing nothing. Implemented here to match the single-file build, and skipped
   entirely (not merely shortened) when the visitor asks for reduced motion. */
.fade-up { opacity: 0; transform: translateY(16px); transition: opacity 0.5s var(--ease), transform 0.5s var(--ease); }
.fade-up.is-revealed { opacity: 1; transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; scroll-behavior: auto !important; }
  .fade-up { opacity: 1; transform: none; }
}

/* Skip link: keyboard users would otherwise tab the whole header before reaching content. */
.skip-link {
  position: fixed; top: -100px; left: var(--sp-4); z-index: 600;
  background: var(--ink); color: var(--bg); padding: 0.7rem 1.1rem;
  border-radius: var(--radius-sm); font-size: var(--text-sm); font-weight: 600;
  transition: top 0.18s var(--ease);
}
.skip-link:focus { top: var(--sp-4); color: var(--bg); }

/* ---------------------------- Buy-decision detail ----------------------------
   Shipping used to appear for the first time on the checkout page. A fee that only shows up
   at the final step is one of the most common reasons a basket gets abandoned, so it is
   stated next to the price instead. */
.pdp-price-meta { margin-top: var(--sp-2); font-size: var(--text-sm); color: var(--ink-muted); display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); }
/* separator rides on the preceding item, so a wrap never strands a bare dot on its own line */
.pdp-price-meta > span:not(:last-child)::after { content: " \00B7"; color: var(--ink-faint); margin-left: var(--sp-3); }
/* Narrow enough and every item is on its own line anyway, at which point the separators are
   no longer separating anything — they just trail off the end of each line looking like typos.
   Stack the list properly and drop them. */
@media (max-width: 520px) {
  .pdp-price-meta { flex-direction: column; gap: var(--sp-1); }
  .pdp-price-meta > span:not(:last-child)::after { content: none; }
}

.model-help { margin-top: var(--sp-3); margin-bottom: var(--sp-5); font-size: var(--text-sm); }
.model-help summary { cursor: pointer; color: var(--ink-muted); display: inline-flex; align-items: center; gap: var(--sp-2); list-style: none; }
.model-help summary::-webkit-details-marker { display: none; }
.model-help summary::before { content: "?"; display: inline-flex; align-items: center; justify-content: center; width: 17px; height: 17px; border-radius: 50%; border: 1px solid var(--border-strong); font-size: 11px; font-weight: 700; flex-shrink: 0; }
.model-help summary:hover { color: var(--ink); }
.model-help[open] summary { color: var(--ink); margin-bottom: var(--sp-3); }
.model-help-body { color: var(--ink-muted); background: var(--surface-sunken); border-radius: var(--radius-md); padding: var(--sp-4); line-height: 1.6; }
.model-help-body strong { color: var(--ink); }
.model-help-body ol { margin: var(--sp-2) 0 0; padding-left: 1.1rem; list-style: decimal; }
.model-help-body li { margin-top: var(--sp-1); }

/* Product pages linked nowhere, so every one was a dead end. */
.related { margin-top: var(--sp-9); padding-top: var(--sp-8); border-top: 1px solid var(--border); }
.related h2 { font-size: var(--text-2xl); margin-bottom: var(--sp-6); }

/* ---------------------------- Case comparison ----------------------------
   Three shells at three prices is the biggest question on the collection page, so it gets
   answered above the grid rather than buried on a product page. */
.compare-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); }
.compare-card { display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--sp-6); transition: border-color 0.25s var(--ease), transform 0.25s var(--ease), box-shadow 0.25s var(--ease); }
.compare-card:hover { border-color: var(--border-strong); transform: translateY(-4px); box-shadow: var(--shadow-md); }
.compare-card.is-featured { border-color: var(--accent); }
.compare-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.compare-card h3 { font-size: var(--text-xl); }
.compare-price { font-family: var(--font-body); font-weight: 700; font-size: var(--text-lg); white-space: nowrap; }
.compare-tagline { color: var(--accent-strong); font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; margin-top: var(--sp-2); }
.compare-blurb { color: var(--ink-muted); font-size: var(--text-sm); margin-top: var(--sp-4); line-height: 1.6; }
.compare-best { margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--border); font-size: var(--text-sm); color: var(--ink-muted); }
.compare-best strong { color: var(--ink); display: block; font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: var(--sp-1); }
.compare-bulk { margin-top: var(--sp-4); display: flex; align-items: center; gap: var(--sp-2); font-size: var(--text-xs); color: var(--ink-muted); }
.compare-pips { display: inline-flex; gap: 3px; }
.compare-pip { width: 18px; height: 5px; border-radius: 3px; background: var(--border-strong); }
.compare-pip.on { background: var(--accent); }
.compare-note { margin-top: var(--sp-5); font-size: var(--text-sm); color: var(--ink-muted); }
@media (max-width: 860px) { .compare-grid { grid-template-columns: 1fr; } }

.type-blurb { margin-top: var(--sp-3); font-size: var(--text-sm); color: var(--ink-muted); line-height: 1.6; }

/* ---------------------------- Design request ---------------------------- */
.request-layout { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: var(--sp-8); align-items: start; }
@media (max-width: 880px) { .request-layout { grid-template-columns: 1fr; gap: var(--sp-6); } }
.request-form { display: flex; flex-direction: column; gap: var(--sp-4); }
.request-form textarea { width: 100%; padding: 0.7rem 0.85rem; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); min-height: 130px; resize: vertical; font-family: inherit; font-size: inherit; line-height: 1.55; }
.request-form textarea:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px var(--accent-soft); }
.request-form select { width: 100%; padding: 0.7rem 0.85rem; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); min-height: 42px; }
.field-hint { font-size: var(--text-xs); color: var(--ink-faint); margin-top: var(--sp-1); }
/* honeypot: off-screen rather than display:none, which some bots detect */
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.request-status { display: none; border-radius: var(--radius-md); padding: var(--sp-4); font-size: var(--text-sm); line-height: 1.55; }
.request-status.is-visible { display: block; }
.request-status.is-ok { background: var(--accent-soft); color: var(--ink); }
.request-status.is-err { background: var(--surface-sunken); color: var(--accent-strong); border: 1px solid var(--accent-strong); }
.request-points { list-style: none; margin-top: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-4); }
.request-points li { display: flex; gap: var(--sp-3); font-size: var(--text-sm); color: var(--ink-muted); line-height: 1.55; }
.request-points svg { width: 18px; height: 18px; color: var(--accent); flex-shrink: 0; margin-top: 2px; }

/* ---------------------------- Cart ----------------------------
   A real basket: add, remove, change quantity, kept in this browser between visits. A line is
   a design AND a case type AND a phone model AND a size, because those are four different
   things to make — the same artwork on a Slim iPhone 13 and a Tough iPhone 17 Pro Max are two
   separate orders, not one line with quantity two. */
.icon-btn { position: relative; }
.icon-btn .badge {
  position: absolute; top: 2px; right: 2px;
  background: var(--accent); color: var(--accent-ink);
  font-size: 10px; font-weight: 700; width: 16px; height: 16px;
  border-radius: 50%; display: flex; align-items: center; justify-content: center;
}
.overlay { position: fixed; inset: 0; background: oklch(0% 0 0 / 0.4); opacity: 0; pointer-events: none; transition: opacity 0.25s var(--ease); z-index: 300; }
.overlay.is-open { opacity: 1; pointer-events: auto; }
.cart-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(380px, 90vw);
  background: var(--bg); z-index: 301; transform: translateX(100%);
  transition: transform 0.3s var(--ease); display: flex; flex-direction: column;
  box-shadow: var(--shadow-lg);
}
.cart-drawer.is-open { transform: translateX(0); }
.cart-head { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-5); border-bottom: 1px solid var(--border); }
.cart-head h3 { font-size: var(--text-lg); font-family: var(--font-body); font-weight: 700; }
/* the drawer borrowed .modal-close from the other build, which has no rule here — it rendered
   as an empty box */
.modal-close {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: none; border: none; color: var(--ink-muted); cursor: pointer;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}
.modal-close:hover { background: var(--surface-sunken); color: var(--ink); }
.modal-close svg { width: 18px; height: 18px; }
/* a colour swatch taken from the design, not a fake product photo */
.cart-item-media { background: var(--surface-sunken); }
.cart-item-swatch { width: 100%; height: 100%; display: block; }
.cart-items { flex: 1; overflow-y: auto; padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-5); }
.cart-empty { text-align: center; color: var(--ink-muted); padding-block: var(--sp-8); display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); }
.cart-item { display: flex; gap: var(--sp-4); align-items: flex-start; }
.cart-item-media { width: 56px; height: 64px; border-radius: var(--radius-sm); background: var(--surface-sunken); flex-shrink: 0; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.cart-item-media .case-art { width: 46%; }
.cart-item-info { flex: 1; min-width: 0; }
.cart-item-title { font-size: var(--text-sm); font-weight: 600; }
.cart-item-meta { font-size: var(--text-xs); color: var(--ink-muted); margin-top: 2px; line-height: 1.45; }
.cart-qty { display: inline-flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); }
.cart-qty button {
  width: 26px; height: 26px; border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong); background: var(--surface);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--text-sm); line-height: 1; color: var(--ink); cursor: pointer;
}
.cart-qty button:hover { border-color: var(--ink); }
.cart-qty span { font-size: var(--text-sm); min-width: 1.4em; text-align: center; font-variant-numeric: tabular-nums; }
.cart-item-remove { background: none; border: none; padding: 0; margin-top: var(--sp-2); font-size: var(--text-xs); color: var(--ink-faint); text-decoration: underline; cursor: pointer; }
.cart-item-remove:hover { color: var(--accent-strong); }
.cart-item-price { font-size: var(--text-sm); font-weight: 600; white-space: nowrap; }
.cart-foot { padding: var(--sp-5); border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: var(--sp-4); }
.cart-subtotal { display: flex; justify-content: space-between; font-weight: 700; }
.cart-foot .btn { text-align: center; }

.toast {
  position: fixed; left: 50%; bottom: var(--sp-6); transform: translate(-50%, 12px);
  background: var(--ink); color: var(--bg); padding: 0.7rem 1.2rem;
  border-radius: var(--radius-md); font-size: var(--text-sm); z-index: 400;
  opacity: 0; pointer-events: none; transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
  max-width: calc(100vw - 2rem); text-align: center;
}
.toast.is-open { opacity: 1; transform: translate(-50%, 0); }

/* ---------------------------- Dark mode ----------------------------
   Only the tokens are redefined; every component reads through them, so nothing else changes.
   Three states are covered: an explicit light choice wins over a dark OS, an explicit dark
   choice wins over a light OS, and the default (nothing stamped) follows the system. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:            oklch(17% 0.012 80);
    --surface:       oklch(21% 0.014 80);
    --surface-sunken:oklch(24% 0.014 80);
    --border:        oklch(32% 0.014 80);
    --border-strong: oklch(40% 0.014 80);

    --ink:           oklch(94% 0.008 85);
    --ink-muted:     oklch(72% 0.012 85);
    --ink-faint:     oklch(64% 0.012 85);

    --accent:        oklch(68% 0.135 45);
    --accent-strong: oklch(75% 0.135 45);
    --accent-soft:   oklch(30% 0.05  50);
    --accent-ink:    oklch(15% 0.010 80);

    --success:       oklch(70% 0.13 150);
    --success-soft:  oklch(28% 0.05 150);
    --danger:        oklch(70% 0.15 28);

    --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.3);
    --shadow-md: 0 8px 24px oklch(0% 0 0 / 0.35);
    --shadow-lg: 0 24px 64px oklch(0% 0 0 / 0.5);
  }
}

:root[data-theme="dark"] {
  --bg:            oklch(17% 0.012 80);
  --surface:       oklch(21% 0.014 80);
  --surface-sunken:oklch(24% 0.014 80);
  --border:        oklch(32% 0.014 80);
  --border-strong: oklch(40% 0.014 80);

  --ink:           oklch(94% 0.008 85);
  --ink-muted:     oklch(72% 0.012 85);
  --ink-faint:     oklch(64% 0.012 85);

  --accent:        oklch(68% 0.135 45);
  --accent-strong: oklch(75% 0.135 45);
  --accent-soft:   oklch(30% 0.05  50);
  --accent-ink:    oklch(15% 0.010 80);

  --success:       oklch(70% 0.13 150);
  --success-soft:  oklch(28% 0.05 150);
  --danger:        oklch(70% 0.15 28);

  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.3);
  --shadow-md: 0 8px 24px oklch(0% 0 0 / 0.35);
  --shadow-lg: 0 24px 64px oklch(0% 0 0 / 0.5);
}

/* theme toggle icon swap, matching the other build */
.theme-toggle .icon-moon { display: block; }
.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: block; }
}

/* ==========================================================================
   Site-wide utilities: search, scroll progress, back to top, contact bubble,
   destructive-action confirmation. These existed in the single-file build and
   were missing here — including a search button in the header that opened
   nothing, which is worse than no button at all.
   ========================================================================== */

/* ---------- scroll progress ---------- */
.scroll-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 0%;
  background: var(--accent); z-index: 500; pointer-events: none;
}

/* ---------- search ---------- */
.search-panel {
  position: fixed; top: 0; left: 0; right: 0;
  background: var(--bg); border-bottom: 1px solid var(--border);
  z-index: 301; transform: translateY(-100%);
  transition: transform 0.25s var(--ease);
  padding: var(--sp-6) 0; box-shadow: var(--shadow-md);
}
.search-panel.is-open { transform: translateY(0); }
.search-input-row { display: flex; align-items: center; gap: var(--sp-3); }
.search-input-row > svg { width: 20px; height: 20px; color: var(--ink-faint); flex-shrink: 0; }
.search-input-row input {
  flex: 1; border: none; background: none; min-width: 0;
  font-size: var(--text-xl); font-family: var(--font-display); color: var(--ink);
}
.search-input-row input:focus { outline: none; }
.search-results { margin-top: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-1); max-height: 320px; overflow-y: auto; }
.search-result {
  display: flex; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-3); border-radius: var(--radius-sm);
  font-size: var(--text-sm); background: none; border: none;
  width: 100%; text-align: left; color: var(--ink); cursor: pointer;
}
.search-result:hover, .search-result:focus-visible { background: var(--surface-sunken); color: var(--ink); }
.search-result span:last-child { color: var(--ink-muted); flex-shrink: 0; }
.search-empty { color: var(--ink-faint); font-size: var(--text-sm); padding: var(--sp-3) 0; }

/* ---------- back to top ---------- */
.back-to-top {
  position: fixed; left: var(--sp-5); bottom: var(--sp-5); z-index: 90;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--ink); color: var(--bg); border: none;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-md);
  opacity: 0; transform: translateY(8px); pointer-events: none;
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease), background 0.2s, bottom 0.3s var(--ease);
  cursor: pointer;
}
.back-to-top.is-visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
.back-to-top:hover { background: var(--accent-strong); color: var(--accent-ink); }
.back-to-top svg { width: 20px; height: 20px; }

/* ---------- floating contact ---------- */
.floating-contact {
  position: fixed; right: var(--sp-5); bottom: var(--sp-5); z-index: 90;
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-3);
  transition: bottom 0.3s var(--ease);
}
.floating-contact-panel {
  display: none; flex-direction: column; gap: 2px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  padding: var(--sp-2); min-width: 200px;
}
.floating-contact-panel.is-open { display: flex; }
.floating-contact-panel a, .floating-contact-panel button {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3); border-radius: var(--radius-sm);
  font-size: var(--text-sm); color: var(--ink);
  background: none; border: none; text-align: left; width: 100%; cursor: pointer;
}
.floating-contact-panel a:hover, .floating-contact-panel button:hover { background: var(--surface-sunken); color: var(--ink); }
.floating-contact-toggle {
  width: 52px; height: 52px; border-radius: 50%;
  background: var(--accent); color: var(--accent-ink); border: none;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-md); cursor: pointer;
  transition: background 0.2s, transform 0.2s var(--ease);
}
.floating-contact-toggle:hover { background: var(--accent-strong); transform: scale(1.05); }
.floating-contact-toggle svg { width: 22px; height: 22px; }

/* the product page's sticky buy bar occupies the bottom of the screen; lift both
   bubbles above it rather than letting them sit on top of the Add to cart button */
body.buy-bar-active .back-to-top,
body.buy-bar-active .floating-contact { bottom: calc(var(--sp-5) + 68px); }

/* ---------- destructive-action confirmation ---------- */
.confirm-modal {
  position: fixed; top: 50%; left: 50%;
  transform: translate(-50%, -46%);
  width: min(360px, calc(100vw - var(--sp-6)));
  background: var(--surface); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); padding: var(--sp-6); z-index: 302;
  opacity: 0; pointer-events: none;
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
}
.confirm-modal.is-open { opacity: 1; pointer-events: auto; transform: translate(-50%, -50%); }
.confirm-modal h3 { margin: 0 0 var(--sp-2); font-size: var(--text-xl); }
.confirm-modal p { margin: 0 0 var(--sp-5); color: var(--ink-muted); font-size: var(--text-sm); }
.confirm-actions { display: flex; gap: var(--sp-3); }
.confirm-actions .btn { flex: 1; }

@media print {
  /* Only .scroll-progress/.search-panel/.back-to-top/.floating-contact/.confirm-modal were
     hidden here — the sticky header still printed with its blurred, semi-transparent
     background, which either repeats on every page or renders as a grey band depending on
     the browser. Someone printing a Terms page or an order for their records shouldn't get
     any of the on-screen chrome: header, footer, both drawers, the cart, toasts, the cookie
     banner and the product page's sticky buy bar are all screen-only navigation. */
  .site-header, .site-footer, .mobile-drawer, .drawer-overlay, .overlay, .cart-drawer,
  .search-panel, .confirm-modal, .toast, .cookie-banner, .scroll-progress, .back-to-top,
  .floating-contact, .buy-bar { display: none !important; }
  body { background: #fff; color: #000; }
  a { color: #000; text-decoration: underline; }
}
@media (max-width: 600px) {
  .back-to-top { left: var(--sp-4); bottom: var(--sp-4); }
  .floating-contact { right: var(--sp-4); bottom: var(--sp-4); }
  /* A desktop window has margin either side of the content for these to sit in. A phone has
     none, so a permanently parked bubble covers whatever is underneath it — measured doing
     exactly that to prices, headings and the shop grid's Quick add button. They now get out
     of the way while you are reading down the page and come back the moment you scroll up,
     which is when you are looking for a control rather than reading. */
  .back-to-top, .floating-contact {
    transition: transform 0.25s var(--ease), opacity 0.25s var(--ease);
  }
  body.scrolling-down .back-to-top {
    opacity: 0;
    transform: translateY(140%);
    pointer-events: none;
  }
  /* The contact bubble used to be disabled here too, which is why tapping it while
     scrolling down did nothing at all. It now dims and stays reachable. */
  body.scrolling-down .floating-contact {
    opacity: 0.55;
    transform: none;
  }
  body.scrolling-down .floating-contact:hover,
  body.scrolling-down .floating-contact:focus-within { opacity: 1; }
  /* never hide it while its own panel is open — that would snatch the menu mid-tap */
  body.scrolling-down .floating-contact:has(.floating-contact-panel.is-open) {
    opacity: 1; transform: none; pointer-events: auto;
  }
  .floating-contact-toggle { width: 46px; height: 46px; }
  .floating-contact-toggle svg { width: 20px; height: 20px; }
}

/* ---------------------------- Size guide table ----------------------------
   The footer's "Size guide" link used to point at the general FAQ, which contained no size
   guide. This is the real thing, built from the same per-generation data the product pages
   use, so the two cannot disagree. */
/* position: relative matters here. The screen-reader-only spans inside each cell are
   position:absolute, and without a positioned ancestor their containing block is the page —
   so on a phone they sat at their static position out past the right edge of a 544px table
   and dragged the whole document sideways. Making the wrapper their containing block keeps
   them inside the scroll area where they belong. */
.size-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; position: relative; max-width: 100%; }
.size-table { border-collapse: collapse; width: 100%; min-width: 34rem; font-size: var(--text-sm); }
.size-table th, .size-table td { padding: var(--sp-3); text-align: center; border-bottom: 1px solid var(--border); }
.size-table thead th {
  font-family: var(--font-body); font-size: var(--text-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-muted);
  border-bottom: 1px solid var(--border-strong);
}
.size-table tbody th { text-align: left; font-weight: 600; white-space: nowrap; font-family: var(--font-body); font-size: var(--text-sm); }
.size-table td.yes { color: var(--accent-strong); font-weight: 700; }
.size-table td.no { color: var(--ink-faint); }
.size-table tbody tr:hover { background: color-mix(in oklch, var(--accent) 5%, transparent); }

/* The catalogue is four designs, which left a wide empty band under a single row at desktop
   widths. This tile fills it with a real destination rather than whitespace — and a custom
   request is the highest-value thing a browsing visitor can do here. */
.shop-cta-card .shop-cta-media {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2); text-align: center; padding: var(--sp-6);
  border: 1px dashed var(--border-strong); background: transparent;
}
.shop-cta-card:hover .shop-cta-media { border-color: var(--accent); }
.shop-cta-card .shop-cta-media svg { width: 34px; height: 34px; color: var(--accent); }
.shop-cta-title { font-family: var(--font-display); font-size: var(--text-lg); color: var(--ink); }
.shop-cta-sub { font-size: var(--text-sm); color: var(--ink-muted); }


/* ---------- shipping figure on the case comparison cards ---------- */
.compare-ship {
  margin-top: calc(var(--sp-1) * -1);
  font-size: var(--text-xs);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

/* ---------- reserve-order note (replaces the old preview banner) ---------- */
.checkout-reserve-note {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  color: var(--ink-muted);
  font-size: var(--text-sm);
  line-height: 1.55;
  margin-bottom: var(--sp-6);
}
.checkout-reserve-note svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--accent); margin-top: 1px; }

/* ---------- page transitions ----------
   Chrome and Edge run this natively across a normal page load; everywhere else the
   navigation simply happens the way it always did, with no broken half-state. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: nyrox-page-out 0.26s var(--ease) both; }
::view-transition-new(root) { animation: nyrox-page-in 0.30s var(--ease) both; }
@keyframes nyrox-page-out { to { opacity: 0; transform: translateX(-3%); } }
@keyframes nyrox-page-in { from { opacity: 0; transform: translateX(4%); } }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}


/* ---------- case comparison cards are now links into the filtered grid ---------- */
.compare-card {
  position: relative;
  display: block;
  color: inherit;
  text-decoration: none;
  transition: transform 0.2s var(--ease), border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.compare-card:hover { border-color: var(--accent); box-shadow: var(--shadow-md); transform: translateY(-2px); }
.compare-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* Sat in the flow at first, which pushed the middle card's price, pips and Best for out of
   line with its neighbours. Lifting it onto the card's top edge keeps all three rows level. */
.compare-recommended {
  position: absolute;
  top: -0.7em;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}
.compare-cta {
  margin-top: var(--sp-4);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent-strong);
}
.compare-card:hover .compare-cta span { display: inline-block; transform: translateX(3px); }
.compare-cta span { transition: transform 0.2s var(--ease); }
@media (prefers-reduced-motion: reduce) {
  .compare-card, .compare-cta span { transition: none; }
  .compare-card:hover { transform: none; }
}

/* the three cards read as one row, so the arrow line sits at the same height in each */
.compare-grid { align-items: stretch; }
.compare-card { display: flex; flex-direction: column; }
.compare-card .compare-cta { margin-top: auto; padding-top: var(--sp-4); }


/* ==========================================================================
   Small-screen refinements
   ========================================================================== */

/* ---- 2. the display face is set for a desktop measure; at phone width the hero
     headline ran to four lines and pushed the Shop button off screen ---- */
@media (max-width: 560px) {
  .hero h1 { font-size: clamp(2rem, 9.5vw, 2.6rem); line-height: 1.08; }
  .hero { padding-block: var(--sp-7) var(--sp-8); }
  /* Three flex items at desktop sizing squeezed the third until "UK-wide" broke across
     two lines. An even grid gives each the same column and keeps the figures whole. */
  .hero-trust {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-4);
    align-items: start;
  }
  .hero-trust strong { font-size: var(--text-lg); white-space: nowrap; }
  .hero-trust div { font-size: var(--text-xs); line-height: 1.35; }
}

/* ---- 3. "View design" was revealed on :hover, which a touch screen never fires.
     It either stayed invisible or stuck on after a tap. Pinned open where there is
     no hover, kept as a reveal where there is. ---- */
@media (hover: none) {
  .product-card-quick { opacity: 1; transform: none; }
  .compare-card:hover { transform: none; }
}
/* Belt and braces: some in-app browsers and embedded views report a hover-capable pointer
   even on a phone, so narrow screens pin it open regardless of what the pointer claims. */
@media (max-width: 860px) {
  .product-card-quick { opacity: 1; transform: none; }
}

/* ---- 4. three full-height comparison cards meant three screens of explanation
     before the first design. Trimmed to the parts that actually decide it. ---- */
@media (max-width: 620px) {
  .compare-card { padding: var(--sp-5); }
  .compare-blurb { display: none; }
  .compare-bulk { margin-top: var(--sp-3); }
  .compare-best { margin-top: var(--sp-3); padding-top: var(--sp-3); }
  .compare-card .compare-cta { padding-top: var(--sp-3); }
  .compare-grid { gap: var(--sp-6); }
}

/* ---- 5. the Filters button reported no state, so a filtered grid looked like a short
     catalogue. The count is written in by script. ---- */
.filter-toggle .filter-count {
  display: none;
  margin-left: var(--sp-2);
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--text-xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.filter-toggle.has-filters .filter-count { display: inline-block; }
.filter-toggle.has-filters { border-color: var(--accent); color: var(--ink); }

/* ---- 6. the shipping note carried a bottom margin and the toolbar a top one, which
     stacked into a dead band above the Filters button on narrow screens ---- */
@media (max-width: 860px) {
  .compare-note { margin-bottom: var(--sp-6); }
  .filter-toggle { margin-top: 0; }
  #compare-cases { padding-bottom: var(--sp-6); }
}

/* ---- 7. the contact bubble is fixed bottom-right, directly over the last product card's
     button on a phone. Give the grid room to end above it. ---- */
@media (max-width: 860px) {
  .product-grid { padding-bottom: 84px; }
}


/* The confirmation dialog's own backdrop, above the cart drawer (301) and below the dialog
   (302). Before this the drawer stayed clickable behind an open dialog. */
.confirm-scrim {
  position: fixed; inset: 0; z-index: 301;
  background: rgba(18, 15, 13, 0.45);
  opacity: 0; pointer-events: none;
  transition: opacity 0.2s var(--ease);
}
.confirm-scrim.is-open { opacity: 1; pointer-events: auto; }

/* A button mid-request. There was no rule for this at all, so "Reserve order" looked
   completely inert while the request was in flight and people pressed it twice. */
.btn.is-loading { position: relative; color: transparent !important; pointer-events: none; }
.btn.is-loading::after {
  content: "";
  position: absolute; top: 50%; left: 50%;
  width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border: 2px solid currentColor; border-top-color: transparent;
  border-radius: 50%;
  color: var(--bg);
  animation: nyrox-spin 0.6s linear infinite;
}
.btn-outline.is-loading::after, .btn-ghost.is-loading::after { color: var(--ink); }
@keyframes nyrox-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .btn.is-loading::after { animation-duration: 2s; }
  .confirm-scrim { transition: none; }
}


/* ---------- "not selling yet" panel, where Add to cart used to be ---------- */
.notyet {
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  padding: var(--sp-5);
}
.notyet-title {
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--sp-2);
}
.notyet p {
  color: var(--ink-muted);
  font-size: var(--text-sm);
  line-height: 1.6;
}
.notyet .btn { margin-top: var(--sp-4); }
