/* ==========================================================================
   ZUZU — Wireframe Design System
   Black & white, greyscale-only. Grey boxes stand in for all imagery.
   Fonts: Funnel Display (headings) / Funnel Sans (body, UI)

   Audited against design-layout-skill (interfaces.dev cheat sheet) —
   see DECISIONS.md #14 for what was applied, what was deliberately
   deferred, and why.
   ========================================================================== */

:root {
  /* Greyscale primitives — raw values only. Component rules and markup
     reference the semantic tokens below, never these directly, except
     where noted in DECISIONS.md #14 (a handful of inline styles in the
     HTML still reference --border-strong directly; left alone rather
     than risk an untested find-replace across markup). */
  --black: #0a0a0a;
  --charcoal: #1f1f1f;
  --dark-grey: #4a4a4a;
  --mid-grey: #767676;
  --grey: #9c9c9c;
  --light-grey: #d4d4d4;
  --off-white: #f6f6f4;
  --white: #ffffff;

  /* Placeholder imagery */
  --placeholder-fill: #c9c9c9;
  --placeholder-border: #9c9c9c;

  --border: #dcdcdc;
  --border-strong: #0a0a0a;

  /* Semantic tokens — every step below exists because something actually
     uses it (§14). Two tokens can share a primitive on purpose — same
     raw value, different role — so each can move independently later. */
  --color-text: var(--charcoal);              /* default body copy */
  --color-text-muted: var(--mid-grey);        /* meta, captions, secondary labels */
  --color-text-faint: var(--grey);            /* tertiary — struck price, inactive step */
  --color-text-on-ink: var(--white);          /* text/icons on a filled-ink surface */
  --color-text-on-inverse: var(--off-white);  /* body text on the black footer/announce band */
  --color-heading-on-inverse: var(--white);   /* headings/links-hover on the black footer */
  --color-caption: var(--dark-grey);          /* placeholder-box captions */
  --color-ink: var(--black);                  /* strongest fill — buttons, badges, active states, headings */
  --color-ink-hover: var(--charcoal);         /* hover state of a filled-ink surface */
  --color-control-border: var(--charcoal);    /* icon-button / nav-toggle outline */
  --color-focus-ring: var(--black);           /* focus-visible outline color */
  --color-surface: var(--white);              /* default page/card surface */
  --color-surface-alt: var(--off-white);      /* alternating section background */
  --color-surface-inverse: var(--black);      /* footer, announcement band */
  --color-border: var(--border);              /* hairline dividers */
  --color-border-strong: var(--border-strong);/* defined form/container edges */

  /* Type scale — 1.25 modular ratio, see DECISIONS.md #3 */
  --fs-display-xl: clamp(2.75rem, 5vw + 1rem, 5rem);
  --fs-display-l: clamp(2.25rem, 3vw + 1rem, 3rem);
  --fs-display-m: clamp(1.75rem, 2vw + 1rem, 2.25rem);
  --fs-heading: 1.375rem;
  --fs-body-l: 1.125rem;
  --fs-body: 0.9375rem;
  --fs-label: 0.8125rem;

  /* 8pt spacing grid — see DECISIONS.md #4. --sp-8/9 added in #15 for the
     narrative homepage's more spacious statement sections. */
  --sp-1: 8px;
  --sp-2: 16px;
  --sp-3: 24px;
  --sp-4: 32px;
  --sp-5: 48px;
  --sp-6: 64px;
  --sp-7: 96px;
  --sp-8: 160px;
  --sp-9: 200px;

  /* Decelerating eases for scroll reveals — see DECISIONS.md #15 /
     RESEARCH-microsoft-ai.md. Named by feel, not just curve shape. */
  --ease-out: cubic-bezier(0.43, 0.195, 0.02, 1);
  --ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);

  --container: 1280px;
  --radius: 2px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

/* Respect reduced-motion system-wide rather than gating every individual
   rule — one override neutralizes all transitions/animations/smooth
   scroll at once, including third-party or future additions. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  font-family: 'Funnel Sans', -apple-system, sans-serif;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--color-text);
  background: var(--color-surface);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-wrap: break-word;
}

h1, h2, h3, h4,
.font-display {
  font-family: 'Funnel Display', 'Funnel Sans', serif;
  font-weight: 600;
  line-height: 1.1;
  margin: 0;
  color: var(--color-ink);
  letter-spacing: -0.01em;
  text-wrap: balance;
}

p { margin: 0 0 var(--sp-2); color: var(--color-text); text-wrap: pretty; }
a {
  color: inherit;
  text-decoration: none;
  text-underline-position: from-font;
  text-decoration-skip-ink: auto;
}
img, svg { display: block; max-width: 100%; }
ul { list-style: none; margin: 0; padding: 0; }
button { font-family: inherit; cursor: pointer; }

/* Every interactive element gets a visible focus state — outline:none is
   never used without this replacement. Mouse clicks don't show it;
   keyboard/switch focus always does. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* Skip-to-content — first focusable element on every page, invisible
   until it receives keyboard focus. */
.skip-link {
  position: fixed;
  top: -100%;
  left: var(--sp-2);
  z-index: 300;
  background: var(--color-ink);
  color: var(--color-text-on-ink);
  padding: 12px 20px;
  font-size: var(--fs-label);
  font-weight: 600;
  transition: top 150ms ease-out;
}
.skip-link:focus {
  top: var(--sp-2);
}
[id] {
  scroll-margin-top: 84px; /* clears the sticky header when a hash link lands */
}

.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--sp-4);
}

.label {
  font-family: 'Funnel Sans', sans-serif;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-text-muted);
  font-weight: 500;
  white-space: nowrap;
}

/* Numerals that represent a value which changes or that sit in a
   price/quantity/total context get fixed-width digits so they don't
   jiggle the layout as they update. */
.tabular-nums,
.card__price,
.stepper span,
#qty-value,
[data-cart-count],
[data-cart-item-count],
[data-cart-subtotal],
[data-cart-total],
[data-discount-amount],
[data-checkout-subtotal],
[data-checkout-total],
[data-checkout-discount-amount],
[data-order-total],
[data-pd-price],
[data-pd-cart-price],
[data-pd-rating-big],
[data-pd-review-count],
[data-pd-review-count-2] {
  font-variant-numeric: tabular-nums;
}

/* ---------- Placeholder image boxes ---------- */
/* Every product photo / lifestyle image / icon is a flat grey box.
   Diagonal hatch = "image" marker so wireframe reads unambiguously
   as a placeholder, never as a finished visual. See DECISIONS.md #1.
   The 1px inset outline follows the design-layout-skill convention for
   real photography (black @ 8% opacity) so swapping a .ph for a real
   <img> later needs no extra styling — see DECISIONS.md #14. */
.ph {
  background-color: var(--placeholder-fill);
  background-image: repeating-linear-gradient(
    135deg,
    rgba(0,0,0,0.05) 0px,
    rgba(0,0,0,0.05) 1px,
    transparent 1px,
    transparent 12px
  );
  border: 1px solid var(--placeholder-border);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-caption);
  font-size: var(--fs-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  width: 100%;
}
.ph span { padding: var(--sp-2); }

.ph--hero { aspect-ratio: 16 / 9; }
.ph--square { aspect-ratio: 1 / 1; }
.ph--portrait { aspect-ratio: 4 / 5; }
.ph--tall { aspect-ratio: 3 / 4; }
.ph--wide { aspect-ratio: 21 / 9; }
.ph--icon { aspect-ratio: 1/1; width: 48px; height: 48px; font-size: 10px; }
.ph--thumb { aspect-ratio: 1/1; width: 72px; }
.ph--swatch { aspect-ratio: 1/1; width: 40px; border-radius: 50%; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  padding: 15px 28px;
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1px solid var(--color-ink);
  border-radius: var(--radius);
  transition: background 150ms ease, color 150ms ease, transform 200ms ease-out;
  white-space: nowrap;
  will-change: transform;
}
.btn:active { transform: scale(0.97); }
.btn--primary { background: var(--color-ink); color: var(--color-text-on-ink); }
.btn--secondary { background: transparent; color: var(--color-ink); }
.btn--full { width: 100%; }
.btn--sm { padding: 10px 18px; font-size: var(--fs-label); }

/* ---------- Header ---------- */
.announce {
  background: var(--color-surface-inverse);
  color: var(--color-text-on-inverse);
  text-align: center;
  font-size: var(--fs-label);
  letter-spacing: 0.08em;
  padding: 10px var(--sp-2);
  text-transform: uppercase;
}

.site-header {
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  background: var(--color-surface);
  z-index: 50;
}
/* Nav sits left, logo is dead-center of the header regardless of how wide
   the nav or actions groups are — a 3-column grid with explicit column
   placement does this without needing the HTML in visual order. Collapses
   to a simple flex row on mobile, where nav is a toggled dropdown anyway
   (see the responsive block). */
.site-header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: var(--sp-3) var(--sp-4);
  gap: var(--sp-4);
}
.logo {
  grid-column: 2;
  justify-self: center;
  font-family: 'Funnel Display', serif;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: 0.06em;
}
.main-nav { grid-column: 1; justify-self: start; display: flex; gap: var(--sp-4); }
.main-nav a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-body);
  font-weight: 500;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: border-color 150ms ease;
}
.main-nav a.active { border-bottom-color: var(--color-ink); }
.header-actions { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: var(--sp-3); }

/* ---------- Icon system ---------- */
/* Every icon on the site is an inline SVG from Lucide (unpkg CDN, no
   build step — consistent with the rest of this wireframe). See
   DECISIONS.md #16 for why Lucide over Phosphor: Phosphor's default CSS
   class is literally `.ph`, which collides with this codebase's existing
   `.ph` placeholder-image class everywhere. */
.icon {
  width: 20px;
  height: 20px;
  stroke-width: 1.75px;
  flex-shrink: 0;
}
.icon--sm { width: 16px; height: 16px; }
.icon--lg { width: 28px; height: 28px; }

/* Icon-only controls: a 20px glyph inside a 40px hit area (24px minimum,
   40px desktop / 44px touch per design-layout-skill). The visible ring
   stays small and quiet; the clickable area doesn't. */
.icon-btn {
  width: 40px; height: 40px;
  border: 1px solid var(--color-control-border);
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  position: relative;
  background: none;
  transition: transform 200ms ease-out;
  will-change: transform;
}
.icon-btn:active { transform: scale(0.95); }
@media (pointer: coarse) {
  .icon-btn { width: 44px; height: 44px; }
}
.cart-count {
  position: absolute; top: -8px; inset-inline-end: -10px;
  background: var(--color-ink); color: var(--color-text-on-ink);
  font-size: 10px; width: 16px; height: 16px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.breadcrumb {
  padding: var(--sp-3) var(--sp-4) 0;
  font-size: var(--fs-label);
  color: var(--color-text-muted);
  letter-spacing: 0.04em;
}
/* The breadcrumb link's text alone renders under the 24px minimum
   tap-target height — pad it out rather than leave a fiddly target. */
.breadcrumb a { display: inline-block; padding: 4px 0; }

/* ---------- Sections ---------- */
section { padding: var(--sp-7) 0; }
section.tight { padding: var(--sp-5) 0; }
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: var(--sp-4);
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.eyebrow { display: block; margin-bottom: var(--sp-1); }

/* ---------- Grids ---------- */
.grid { display: grid; gap: var(--sp-4); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

/* ---------- Product Card ---------- */
.card { display: flex; flex-direction: column; gap: var(--sp-2); position: relative; }
.card__badge {
  position: absolute;
  top: var(--sp-2); inset-inline-start: var(--sp-2);
  background: var(--color-ink); color: var(--color-text-on-ink);
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
  padding: 4px 10px;
  white-space: nowrap;
}
.card__media { position: relative; }
.card__title { font-size: var(--fs-body-l); font-weight: 600; margin: 0; }
.card__meta { font-size: var(--fs-label); color: var(--color-text-muted); letter-spacing: 0.04em; }
.card__price { font-size: var(--fs-body-l); font-weight: 600; }
.card__price .strike { color: var(--color-text-faint); text-decoration: line-through; font-weight: 400; margin-inline-end: var(--sp-1); }

/* ---------- Category tile ---------- */
.cat-tile { position: relative; overflow: hidden; }
.cat-tile__label {
  position: absolute; bottom: var(--sp-3); inset-inline-start: var(--sp-3);
  background: var(--color-surface); padding: var(--sp-1) var(--sp-2);
  font-weight: 600; font-size: var(--fs-body-l);
}

/* ---------- Feature strip ---------- */
.trust-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
}
.trust-strip__item {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-inline-end: 1px solid var(--color-border);
}
.trust-strip__item:last-child { border-inline-end: none; }
.trust-strip__item strong { display: block; font-size: var(--fs-body); font-weight: 600; }
.trust-strip__item span.sub { color: var(--color-text-muted); font-size: var(--fs-label); }

/* ---------- Split editorial block ---------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-6); align-items: center; }
.split.reverse .split__media { order: 2; }

/* ---------- Testimonial ---------- */
.quote-card {
  border: 1px solid var(--color-border);
  padding: var(--sp-4);
}
.quote-card__stars { letter-spacing: 4px; color: var(--color-ink); margin-bottom: var(--sp-2); font-size: var(--fs-body); }
.quote-card__name { font-weight: 600; margin-top: var(--sp-2); }
.quote-card__role { color: var(--color-text-muted); font-size: var(--fs-label); }

/* ---------- Newsletter band ---------- */
.newsletter-band {
  background: var(--color-surface-alt);
  text-align: center;
  padding: var(--sp-7) var(--sp-4);
}
.newsletter-form {
  display: flex; max-width: 460px; margin: var(--sp-3) auto 0;
  border: 1px solid var(--color-ink);
  transition: box-shadow 150ms ease;
}
.newsletter-form:focus-within {
  box-shadow: inset 0 0 0 1px var(--color-ink);
}
.newsletter-form input {
  flex: 1; border: none; background: transparent; padding: 14px var(--sp-2);
  font-family: inherit; font-size: var(--fs-body);
}
/* Outline suppressed only because :focus-within on the parent (above)
   supplies the visible replacement — never remove without one. */
.newsletter-form input:focus { outline: none; }
.newsletter-form button {
  border: none; background: var(--color-ink); color: var(--color-text-on-ink);
  padding: 0 var(--sp-3); font-weight: 600; font-size: var(--fs-label); letter-spacing: 0.06em;
}

/* ---------- Footer ---------- */
.site-footer { background: var(--color-surface-inverse); color: var(--color-text-on-inverse); }
.site-footer__top {
  display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: var(--sp-4);
  padding: var(--sp-7) var(--sp-4) var(--sp-5);
}
.site-footer h4 {
  color: var(--color-heading-on-inverse); font-size: var(--fs-label); text-transform: uppercase;
  letter-spacing: 0.1em; margin-bottom: var(--sp-2); font-family: 'Funnel Sans';
  font-weight: 600;
}
.site-footer a { color: #b8b8b8; display: block; padding: 6px 0; font-size: var(--fs-body); transition: color 150ms ease; }
.site-footer__bottom {
  border-top: 1px solid #2c2c2c;
  padding: var(--sp-3) var(--sp-4);
  display: flex; justify-content: space-between; align-items: center;
  font-size: var(--fs-label); color: #8a8a8a;
}
.payment-icons { display: flex; gap: var(--sp-1); }

/* ---------- Forms (checkout) ---------- */
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--sp-2); }
.field label { font-size: var(--fs-label); font-weight: 600; letter-spacing: 0.04em; }
.field input, .field select {
  border: 1px solid var(--color-border-strong);
  padding: 13px var(--sp-2);
  font-family: inherit; font-size: var(--fs-body);
  border-radius: var(--radius);
  background: var(--color-surface);
}
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
.field [aria-invalid="true"] { border-color: var(--zz-danger); }
.field-error {
  color: var(--zz-danger);
  font-size: var(--fs-label);
  margin-top: -4px;
}

/* ---------- Misc UI ---------- */
.divider { border: none; border-top: 1px solid var(--color-border); margin: var(--sp-4) 0; }
.tag {
  display: inline-block; border: 1px solid var(--color-border-strong);
  padding: 4px 10px; font-size: var(--fs-label); letter-spacing: 0.04em;
  background: transparent;
  font-family: inherit;
  transition: background 150ms ease, color 150ms ease, transform 200ms ease-out;
  will-change: transform;
}
.tag:active { transform: scale(0.96); }
.tag.active { background: var(--color-ink); color: var(--color-text-on-ink); }
.tag.active::before { content: "✓ "; }
.tag:disabled { opacity: 0.35; cursor: not-allowed; text-decoration: line-through; }
.stepper {
  display: inline-flex; align-items: center; border: 1px solid var(--color-border-strong);
}
.stepper button { border: none; background: none; width: 44px; height: 44px; font-size: 16px; transition: transform 200ms ease-out; }
.stepper button:active { transform: scale(0.9); }
.stepper span { width: 32px; text-align: center; font-weight: 600; }

.accordion { border-top: 1px solid var(--color-border); }
.accordion__item { border-bottom: 1px solid var(--color-border); }
.accordion__head {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--sp-2);
  width: 100%;
  border: none;
  background: none;
  text-align: start;
  padding: var(--sp-3) 0; font-weight: 600; font-size: var(--fs-body); cursor: pointer;
  color: var(--color-text);
}
.accordion__body { padding-bottom: var(--sp-3); color: var(--color-text); display: none; }
.accordion__item.open .accordion__body { display: block; }

/* Plus/minus glyph built from two bars instead of swapped text, so
   opening an accordion morphs the icon instead of jump-cutting it. */
.accordion__icon {
  position: relative;
  width: 14px; height: 14px;
  flex-shrink: 0;
}
.accordion__icon::before,
.accordion__icon::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  background: var(--color-ink);
  transform: translate(-50%, -50%);
}
.accordion__icon::before { width: 14px; height: 2px; }
.accordion__icon::after { width: 2px; height: 14px; transition: transform 200ms ease-out; }
.accordion__item.open .accordion__icon::after { transform: translate(-50%, -50%) scaleY(0); }

.progress-steps { display: flex; justify-content: center; gap: var(--sp-2); align-items: center; margin-bottom: var(--sp-5); }
.progress-steps__step { display: flex; align-items: center; gap: 8px; font-size: var(--fs-label); letter-spacing: 0.04em; color: var(--color-text-faint); }
.progress-steps__step.done, .progress-steps__step.active { color: var(--color-ink); font-weight: 600; }
.progress-steps__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--light-grey); }
.progress-steps__step.done .progress-steps__dot,
.progress-steps__step.active .progress-steps__dot { background: var(--color-ink); }
.progress-steps__sep { width: 32px; height: 1px; background: var(--light-grey); }
/* Step status is never color-only: "done" gets a check mark, "active"
   gets an underline, so the state reads without perceiving color. */
.progress-steps__step.done::before { content: "✓"; font-weight: 700; }
.progress-steps__step.active { text-decoration: underline; text-underline-offset: 4px; }

/* ---------- Nav toggle (mobile) ---------- */
.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--color-control-border);
  padding: 9px 16px;
  min-height: 40px;
  font-size: var(--fs-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
}
@media (pointer: coarse) {
  .nav-toggle { min-height: 44px; }
}

/* ---------- Account popover ---------- */
.account-wrap { position: relative; }
.popover {
  position: absolute;
  top: calc(100% + 12px);
  inset-inline-end: 0;
  width: 240px;
  max-width: calc(100vw - 32px);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  padding: var(--sp-3);
  box-shadow: 0 12px 32px rgba(0,0,0,0.12);
  z-index: 80;
}
.popover p { margin-bottom: var(--sp-2); font-size: var(--fs-body); }

/* ---------- Toast ---------- */
.toast {
  position: fixed;
  inset-inline-start: 50%;
  bottom: 32px;
  transform: translateX(-50%) translateY(16px);
  background: var(--color-ink);
  color: var(--color-text-on-ink);
  padding: 14px 24px;
  font-size: var(--fs-body);
  font-weight: 500;
  border-radius: var(--radius);
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease, transform 200ms ease;
  will-change: opacity, transform;
  z-index: 200;
  white-space: nowrap;
}
.toast--visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------- Selectable variant / filter states ---------- */
.swatch-btn {
  width: 40px; height: 40px; border-radius: 50%;
  border: 2px solid transparent;
  padding: 0; cursor: pointer;
  display: inline-flex;
  transition: border-color 150ms ease, transform 200ms ease-out;
  will-change: transform;
}
.swatch-btn:active { transform: scale(0.95); }
.swatch-btn .ph { pointer-events: none; }
.swatch-btn.active { border-color: var(--color-ink); box-shadow: 0 0 0 1px var(--color-surface) inset, 0 0 0 3px var(--color-ink); }

/* ---------- Quick add (product card) ---------- */
.card__quick-add {
  position: absolute;
  bottom: var(--sp-2); inset-inline: var(--sp-2);
  background: var(--color-ink); color: var(--color-text-on-ink);
  border: none; padding: 12px;
  font-size: var(--fs-label); font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase;
  min-height: 40px;
  opacity: 0; transform: translateY(6px);
  transition: opacity 150ms ease, transform 150ms ease;
  will-change: opacity, transform;
}
.card:focus-within .card__quick-add { opacity: 1; transform: translateY(0); }
/* Always visible for touch (no hover to reveal it with); revealed on
   hover only where hover is a real pointer capability, so it doesn't
   stay stuck "on" after a tap on a touch laptop or hover-capable tablet. */
.card__quick-add { opacity: 1; transform: none; position: static; margin-top: 6px; width: 100%; }
@media (hover: hover) and (min-width: 961px) {
  .card__quick-add {
    position: absolute; margin-top: 0; width: auto;
    opacity: 0; transform: translateY(6px);
  }
  .card:hover .card__quick-add { opacity: 1; transform: translateY(0); }
}

/* ---------- Empty states ---------- */
.empty-state {
  text-align: center;
  padding: var(--sp-7) var(--sp-4);
}
.empty-state .ph--icon { margin: 0 auto var(--sp-3); width: 56px; height: 56px; }

/* ---------- Fixed-column page layouts ---------- */
/* These were inline grid-template-columns with a hard pixel column
   (e.g. "1fr 360px") — safe on desktop, but an inline style can't be
   touched by any responsive rule, so they never collapsed on mobile.
   Given real classes here specifically so they can. See DECISIONS.md #20. */
.cart-layout { grid-template-columns: 1fr 360px; gap: var(--sp-6); }
.checkout-layout { grid-template-columns: 1fr 400px; gap: var(--sp-6); }
.pdp-layout { grid-template-columns: 1fr 1fr; gap: var(--sp-6); }
.pdp-reviews-layout { grid-template-columns: 280px 1fr; gap: var(--sp-6); }

.checkout-summary { position: sticky; top: 100px; }

@media (max-width: 760px) {
  .cart-layout,
  .checkout-layout,
  .pdp-layout,
  .pdp-reviews-layout {
    grid-template-columns: 1fr;
  }
  /* Once the summary stacks below a long form instead of sitting beside
     it, sticking it mid-scroll just traps it awkwardly over whatever's
     underneath — let it sit in normal flow instead. */
  .checkout-summary { position: static; }
}

/* ==========================================================================
   Sticky chapter rail — About page only. A pinned image stays in view
   while four content blocks ("chapters") scroll past beside it, each
   with its own number/label. Genuinely different composition from
   Home's stacked full-width sections and from the removed jump-nav —
   this is a real layout change, not a bolted-on component. See
   DECISIONS.md #23.
   ========================================================================== */
.sticky-rail {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: var(--sp-6);
  align-items: start;
}
.sticky-rail__pin {
  position: sticky;
  top: 96px;
}
.sticky-rail__content {
  display: flex;
  flex-direction: column;
}
.sticky-rail__chapter {
  min-height: 60vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: var(--sp-6);
  border-top: 1px solid var(--color-border);
}
.sticky-rail__chapter:first-child { border-top: none; }
.sticky-rail__number {
  font-family: 'Funnel Display', serif;
  font-size: var(--fs-display-m);
  color: var(--color-text-faint);
  margin-bottom: var(--sp-2);
}

/* By The Numbers, re-shaped as an inline stat row within a chapter
   rather than a separate 4-icon grid section — the rail's pinned image
   already carries the visual weight, so the stats read as data, not a
   second illustration beat. */
.sticky-rail__stats { display: flex; flex-wrap: wrap; gap: var(--sp-5); margin-top: var(--sp-3); }
.sticky-rail__stat-value { font-family: 'Funnel Display', serif; font-size: var(--fs-display-m); color: var(--color-ink); }
.sticky-rail__stat-label { font-size: var(--fs-label); color: var(--color-text-muted); }

/* Process steps, re-shaped as a compact numbered list rather than a
   4-photo grid, for the same reason. */
.sticky-rail__steps { margin-top: var(--sp-3); }
.sticky-rail__step {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--color-border);
}
.sticky-rail__step:first-child { border-top: none; }
.sticky-rail__step-index { font-family: 'Funnel Display', serif; color: var(--color-text-faint); flex-shrink: 0; width: 2ch; }

@media (max-width: 760px) {
  /* The full pin-image-beside-scrolling-text pattern needs real width to
     read; on a phone it shrinks to a small sticky thumbnail marker
     instead of disappearing outright — the pin interaction stays real
     and testable on mobile, just smaller. */
  .sticky-rail { grid-template-columns: 88px 1fr; gap: var(--sp-3); }
  .sticky-rail__pin { top: 76px; }
  .sticky-rail__pin .ph { aspect-ratio: 1/1; }
  .sticky-rail__chapter { min-height: 0; padding-block: var(--sp-4); }
}

/* ---------- Resource band ---------- */
/* Adapted from the same model page's "Dig Deeper" band — a heading and a
   row of outbound links in one tinted card, stacking to a vertical list
   on mobile. */
.resource-band {
  background: var(--color-surface-alt);
  padding: var(--sp-4) var(--sp-5);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.resource-band h2 { margin: 0; font-size: var(--fs-heading); }
.resource-band__links { display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap; }
.resource-band__links a { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; font-size: var(--fs-body); }
@media (hover: hover) {
  .resource-band__links a:hover { text-decoration: underline; }
}
@media (max-width: 600px) {
  .resource-band { flex-direction: column; align-items: flex-start; }
  .resource-band__links { flex-direction: column; align-items: flex-start; gap: var(--sp-2); }
}

/* ==========================================================================
   Bespoke product story — Notebooks / To-Do Lists / Day Planners each get
   a long-form scroll story instead of a listing page, with the variant
   choice made inline as part of the narrative and a persistent bottom bar
   tracking the build. Shared mechanics live here and in story.js; each
   template composes its own section order/copy/motif on top. See
   DECISIONS.md #18.
   ========================================================================== */

/* ---------- Choice cards (inline variant picker, narrative-scale) ---------- */
.story-choice-grid { display: grid; gap: var(--sp-3); margin-top: var(--sp-4); }
.story-choice-grid--2 { grid-template-columns: repeat(2, 1fr); }
.story-choice-grid--3 { grid-template-columns: repeat(3, 1fr); }

.story-choice-card {
  position: relative;
  text-align: start;
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface);
  padding: 0;
  overflow: hidden;
  cursor: pointer;
  transition: transform 200ms ease-out, box-shadow 150ms ease;
  will-change: transform;
}
.story-choice-card:active { transform: scale(0.98); }
.story-choice-card__media { aspect-ratio: 4/3; }
.story-choice-card__body { padding: var(--sp-3); }
.story-choice-card__label { font-weight: 600; font-size: var(--fs-body-l); display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.story-choice-card__desc { color: var(--color-text-muted); font-size: var(--fs-body); margin-top: 4px; }
.story-choice-card__check {
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 1px solid var(--color-border-strong);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.story-choice-card__check .icon { width: 14px; height: 14px; opacity: 0; transition: opacity 150ms ease; }
.story-choice-card.active {
  box-shadow: 0 0 0 2px var(--color-ink);
}
.story-choice-card.active .story-choice-card__check {
  background: var(--color-ink);
  border-color: var(--color-ink);
}
.story-choice-card.active .story-choice-card__check .icon { opacity: 1; color: var(--color-text-on-ink); }

/* Color/material swatches — larger than the PDP's compact .swatch-btn,
   since here the swatch IS the content of a full narrative beat, not a
   footnote in a sidebar. */
.story-swatch-grid { display: flex; gap: var(--sp-3); margin-top: var(--sp-4); flex-wrap: wrap; }
.story-swatch {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-1);
  border: none; background: none; cursor: pointer;
}
.story-swatch__circle {
  width: 64px; height: 64px; border-radius: 50%;
  border: 2px solid transparent;
  transition: border-color 150ms ease, transform 200ms ease-out;
  will-change: transform;
}
.story-swatch:active .story-swatch__circle { transform: scale(0.94); }
.story-swatch.active .story-swatch__circle { border-color: var(--color-ink); box-shadow: 0 0 0 1px var(--color-surface) inset, 0 0 0 3px var(--color-ink); }
.story-swatch__label { font-size: var(--fs-label); color: var(--color-text-muted); }
.story-swatch.active .story-swatch__label { color: var(--color-ink); font-weight: 600; }

/* ---------- Persistent build bar ---------- */
/* Appears once the hero has scrolled past (see story.js), stays pinned
   for the rest of the story so "add to cart" is always one tap away no
   matter how deep into the narrative the shopper has scrolled. */
.story-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 90;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border-strong);
  transform: translateY(100%);
  transition: transform 250ms var(--ease-out);
  will-change: transform;
}
.story-bar.visible { transform: translateY(0); }
.story-bar__inner {
  max-width: var(--container);
  margin: 0 auto;
  padding: var(--sp-2) var(--sp-4);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.story-bar__thumb { width: 48px; height: 48px; flex-shrink: 0; }
.story-bar__info { flex: 1; min-width: 0; }
.story-bar__title { font-weight: 600; font-size: var(--fs-body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.story-bar__meta { font-size: var(--fs-label); color: var(--color-text-muted); white-space: normal; }
@media (max-width: 760px) {
  .story-bar__meta { display: none; }
  .story-bar__thumb { display: none; }
  /* Title, quantity and both buttons no longer fit in one row once the
     Checkout CTA is visible — wrap onto a second row rather than
     squeezing everything down until it's unreadable or untappable. */
  .story-bar__inner { flex-wrap: wrap; row-gap: var(--sp-2); padding-block: var(--sp-2); }
  .story-bar__info { flex-basis: 100%; }
  .story-bar .stepper { order: 1; }
  .story-bar [data-story-add-to-cart] { order: 2; flex: 1; }
  .story-bar [data-story-checkout] { order: 3; flex: 1; }
}

/* ---------- Story sections ---------- */
.story-section { padding: var(--sp-9) var(--sp-4); }
.story-section__inner { max-width: 640px; margin: 0 auto; text-align: center; }
.story-section__inner--wide { max-width: 900px; }
.story-fact-strip {
  display: flex; justify-content: center; gap: var(--sp-4);
  margin-top: var(--sp-3); flex-wrap: wrap;
}
.story-fact { text-align: center; }
.story-fact__value { font-family: 'Funnel Display', serif; font-size: var(--fs-display-m); color: var(--color-ink); }
.story-fact__label { font-size: var(--fs-label); color: var(--color-text-muted); }

/* Recap card — the closing "here's what you've built" moment before the
   final add-to-cart, in case a shopper never noticed the sticky bar. */
.story-recap {
  border: 1px solid var(--color-border-strong);
  max-width: 560px;
  margin: var(--sp-4) auto 0;
  padding: var(--sp-4);
  text-align: start;
}
.story-recap__row { display: flex; justify-content: space-between; padding: var(--sp-1) 0; border-bottom: 1px solid var(--color-border); font-size: var(--fs-body); }
.story-recap__row:last-of-type { border-bottom: none; }
.story-recap__row dt { color: var(--color-text-muted); }
.story-recap__row dd { margin: 0; font-weight: 600; }

/* To-Do template's checklist motif — items tick on scroll instead of a
   photo-led narrative, since a to-do pad's story is about the feeling of
   finishing things, not a material close-up. */
.story-checklist { max-width: 420px; margin: var(--sp-4) auto 0; text-align: start; }
.story-checklist__item {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--color-border);
  font-size: var(--fs-body-l);
  color: var(--color-text-faint);
  text-decoration: line-through;
  transition: color 400ms var(--ease-out);
}
.story-checklist__item .icon { color: var(--color-text-faint); transition: color 400ms var(--ease-out); }

/* Planner template's time-of-day motif */
.story-daypart {
  display: inline-flex; align-items: center; gap: 8px;
  margin-bottom: var(--sp-2);
}

/* Scroll cue on the story hero — a quiet nudge, not an instruction */
.story-scroll-cue {
  position: absolute;
  bottom: var(--sp-4);
  left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  color: var(--color-text-on-ink);
  opacity: 0.8;
}

@media (max-width: 760px) {
  .story-choice-grid--3 { grid-template-columns: 1fr; }
  .story-choice-grid--2 { grid-template-columns: 1fr; }
}

/* ---------- Hover-only interactions ---------- */
/* Grouped under one guard so nothing here can "stick" after a tap on
   touch devices — see design-layout-skill's hover guidance. */
@media (hover: hover) {
  .btn--primary:hover { background: var(--color-ink-hover); }
  .btn--secondary:hover { background: var(--color-ink); color: var(--color-text-on-ink); }
  .main-nav a:hover { border-bottom-color: var(--color-ink); }
  .breadcrumb a:hover { color: var(--color-ink); }
  .site-footer a:hover { color: var(--color-heading-on-inverse); }
  .story-choice-card:hover { box-shadow: 0 0 0 1px var(--color-border-strong); }
  .story-swatch:hover .story-swatch__circle { border-color: var(--color-border-strong); }
}

/* ==========================================================================
   Scroll narrative — pinned hero, staggered reveals, scroll-linked expand.
   Pattern researched from microsoft.ai; see RESEARCH-microsoft-ai.md and
   DECISIONS.md #15 for what was kept, adapted, or deliberately dropped.
   ========================================================================== */

/* ---------- Full-bleed hero (image with copy over it) ---------- */
.pin-hero { position: relative; height: min(80vh, 760px); min-height: 480px; }
.pin-hero__visual {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.pin-hero__content {
  position: relative;
  width: 100%; height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  flex-direction: column;
  padding: 0 var(--sp-4);
}
.pin-hero__content h1 { font-size: var(--fs-display-xl); }
@media (max-width: 760px) {
  /* Phones: image first, copy below it. */
  .pin-hero { height: auto; min-height: 0; }
  .pin-hero__visual { position: relative; height: 70vh; }
  .pin-hero__content { position: relative; height: auto; padding: var(--sp-7) var(--sp-4); }
  /* The scroll cue was positioned absolute-bottom against a 100vh
     overlay; once content flows normally instead it would sit on top of
     the CTA buttons rather than below them. The content stacking below
     the visual already makes "scroll for more" obvious without a cue. */
  .pin-hero__content .story-scroll-cue { display: none; }
}

/* ---------- Statement band (claim / proof rhythm) ---------- */
.statement-band {
  padding: var(--sp-8) var(--sp-4);
  text-align: center;
}
.statement-band__text {
  max-width: 820px;
  margin: 0 auto;
  font-size: var(--fs-display-m);
  font-family: 'Funnel Display', serif;
  color: var(--color-ink);
  line-height: 1.25;
}
.statement-band__text + .statement-band__text {
  margin-top: var(--sp-4);
  font-size: var(--fs-body-l);
  font-family: 'Funnel Sans', sans-serif;
  color: var(--color-text);
  font-weight: 400;
}
.statement-band--inverse {
  background: var(--color-surface-inverse);
}
.statement-band--inverse .statement-band__text { color: var(--color-text-on-inverse); }
.statement-band--inverse .statement-band__text:first-child { color: var(--color-heading-on-inverse); }

/* ---------- Portrait gallery ---------- */
.portrait-row {
  display: flex;
  gap: var(--sp-3);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-bottom: var(--sp-2);
}
.portrait-row__item { flex: 0 0 auto; width: 200px; scroll-snap-align: start; }
.portrait-row__name { font-weight: 600; margin-top: var(--sp-2); font-size: var(--fs-body); }
.portrait-row__role { color: var(--color-text-muted); font-size: var(--fs-label); }

/* ---------- Founder / leadership quote ---------- */
.lead-quote {
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
}
.lead-quote__text {
  font-family: 'Funnel Display', serif;
  font-size: var(--fs-display-m);
  line-height: 1.3;
  color: var(--color-ink);
}

/* ---------- Responsive ---------- */
@media (max-width: 960px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
  .split { grid-template-columns: 1fr; gap: var(--sp-3); }
  .split.reverse .split__media { order: 0; }
  .trust-strip { grid-template-columns: repeat(2, 1fr); }
  .trust-strip__item:nth-child(2) { border-inline-end: none; }
  .site-footer__top { grid-template-columns: 1fr 1fr; }

  .nav-toggle { display: inline-flex; }

  /* The 3-column nav-left/logo-center grid only makes sense once the nav
     is a visible row; below this width nav is a toggled dropdown, so the
     header goes back to a simple flex row (logo, then actions). */
  .site-header__inner { display: flex; justify-content: space-between; }
  .logo { grid-column: auto; justify-self: auto; }
  .header-actions { grid-column: auto; justify-self: auto; }
  /* .main-nav's justify-self:start (desktop grid) also applies to it once
     absolutely positioned for the mobile dropdown — self-alignment
     properties apply to abs-pos boxes too, and "start" overrides the
     default stretch behaviour that inset-inline:0 would otherwise give
     it, shrinking the dropdown to fit its content instead of spanning
     the full width. Reset it here. */
  .main-nav { justify-self: auto; }

  .main-nav {
    display: none;
    position: absolute;
    top: 100%; inset-inline: 0;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    flex-direction: column;
    padding: 0 var(--sp-4);
    gap: 0;
  }
  .main-nav.nav-open { display: flex; }
  .main-nav a { padding: 14px 0; border-bottom: 1px solid var(--color-border); }
}
@media (max-width: 600px) {
  .grid-4, .grid-3, .grid-2 { grid-template-columns: 1fr; }
  .site-footer__top { grid-template-columns: 1fr; }
  .field-row { grid-template-columns: 1fr; }
}
