/* ============================================================
   3D Printed World — shared design system
   Light, warm, workshop-modern. Accent = filament orange.
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@500;600;700&family=Inter:wght@400;500;600;700&display=swap');

:root {
  --bg: #faf7f2;
  /* The seven filaments, in spool order — the rainbow every accent draws from. */
  --rainbow: linear-gradient(90deg, #d63b2f, #f0731f, #f4c430, #2fa84f, #2f63c9, #22b8cf, #7c3aed);
  --surface: #ffffff;
  --surface-2: #f3efe7;
  --ink: #1f1c18;
  --ink-soft: #413b34;  /* darkened so body text holds 4.5:1 on the colorful backdrop */
  --ink-faint: #665f55;
  --line: #e7e1d6;
  --accent: #f05a24;
  --accent-deep: #c74413;
  --accent-soft: #fdeee6;
  --blue: #2f63c9;
  --blue-soft: #e8eefb;
  --green: #1f9d6b;
  --green-soft: #e4f5ed;
  --radius: 16px;
  --radius-sm: 10px;
  --shadow: 0 1px 2px rgba(31, 28, 24, 0.05), 0 8px 24px rgba(31, 28, 24, 0.07);
  --shadow-lift: 0 2px 4px rgba(31, 28, 24, 0.06), 0 16px 40px rgba(31, 28, 24, 0.12);
  --font-head: 'Fredoka', 'Segoe UI Variable Display', 'Segoe UI', system-ui, sans-serif;
  --font-body: 'Inter', 'Segoe UI', system-ui, sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

/* Keep anchor targets clear of the sticky header */
[id] { scroll-margin-top: 84px; }

body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.6;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  position: relative;
  min-height: 100vh;
}

/* ---------- Living backdrop ----------
   Soft pools of the filament colors drift behind every page, over a faint
   print-bed grid. Cards and panels keep their solid surfaces on top, so
   nothing gets harder to read. Both layers are fixed and cheap: one radial
   gradient stack animated by transform, one repeating dot pattern. */
body::before {
  content: '';
  /* A square 160vmax on a side, centered: big enough to keep the viewport
     covered at any rotation, on any aspect ratio. The whole color field
     swirls around the screen (one turn every 48 s, breathing as it goes),
     so every corner cycles through all the colors; the dot grid on top stays
     still, which makes the movement read. */
  position: fixed; z-index: -2;
  left: 50%; top: 50%;
  width: 160vmax; height: 160vmax;
  pointer-events: none;
  /* Bright pastel versions of the filament colors at near-full strength over
     a rainbow wash, so there's no cream left showing — light enough that
     dark text stays readable on any part of it. */
  /* Pulled toward the filament colors themselves rather than their pastel
     shadows. Saturation is up and the pools overlap harder, which is what
     reads as "vibrant"; lightness is held high enough that dark text on the
     bare backdrop still clears 4.5:1. */
  background:
    radial-gradient(46% 48% at 14% 18%, rgba(255, 124, 40, 0.95), transparent 68%),
    radial-gradient(42% 46% at 86% 14%, rgba(74, 128, 255, 0.95), transparent 68%),
    radial-gradient(46% 46% at 80% 82%, rgba(167, 108, 255, 0.95), transparent 68%),
    radial-gradient(42% 42% at 18% 86%, rgba(62, 212, 120, 0.93), transparent 68%),
    radial-gradient(38% 36% at 50% 48%, rgba(255, 214, 54, 0.92), transparent 68%),
    radial-gradient(34% 36% at 50% 6%, rgba(44, 212, 236, 0.92), transparent 68%),
    radial-gradient(32% 32% at 50% 94%, rgba(255, 94, 116, 0.88), transparent 68%),
    radial-gradient(30% 30% at 4% 52%, rgba(255, 86, 174, 0.82), transparent 68%),
    radial-gradient(30% 30% at 96% 50%, rgba(72, 226, 182, 0.82), transparent 68%),
    linear-gradient(135deg, #ffc7a4 0%, #ffe97e 22%, #a9efc0 44%, #a6d2ff 64%, #d2b8ff 82%, #ffb6d6 100%);
  transform: translate(-50%, -50%);
  animation: backdrop-swirl 26s linear infinite;
  will-change: transform;
}
/* A second, slower field turning the other way. Two layers crossing is what
   makes the motion obvious — one rotating field alone reads as almost still,
   because every part of it moves together. */
body .backdrop-counter {
  content: '';
  position: fixed; z-index: -3;
  left: 50%; top: 50%;
  width: 150vmax; height: 150vmax;
  pointer-events: none;
  background:
    radial-gradient(40% 40% at 30% 70%, rgba(255, 196, 60, 0.75), transparent 66%),
    radial-gradient(38% 38% at 70% 30%, rgba(96, 160, 255, 0.72), transparent 66%),
    radial-gradient(36% 36% at 24% 30%, rgba(120, 232, 190, 0.7), transparent 66%),
    radial-gradient(36% 36% at 76% 74%, rgba(255, 120, 170, 0.68), transparent 66%);
  transform: translate(-50%, -50%);
  animation: backdrop-counter 37s linear infinite;
  will-change: transform;
}
body::after {
  content: '';
  position: fixed; z-index: -1; inset: 0;
  pointer-events: none;
  background-image: radial-gradient(rgba(31, 28, 24, 0.12) 1px, transparent 1.2px);
  background-size: 22px 22px;
  mask-image: linear-gradient(180deg, rgba(0,0,0,0.9), rgba(0,0,0,0.35));
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,0.9), rgba(0,0,0,0.35));
}
@keyframes backdrop-swirl {
  0%   { transform: translate(-50%, -50%) rotate(0deg) scale(1); }
  25%  { transform: translate(-45%, -55%) rotate(90deg) scale(1.18); }
  50%  { transform: translate(-50%, -50%) rotate(180deg) scale(1.02); }
  75%  { transform: translate(-55%, -45%) rotate(270deg) scale(1.18); }
  100% { transform: translate(-50%, -50%) rotate(360deg) scale(1); }
}
@keyframes backdrop-counter {
  0%   { transform: translate(-50%, -50%) rotate(360deg) scale(1.1); }
  50%  { transform: translate(-53%, -47%) rotate(180deg) scale(1); }
  100% { transform: translate(-50%, -50%) rotate(0deg) scale(1.1); }
}

/* Shelves, tiles, and hero bands drift through their gradient; a sheen band
   sweeps across now and then. Both are keyed off --i so rows never move in
   step. Reduced motion turns them off. */
@keyframes gradient-drift {
  0%   { background-position: 0% 0%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 100%; }
}
@keyframes sheen {
  0%, 55% { transform: translateX(-110%); }
  100%    { transform: translateX(110%); }
}
@media (prefers-reduced-motion: reduce) {
  body::before, body .backdrop-counter, .product-thumb { animation: none; }
}

/* Rainbow lettering: the filament gradient clipped to the text. */
.rainbow-text {
  background: var(--rainbow);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

img, svg { max-width: 100%; display: block; }

h1, h2, h3, h4 {
  font-family: var(--font-head);
  line-height: 1.15;
  letter-spacing: -0.01em;
  font-weight: 700;
}

h1 { font-size: clamp(2.1rem, 5vw, 3.4rem); font-weight: 800; }
h2 { font-size: clamp(1.5rem, 3.2vw, 2.1rem); }
h3 { font-size: 1.15rem; }

p { color: var(--ink-soft); }

a { color: var(--accent-deep); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Inline links in page text can sit right on the colorful backdrop, where
   orange text is too faint to read. They take the ink color and wear the
   orange as an underline instead. */
main p a:not(.btn) {
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
main p a:not(.btn):hover { color: var(--accent-deep); }

:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 2px;
  border-radius: 4px;
}

.container {
  max-width: 1160px;
  margin: 0 auto;
  padding: 0 clamp(16px, 4vw, 32px);
}

.section { padding: clamp(40px, 7vw, 80px) 0; }
.section-tight { padding: clamp(24px, 4vw, 44px) 0; }

.eyebrow {
  display: inline-block;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-deep);
  background: var(--accent-soft);
  padding: 4px 12px;
  border-radius: 999px;
  margin-bottom: 14px;
}

.section-head { max-width: 640px; margin-bottom: clamp(24px, 4vw, 40px); }
.section-head p { margin-top: 10px; font-size: 1.05rem; }

/* ---------- Header / nav ---------- */

/* The header is a band of deep jewel tones drifting sideways, with a sheen
   passing over it. The stops are dark enough that white nav text holds at
   least 5:1 on every one of them. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  overflow: visible;
  /* The stop sequence appears twice across a 200%-wide image, so shifting it
     by exactly one copy lands on an identical frame: the loop has no seam. */
  background: linear-gradient(90deg,
    #c2410c 0%, #be185d 10%, #6d28d9 20%, #1d4ed8 30%, #0e7490 40%,
    #c2410c 50%, #be185d 60%, #6d28d9 70%, #1d4ed8 80%, #0e7490 90%, #c2410c 100%);
  background-size: 200% 100%;
  animation: header-drift 14s linear infinite;
  box-shadow: 0 6px 20px rgba(31, 28, 24, 0.18);
}
@keyframes header-drift {
  from { background-position: 0% 50%; }
  to   { background-position: 100% 50%; }
}
.site-header::before {
  content: '';
  position: absolute; inset: 0 0 3px; pointer-events: none;
  background: linear-gradient(110deg, transparent 40%, rgba(255,255,255,0.18) 50%, transparent 60%);
  background-size: 250% 100%;
  animation: header-sheen 7s ease-in-out infinite;
}
@keyframes header-sheen {
  0%, 20% { background-position: 150% 0; }
  100%    { background-position: -50% 0; }
}
.site-header > * { position: relative; }
/* A thin run of the seven filaments under the header, flowing the other way. */
.site-header::after {
  content: '';
  display: block;
  height: 3px;
  background: linear-gradient(90deg,
    #d63b2f 0%, #f0731f 7.14%, #f4c430 14.28%, #2fa84f 21.42%, #2f63c9 28.57%, #22b8cf 35.71%, #7c3aed 42.85%,
    #d63b2f 50%, #f0731f 57.14%, #f4c430 64.28%, #2fa84f 71.42%, #2f63c9 78.57%, #22b8cf 85.71%, #7c3aed 92.85%, #d63b2f 100%);
  background-size: 200% 100%;
  animation: header-drift 6s linear infinite reverse;
}
@media (prefers-reduced-motion: reduce) {
  .site-header, .site-header::after { animation: none; }
  .site-header::before { display: none; }
}

.nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: 68px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.3rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.brand:hover { text-decoration: none; }
.brand:hover .logo-mark { transform: rotate(-8deg) scale(1.06); }
/* On the colored header the mark and wordmark ride in a white sticker pill,
   so the rainbow "World" keeps its contrast. */
.site-header .brand {
  background: rgba(255, 255, 255, 0.95);
  padding: 4px 14px 4px 4px;
  border-radius: 999px;
  box-shadow: 0 3px 10px rgba(31, 28, 24, 0.22);
}
/* The mark is the flexi-dragon app icon, worn like a sticker. */
.brand .logo-mark {
  width: 38px; height: 38px; flex: none;
  border-radius: 10px;
  box-shadow: 0 2px 6px rgba(31, 28, 24, 0.18), 0 0 0 2px #fff;
  transition: transform 0.2s ease;
}
.brand-word em {
  font-style: normal;
  background: var(--rainbow);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
  list-style: none;
}

.nav-links a {
  display: block;
  padding: 8px 14px;
  border-radius: 999px;
  color: #fff;
  font-weight: 700;
  font-size: 0.95rem;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
.nav-links a:hover { color: #fff; background: rgba(255, 255, 255, 0.2); text-decoration: none; }
.nav-links a.active { color: var(--ink); background: #fff; text-shadow: none; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18); }

.nav-cart {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.cart-badge {
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.cart-badge[data-empty="true"] { display: none; }

.nav-toggle {
  display: none;
  background: rgba(255, 255, 255, 0.16);
  border: 2px solid rgba(255, 255, 255, 0.7);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  cursor: pointer;
  color: #fff;
  font-size: 1.1rem;
}

@media (max-width: 820px) {
  .nav-toggle { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; }
  .nav-links {
    position: absolute;
    top: 68px;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    padding: 12px clamp(16px, 4vw, 32px) 18px;
    display: none;
    box-shadow: var(--shadow);
  }
  .nav-links.open { display: flex; }
  /* The phone menu drops onto a white panel, so its links go back to ink. */
  .nav-links a { padding: 12px 14px; color: var(--ink); text-shadow: none; }
  .nav-links a:hover { color: var(--ink); background: var(--surface-2); }
  .nav-links a.active { color: var(--accent-deep); background: var(--accent-soft); box-shadow: none; }
  .nav-links { top: 71px; }
}
@media (max-width: 420px) {
  .site-header .brand { font-size: 1.12rem; padding-right: 10px; }
  .site-header .brand .logo-mark { width: 32px; height: 32px; }
}

/* ---------- Announcement bar ---------- */

.announce {
  background: var(--ink);
  color: #f5f1ea;
  text-align: center;
  font-size: 0.85rem;
  font-weight: 500;
  padding: 8px 16px;
}
.announce strong { color: #ffb46b; }
@media (max-width: 600px) {
  .announce { font-size: 0.8rem; padding: 7px 12px; }
  .announce-deals { display: none; } /* one line on phones; the deals have their own homepage cards */
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.98rem;
  padding: 13px 26px;
  border-radius: 999px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
  text-decoration: none;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn-primary { background: var(--accent); color: #fff; box-shadow: 0 6px 18px rgba(240, 90, 36, 0.35); }
.btn-primary:hover { background: var(--accent-deep); color: #fff; }

.btn-dark { background: var(--ink); color: #fff; }
.btn-dark:hover { background: #35302a; color: #fff; }

.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn-ghost:hover { background: var(--surface-2); color: var(--ink); }

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

/* ---------- Badges & chips ---------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 10px;
  border-radius: 999px;
}
.badge-bestseller { background: var(--accent-soft); color: var(--accent-deep); }
.badge-custom { background: var(--blue-soft); color: var(--blue); }
.badge-value { background: var(--green-soft); color: var(--green); }
.badge-business { background: #f4ecfb; color: #7c3aed; }
/* The season's picks. Uses the seasonal accent tokens, so it recolours with
   the rest of the site and needs no per-season CSS. */
.badge-season { background: var(--accent-soft); color: var(--accent-deep); font-weight: 700; }
.badge-multicolor { background: linear-gradient(90deg, #fde8e8, #e8f0fd); color: #6b21a8; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
  transition: all 0.12s ease;
}
.chip:hover { border-color: var(--ink-faint); color: var(--ink); }
.chip.active { background: var(--ink); border-color: var(--ink); color: #fff; }

/* ---------- Product cards ---------- */

.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: clamp(16px, 2.5vw, 24px);
}

.product-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
  position: relative;
}
.product-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); }

.product-card a.card-link { color: inherit; text-decoration: none; display: flex; flex-direction: column; flex: 1; }

.product-thumb {
  aspect-ratio: 4 / 3;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(3rem, 8vw, 4.2rem);
  position: relative;
  /* The category gradient is set inline. Oversizing it gives the drift
     somewhere to travel, and the saturation lifts it to match the backdrop.
     --i staggers the rows so a grid never pulses in unison. */
  background-size: 220% 220% !important;
  filter: saturate(1.28) contrast(1.04);
  animation: gradient-drift 15s ease-in-out infinite;
}
/* Stagger by position so a grid never drifts in unison. Seven steps, which
   is coprime with the 2, 3 and 4 column counts the grid uses, so neighbours
   never share a phase at any breakpoint. */
.product-thumb:nth-child(7n+1) { animation-delay: -0.0s; }
.product-thumb:nth-child(7n+2) { animation-delay: -2.1s; }
.product-thumb:nth-child(7n+3) { animation-delay: -4.3s; }
.product-thumb:nth-child(7n+4) { animation-delay: -6.4s; }
.product-thumb:nth-child(7n+5) { animation-delay: -8.6s; }
.product-thumb:nth-child(7n+6) { animation-delay: -10.7s; }
.product-thumb:nth-child(7n+7) { animation-delay: -12.9s; }
/* Rendered 3D thumbnails — any positioned [data-pid] host (cards, hero tiles, cart rows) */
.thumb-emoji { transition: opacity 0.3s ease; }
.thumb-3d {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 6%;
  opacity: 0;
  transition: opacity 0.35s ease;
}
.thumb-3d.show { opacity: 1; }
.product-thumb .thumb-note {
  z-index: 1;
  position: absolute;
  bottom: 8px;
  right: 10px;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(0, 0, 0, 0.25);
  padding: 2px 8px;
  border-radius: 999px;
}

.product-body { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.product-body .badges { display: flex; flex-wrap: wrap; gap: 6px; min-height: 22px; }
.product-body h3 { font-size: 1.02rem; }
.product-body .blurb { font-size: 0.88rem; color: var(--ink-soft); flex: 1; }

.product-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 4px;
}
.price { font-family: var(--font-head); font-weight: 700; font-size: 1.15rem; }
.price .from { font-size: 0.75rem; font-weight: 600; color: var(--ink-faint); margin-right: 3px; }

.swatch-row { display: flex; gap: 5px; }
.swatch {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--surface);
  box-shadow: 0 0 0 1px var(--line);
}

/* ---------- Color / option pickers (product page) ---------- */

.option-group { margin-bottom: 22px; }
.option-group > label, .option-label {
  display: block;
  font-weight: 700;
  font-size: 0.9rem;
  margin-bottom: 10px;
  color: var(--ink);
}
.option-label .hint { font-weight: 500; color: var(--ink-faint); }

.swatch-picker { display: flex; gap: 10px; flex-wrap: wrap; }
.swatch-btn {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  cursor: pointer;
  border: 2px solid var(--line);
  position: relative;
  transition: transform 0.1s ease;
}
.swatch-btn:hover { transform: scale(1.08); }
.swatch-btn.selected { border-color: var(--ink); box-shadow: 0 0 0 3px var(--surface), 0 0 0 5px var(--ink); }

.pill-picker { display: flex; gap: 8px; flex-wrap: wrap; }
.pill-btn {
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--line);
  background: var(--surface);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink-soft);
  cursor: pointer;
  transition: all 0.12s ease;
}
.pill-btn:hover { border-color: var(--ink-faint); }
.pill-btn.selected { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-deep); }

/* ---------- Forms ---------- */

.field { margin-bottom: 18px; }
.field label { display: block; font-weight: 600; font-size: 0.9rem; margin-bottom: 6px; }
.field label .hint { font-weight: 500; color: var(--ink-faint); }
.field .help { font-size: 0.8rem; color: var(--ink-faint); margin-top: 4px; }

/*
 * The honeypot. A field no person ever sees, which a form-filling bot cannot resist; anything in it
 * means the submission was not typed by a human. Moved off-screen rather than hidden with
 * `display: none` or `hidden`, because the crude bots this catches do skip those — and a real
 * person using a screen reader never reaches it either, since the wrapper is aria-hidden and the
 * input is tabindex="-1". It must never be marked required.
 */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

input[type="text"], input[type="email"], input[type="tel"], input[type="number"], input[type="url"], input[type="date"], textarea, select {
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 12px 14px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  transition: border-color 0.12s ease;
}
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--accent); }
textarea { resize: vertical; min-height: 100px; }

.qty-stepper {
  display: inline-flex;
  align-items: center;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
}
.qty-stepper button {
  width: 40px;
  height: 40px;
  border: none;
  background: var(--surface);
  font-size: 1.1rem;
  font-weight: 700;
  cursor: pointer;
  color: var(--ink);
}
.qty-stepper button:hover { background: var(--surface-2); }
.qty-stepper .qty-value {
  min-width: 44px;
  text-align: center;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---------- Panels / cards ---------- */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(20px, 3vw, 28px);
}
.panel + .panel { margin-top: 16px; }

.info-strip {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: var(--blue-soft);
  border: 1px solid #d3dff5;
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  font-size: 0.9rem;
  color: #27406e;
}
.info-strip.warm { background: var(--accent-soft); border-color: #f6d8c8; color: #8a3c14; }
.info-strip .icon { flex: none; font-size: 1.1rem; line-height: 1.4; }

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

.site-footer {
  background: var(--ink);
  color: #cfc8bd;
  margin-top: clamp(40px, 7vw, 80px);
}
.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1.4fr;
  gap: clamp(24px, 4vw, 48px);
  padding: clamp(36px, 6vw, 60px) 0 32px;
}
@media (max-width: 820px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .footer-grid { grid-template-columns: 1fr; } }

.site-footer h4 { color: #fff; font-size: 0.95rem; margin-bottom: 14px; }
.site-footer ul { list-style: none; display: grid; gap: 8px; }
.site-footer a { color: #cfc8bd; font-size: 0.92rem; display: inline-block; padding: 4px 0; }
.site-footer a:hover { color: #fff; }
.site-footer .brand { color: #fff; margin-bottom: 12px; }
.site-footer .foot-blurb { font-size: 0.9rem; color: #a89f92; max-width: 30ch; }

.footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding: 18px 0 24px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  justify-content: space-between;
  font-size: 0.82rem;
  color: #8d8578;
}

/* ---------- Toast ---------- */

.toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--ink);
  color: #fff;
  padding: 13px 22px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.92rem;
  box-shadow: var(--shadow-lift);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 100;
  max-width: min(92vw, 480px);
  text-align: center;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------- Misc ---------- */

.breadcrumb { font-size: 0.85rem; color: var(--ink-faint); margin: 20px 0 8px; }
.breadcrumb a { color: var(--ink-faint); }
.breadcrumb a:hover { color: var(--ink); }

.divider { border: none; border-top: 1px solid var(--line); margin: 28px 0; }

.empty-state {
  text-align: center;
  padding: 60px 20px;
  color: var(--ink-faint);
}
.empty-state .big { font-size: 3rem; margin-bottom: 12px; }

table.simple {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
table.simple th, table.simple td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
}
table.simple th { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-faint); }

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

::selection { background: var(--accent-soft); color: var(--accent-deep); }

/* ---------- Deals ---------- */
.badge-deal { background: #fff1c2; color: #8a5a00; }

/* ---------- Hover peek: a larger copy of a tile/card image, centered over it ---------- */
/* Built by initHoverPeek() in js/main.js (Start-here shelves, shop grid). */
.peek {
  position: fixed; z-index: 40;
  width: 300px;
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 18px 48px rgba(0,0,0,0.28);
  color: var(--ink);
  text-decoration: none;
  overflow: hidden;
  opacity: 0;
  transform: scale(0.9);
  pointer-events: none;
  transition: opacity 0.14s ease, transform 0.14s ease;
}
.peek.show { opacity: 1; transform: none; pointer-events: auto; }
.peek:hover { text-decoration: none; }
.peek-img {
  position: relative;
  aspect-ratio: 4 / 3; /* the rendered thumbnails are 640x480 */
  display: flex; align-items: center; justify-content: center;
  font-size: 5rem;
  background: linear-gradient(180deg, #fff, #f3efe7);
}
.peek-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; padding: 4%; }
.peek-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px 12px; }
.peek-meta b { font-size: 0.95rem; line-height: 1.2; }
.peek-meta b small { display: block; font-size: 0.72rem; font-weight: 600; color: var(--ink-faint); margin-top: 2px; }
.peek-meta span { flex: none; font-family: var(--font-head); font-weight: 700; }
@media (prefers-reduced-motion: reduce) { .peek { transition: none; } }
@media (hover: none) { .peek { display: none; } }

/* Product page → Studio hand-off line under the price. */
.studio-link { margin: 6px 0 14px; font-size: 0.9rem; }
.studio-link .hint { color: var(--ink-faint); font-size: 0.82rem; margin-left: 6px; }

/* ---------- Start-here coupons ----------
   A ticket look: sunny yellow, dashed tear line, bold code. Used on the
   quiz (banner, row tickets, tile stickers) and the product page strip. */
.coupon-strip {
  background: linear-gradient(90deg, #fff4c2, #ffe27a) !important;
  border: 2px dashed #d69e00 !important;
  color: #5a3d00 !important;
}
@keyframes ticket-pulse {
  0%, 100% { transform: rotate(-2deg) scale(1); }
  50%      { transform: rotate(-2deg) scale(1.06); }
}
@keyframes ticket-shine {
  0%, 60% { background-position: 160% 0; }
  100%    { background-position: -60% 0; }
}
