:root{
  --ink:#3A3D42;
  --paper:#FAFAF8;
  --steel:#2A2D31;
  --steel-2:#3A3E43;
  --amber:#4A7FB5;
  --amber-dark:#3A6389;
  --orange:#E8871E;
  --orange-dark:#C36F14;
  --whatsapp:#25D366;
  --line: rgba(58,61,66,0.14);
  --line-light: rgba(250,250,248,0.14);
  --header-h: 88px;
  --marquee-h: 36px;

  /* ---- New design-reference palette (site-wide update in progress) ----
     Several of these are the exact same colors we already had under
     different names (kept as separate aliases rather than renaming
     everything at once, to avoid breaking sections not yet migrated). */
  --bg-light:#FAFAF8;        /* = --paper */
  --carbon-dark:#2A2D31;     /* = --steel */
  --carbon-mid:#3A3D42;      /* = --ink */
  --steel-blue:#4A7FB5;      /* = --amber */
  --accent-teal:#2f6f78;     /* NEW primary CTA color — replaces --orange going forward */
  --accent-teal-dark:#244f56;
  --accent-teal-soft:#d9eeed;
  --sky-blue:#8FD3F4;
  --whatsapp-green:#25D366;  /* = --whatsapp */
  --cream:#f3f0e8;
  --ink-on-cream:#202a2d;    /* spec calls this "--ink" but that name is already our body text color */
  --gold-accent:#e6a52f;

  /* Una sola familia para todo el sitio: la del propio dispositivo (Segoe UI
     en Windows, San Francisco en Apple, Roboto en Android). No se descarga
     ninguna fuente, así que el texto se pinta en el primer frame y no hay
     petición externa que pueda fallar o tardar. */
  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
@media (max-width:780px){ :root{ --header-h: 64px; } }

/* ============================================================
   Design-reference animation kit (pasted as given — class names
   kept exactly so future sections can wire straight into them).
   ============================================================ */
.announcement-marquee {
  overflow: hidden;
  white-space: nowrap;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
}
.announcement-track {
  display: flex;
  width: max-content;
  animation: announcement-scroll 14s linear infinite;
}
.announcement-group { display: flex; flex: 0 0 auto; align-items: center; gap: 1.5rem; padding-right: 1.5rem; }
@keyframes announcement-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }

.reveal { animation: reveal .7s cubic-bezier(.2,.75,.25,1) both; }
.reveal-delay-1 { animation-delay: .1s; }
.reveal-delay-2 { animation-delay: .2s; }
.reveal-delay-3 { animation-delay: .3s; }
@keyframes reveal { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }

.hero-arrow {
  position: absolute; top: 50%; z-index: 20; display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: 9999px; color: #fff;
  background: rgba(255,255,255,.14); backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,.22); transform: translateY(-50%);
  transition: transform .35s cubic-bezier(.34,1.56,.64,1), background .25s ease;
}
.hero-arrow:hover { background: rgba(255,255,255,.26); transform: translateY(-50%) scale(1.08); }

.hero-dot { position: relative; height: 6px; padding: 0; border: none; cursor: pointer; }
.hero-dot-fill { display: block; height: 100%; width: 100%; border-radius: 9999px; background: #8fd3f4; transform-origin: left; animation-name: hero-dot-fill; animation-timing-function: linear; animation-fill-mode: forwards; }
@keyframes hero-dot-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.wa-float {
  position: fixed; right: 22px; bottom: 22px; z-index: 80; display: flex; align-items: center;
  /* Centred so the collapsed pill reads as a circle - without it the icon sits
     against the left padding and looks off inside the 58px puck. */
  justify-content: center;
  height: 58px; min-width: 58px; padding: 0 15px; border-radius: 9999px;
  background: #25d366; color: #fff; box-shadow: 0 6px 20px rgba(37,211,102,.45);
  transition: transform .3s cubic-bezier(.34,1.56,.64,1);
}
.wa-float:hover { transform: translateY(-3px) scale(1.05); }
.wa-float-label { max-width: 0; overflow: hidden; white-space: nowrap; font-size: 13px; font-weight: 700; opacity: 0; transition: max-width .35s ease, opacity .25s ease, margin-left .35s ease; }
.wa-float:hover .wa-float-label { max-width: 140px; margin-left: 10px; opacity: 1; }
.wa-float-ring { position: absolute; inset: 0; border-radius: 9999px; border: 2px solid rgba(37,211,102,.7); animation: wa-pulse 2.4s ease-out infinite; pointer-events: none; }
@keyframes wa-pulse { 0% { transform: scale(1); opacity: .8; } 70% { transform: scale(1.45); opacity: 0; } 100% { transform: scale(1.45); opacity: 0; } }

/* Idle motion on the floating button. It has to earn a glance from someone who
   came to look at glasses, so it breathes and sends out a ring - the point is
   to invite the WhatsApp message, not to sit there waiting to be found.
   Both stop on hover: once the pointer is on it the button already has the
   attention it was asking for, and the lift/expand reads better without a
   pulse fighting it. The stop is `animation:none` rather than a paused state
   because a paused animation keeps its transform applied, which would win the
   cascade over the hover transform and cancel the lift. */
@keyframes wa-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
.wa-float { animation: wa-bob 3.4s ease-in-out infinite; }
.wa-float:hover { animation: none; }
.wa-float:hover .wa-float-ring { animation: none; opacity: 0; }
/* Both of these are continuous, unprompted motion in the corner of the eye -
   exactly what reduced motion is asking us to drop. Killed outright rather
   than sped up to .01ms like the marquee above: a transform pulse looping at
   that rate is a jitter, not a still frame. */
@media (prefers-reduced-motion: reduce) {
  .wa-float, .wa-float-ring { animation: none; }
  .wa-float-ring { opacity: 0; }
}

.product-image-wrap img { transition: transform .55s cubic-bezier(.2,.75,.25,1); }
.product-image-wrap:hover img { transform: scale(1.07); }
.product-card { transition: transform .3s ease, box-shadow .3s ease; }
.product-card:hover { transform: translateY(-4px); box-shadow: 0 18px 38px rgba(42,45,49,.11); }

@media (prefers-reduced-motion: reduce) {
  .announcement-track, .hero-dot-fill, .wa-float-ring { animation-duration: .01ms !important; }
}
*{box-sizing:border-box; margin:0; padding:0;}
html{scroll-behavior:smooth;}
body{
  font-family:var(--font-sans);
  color:var(--ink);
  background:var(--paper);
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,.display{
  font-family:var(--font-sans);
  text-transform:uppercase;
  letter-spacing:0.01em;
  line-height:1.05;
}
/* El nombre .mono se conserva porque lo usa el marcado de las 11 páginas.
   Ya no cambia la familia — lo que distingue a estas etiquetas es el
   interletrado y las mayúsculas. tabular-nums mantiene los dígitos
   alineados en columna, que era la razón práctica de usar monoespaciada. */
.mono{ letter-spacing:0.03em; font-variant-numeric:tabular-nums; }
a{color:inherit; text-decoration:none;}
img{max-width:100%; display:block;}
.wrap{max-width:1180px; margin:0 auto; padding:0 32px;}
@media (max-width:640px){ .wrap{padding:0 20px;} }

/* ---------- Hazard stripe divider (signature element) ---------- */
.hazard{
  height:14px;
  background: repeating-linear-gradient(
    45deg,
    var(--steel) 0px, var(--steel) 22px,
    var(--orange) 22px, var(--orange) 44px
  );
}

/* ---------- Announcement marquee ---------- */
.announcement-marquee{
  background:var(--carbon-dark); color:rgba(250,250,248,0.85);
  padding:9px 0;
}
.announcement-track{ align-items:center; }
.announcement-group span{
  font-family:var(--font-sans); font-size:11px;
  text-transform:uppercase; letter-spacing:0.08em;
}
.announcement-group span:nth-child(even){ color:var(--sky-blue); padding:0 2px; }

/* ---------- Header: transparent/blur over the hero-mode, light elsewhere ---------- */
/* Sits right below the marquee (absolute, not fixed) so it floats over the
   hero photo on load and then scrolls away with the page like any other
   element — it never sticks to the viewport while scrolling. */
header{
  background:var(--bg-light);
  color:var(--carbon-mid);
  position:absolute; top:var(--marquee-h); left:0; right:0; z-index:50;
  border-bottom:1px solid var(--line);
  transition:background 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}
header.is-transparent{
  /* Fully transparent over the hero: no tint, no blur, no divider. The slide
     runs edge to edge behind the nav, which is what keeps faces in the video
     readable instead of sitting behind a bar. Legibility is bought back with
     a text shadow on the links rather than a scrim — see the rules below. */
  background:transparent;
  color:#fff;
  border-bottom-color:transparent;
}
header.is-transparent .nav-links a{
  opacity:0.94;
  text-shadow:0 1px 3px rgba(0,0,0,0.6), 0 0 12px rgba(0,0,0,0.35);
}
header.is-transparent .icon-btn{
  opacity:0.94;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,0.6));
}
body{ position:relative; }
/* header is position:absolute (out of flow), so whatever follows it in the
   DOM needs its own clearance — except .hero-bleed, which *wants* the
   header to float transparently over its top edge. */
header + *{ margin-top:var(--header-h); }
header + .hero-bleed{ margin-top:0; }
.nav-top{
  display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:24px;
  padding:14px 32px; max-width:1180px; margin:0 auto;
}
.logo-mark{
  grid-column:1;
  display:flex; align-items:center; justify-content:flex-start;
}
.logo-mark span{ font-style:normal; color:var(--steel-blue); }
/* The lockup carries its own contrast, so it gets no halo — only a tight,
   offset shadow to keep its edge off the darker frames of the video. Blur
   radii stay at 1-2px on purpose: anything wider reads as a glow around the
   letters instead of an edge, which is exactly what we don't want here. */
.logo-img{
  height:60px; width:auto; display:block;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,0.28));
  transition:filter 0.3s ease;
}
header.is-transparent .logo-img{
  filter:drop-shadow(0 1px 2px rgba(0,0,0,0.65));
}
.nav-icons{
  grid-column:3;
  display:flex; gap:18px; justify-content:flex-end; align-items:center;
}
.icon-btn{
  position:relative;
  background:none; border:none; color:inherit; cursor:pointer;
  display:flex; align-items:center; opacity:0.75; transition:opacity .15s, transform .25s ease, color .15s ease;
}
.icon-btn:hover{ opacity:1; color:var(--accent-teal); transform:translateY(-1px); }
header.is-transparent .icon-btn:hover{ color:var(--sky-blue); }
#favorites-btn.is-active{ color:var(--accent-teal); opacity:1; }
#favorites-btn.is-active svg{ fill:currentColor; }
.cart-count{
  position:absolute; top:-6px; right:-8px;
  min-width:16px; height:16px; padding:0 3px; border-radius:999px;
  background:var(--accent-teal); color:#fff;
  font-family:var(--font-sans); font-size:10px; font-weight:600;
  display:flex; align-items:center; justify-content:center;
}
/* The markup ships this span with [hidden], but the display:flex above is a
   class selector and so beats the UA stylesheet's [hidden]{display:none} —
   which is why an empty cart still painted a "0". Toggle the badge with
   el.hidden and this rule keeps it honest. */
.cart-count[hidden]{ display:none; }
.nav-links{
  grid-column:2;
  display:flex; align-items:center; justify-content:center; gap:2px;
  font-family:var(--font-sans); font-size:13px; font-weight:600;
  text-transform:uppercase; letter-spacing:0.07em;
}
.nav-links a{
  position:relative; z-index:1;
  padding:8px 14px; border-radius:999px; white-space:nowrap;
  color:inherit; opacity:0.62;
  transition:opacity 0.3s ease, background 0.3s ease, transform 0.3s ease;
}
.nav-links a:hover{ opacity:1; background:rgba(58,61,66,0.06); transform:translateY(-1px); }
/* The frosted-glass pill. It sits here rather than on the whole header so the
   blur only ever appears under the link you're pointing at, instead of
   smearing the top of the hero. backdrop-filter needs something translucent
   above it to be visible, hence the white wash on top of the blur. */
header.is-transparent .nav-links a:hover{
  background:rgba(255,255,255,0.14);
  backdrop-filter:blur(10px) saturate(160%);
  -webkit-backdrop-filter:blur(10px) saturate(160%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,0.18);
}
/* Sat at the far right when the links had their own full-width row; inside
   the single-row header it just trails the other links in the centre group. */
.nav-links-end{ margin-left:0; }
/* Uppercase links need more room than the old sentence-case row, so the nav
   folds away a little earlier rather than wrapping onto two lines. */
@media (max-width:980px){
  .nav-links{ display:none; }
  .nav-top{ padding:12px 20px; gap:12px; }
  .logo-img{ height:40px; }
}

/* ---------- Mobile nav ---------- */
/* The burger is the counterpart to the rule above: it only exists in the
   breakpoint where .nav-links is gone, so the two can never both be on
   screen. */
.nav-burger{ display:none; }
@media (max-width:980px){
  .nav-burger{ display:flex; }
}
.mobile-nav{
  position:absolute; top:100%; left:0; right:0; z-index:60;
  background:var(--bg-light); color:var(--carbon-mid);
  border-bottom:1px solid var(--line);
  box-shadow:0 18px 40px rgba(0,0,0,0.18);
  padding:8px 20px 20px;
  /* Tall menus on short phones (landscape, or a small device) have to be able
     to scroll, or the WhatsApp CTA at the bottom is simply unreachable. */
  max-height:calc(100vh - var(--marquee-h) - var(--header-h));
  overflow-y:auto;
}
/* [hidden] alone loses to the display:flex/grid below, same trap as
   .cart-count — so it gets stated explicitly here too. */
.mobile-nav[hidden], .mobile-nav-scrim[hidden]{ display:none; }
.mobile-nav-links{ display:flex; flex-direction:column; }
.mobile-nav-links a{
  padding:15px 4px;
  border-bottom:1px solid var(--line);
  font-family:var(--font-sans); font-size:15px; font-weight:600;
  text-transform:uppercase; letter-spacing:0.07em;
  color:inherit;
}
.mobile-nav-links a:last-child{ border-bottom:none; }
.mobile-nav-foot{ display:flex; flex-direction:column; gap:12px; margin-top:18px; }
.mobile-nav-cta{
  display:flex; align-items:center; justify-content:center; gap:9px;
  padding:14px; border-radius:6px;
  background:var(--accent-teal); color:#fff;
  font-family:var(--font-sans); font-size:14px; font-weight:700;
  text-transform:uppercase; letter-spacing:0.06em;
}
.mobile-nav-phone{
  text-align:center; color:inherit; opacity:0.7;
  font-family:var(--font-sans); font-size:14px;
}
/* Dims the page behind the open menu. The z-index has to stay *below* the
   header's 50: the header is a positioned, z-indexed element and so opens its
   own stacking context, which the panel nested inside it can never escape —
   no matter how high its own z-index goes. A scrim above 50 therefore greys
   out the very panel it is meant to sit behind. */
.mobile-nav-scrim{
  position:fixed; inset:0; z-index:45;
  background:rgba(0,0,0,0.45);
}
/* While the menu is open the header stops being transparent even over the
   hero, otherwise the open panel hangs off an invisible bar. */
header.is-transparent.nav-open{
  background:var(--bg-light); color:var(--carbon-mid);
  border-bottom-color:var(--line);
}
header.is-transparent.nav-open .icon-btn{ opacity:0.75; filter:none; }
header.is-transparent.nav-open .logo-img{ filter:drop-shadow(0 1px 2px rgba(0,0,0,0.28)); }
/* Locks the page behind the open menu. overflow:hidden rather than
   position:fixed on purpose — fixed would collapse the body out of flow and
   jump the page back to the top the moment the menu opens. */
body.nav-locked{ overflow:hidden; }

/* ---------- Hero ---------- */
.eyebrow{
  font-family:var(--font-sans);
  font-size:12px; letter-spacing:0.12em; text-transform:uppercase;
  color:var(--amber); margin-bottom:18px;
  display:flex; align-items:center; gap:10px;
}
.eyebrow::before{content:""; width:22px; height:2px; background:var(--amber); display:inline-block;}
.hero-bleed-content h1{
  font-size:clamp(38px, 5.4vw, 62px);
  font-weight:700;
  margin-bottom:22px;
}
.hero-bleed-content p.lead{
  font-size:17px; max-width:460px; opacity:0.82; margin-bottom:32px;
}
.cta-row{display:flex; gap:14px; flex-wrap:wrap; align-items:center;}
/* Only in the hero, where the two-line WhatsApp button sits next to the
   single-line primary: stretch keeps both the same height instead of leaving
   the shorter one floating in the middle. Other .cta-row instances
   (success.html) stay centred. */
.hero-bleed-content .cta-row{ align-items:stretch; }
.btn{
  display:inline-flex; align-items:center; gap:10px;
  padding:15px 26px; font-size:14px; font-weight:600;
  text-transform:uppercase; letter-spacing:0.05em;
  border-radius:2px; border:1px solid transparent;
  cursor:pointer;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.35s ease,
    background 0.35s ease, border-color 0.35s ease, color 0.35s ease;
}
.btn:hover{ transform:translateY(-2px); }
.btn-amber{ background:var(--accent-teal); color:#fff; }
.btn-amber:hover{
  background:linear-gradient(120deg, var(--accent-teal), var(--accent-teal-dark));
  box-shadow:0 10px 24px rgba(47,111,120,0.4);
}
.btn-outline{ border-color:var(--line-light); color:var(--paper); }
.btn-outline:hover{
  border-color:transparent; color:#fff;
  background:linear-gradient(120deg, var(--accent-teal), var(--accent-teal-dark));
  box-shadow:0 10px 24px rgba(47,111,120,0.35);
}

/* ---------- WhatsApp CTA (two-line label) ---------- */
/* The label is a stack, so the uppercase/letter-spacing that .btn sets for a
   single line is cleared here and re-applied to the title only - left on the
   wrapper it would space out the subtitle into a caption. */
.btn-wa{
  gap:12px; padding:11px 22px;
  border-color:rgba(255,255,255,0.4); color:#fff;
  text-transform:none; letter-spacing:normal;
}
.btn-wa svg{ flex-shrink:0; }
.btn-wa-stack{ display:flex; flex-direction:column; align-items:flex-start; line-height:1.25; }
.btn-wa-title{ font-size:14px; font-weight:700; text-transform:uppercase; letter-spacing:0.05em; }
.btn-wa-sub{ font-size:12px; font-weight:400; opacity:0.78; }
/* Hover reads as "this is the WhatsApp one" instead of the generic teal fill
   every other outline button gets. The wash stays translucent on purpose: the
   photo keeps showing through, which is what stops it looking like a solid
   green block dropped onto the hero. Beats .btn-outline:hover on specificity
   (0,3,0 vs 0,2,0), so the teal gradient never applies here. */
.btn-outline.btn-wa:hover{
  border-color:var(--whatsapp);
  background:rgba(37,211,102,0.14);
  box-shadow:0 0 0 1px rgba(37,211,102,0.35), 0 10px 26px rgba(37,211,102,0.22);
  color:#fff;
}
.btn-outline.btn-wa:hover .btn-wa-sub{ opacity:0.92; }
.btn-sky{ background:var(--sky-blue); color:var(--carbon-dark); }
.btn-sky:hover{
  background:linear-gradient(120deg, var(--sky-blue), #6bc2ec);
  box-shadow:0 10px 24px rgba(143,211,244,0.45);
}
.btn-whatsapp{ background:var(--whatsapp); color:#fff; }
.btn-whatsapp:hover{
  background:linear-gradient(120deg, var(--whatsapp), #1ebe57);
  box-shadow:0 10px 24px rgba(37,211,102,0.4);
}
.btn-steel{ background:var(--steel); color:var(--paper); }
.btn-steel:hover{
  background:linear-gradient(120deg, var(--steel-2), var(--amber-dark));
  box-shadow:0 10px 24px rgba(74,127,181,0.3);
}

/* hero visual: spec-plate style glasses illustration */
.spec-plate{
  background:var(--steel-2);
  border:1px solid var(--line-light);
  padding:28px;
  position:relative;
}
.spec-plate::before{
  content:""; position:absolute; top:10px; left:10px; width:8px; height:8px;
  background:var(--amber); border-radius:50%;
}
.spec-plate::after{
  content:""; position:absolute; top:10px; right:10px; width:8px; height:8px;
  background:var(--amber); border-radius:50%;
}
.spec-plate svg{width:100%; height:auto; margin-bottom:18px;}
.spec-row{
  display:flex; justify-content:space-between; gap:8px 16px;
  font-family:var(--font-sans); font-size:12px;
  padding:10px 0; border-top:1px solid var(--line-light);
  text-transform:uppercase; letter-spacing:0.04em;
}
.spec-row span:first-child{opacity:0.55;}
.spec-row span:last-child{color:var(--amber); text-align:right;}
@media (max-width:460px){
  .spec-row{ flex-direction:column; gap:4px; }
  .spec-row span:last-child{ text-align:left; }
}

/* ---------- Trust bar ---------- */
.trustbar{
  background:var(--paper);
  border-bottom:1px solid var(--line);
  padding:22px 0;
}
.trustbar .wrap{
  display:flex; justify-content:space-between; flex-wrap:wrap; gap:18px;
}
.trust-item{
  display:flex; align-items:center; gap:10px;
  font-family:var(--font-sans); font-size:12px;
  text-transform:uppercase; letter-spacing:0.05em;
}
.trust-item .num{ color:var(--amber); font-weight:600; }

.hero-bleed{
  position:relative;
  /* Live pan offset written by js/carousels.js on mousemove. Declared here so
     the slides have something to read before the pointer has ever entered. */
  --hero-pan-x:0px; --hero-pan-y:0px;
  min-height:640px;
  padding-top:var(--header-h);
  display:flex; align-items:center;
  overflow:hidden;
  background:var(--steel);
}
.hero-bleed-img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover; object-position: 68% center;
  opacity:0;
  transition:opacity 1.2s ease, transform 0.7s cubic-bezier(0.25, 0.1, 0.25, 1);
  /* Dark ground so a <video> slide that hasn't decoded its first frame yet
     fades in from the hero's own darkness instead of a white flash. */
  background:#0d0d0d;
}
/* Video slides are decorative and muted — never let controls or the iOS
   play overlay show through. */
video.hero-bleed-img::-webkit-media-controls{ display:none !important; }
video.hero-bleed-img::-webkit-media-controls-start-playback-button{ display:none !important; }

.hero-bleed-img.is-active{ opacity:1; z-index:1; }
/* Cursor parallax. The headroom comes from oversizing the slide box by a fixed
   14px on every side rather than from a percentage scale. That distinction
   matters: scale(1.06) magnified the photograph by 6% at every viewport width,
   and with object-fit:cover already upscaling these files well past 1:1, those
   six points were pure extra zoom. 24px covers the +/-18px and +/-9px the pan
   can ask for with margin to spare, and still costs under 3% of magnification
   on a desktop hero - the wider the screen, the smaller the penalty, where the
   old scale got worse. Raise this whenever PAN_X grows: the oversize is the
   hard ceiling on the pan, and going past it exposes a bare edge. The size is written out rather than left to the insets:
   on a replaced element like <img> or <video>, width:auto resolves to the
   file's own intrinsic pixel size instead of stretching between left and
   right, which silently shrinks the slide down to the photo's dimensions.
   The class is added by js/carousels.js only when parallax actually runs
   (real pointer, motion allowed) - on touch and under reduced motion the
   framing stays exactly as it was tuned, with no oversize at all. Applies to
   <video> slides as well as photos: both are .hero-bleed-img. */
.hero-bleed.is-parallax .hero-bleed-img{
  inset:-24px; width:calc(100% + 48px); height:calc(100% + 48px);
  /* The global `img{max-width:100%}` reset would clamp that width straight
     back to the hero's, leaving zero horizontal headroom and exposing a bare
     edge on every pan. */
  max-width:none;
  transform:translate3d(var(--hero-pan-x), var(--hero-pan-y), 0);
}
.hero-dots{
  position:absolute; z-index:3; right:32px; bottom:26px;
  display:flex; gap:8px;
}
.hero-dot{ width:30px; background:rgba(255,255,255,0.3); border-radius:999px; cursor:pointer; }
.hero-dot-fill{ transform:scaleX(0); animation-play-state:paused; }
.hero-dot.is-active .hero-dot-fill{ animation-play-state:running; }
.hero-arrow-prev{ left:20px; }
.hero-arrow-next{ right:20px; }
@media (max-width:700px){
  .hero-arrow{ display:none; }
  .hero-dots{ right:20px; bottom:18px; }
}
.hero-bleed-scrim{
  /* Must sit above .hero-bleed-img.is-active (z-index:1) — without this the
     scrim paints *behind* the slides and does nothing at all. */
  position:absolute; inset:0; z-index:2;
  /* Pulled back from 0.88/0.62/0.18 so the photograph reads at close to its
     real brightness. The dark end is still anchored on the left, where the
     copy sits, but it now falls off to nothing by 68% instead of dragging a
     film across the whole frame. The legibility this gives up is bought back
     with type shadows below, which cost the image nothing. */
  background: linear-gradient(90deg,
    rgba(20,22,24,0.78) 0%,
    rgba(20,22,24,0.48) 30%,
    rgba(20,22,24,0.10) 54%,
    rgba(20,22,24,0) 68%);
}
/* The clips are far brighter than the photo slides (open sun, pale grass), so
   the hero copy loses contrast over them. Boost the scrim only while a video
   is up — the photos stay exactly as tuned. Opacity is used rather than
   swapping the gradient because gradients don't transition. */
.hero-bleed-scrim::after{
  content:''; position:absolute; inset:0;
  opacity:0; transition:opacity 1.2s ease;
  background: linear-gradient(90deg,
    rgba(20,22,24,0.32) 0%,
    rgba(20,22,24,0.24) 45%,
    rgba(20,22,24,0.14) 70%,
    rgba(20,22,24,0.05) 100%);
}
.hero-bleed.is-video-slide .hero-bleed-scrim::after{ opacity:1; }
.hero-bleed-content{
  position:relative; z-index:3;
  /* .hero-bleed is display:flex, so this is a flex item and would otherwise be
     shrink-to-fit - at which point .wrap's `margin:0 auto` centres the copy in
     the hero instead of anchoring it. That is width-dependent and easy to miss:
     on a narrow window the block is nearly as wide as the hero and looks
     left-aligned, but past ~1200px it drifts to the middle, straight onto the
     bright part of the photo where the scrim has already faded out. Filling the
     line first lets .wrap's max-width do the centring, with the text flush left
     inside the same 1180px column every other section uses. */
  width:100%;
  padding:80px 32px;
}
/* Contrast now comes from the type instead of from a heavier wash over the
   photograph: a shadow costs nothing on the image, a darker scrim costs the
   whole left half of it. .eyebrow is scoped to the hero on purpose - the same
   class is used on light sections further down the page. */
.hero-bleed-content h1,
.hero-bleed-content p.lead,
.hero-bleed-content .eyebrow,
.hero-trust,
.hero-price,
.hero-badges span{
  text-shadow:0 1px 2px rgba(12,14,16,0.55), 0 2px 16px rgba(12,14,16,0.35);
}
.hero-trust{
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  color:rgba(255,255,255,0.75); font-size:13px; margin-bottom:14px;
}
.hero-trust svg{ flex-shrink:0; color:var(--sky-blue); }
.hero-trust-dot{ opacity:0.5; }
.hero-price{
  font-family:var(--font-sans); font-size:13px;
  color:rgba(255,255,255,0.85); margin-bottom:26px;
}
.hero-price strong{ color:var(--sky-blue); font-size:15px; }
.hero-badges{
  display:flex; flex-wrap:wrap; gap:10px 18px; margin-top:28px;
}
.hero-badges span{
  font-family:var(--font-sans); font-size:11px; text-transform:uppercase;
  letter-spacing:0.06em; color:rgba(255,255,255,0.7);
  padding-left:14px; position:relative;
}
.hero-badges span::before{
  content:""; position:absolute; left:0; top:50%; transform:translateY(-50%);
  width:5px; height:5px; border-radius:50%; background:var(--accent-teal);
}
@media (max-width:700px){
  .hero-bleed{ min-height:560px; }
  .hero-bleed-scrim{ background: linear-gradient(180deg, rgba(20,22,24,0.55) 0%, rgba(20,22,24,0.92) 65%, rgba(20,22,24,0.96) 100%); }
  /* The mobile scrim is already heavy where the copy sits, so the video boost
     would only crush the footage at the top. Base gradient is enough here. */
  .hero-bleed.is-video-slide .hero-bleed-scrim::after{ opacity:0; }
  .hero-bleed-content{ padding:32px 20px 48px; align-self:flex-end; }
}

/* ---------- Section basics ---------- */
section{padding:84px 0;}
.section-head{ max-width:640px; margin-bottom:48px; }
.section-tag{
  font-family:var(--font-sans); font-size:12px;
  color:var(--amber-dark); text-transform:uppercase; letter-spacing:0.12em;
  margin-bottom:12px; display:block;
}
.section-head h2{ font-size:clamp(28px,3.4vw,40px); }
.section-head p{ margin-top:14px; opacity:0.72; font-size:16px; max-width:520px; }

/* ---------- About section ---------- */
.about-grid{ display:grid; grid-template-columns:1fr 1fr; gap:56px; align-items:center; }
@media (max-width:780px){ .about-grid{ grid-template-columns:1fr; gap:32px; } }

/* ---------- Product grid ---------- */
.products{
  display:grid; grid-template-columns:repeat(3,1fr); gap:2px;
  background:var(--line);
  border:1px solid var(--line);
}
@media (max-width:820px){ .products{grid-template-columns:1fr 1fr;} }
@media (max-width:560px){ .products{grid-template-columns:1fr;} }
.product-card{
  background:var(--paper);
  padding:30px 26px;
  display:flex; flex-direction:column; gap:14px;
}
.product-card{ perspective:800px; }
.product-card .icon-wrap{
  width:100%; aspect-ratio:4/3;
  background:#F1F1EC; border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center;
  position:relative;
  overflow:hidden;
  cursor:pointer;
  transform-style:preserve-3d;
  transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;
}
.product-card .icon-wrap svg{
  width:58%;
  pointer-events:none;
}
.product-card .icon-wrap .product-photo{
  width:86%; height:82%;
  object-fit:contain;
  pointer-events:none;
}
/* Cursor-tracked glare — position set via --mx/--my custom properties by js/tilt.js */
.product-card .icon-wrap::after{
  content:"";
  position:absolute; inset:0;
  background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), rgba(74,127,181,0.22), rgba(74,127,181,0) 55%);
  opacity:0; transition: opacity 0.2s ease;
  pointer-events:none;
}
.product-card .icon-wrap.is-tilting::after{ opacity:1; }
.tint-swatches{ display:flex; gap:8px; }
.tint-swatch{
  width:18px; height:18px; border-radius:50%; cursor:pointer;
  border:2px solid var(--line); padding:0;
  transition:transform 0.2s ease, border-color 0.2s ease;
}
.tint-swatch:hover{ transform:scale(1.15); }
.tint-swatch.is-active{ border-color:var(--amber); }
.tint-swatch.tint-clear{ background:linear-gradient(135deg, #fff, #d8dee6); }
.tint-swatch.tint-amber{ background:#C98A3E; }
.tint-swatch.tint-smoke{ background:#3A3D42; }
.product-card{ transition: transform 0.35s ease, box-shadow 0.35s ease; }
.product-card:hover{ transform: translateY(-4px); box-shadow: 0 14px 30px rgba(12,15,18,0.10); }
.product-card .price{
  font-family:var(--font-sans); color:var(--amber-dark); font-weight:600;
}
.product-card h3{ font-size:19px; }
.product-card p{ font-size:14px; opacity:0.7; }
.product-card .btn{ align-self:flex-start; padding:10px 18px; font-size:12px; margin-top:4px;
  background:var(--steel); color:var(--paper); }
.product-card .btn:hover{
  background:linear-gradient(120deg, var(--amber), var(--amber-dark)); color:#fff;
  box-shadow:0 10px 24px rgba(74,127,181,0.35);
}

/* ---------- "A better process" — photo left, numbered rail right ----------
   Second pass on this section: it was a four-across ruled row, now it is a
   two-column split with the steps stacked on a connecting rail. */
.process{ background:var(--bg-light); color:var(--ink-on-cream); padding:100px 0 108px; }
.process .section-tag{ color:var(--steel-blue); }

.process-grid{
  display:grid; grid-template-columns:1fr 1.06fr; gap:62px; align-items:center;
}
.process-shot{ margin:0; overflow:hidden; border-radius:14px; }
.process-shot img{
  width:100%; height:100%; aspect-ratio:1; object-fit:cover; display:block;
}

/* Sentence case, escaping the global uppercase on h1,h2,h3 — same editorial
   treatment as .lineup-title and the craft heading. */
.process-title{
  text-transform:none; margin-top:13px;
  font-size:clamp(26px, 2.9vw, 38px);
  line-height:1.14; letter-spacing:-0.01em;
}
.process-title em{ font-style:italic; }
.process-lead{ margin-top:13px; font-size:15.5px; line-height:1.6; opacity:0.7; }

.process-steps{ list-style:none; margin-top:32px; }
.process-step{
  position:relative;
  display:grid; grid-template-columns:auto 1fr; gap:17px;
  padding-bottom:24px;
}
.process-step:last-child{ padding-bottom:0; }
.process-num{
  position:relative; z-index:1;
  width:34px; height:34px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  border:1px solid var(--steel-blue); background:var(--bg-light);
  color:var(--steel-blue); font-size:12px; font-weight:600;
}
/* The rail joining one circle to the next. It sits behind the circles, which
   carry an opaque background so the line stops cleanly at their edge. */
.process-step:not(:last-child)::before{
  content:''; position:absolute; left:17px; top:34px; bottom:0;
  width:1px; background:rgba(74,127,181,0.4);
}
.process-step h3{ text-transform:none; font-size:17px; line-height:1.3; margin-bottom:5px; }
.process-step p{ font-size:14px; line-height:1.55; opacity:0.66; }

.process-actions{
  display:flex; align-items:center; gap:26px; flex-wrap:wrap; margin-top:32px;
}
/* .btn is uppercase by default; the reference sets this one in sentence case. */
.process-cta{
  background:var(--steel-blue); color:#fff;
  text-transform:none; letter-spacing:0; font-size:15px;
}
.process-cta:hover{ background:var(--amber-dark); }
.process-link{
  font-size:14px; color:var(--steel-blue);
  text-decoration:underline; text-underline-offset:3px;
}

@media (max-width:900px){
  .process{ padding:72px 0 78px; }
  .process-grid{ grid-template-columns:1fr; gap:34px; }
  /* Square at full width would eat the whole screen, so the photo takes a
     letterbox crop once the columns stack. */
  .process-shot img{ aspect-ratio:16/10; }
}

@media (max-width:520px){
  .process-actions{ gap:18px; }
  .process-cta{ width:100%; justify-content:center; }
}

/* ---------- "Nothing precious about it" — process steps with photos ---------- */
.craft{ background:var(--cream); color:var(--ink-on-cream); }

/* The heading opts out of the global uppercase on h1/h2/h3: this section is
   set in sentence case, with the second line italic and dropped in contrast so
   the two lines read as one phrase rather than two headings. */
.craft-title{
  text-transform:none;
  font-size:clamp(38px, 5vw, 66px);
  line-height:1.02;
  letter-spacing:-0.01em;
  margin-bottom:56px;
}
.craft-title em{
  font-style:italic;
  color:var(--ink-on-cream); opacity:0.45;
}

.craft-steps{ display:grid; grid-template-columns:repeat(3,1fr); gap:40px; align-items:start; }
/* Editorial staircase: each column starts lower than the one before it, so the
   row reads as a composition instead of a plain grid. Dropped below 900px,
   where the columns reflow and the offset would just look like broken spacing. */
.craft-steps > .craft-step:nth-child(2){ margin-top:56px; }
.craft-steps > .craft-step:nth-child(3){ margin-top:112px; }

.craft-shot{
  position:relative;
  overflow:hidden;
  aspect-ratio:4/5; background:var(--carbon-dark);
}
.craft-shot img{ width:100%; height:100%; object-fit:cover; }

/* Number and title share a baseline row under the photo. */
.craft-step-head{
  display:flex; align-items:baseline; gap:14px;
  margin-top:22px; padding-bottom:14px;
  border-bottom:1px solid rgba(32,42,45,0.16);
}
.craft-num{
  font-size:15px; font-weight:600; letter-spacing:0.04em;
  color:var(--steel-blue); flex-shrink:0;
}
.craft-step h3{
  text-transform:none;
  font-size:21px; font-weight:600; letter-spacing:0;
}
.craft-step p{
  margin-top:14px;
  font-size:15px; line-height:1.65; opacity:0.72;
}

/* ---------- Hover: 3D tilt ---------- */
/* The card leans away from the cursor, like a photograph held in the hand and
   angled to catch the light. The two angles arrive from js/craft-tilt.js as
   custom properties; everything else here is CSS.

   perspective() is a transform function on the card rather than a `perspective`
   property on .craft-steps, and the difference is visible: a perspective on the
   grid gives all three cards one shared vanishing point at the centre of the
   row, so the outer two keystone away from it instead of each turning about its
   own centre. As a function, every card gets its own vanishing point.

   Sign conventions were measured, not assumed: rotateX(+) sends the TOP edge
   away from the viewer and rotateY(+) sends the RIGHT edge away, so the corner
   under the cursor is the one that recedes - which is the ask. */
.craft-step{
  --tilt-x:0deg; --tilt-y:0deg; --tilt-lift:0px;
  transform-style:preserve-3d;
  transform:perspective(1000px)
            translateY(var(--tilt-lift))
            rotateX(var(--tilt-x))
            rotateY(var(--tilt-y));
  transition:transform 0.45s cubic-bezier(.2,.75,.25,1);
}
.craft-step:hover{ --tilt-lift:-10px; }
/* While the pointer is inside the card the transition drops to a hair, so the
   card tracks the cursor instead of trailing it - 450ms of easing applied to
   every mousemove feels like dragging it through syrup. The class comes off on
   mouseleave, which hands the trip back to centre to the long transition. */
.craft-step.is-tilting{
  transition:transform 0.12s ease-out;
  will-change:transform;
}

/* Small and tight at rest, large and soft on hover. This carries most of the
   "lifting off the page" read - more than the 10px of travel does. */
.craft-shot{
  box-shadow:0 2px 8px rgba(42,45,49,0.10);
  transition:box-shadow 0.45s cubic-bezier(.2,.75,.25,1);
}
.craft-step:hover .craft-shot{ box-shadow:0 22px 44px rgba(42,45,49,0.22); }

.craft-shot img{ transition:transform 0.5s cubic-bezier(.2,.75,.25,1); }
.craft-step:hover .craft-shot img{ transform:scale(1.04); }

/* js/craft-tilt.js already bails out under reduced motion, so the angles stay
   at 0; this drops the travel that is pure CSS. */
@media (prefers-reduced-motion: reduce){
  .craft-step, .craft-shot, .craft-shot img{ transition:none; }
  .craft-step{ transform:none; }
  .craft-step:hover .craft-shot img{ transform:none; }
}


@media (max-width:900px){
  .craft-steps{ grid-template-columns:1fr 1fr; gap:32px; }
  .craft-steps > .craft-step:nth-child(2),
  .craft-steps > .craft-step:nth-child(3){ margin-top:0; }
  .craft-steps > .craft-step:last-child{ grid-column:1 / -1; max-width:calc(50% - 16px); }
}
@media (max-width:640px){
  .craft-steps{ grid-template-columns:1fr; gap:40px; }
  .craft-steps > .craft-step:last-child{ max-width:none; }
  .craft-title{ margin-bottom:40px; }
}

/* ---------- "The Lineup" — cinematic catalog ---------- */
/* The whole effect is one idea: whichever card you're engaging with grows and
   sharpens, and the other two retreat (smaller, dimmer, desaturated). The
   active card is set by JS (hover, focus, or a click that pins it). */
/* The section used to be a dark carbon cut between the two light sections
   around it. It is light now, on a faint drafting grid - the cards carry the
   contrast themselves rather than borrowing it from the ground. */
.lineup{
  background-color:var(--bg-light); color:var(--ink-on-cream);
  background-image:
    linear-gradient(to right, rgba(32,42,45,0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(32,42,45,0.05) 1px, transparent 1px);
  background-size:64px 64px;
}
.lineup .section-tag{ color:var(--steel-blue); }

/* Masthead: two-line title on the left, catalogue link on the right, one rule
   under both. Same sentence-case treatment as the craft section, so the two
   editorial headings on the page match. */
.lineup-masthead{
  display:flex; align-items:center; justify-content:space-between; gap:40px;
  padding-bottom:30px; margin-bottom:54px;
  border-bottom:1px solid rgba(32,42,45,0.16);
}
.lineup-title{
  text-transform:none;
  font-size:clamp(34px, 4.2vw, 54px);
  line-height:1.04; letter-spacing:-0.01em;
}
.lineup-title em{ font-style:italic; opacity:0.45; }
.lineup-all{
  flex-shrink:0;
  border-color:rgba(32,42,45,0.34); color:var(--ink-on-cream);
}
.lineup-all:hover{
  background:var(--ink-on-cream); color:var(--bg-light);
  border-color:var(--ink-on-cream);
}
@media (max-width:760px){
  .lineup-masthead{
    flex-direction:column; align-items:flex-start; gap:24px;
    margin-bottom:38px;
  }
}
.btn-teal{ background:var(--accent-teal); color:#fff; }
.btn-teal:hover{ background:var(--accent-teal-dark); }

.lineup-track{
  display:grid; grid-template-columns:repeat(3,1fr); gap:26px;
  align-items:start;
}
/* Editorial offset — the middle card hangs lower so the row doesn't read as
   a plain grid. Dropped on mobile, where the cards become a carousel. */
.lineup-track > .lineup-card:nth-child(2){ margin-top:48px; }

.lineup-card{
  position:relative; z-index:1;
  background:var(--cream); color:var(--ink-on-cream);
  /* On the old dark ground the cards separated themselves. On a light one
     they need an edge, or they dissolve into the section. */
  border:1px solid rgba(32,42,45,0.10);
  padding:22px 22px 26px;
  display:flex; flex-direction:column; gap:13px;
  outline:none;
  transition:
    transform 700ms cubic-bezier(0.23, 1, 0.32, 1),
    opacity   700ms cubic-bezier(0.23, 1, 0.32, 1),
    filter    700ms cubic-bezier(0.23, 1, 0.32, 1),
    box-shadow 700ms cubic-bezier(0.23, 1, 0.32, 1);
}
.lineup.has-active .lineup-card.is-active{
  transform:scale(1.04) translateY(-3px);
  z-index:5;
  /* Was 0.45 black, which was calibrated against a carbon background and
     reads as a bruise on a light one. */
  box-shadow:0 30px 60px rgba(32,42,45,0.18);
}
.lineup.has-active .lineup-card:not(.is-active){
  transform:scale(0.96) translateY(2px);
  opacity:0.8;
  filter:grayscale(0.3);
}
/* Keyboard users get a visible ring; mouse users get the scale instead. */
.lineup-card:focus-visible{ box-shadow:0 0 0 3px var(--sky-blue); }

.lineup-head{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
}
.lineup-index{
  font-size:11px; text-transform:uppercase; letter-spacing:0.12em;
  color:var(--steel-blue); font-weight:600;
}
.lineup-slash{ opacity:0.45; }
.lineup-badge{
  font-size:10px; text-transform:uppercase; letter-spacing:0.08em;
  padding:4px 9px; border:1px solid rgba(32,42,45,0.22);
  color:var(--ink-on-cream); opacity:0.7; white-space:nowrap;
}

.lineup-shot{
  width:100%; aspect-ratio:4/3; overflow:hidden;
  background:#fff; border:1px solid rgba(32,42,45,0.10);
  display:flex; align-items:center; justify-content:center;
}
.lineup-shot .product-photo{
  width:86%; height:82%; object-fit:contain;
  transition:transform 1000ms cubic-bezier(0.23, 1, 0.32, 1);
}
.lineup-card.is-active .lineup-shot .product-photo{ transform:scale(1.05); }

/* Sentence case, out of the global uppercase on h1/h2/h3 - product names
   read as names here, not as labels. */
.lineup-card h3{ text-transform:none; font-size:23px; margin-top:2px; }
.lineup-card p{ font-size:14px; line-height:1.6; opacity:0.72; }
.lineup-card .price{ font-size:19px; font-weight:600; color:var(--accent-teal); }

.lineup-actions{
  display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-top:4px;
}
.lineup-worn{
  background:none; border:none; padding:0; cursor:pointer;
  font-family:var(--font-sans); font-size:12px;
  text-transform:uppercase; letter-spacing:0.06em;
  color:var(--ink-on-cream); opacity:0.68;
  border-bottom:1px solid currentColor; line-height:1.5;
  transition:opacity 0.25s ease, color 0.25s ease;
}
.lineup-worn:hover{ opacity:1; color:var(--accent-teal); }

/* Mobile: the row becomes a snap carousel. The scale/dim choreography is
   dropped — there is no hover on touch, so it would only ever misfire. */
@media (max-width:780px){
  .lineup-track{
    display:flex; gap:14px;
    overflow-x:auto; scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;
    padding-bottom:8px;
    /* bleed to the screen edges so a card can sit centred */
    margin-inline:-20px; padding-inline:20px;
    scrollbar-width:none;
  }
  .lineup-track::-webkit-scrollbar{ display:none; }
  /* 85% of the *screen*, not of the track's content box — the track carries
     20px of side padding, so a plain 85% would land nearer 76%. */
  .lineup-track > .lineup-card{ flex:0 0 85vw; scroll-snap-align:center; }
  .lineup-track > .lineup-card:nth-child(2){ margin-top:0; }
  .lineup.has-active .lineup-card.is-active,
  .lineup.has-active .lineup-card:not(.is-active){
    transform:none; opacity:1; filter:none; box-shadow:none;
  }
  .lineup-card.is-active .lineup-shot .product-photo{ transform:none; }
}

@media (prefers-reduced-motion: reduce){
  .lineup-card,
  .lineup-shot .product-photo{ transition-duration:0.01ms; }
  .lineup.has-active .lineup-card.is-active,
  .lineup.has-active .lineup-card:not(.is-active){
    transform:none; filter:none;
  }
  .lineup-card.is-active .lineup-shot .product-photo{ transform:none; }
}

/* ---------- "See it worn" dialog ---------- */
/* Two columns: the lifestyle photo carries the left, the detail panel the
   right. display:grid is scoped to [open] on purpose — a <dialog> switches
   between display:none and display:block itself, so setting display on the
   bare element would leave it permanently visible. */
.worn-modal{
  border:none; padding:0; overflow:hidden;
  max-width:860px; width:calc(100% - 40px);
  /* The global `*{margin:0}` reset at the top of this file wipes out the UA
     stylesheet's `dialog{margin:auto}` — the only thing that centres a modal
     <dialog> inside its inset:0 box. Without this line the modal pins itself
     to the top-left corner of the viewport. Do not remove it. */
  margin:auto;
  max-height:calc(100vh - 64px);
  background:var(--bg-light); color:var(--ink-on-cream);
  box-shadow:0 40px 90px rgba(0,0,0,0.5);
}
/* minmax(0,1fr), not 1fr: an auto-sized row grows to fit the panel's content
   and the dialog then clips whatever sticks out past its max-height — which
   is the buy button. Pinning the row to the dialog's height, with a 0 floor
   so it may shrink below its content, is what lets .worn-body actually
   scroll instead of overflowing. */
.worn-modal[open]{ display:grid; grid-template-columns:1.05fr 1fr; grid-template-rows:minmax(0,1fr); }
.worn-modal::backdrop{
  background:rgba(20,22,24,0.5);
  backdrop-filter:blur(7px);
}

.worn-figure{
  position:relative; margin:0; overflow:hidden;
  background:var(--carbon-dark);
  /* The grid row is sized by the panel on the right; the photo just fills
     whatever height that comes to. */
  min-height:100%;
}
/* Direct child only — the inset cut-out below sizes itself. */
.worn-figure > img{ width:100%; height:100%; object-fit:cover; display:block; }

/* Standing in for a missing worn shot, the main image is the studio cut-out:
   a wide frame on white. Two things have to change for it.

   It must be contained, not cropped — cropping would slice the frame in
   half — and it needs a white ground rather than the carbon one the
   lifestyle shots want.

   And the modal has to stack. The cut-out is roughly 2.3:1 while the left
   column is 0.86:1, so contained in that column the frame renders 388x168
   inside 440x511 and floats in ~340px of empty white. Stacked, the image
   gets a band shaped like itself. Worn photos are portrait-ish and fill the
   two-column layout properly, so none of this applies once they exist. */
.worn-modal.is-product-shot[open]{
  max-width:540px;
  grid-template-columns:1fr;
  grid-template-rows:auto auto;
}
/* Two stacked rows can outgrow max-height, and as in the mobile layout what
   overflows is the grid — so the dialog itself has to scroll. */
.worn-modal.is-product-shot{ overflow-y:auto; }
.worn-modal.is-product-shot .worn-body{ overflow-y:visible; }
.worn-modal.is-product-shot .worn-figure{
  /* 2.25, not the image's own 2.32: it buys back enough height that the
     stacked modal clears an 800px-tall viewport without tripping a
     scrollbar over a 1px rounding overflow. */
  aspect-ratio:2.25; min-height:0; background:#fff;
  border-bottom:1px solid rgba(32,42,45,0.1);
}
.worn-modal.is-product-shot .worn-figure > img{ object-fit:contain; padding:22px 26px; }

.worn-inset{
  position:absolute; left:16px; bottom:16px; z-index:1;
  width:42%; max-width:168px;
  background:#fff; padding:9px;
  box-shadow:0 10px 26px rgba(0,0,0,0.3);
}
.worn-inset[hidden]{ display:none; }
.worn-inset img{ width:100%; height:auto; display:block; }
.worn-tag{
  position:absolute; top:18px; left:18px; z-index:1;
  background:rgba(20,22,24,0.72); color:#fff;
  font-size:10px; text-transform:uppercase; letter-spacing:0.1em;
  padding:6px 11px;
}

.worn-body{
  position:relative;
  padding:34px 34px 36px;
  display:flex; flex-direction:column; align-items:flex-start;
  /* The dialog is capped at the viewport height and clips its overflow, so
     the panel — not the photo — is what scrolls when the copy runs long. */
  overflow-y:auto;
}
.worn-eyebrow{
  font-size:11px; text-transform:uppercase; letter-spacing:0.12em;
  color:var(--steel-blue); margin-bottom:12px;
}
/* Sentence case: the product name is a name here, not a label. */
.worn-body h3{ text-transform:none; font-size:29px; line-height:1.1; }
.worn-desc{
  margin-top:14px; font-size:15px; line-height:1.6; opacity:0.72;
}

.worn-specs{
  display:flex; align-items:flex-start; gap:12px;
  width:100%; margin-top:26px; padding:16px 18px;
  border:1px solid rgba(32,42,45,0.14); background:rgba(32,42,45,0.025);
}
.worn-specs-icon{ color:var(--steel-blue); flex-shrink:0; margin-top:1px; }
.worn-specs-label{
  display:block; font-size:10px; text-transform:uppercase; letter-spacing:0.1em;
  opacity:0.6; margin-bottom:5px;
}
.worn-specs p{ font-size:14.5px; line-height:1.5; }

.worn-body .price{
  /* Sits above its own rule rather than beside the copy, which is what gives
     the panel its "receipt" beat before the action. */
  width:100%; margin-top:26px; padding-top:24px;
  border-top:1px solid rgba(32,42,45,0.16);
  font-size:27px; font-weight:600; color:var(--ink-on-cream);
}
.worn-buy{
  width:100%; margin-top:20px; justify-content:center;
  background:var(--carbon-dark); color:var(--bg-light);
  padding:17px 26px;
}
.worn-buy:hover{ background:#1c1f22; }

.worn-close{
  position:absolute; top:20px; right:20px; z-index:2;
  width:32px; height:32px; padding:0; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  border:none; background:none; color:var(--ink-on-cream); opacity:0.5;
  transition:opacity 0.2s ease;
}
.worn-close:hover{ opacity:1; }

@media (max-width:720px){
  /* Back to two content-sized rows — the dialog scrolls as a whole here, so
     the desktop row cap would only squash the photo. */
  .worn-modal[open]{ grid-template-columns:1fr; grid-template-rows:auto auto; }
  .worn-figure{ aspect-ratio:3/2; min-height:0; }
  .worn-body{ padding:26px 24px 30px; }
  .worn-body h3{ font-size:26px; }

  /* Stacked, the photo's fixed 3:2 block plus the panel can outgrow the
     dialog's max-height. Here the dialog itself has to be the scroller: what
     overflows is the grid, not the panel, so the panel's own overflow-y can
     do nothing and the buy button just gets clipped away. */
  .worn-modal{ overflow-y:auto; }
  .worn-body{ overflow-y:visible; }
}

/* ---------- Closing CTA band ----------
   Was a centred orange block (--orange, the pre-redesign token) with the copy
   stacked over a dark button. Now a pale blue band with the heading on the
   left and the actions on the right. The two blues below are the reference's
   own tints of --steel-blue; they are scoped here rather than added to :root
   because nothing else uses them yet. */
.cta-banner{
  background:#e9f2fa; color:var(--ink-on-cream);
  padding:58px 0 62px;
}
.cta-banner .section-tag{ color:var(--steel-blue); }
.cta-banner-grid{
  display:grid; grid-template-columns:1.25fr auto; gap:48px;
  align-items:center;
}
.cta-banner-title{
  text-transform:none; margin-top:12px;
  font-size:clamp(30px, 3.7vw, 48px);
  line-height:1.05; letter-spacing:-0.015em;
}
/* Blue and italic, where the other section headings only go italic. */
.cta-banner-title em{ font-style:italic; color:var(--steel-blue); }

.cta-banner-actions{ justify-self:end; text-align:left; }
/* .btn is uppercase by default; the reference sets this one in sentence case. */
.cta-banner-btn{
  background:var(--steel-blue); color:#fff;
  text-transform:none; letter-spacing:0; font-size:15.5px;
  padding:16px 28px;
}
.cta-banner-btn:hover{ background:var(--amber-dark); }
.cta-banner-help{ margin-top:13px; font-size:14px; opacity:0.78; }
.cta-banner-help a{
  color:var(--steel-blue); font-weight:600;
  display:inline-flex; align-items:center; gap:5px;
  text-decoration:underline; text-underline-offset:3px;
}

/* ---------- Footer ----------
   Was dark carbon with three columns. Now light, four columns, with a
   separate tinted strip along the bottom. */
footer{ background:var(--bg-light); color:var(--ink-on-cream); padding:62px 0 0; }
.foot-grid{
  display:grid; grid-template-columns:1.5fr 1fr 1fr 1.25fr; gap:44px;
  padding-bottom:52px;
}

.foot-logo{ width:170px; height:auto; display:block; margin-bottom:16px; }
.foot-brand p{ font-size:14.5px; line-height:1.6; opacity:0.72; max-width:290px; }
.foot-label{
  display:block; margin:24px 0 11px;
  font-size:10.5px; text-transform:uppercase; letter-spacing:0.11em;
  color:var(--steel-blue);
}
.foot-social{ display:flex; gap:11px; flex-wrap:wrap; }
.foot-social-btn{
  display:inline-flex; align-items:center; gap:9px;
  padding:11px 17px; border-radius:3px;
  border:1px solid rgba(32,42,45,0.18); background:#fff;
  font-size:14px; font-weight:600; color:var(--ink-on-cream);
  transition:border-color 0.25s ease, background 0.25s ease;
}
.foot-social-btn:hover{ border-color:var(--steel-blue); }
.foot-social-btn.is-wa{
  background:var(--whatsapp-green); border-color:var(--whatsapp-green); color:#fff;
}
.foot-social-btn.is-wa:hover{ background:#1eb955; border-color:#1eb955; }

footer h4{
  font-family:var(--font-sans); font-size:11px; text-transform:uppercase;
  letter-spacing:0.1em; color:var(--steel-blue); margin-bottom:17px;
}
footer ul{ list-style:none; display:flex; flex-direction:column; gap:11px; }
footer li a{ font-size:14.5px; opacity:0.75; }
footer li a:hover{ opacity:1; color:var(--steel-blue); }

.foot-row{
  display:flex; align-items:flex-start; gap:11px;
  font-size:14px; line-height:1.55; opacity:0.78; margin-bottom:14px;
}
.foot-row svg{ color:var(--steel-blue); flex-shrink:0; margin-top:2px; }
.foot-inline-link{
  display:block; margin-top:4px;
  color:var(--steel-blue); text-decoration:underline; text-underline-offset:3px;
}
.foot-wa{
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  margin-top:6px; padding:13px 22px; border-radius:3px;
  background:var(--whatsapp-green); color:#fff;
  font-size:14.5px; font-weight:600;
  transition:background 0.25s ease;
}
.foot-wa:hover{ background:#1eb955; }

.foot-bottom{
  background:#eef3f7;
  border-top:1px solid rgba(32,42,45,0.08);
  padding:20px 0;
}
.foot-bottom-inner{
  display:flex; justify-content:space-between; align-items:center;
  flex-wrap:wrap; gap:14px;
}
.foot-copy{ display:flex; flex-direction:column; gap:4px; font-size:13px; opacity:0.7; }
.foot-tagline{ font-size:10.5px; text-transform:uppercase; letter-spacing:0.09em; opacity:0.62; }
.foot-legal{ display:flex; align-items:center; gap:18px; font-size:13px; }
.foot-legal a{ opacity:0.7; }
.foot-legal a:hover{ opacity:1; color:var(--steel-blue); }
/* Hairline separators between the legal links, as in the reference. */
.foot-legal a + a{ border-left:1px solid rgba(32,42,45,0.2); padding-left:18px; }

@media (max-width:1000px){
  .foot-grid{ grid-template-columns:1fr 1fr; gap:38px; }
  .cta-banner-grid{ grid-template-columns:1fr; gap:28px; }
  .cta-banner-actions{ justify-self:start; }
}

@media (max-width:620px){
  .cta-banner{ padding:46px 0 48px; }
  .foot-grid{ grid-template-columns:1fr; gap:34px; padding-bottom:40px; }
  .foot-brand p{ max-width:none; }
  .foot-bottom-inner{ flex-direction:column; align-items:flex-start; }
  .cta-banner-btn{ width:100%; justify-content:center; }
}

/* floating whatsapp */
/* The old .float-wa lived here: a fixed 56px circle with a flat dark shadow
   and no hover at all. Replaced by .wa-float from the design-reference kit at
   the top of this file, which had been sitting unused the whole time because
   the markup carried the other class name. */

/* ---------- Confirmation page (success.html) ---------- */
.confirm-wrap{
  max-width:560px; margin:0 auto; padding:96px 32px 64px;
  text-align:center;
}
.confirm-icon{
  width:60px; height:60px; border-radius:50%; background:var(--whatsapp);
  display:flex; align-items:center; justify-content:center; margin:0 auto 22px;
}
.confirm-card{
  background:#fff; border:1px solid var(--line); padding:28px;
  margin:28px 0; text-align:left;
}
.confirm-row{
  display:flex; justify-content:space-between; gap:16px;
  font-family:var(--font-sans); font-size:13px;
  padding:10px 0; border-top:1px solid var(--line);
}
.confirm-row:first-child{ border-top:none; }
.confirm-row span:first-child{ opacity:0.55; text-transform:uppercase; letter-spacing:0.04em; }
.confirm-note{
  background:var(--steel); color:var(--paper);
  padding:22px 24px; margin:28px 0; font-size:15px; text-align:left;
}

/* ---------- Cursor lens (magnifier) ---------- */
/* A circular "glass lens" that follows the mouse and shows a zoomed-in
   clone of the page underneath it — see js/lens.js. Desktop only
   (gated on hover+fine pointer) and off when prefers-reduced-motion. */
#cursor-lens{
  --lens-size: 60px;
  position:fixed; top:0; left:0;
  width:var(--lens-size); height:var(--lens-size);
  border-radius:50%;
  pointer-events:none;
  z-index:999;
  overflow:hidden;
  transform:translate(-50%, -50%);
  opacity:0;
  transition:opacity 0.25s ease;
  box-shadow:
    0 0 0 2px rgba(255,255,255,0.6),
    0 0 0 6px rgba(74,127,181,0.28),
    0 14px 32px rgba(0,0,0,0.4);
}
#cursor-lens.is-active{ opacity:1; }
#cursor-lens::after{
  content:"";
  position:absolute; inset:0; border-radius:50%;
  background:radial-gradient(circle at 32% 26%, rgba(255,255,255,0.4), rgba(255,255,255,0) 46%);
  z-index:2;
}
#cursor-lens-inner{
  position:absolute; top:0; left:0;
  z-index:1;
}

/* Legal navigation: narrow screens and keyboard focus. */
.foot-legal{flex-wrap:wrap;row-gap:10px}
.foot-legal a{padding-top:8px;padding-bottom:8px}
.foot-legal a:focus-visible{outline:3px solid #305c7d;outline-offset:4px;opacity:1}
@media(max-width:380px){.foot-legal{gap:8px;font-size:12px}.foot-legal a + a{padding-left:8px}}

/* Keep the fit visible in on-person previews, including on mobile. */
.worn-figure > img{object-position:center 35%}
.worn-preview-note{font-size:12px;line-height:1.6;color:#59686e;margin:0 0 20px}
.worn-modal.is-product-shot .worn-preview-note{display:none}
@media(max-width:780px){.worn-modal:not(.is-product-shot) .worn-figure{aspect-ratio:4/5;max-height:65vh}}
