/* ==========================================================================
   Lead Opticals — Design Foundation
   Tokens, reset, typography, layout primitives, motion primitives.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=IBM+Plex+Mono:wght@400;500&display=swap');

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Brand — taken from the Lead Opticals mark */
  --red:            #C22127;
  --red-dark:       #A7191F;
  --red-bright:     #DE2A31;
  /* The selected state across the whole site: chips, cards, rows, pills.
     Named -wash because it is a tint of the brand red, not a colour of its
     own -- anything selected reads as the same decision everywhere. */
  --red-wash:       #FFF4F3;

  /* Neutrals */
  --ink:            #171717;
  --ink-2:          #2A2624;
  --ink-soft:       #66615E;
  /* DECORATIVE ONLY. 3.06:1 on white -- it fails WCAG AA and must never
     carry text a customer has to read. Rules, disabled marks, placeholder
     glyphs and empty-state artwork only. Readable secondary text is
     --ink-soft, which passes at 5.9:1. */
  --ink-faint:      #9A928D;
  --paper:          #FFFFFF;
  --tint:           #FAF8F5;
  --sand:           #F0E9E1;
  --line:           #DEDAD5;
  --line-strong:    #CFC7BF;

  /* Semantic */
  --bg:             var(--paper);
  --fg:             var(--ink);
  --muted:          var(--ink-soft);
  --accent:         var(--red);
  --on-accent:      #FFFFFF;
  --success:        #267A52;
  --warning:        #B4690E;
  --danger:         #B42318;

  /* Type */
  /* ONE voice. Manrope sets everything a visitor reads — headings, navigation,
     CTA labels, body copy, forms — across five weights. A single well-drawn
     family used properly reads as a brand; two families used adjacently mostly
     read as an accident, and the second face cost three more font files for a
     distinction almost nobody consciously notices.
     IBM Plex Mono stays for the small technical accents — eyebrows, order
     references, prices — where a monospace reads as precise rather than
     decorative, and where the contrast is doing real work. */
  /* Two named faces, and nothing else. The stacks used to carry a list of
     platform fallbacks behind each one; those only ever applied if a
     download failed, but they were still other typefaces named in the
     brand's own stylesheet.
     The generic keyword at the end stays and is not negotiable. Without
     one, a failed font request falls through to the browser's default —
     which is a serif, and is exactly how Times appeared here in the first
     place. `sans-serif` and `monospace` guarantee the failure mode is at
     least the right kind of letterform. */
  --display: 'Manrope', sans-serif;
  --sans:    var(--display);
  --mono:    'IBM Plex Mono', monospace;

  /* Fluid type scale (min 375px → max 1440px) */
  /* The scale bottomed out at 11px, so every smaller label — eyebrows,
     unit hints, badges — was written as a raw pixel value. Sixteen
     different ones accumulated, some half a pixel apart. These two steps
     give the small chrome a token, which is the only way it stays
     consistent as the site grows. */
  --fs-3xs:   clamp(0.563rem, 0.55rem + 0.06vw, 0.594rem);
  --fs-2xs:   clamp(0.625rem, 0.61rem + 0.06vw, 0.656rem);
  --fs-xs:    clamp(0.688rem, 0.66rem + 0.12vw, 0.75rem);
  --fs-sm:    clamp(0.813rem, 0.79rem + 0.10vw, 0.875rem);
  --fs-base:  clamp(1rem, 0.98rem + 0.11vw, 1.0625rem);
  --fs-md:    clamp(1rem, 0.96rem + 0.19vw, 1.125rem);
  --fs-lg:    clamp(1.188rem, 1.10rem + 0.38vw, 1.5rem);
  --fs-xl:    clamp(1.375rem, 1.29rem + 0.36vw, 1.75rem);
  --fs-2xl:   clamp(1.875rem, 1.52rem + 1.50vw, 3rem);
  --fs-3xl:   clamp(2.25rem, 1.55rem + 2.98vw, 4.25rem);
  /* 96px was set for Bodoni, whose thin strokes carry that size gracefully.
     Manrope at 800 is far denser and reads as shouting at the same measure,
     so the hero step comes down to 76px and the mobile floor comes up. */
  --fs-4xl:   clamp(2.5rem, 1.72rem + 3.33vw, 4.75rem);

  /* Spacing. Eight is the primary step and everything from --sp-2 up is a
     multiple of it. --sp-1 (4px) and --sp-3 (12px) are kept deliberately:
     optical adjustments inside a control -- the gap between a checkbox and
     its label, the lift under a chip -- do not want to jump 8px at a time.
     They are for adjustment, not for layout. Layout uses 8 and up. */
  --sp-1:  0.25rem;   /* 4  -- adjustment only */
  --sp-2:  0.5rem;    /* 8  */
  --sp-3:  0.75rem;   /* 12 -- adjustment only */
  --sp-4:  1rem;
  --sp-5:  1.5rem;
  --sp-6:  2rem;
  --sp-7:  2.5rem;
  --sp-8:  3rem;
  --sp-9:  4rem;
  --sp-10: 5rem;
  --sp-11: 6.5rem;
  --sp-12: 8rem;

  --section-y: clamp(4rem, 2.4rem + 6.8vw, 7.5rem);
  --gutter:    clamp(1.25rem, 0.7rem + 2.3vw, 3rem);
  --maxw:      1240px;
  --maxw-wide: 1560px;

  /* Radii, elevation */
  /* The smallest comfortable thumb target, and the sticky header's height.
     Both were repeated as magic numbers; naming them keeps the mobile
     rules honest and consistent. */
  --touch-target: 44px;
  --touch-target-lg: 48px;
  --header-height: 65px;
  /* The mobile action bar: button height, and the bar's true outer height
     including its 1px top border. Both are consumed by components.css. */
  --mobile-cta-btn-h: 52px;
  --mobile-cta-h: 53px;

  /* Four radii, and nothing else. 2px and 5px were both in circulation as
     raw values; --r-xs covers the hairline case so no rule needs one. */
  --r-xs: 2px;
  --r-sm: 3px;
  --r-md: 6px;
  --r-lg: 14px;
  --r-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(18,16,15,.05), 0 2px 8px rgba(18,16,15,.04);
  --shadow-md: 0 4px 12px rgba(18,16,15,.07), 0 12px 32px rgba(18,16,15,.06);
  --shadow-lg: 0 12px 28px rgba(18,16,15,.10), 0 32px 72px rgba(18,16,15,.10);

  /* Motion */
  --e-out:   cubic-bezier(.22, 1, .36, 1);        /* expo.out */
  --e-inout: cubic-bezier(.76, 0, .24, 1);        /* expo.inOut */
  --e-soft:  cubic-bezier(.33, 1, .68, 1);        /* power2.out */
  --e-spring: cubic-bezier(.34, 1.56, .64, 1);    /* gentle overshoot */
  --t-fast:  .18s;
  --t-mid:   .32s;
  --t-slow:  .6s;

  --header-h: 76px;
  color-scheme: light;
}

@media (max-width: 720px) {
  :root { --header-h: 64px; }
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 16px);
  /* Set on the root, not just on body. Anything inheriting from the root
     rather than from body — ::backdrop, and any element inserted outside
     the body chain — would otherwise fall back to the browser default.
     Two families means two, including where the cascade begins. */
  font-family: var(--sans);
  /* `clip` rather than `hidden`: reveal animations translate elements
     sideways before they land, and body's `hidden` just propagates to the
     viewport instead of containing them. `clip` also avoids creating a
     scroll container, which would break every position:sticky on the site. */
  overflow-x: clip;
}

/* Author styles beat the UA sheet on specificity, so components declared with
   display:flex/grid would otherwise ignore the hidden attribute and stay in
   the layout and the tab order. */
[hidden] { display: none !important; }

body {
  font-family: var(--sans);
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: 1.65;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
  text-rendering: optimizeLegibility;
}

img, svg, video, canvas { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; }
table { border-collapse: collapse; width: 100%; }

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

::selection { background: var(--red); color: #fff; }

/* Scrollbar — light touch, desktop only */
@media (pointer: fine) {
  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: var(--tint); }
  ::-webkit-scrollbar-thumb { background: var(--line-strong); border: 3px solid var(--tint); border-radius: 99px; }
  ::-webkit-scrollbar-thumb:hover { background: var(--ink-faint); }
}

.skip-link {
  position: absolute; left: var(--sp-4); top: -100px; z-index: 999;
  background: var(--ink); color: #fff; padding: 12px 20px;
  font-size: var(--fs-sm); font-weight: 500; transition: top var(--t-fast) var(--e-out);
}
.skip-link:focus { top: var(--sp-4); }

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */
/* Hierarchy comes from weight and size, not decoration. Manrope needs real
   weight to feel confident and tighter tracking as it gets larger — a geometric
   sans set loose at display sizes reads as a template. */
h1, h2, h3, h4, h5 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.021em;
  text-wrap: balance;
}
h1 { font-size: var(--fs-3xl); font-weight: 800; letter-spacing: -0.032em; line-height: 1.04; }
h2 { font-size: var(--fs-2xl); letter-spacing: -0.026em; line-height: 1.08; }
h3 { font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.016em; }
h4 { font-size: var(--fs-lg); font-weight: 700; letter-spacing: -0.012em; }
p  { text-wrap: pretty; }

.display-xl {
  font-family: var(--display); font-size: var(--fs-4xl);
  font-weight: 800; line-height: 0.98; letter-spacing: -0.038em;
}
.text-red { color: var(--red); }
.text-muted { color: var(--muted); }

.eyebrow {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--mono); font-size: var(--fs-xs);
  letter-spacing: .18em; text-transform: uppercase; color: var(--red);
  font-weight: 500;
}
.eyebrow::before {
  content: ''; width: 22px; height: 1px; background: currentColor; flex: none;
}
.eyebrow.no-rule::before { display: none; }

.lead { font-size: var(--fs-md); line-height: 1.75; color: var(--muted); }
.mono { font-family: var(--mono); font-size: var(--fs-xs); letter-spacing: .06em; }

/* Figures a customer reads: prices, totals, quantities, counts.
   Manrope, not the monospace face. A price is the most important number on
   the page and belongs in the brand's own voice; the only thing monospace
   was really contributing was column alignment, and font-variant-numeric
   gives that without changing the typeface.
   .mono stays for what it is actually for: short technical labels -- an SKU,
   an order reference, a size in millimetres, an uppercase micro-label. */
.num {
  font-family: var(--display);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
  letter-spacing: -0.01em;
}

/* --------------------------------------------------------------------------
   4. Layout primitives
   -------------------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.wrap-wide { width: 100%; max-width: var(--maxw-wide); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: var(--section-y); }
.section-tight { padding-block: calc(var(--section-y) * .62); }
.bg-tint { background: var(--tint); }
.bg-sand { background: var(--sand); }
.bg-ink { background: var(--ink); color: #fff; }
.bg-ink .text-muted, .bg-ink .lead { color: rgba(255,255,255,.68); }

.stack > * + * { margin-top: var(--sp-4); }
.cluster { display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: center; }
.divider { height: 1px; background: var(--line); border: 0; }

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sp-6); margin-bottom: var(--sp-8); flex-wrap: wrap;
}
.section-head h2 { max-width: 16ch; }
.section-head .eyebrow { margin-bottom: var(--sp-3); }
/* Grid and flex children default to min-width:auto, so one un-shrinkable child
   (a nowrap button, a wide table) widens its track and scrolls the whole page.
   Opting the page-level layout containers out of that is the structural fix. */
.hero-grid > *, .shop > *, .pdp > *, .pdp-detail > *, .reviews-grid > *,
.cart-layout > *, .checkout-grid > *, .book > *, .contact-main > *,
.account > *, .lens-grid > *, .story-grid > *, .visit-inner > *,
.faq-wrap > *, .standards-grid > *, .help-inner > *, .offer-inner > *,
.foot-main > *, .foot-cta-inner > *, .book-head > * { min-width: 0; }

.section-head-center { max-width: 620px; margin: 0 auto var(--sp-9); text-align: center; }
.section-head-center .eyebrow { margin-bottom: var(--sp-4); }
.section-head-center .lead { margin-top: var(--sp-4); }

/* --------------------------------------------------------------------------
   5. Buttons & links
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--ink);
  --btn-fg: #fff;
  --btn-bd: var(--ink);
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 14px 26px; min-height: 48px;
  /* CTA labels are brand voice, so they are set in Manrope. Sentence case at a
     confident weight reads as a considered clinical brand; wide-tracked
     uppercase reads as fashion retail, which is not what an optometry practice
     is selling. */
  font-family: var(--display); font-size: var(--fs-sm); font-weight: 700;
  letter-spacing: -0.004em; text-transform: none; white-space: nowrap;
  border-radius: var(--r-md);
  color: var(--btn-fg); background: var(--btn-bg);
  border: 1px solid var(--btn-bd);
  cursor: pointer; overflow: hidden; isolation: isolate;
  transition: color var(--t-mid) var(--e-out), border-color var(--t-mid) var(--e-out),
              background-color var(--t-mid) var(--e-out), transform var(--t-fast) var(--e-out);
}
/* Wipe fill — the layer slides up under the label on hover */
.btn::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--btn-hover, var(--red));
  transform: translateY(101%);
  transition: transform var(--t-mid) var(--e-out);
}
.btn:hover::after, .btn:focus-visible::after { transform: translateY(0); }
.btn:hover { color: #fff; border-color: var(--btn-hover, var(--red)); }
.btn:active { transform: scale(.98); }

.btn-primary  { --btn-bg: var(--red); --btn-fg: #fff; --btn-bd: var(--red); --btn-hover: var(--ink); }
.btn-dark     { --btn-bg: var(--ink); --btn-fg: #fff; --btn-bd: var(--ink); --btn-hover: var(--red); }
.btn-outline  { --btn-bg: transparent; --btn-fg: var(--ink); --btn-bd: var(--ink); --btn-hover: var(--ink); }
.btn-ghost    { --btn-bg: transparent; --btn-fg: #fff; --btn-bd: rgba(255,255,255,.55); --btn-hover: #fff; }
.btn-ghost:hover { color: var(--ink); border-color: #fff; }
.btn-block { display: flex; width: 100%; }
.btn-sm { padding: 11px 20px; min-height: 40px; font-size: var(--fs-xs); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .45; pointer-events: none; }

.link-u {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--fs-sm); font-weight: 500; letter-spacing: .04em;
  padding-bottom: 4px; position: relative; color: var(--ink);
}
.link-u::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1.5px;
  background: var(--red); transform-origin: right; transform: scaleX(1);
  transition: transform var(--t-mid) var(--e-out);
}
.link-u:hover::after { transform-origin: left; animation: link-sweep .5s var(--e-out); }
@keyframes link-sweep {
  0%   { transform: scaleX(1); transform-origin: right; }
  49%  { transform: scaleX(0); transform-origin: right; }
  50%  { transform: scaleX(0); transform-origin: left; }
  100% { transform: scaleX(1); transform-origin: left; }
}
.link-u .arw { transition: transform var(--t-mid) var(--e-out); }
.link-u:hover .arw { transform: translateX(5px); }
.link-u.muted { color: var(--muted); }
.link-u.muted::after { background: var(--line-strong); }
.link-u.on-dark { color: #fff; }

/* --------------------------------------------------------------------------
   6. Form controls
   -------------------------------------------------------------------------- */
.field { display: block; margin-bottom: var(--sp-4); }
.field > label,
.label {
  display: block; margin-bottom: 7px;
  font-family: var(--mono); font-size: var(--fs-xs);
  letter-spacing: .10em; text-transform: uppercase; color: var(--ink-soft);
}
.input, .select, .textarea {
  width: 100%; padding: 13px 15px; min-height: 48px;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  font-size: var(--fs-base);
  transition: border-color var(--t-fast) var(--e-out), box-shadow var(--t-fast) var(--e-out);
}
.input::placeholder, .textarea::placeholder { color: var(--ink-soft); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-faint); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--red);
  box-shadow: 0 0 0 3px var(--red-wash);
}
.textarea { min-height: 128px; resize: vertical; line-height: 1.6; }
.select {
  appearance: none; cursor: pointer; padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23635C58' stroke-width='1.5'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 15px center; background-size: 11px;
}
.field-hint { margin-top: 6px; font-size: var(--fs-xs); color: var(--ink-soft); }
.field-error {
  margin-top: 6px; font-size: var(--fs-xs); color: var(--danger);
  display: none; align-items: center; gap: 5px;
}
.field.invalid .input,
.field.invalid .select,
.field.invalid .textarea { border-color: var(--danger); box-shadow: 0 0 0 3px rgba(192,57,43,.1); }
.field.invalid .field-error { display: flex; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--sp-4); }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; } }

.check {
  display: flex; align-items: flex-start; gap: 11px;
  font-size: var(--fs-sm); color: var(--ink-soft); cursor: pointer;
  padding: 4px 0; line-height: 1.5;
}
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check .box {
  flex: none; width: 20px; height: 20px; margin-top: 1px;
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--paper); position: relative;
  transition: all var(--t-fast) var(--e-out);
}
.check .box::after {
  content: ''; position: absolute; inset: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5 6.5 11.5 12.5 5'/%3E%3C/svg%3E") center/13px no-repeat;
  opacity: 0; transform: scale(.5); transition: all var(--t-fast) var(--e-spring);
}
.check input:checked + .box { background: var(--red); border-color: var(--red); }
.check input:checked + .box::after { opacity: 1; transform: scale(1); }
.check input:focus-visible + .box { outline: 2px solid var(--red); outline-offset: 2px; }

/* --------------------------------------------------------------------------
   7. Motion primitives  (vanilla equivalents of the GSAP presets)
   -------------------------------------------------------------------------- */

/* Scroll reveal — JS adds .is-in when the element enters the viewport.
   Only applied once JS confirms support, so no-JS users see content. */
[data-reveal] { will-change: opacity, transform; }
.js [data-reveal] {
  opacity: 0;
  transition: opacity .7s var(--e-soft), transform .7s var(--e-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.js [data-reveal="up"]    { transform: translate3d(0, 26px, 0); }
.js [data-reveal="down"]  { transform: translate3d(0, -22px, 0); }
.js [data-reveal="left"]  { transform: translate3d(30px, 0, 0); }
.js [data-reveal="right"] { transform: translate3d(-30px, 0, 0); }
.js [data-reveal="fade"]  { transform: none; }
.js [data-reveal="zoom"]  { transform: scale(.94); }
.js [data-reveal="clip"]  { clip-path: inset(0 0 100% 0); transform: none; transition: opacity .5s linear, clip-path .95s var(--e-out); }
.js [data-reveal].is-in {
  opacity: 1; transform: none; clip-path: inset(0 0 0 0); will-change: auto;
}

/* Split-text headline — one span per word/char, staggered */
.split-line { display: block; overflow: hidden; }
.split-unit { display: inline-block; will-change: transform; }
.js .split-line .split-unit { transform: translate3d(0, 110%, 0) rotate(3deg); opacity: 0; }
.js .split-ready .split-line .split-unit {
  transform: none; opacity: 1;
  transition: transform .95s var(--e-out), opacity .6s linear;
  transition-delay: var(--unit-delay, 0ms);
}

/* Parallax layers — JS writes --py */
[data-parallax] { will-change: transform; transform: translate3d(0, var(--py, 0px), 0); }

/* Magnetic buttons — JS writes --mx/--my */
[data-magnetic] { transition: transform .45s var(--e-out); }
[data-magnetic].is-pulled { transition: transform .12s linear; transform: translate3d(var(--mx,0), var(--my,0), 0); }

/* Tilt cards — JS writes --rx/--ry */
[data-tilt] { transform-style: preserve-3d; transition: transform .5s var(--e-out); }
[data-tilt].is-tilting { transition: transform .1s linear; transform: perspective(900px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)); }

/* Marquee */
.marquee { display: flex; overflow: hidden; user-select: none; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.marquee-track { display: flex; flex: none; gap: var(--sp-7); align-items: center; padding-right: var(--sp-7); animation: marquee var(--marquee-dur, 34s) linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee[data-dir="rev"] .marquee-track { animation-direction: reverse; }
@keyframes marquee { to { transform: translate3d(-100%, 0, 0); } }

/* Page transition curtain */
.curtain {
  position: fixed; inset: 0; z-index: 400; pointer-events: none;
  background: var(--ink); transform: scaleY(0); transform-origin: bottom;
}
.curtain.in  { animation: curtain-in .5s var(--e-inout) forwards; }
.curtain.out { animation: curtain-out .55s var(--e-inout) forwards; }
@keyframes curtain-in  { from { transform: scaleY(0); transform-origin: bottom; } to { transform: scaleY(1); transform-origin: bottom; } }
@keyframes curtain-out { from { transform: scaleY(1); transform-origin: top; }    to { transform: scaleY(0); transform-origin: top; } }

/* Custom cursor (fine pointers only) */
.cursor-dot, .cursor-ring {
  position: fixed; top: 0; left: 0; z-index: 500; pointer-events: none;
  border-radius: 50%; opacity: 0; mix-blend-mode: difference;
}
.cursor-dot  { width: 6px; height: 6px; background: #fff; margin: -3px 0 0 -3px; transition: opacity .25s, width .25s var(--e-out), height .25s var(--e-out); }
.cursor-ring { width: 38px; height: 38px; border: 1px solid rgba(255,255,255,.7); margin: -19px 0 0 -19px; transition: opacity .25s, width .3s var(--e-out), height .3s var(--e-out), border-color .3s, background-color .3s; }
.cursor-ready .cursor-dot, .cursor-ready .cursor-ring { opacity: 1; }
.cursor-hover .cursor-ring { width: 62px; height: 62px; background: rgba(255,255,255,.14); }
.cursor-hover .cursor-dot { width: 0; height: 0; }
@media (pointer: coarse), (max-width: 900px) { .cursor-dot, .cursor-ring { display: none; } }

/* Count-up numerals hold their width so the layout can't jitter */
[data-count] { font-variant-numeric: tabular-nums; }

/* Preloader */
#preloader {
  position: fixed; inset: 0; z-index: 600;
  display: grid; place-items: center; gap: 0;
  background: var(--paper);
  transition: opacity .6s var(--e-out), visibility .6s;
}
#preloader.done { opacity: 0; visibility: hidden; }
.pre-inner { display: flex; flex-direction: column; align-items: center; gap: var(--sp-5); }
.pre-mark { width: 96px; height: auto; }
.pre-mark path, .pre-mark ellipse {
  stroke-dasharray: 620; stroke-dashoffset: 620;
  animation: draw 1.5s var(--e-soft) forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }
.pre-bar { width: 168px; height: 1.5px; background: var(--line); overflow: hidden; }
.pre-bar span { display: block; height: 100%; width: 0; background: var(--red); transition: width .3s linear; }
.pre-pct { font-family: var(--mono); font-size: var(--fs-xs); letter-spacing: .2em; color: var(--ink-soft); }

/* --------------------------------------------------------------------------
   8. Reduced motion — the whole engine collapses to instant final state
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .js [data-reveal],
  .js .split-line .split-unit {
    opacity: 1 !important; transform: none !important; clip-path: none !important;
  }
  [data-parallax] { transform: none !important; }
  .marquee-track { animation: none !important; }
  .cursor-dot, .cursor-ring { display: none !important; }
}

/* --------------------------------------------------------------------------
   9. Utilities
   -------------------------------------------------------------------------- */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.center { text-align: center; }
.hide { display: none !important; }
@media (max-width: 900px) { .hide-md { display: none !important; } }
@media (max-width: 620px) { .hide-sm { display: none !important; } }

/* ==========================================================================
   Focus, and the smallest thing a thumb can hit
   ==========================================================================
   Two rules that were carrying most of the accessibility debt: a handful of
   controls removed their outline without putting anything back, and a set of
   small controls sat under 44px. Both are fixed here rather than per
   component, so a new control inherits the right behaviour by default.
   ========================================================================== */

/* One visible focus ring for everything reachable by keyboard. :focus-visible
   so a mouse click does not leave a ring behind, which is what tempted the
   original code into `outline: none` in the first place. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* The search field and the range slider both cleared their outline with no
   replacement, so a keyboard user could not see where they were. */
.search-input:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
.price-range:focus-visible  { outline: 2px solid var(--red); outline-offset: 3px; }

/* Small controls that fell short of a thumb. Sized here rather than in each
   component so the rule is stated once and cannot drift. */
.gallery-expand,
.card-wish,
.swatch-mini {
  min-width: var(--touch-target);
  min-height: var(--touch-target);
}
/* The visual mark stays its original size; the target around it grows. */
.swatch-mini { background-clip: content-box; padding: 9px; }

/* An inline help link ("Which width am I?") is text, not a button, but it is
   still tapped — give it a target without turning it into a block. */
.opt-help {
  display: inline-flex; align-items: center;
  min-height: var(--touch-target);
}
