
/* ════════════════════════════════════════════════════════════════════
   0. FONTS - self-hosted
   Previously loaded from fonts.googleapis.com via a render-blocking <link>
   in every <head>: a third-party round trip on the LCP path, and a request
   to Google on every page view of a medical-adjacent site. Both families
   are VARIABLE, so one file per family covers all weights. latin-ext is
   fetched only if the page actually contains those codepoints.
   ════════════════════════════════════════════════════════════════════ */
@font-face {
  font-family: 'Rubik';
  font-style: normal;
  font-weight: 100 900;                 /* variable: one file covers every weight used */
  font-display: swap;
  src: url('fonts/rubik-var-latin.h99ec7ccb.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Rubik';
  font-style: normal;
  font-weight: 100 900;                 /* variable: one file covers every weight used */
  font-display: swap;
  src: url('fonts/rubik-var-latin-ext.hb11446f4.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;                 /* variable: one file covers every weight used */
  font-display: swap;
  src: url('fonts/inter-var-latin.hc9407645.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;                 /* variable: one file covers every weight used */
  font-display: swap;
  src: url('fonts/inter-var-latin-ext.ha28eb6d3.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* ════════════════════════════════════════════════════════════════════
   1. RESET
   ════════════════════════════════════════════════════════════════════ */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body { min-height: 100vh; min-height: 100dvh; }  /* dvh second: no phantom scroll under the iOS Safari bar */
img, svg, video, picture { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: none; cursor: pointer; }
ul[class], ol[class] { list-style: none; }
a { color: inherit; }

/* ════════════════════════════════════════════════════════════════════
   2. TOKENS
   ════════════════════════════════════════════════════════════════════ */
:root {
  /* ══ ION CYAN / DEEP OCEAN — semantic colour system ══════════════════
     Components reference these tokens, never raw hex. Deep technical teal
     carries interaction, deep-ocean navy carries structure, ion cyan is a
     restrained signal accent (never a large surface, never behind white
     text), on cool clinical neutrals. */
  --color-primary:#006B78;
  --color-primary-hover:#00515D;
  --color-primary-pressed:#003F49;
  --color-primary-dark:#064454;
  --color-primary-light:#D9F5F7;

  --color-secondary:#0D2E3D;
  --color-accent:#23D3E3;
  --color-supporting-teal:#2B7F8C;
  --color-cushion-ice:#A8DDE2;

  --color-background:#F7FAFB;
  --color-background-alt:#EAF4F6;
  --color-surface:#FFFFFF;

  --color-text-primary:#11232C;
  --color-text-secondary:#52656E;

  --color-border:#C8D8DE;
  /* Control borders carry WCAG 1.4.11 non-text contrast, so this is measured
     against the WORST surface it lands on, not white: 3.46:1 on --bg-alt,
     3.69:1 on --bg, 3.87:1 on --surface. The old #7B929C fell to 2.92:1 on
     the .alt band, so the newsletter field failed only in that one place. */
  --color-control-border:#6E8590;

  --color-success:#1B7F5A;
  --color-warning:#A85B00;
  --color-error:#B42318;

  /* Deep-ocean elevation (never purple- or neutral-black-tinted). */
  --shadow-soft:0 12px 32px rgba(13,46,61,.10);
  --shadow-elevated:0 20px 50px rgba(13,46,61,.16);

  /* ══ Structural aliases — the existing component layer resolves through
     these, so the whole site re-themes from the tokens above. ══ */
  --bg:var(--color-background); --bg-alt:var(--color-background-alt); --surface:var(--color-surface);
  --ink:var(--color-secondary); --ink-2:#123A4B;
  --text:var(--color-text-primary); --muted:var(--color-text-secondary);
  --text-inv:#F4FAFB; --muted-inv:var(--color-cushion-ice);
  --line:var(--color-border); --line-strong:var(--color-control-border);
  --line-inv:rgba(244,250,251,.14); --line-inv-strong:rgba(244,250,251,.26);
  --focus-ring: var(--color-primary);   /* visible teal focus ring on light backgrounds (≥3:1) */
  --grad:linear-gradient(135deg,#0D2E3D 0%,#006B78 58%,#23D3E3 100%);
  /* ══ SHAPE RULE (documented so the mixed system is deliberate) ══════
     Interactive controls  -> --radius-pill  (buttons, chips, swatches, inputs)
     Cards and media       -> --radius       (product cards, figures, tiles)
     Nested / small parts  -> --radius-sm    (inline tags, thumbnails)
     Large panels          -> --radius-lg    (account panels, explore stage)
     Circles               -> 50%            (avatars, dots) only.
     Do not introduce a new pixel radius. If a shape does not fit one of these,
     the shape is wrong, not the scale. */
  --radius:12px; --radius-sm:8px; --radius-lg:20px; --radius-pill:999px;
  --container:1200px; --section-pad:120px; --section-pad-mobile:72px;
  --nav-h:80px; --nav-h-shrunk:64px;
  --font-display:'Rubik',system-ui,-apple-system,'Segoe UI',sans-serif;
  --font-body:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif;
  --ease-out:cubic-bezier(0.16,1,0.3,1); --ease-in-out:cubic-bezier(0.65,0,0.35,1);
}

/* JS toggles .is-scrolled on <html>; swapping --nav-h here means the nav
   height, drawer offset and anchor scroll-margins all shrink together. */
:root.is-scrolled { --nav-h: var(--nav-h-shrunk); }

/* ════════════════════════════════════════════════════════════════════
   3. BASE / TYPOGRAPHY
   ════════════════════════════════════════════════════════════════════ */
body {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden; /* word-split / reveal transforms must never cause a horizontal scrollbar */
}
body.menu-open { overflow: hidden; } /* scroll lock behind the mobile drawer */

h1, h2, h3, h4 { font-family: var(--font-display); color: var(--text); }
h1 {
  font-size: clamp(2.6rem, 5.6vw, 4.4rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
}
h3 { font-size: 1.25rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.3; }
p { line-height: 1.65; }

::selection { background: rgba(35,211,227,.32); }

/* One shared focus treatment: visible, on-brand, never removed. Uses --focus-ring
   (dark ink on light backgrounds for ≥3:1 non-text contrast, WCAG 1.4.11; flips to
   cyan inside dark .ink sections where the ink ring would vanish). */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Highlighted headline word — SOLID deep technical teal, never a gradient.
   Essential text is never set on a gradient, so the highlight keeps a fixed,
   measurable contrast ratio (#006B78 on #F7FAFB ≈ 5.9:1). */
.grad-word {
  color: var(--color-primary);
  -webkit-text-fill-color: currentColor;
}
/* On deep-ocean sections the teal would fall to ~2.4:1, so the highlight
   switches to ion cyan (#23D3E3 on #0D2E3D ≈ 7.8:1). */
.ink .grad-word,
.home-tech .grad-word { color: var(--color-accent); }

/* ════════════════════════════════════════════════════════════════════
   4. LAYOUT — container, section palettes, rhythm
   ════════════════════════════════════════════════════════════════════ */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 32px;
}
@media (max-width: 640px) {
  .container { padding-inline: 20px; }
}

main > section { padding: var(--section-pad) 0; position: relative; }
@media (max-width: 820px) {
  main > section { padding: var(--section-pad-mobile) 0; }
}

/* Light / ink alternation. .ink remaps the shared component tokens so
   buttons, chips, cards and fields invert without extra classes. */
.light { background: var(--bg); color: var(--text); }
.light.alt { background: var(--bg-alt); }
.ink {
  --text: var(--text-inv);
  --muted: var(--muted-inv);
  --line: var(--line-inv);
  --line-strong: var(--line-inv-strong);
  --focus-ring: var(--color-accent);   /* dark sections: ion cyan reads on deep ocean */
  --surface: var(--ink-2);
  background: var(--ink);
  color: var(--text);
}

/* Anchor landing position compensates for the fixed nav (shrunk height
   applies automatically via the --nav-h swap above). */
[id] { scroll-margin-top: calc(var(--nav-h) + 12px); }

/* ════════════════════════════════════════════════════════════════════
   5. EYEBROW + SECTION HEADINGS
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 480px) {
  /* Long tracked-caps eyebrows wrap to 2-3 lines on phones: top-align the
     gradient tick and relax the tracking so the block reads intentional. */
  .eyebrow { align-items: flex-start !important; letter-spacing: .14em !important; }
  .eyebrow::before { margin-top: .5em; }
}
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font: 600 12.5px/1 var(--font-body);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}
/* THE HEXAGON, 2026-08-18.
   A solid gradient hexagon used to sit before EVERY eyebrow on the site, 22 of
   them. Repeated that often it stopped reading as a brand mark and started
   reading as generic decoration. It is now removed from ordinary section
   eyebrows and kept only on the product TIER BADGES, where a mark is doing real
   work: telling Maximum Support apart from Everyday Support at a glance.
   Where it is kept, it is no longer a solid blob. It is a hexagon OUTLINE with a
   stack of smaller hexagons inside, so the mark actually depicts the splint's
   open lattice, the same structure the logo draws. */
.eyebrow::before { content: none; }

.eyebrow.products-tier-tag::before,
.eyebrow.pdp-tier::before {
  content: "";
  width: 15px;
  height: 15px;
  flex: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='0' y2='24' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%2323D3E3'/%3E%3Cstop offset='.55' stop-color='%23006B78'/%3E%3Cstop offset='1' stop-color='%230D2E3D'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cg stroke='url(%23g)' stroke-width='1.9' stroke-linejoin='round'%3E%3Cpath d='M12.00 23.20 L2.30 17.60 L2.30 6.40 L12.00 0.80 L21.70 6.40 L21.70 17.60 Z'/%3E%3Cg stroke-width='1.35'%3E%3Cpath d='M12.00 15.50 L8.97 13.75 L8.97 10.25 L12.00 8.50 L15.03 10.25 L15.03 13.75 Z'/%3E%3Cpath d='M12.00 9.44 L8.97 7.69 L8.97 4.19 L12.00 2.44 L15.03 4.19 L15.03 7.69 Z'/%3E%3Cpath d='M12.00 21.56 L8.97 19.81 L8.97 16.31 L12.00 14.56 L15.03 16.31 L15.03 19.81 Z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
}

.section-h {
  font-size: clamp(1.9rem, 3.4vw, 2.9rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.12;
  margin-top: 18px;
}
.section-intro {
  max-width: 620px;
  margin-top: 18px;
  font-size: 17px;
  color: var(--muted);
}

/* ════════════════════════════════════════════════════════════════════
   6. BUTTONS
   ════════════════════════════════════════════════════════════════════ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px 30px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font: 600 15px/1.1 var(--font-body);
  letter-spacing: .01em;
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
  transition:
    transform .3s var(--ease-out),
    box-shadow .3s var(--ease-out),
    background-color .3s var(--ease-out),
    border-color .3s var(--ease-out),
    color .3s var(--ease-out);
}
.btn:active { transform: translateY(0); }

.btn-primary {
  /* Solid deep technical teal — no gradient behind essential button text.
     White on #006B78 is ≈6.2:1, so it passes AA at every size. */
  background-image: none;
  background-color: var(--color-primary);
  color: #fff;
  border: none;
  transition: background-color .2s var(--ease-out), transform .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.btn-primary:hover {
  transform: translateY(-2px);
  background-color: var(--color-primary-hover);
  box-shadow: var(--shadow-soft);
}
.btn-primary:active { background-color: var(--color-primary-pressed); }
/* Disabled: clearly inert, but white-on-slate stays ≈4.9:1 so the label
   remains fully readable (never communicated by colour alone — the control
   is also non-interactive and exposes its disabled state to AT). */
.btn-primary:disabled,
.btn-primary[disabled],
.btn-primary[aria-disabled="true"] {
  background-color: #5E7580;
  color: #FFFFFF;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
/* Liquid sheen: a soft highlight sweeps across the CTA on hover. Clipped
   to the pill; transient (no base transition, so it re-arms each hover).
   Motion is removed by the global reduced-motion block. */
.btn-primary { position: relative; overflow: hidden; }
.btn-primary::before {
  content: "";
  position: absolute;
  top: 0; left: 0; width: 100%; height: 100%;
  background: linear-gradient(100deg, transparent 25%, rgba(255,255,255,.28) 50%, transparent 75%);
  transform: translateX(-130%);
  pointer-events: none;
}
.btn-primary:hover::before { transform: translateX(130%); transition: transform .7s var(--ease-out); }

.btn-ghost {
  background: transparent;
  border: 1px solid var(--color-primary);
  color: var(--color-primary);
  transition: background-color .2s var(--ease-out), border-color .2s var(--ease-out), transform .2s var(--ease-out);
}
.btn-ghost:hover {
  transform: translateY(-2px);
  background-color: var(--color-primary-light);
  border-color: var(--color-primary-hover);
  color: var(--color-primary-hover);
}
.btn-ghost:active { background-color: var(--color-primary-light); color: var(--color-primary-pressed); }
/* On deep-ocean sections teal would drop to ~2.4:1, so the secondary button
   inverts to ice/cyan against the navy. */
.ink .btn-ghost { border-color: var(--line-inv-strong); color: var(--text-inv); }
.ink .btn-ghost:hover { background-color: rgba(35,211,227,.12); border-color: var(--color-accent); color: var(--color-accent); }

.btn-sm { padding: 13px 22px; font-size: 14px; }

/* Optional arrow affordance: <span class="btn-arrow" aria-hidden="true">→</span> */
.btn-arrow { display: inline-block; transition: transform .3s var(--ease-out); }
.btn:hover .btn-arrow { transform: translateX(4px); }

/* ════════════════════════════════════════════════════════════════════
   7. CHIPS
   ════════════════════════════════════════════════════════════════════ */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line-strong);
  font: 500 13px/1.2 var(--font-body);
  color: var(--text);
  white-space: nowrap;
}
.chip-sku {
  font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--muted);
}

/* ════════════════════════════════════════════════════════════════════
   8. CARDS
   ════════════════════════════════════════════════════════════════════ */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition:
    transform .45s var(--ease-out),
    box-shadow .45s var(--ease-out),
    border-color .45s var(--ease-out);
}
/* Lift + shadow on hover only. When GSAP tilt is active its inline
   transform wins over this rule — intentional; the shadow still applies. */
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 24px 48px -28px rgba(13,46,61,.22);
  border-color: var(--line-strong);
}
.card-media {
  background: var(--bg-alt);   /* graceful placeholder while images resolve */
  aspect-ratio: 4 / 3;
  overflow: hidden;
}
.card-media img { width: 100%; height: 100%; object-fit: cover; }
.card-body { padding: 24px; }
.card-body h3 { margin-bottom: 8px; }
.card-body p { font-size: 14.5px; color: var(--muted); }

/* ════════════════════════════════════════════════════════════════════
   9. FORMS
   ════════════════════════════════════════════════════════════════════ */
.field { display: flex; flex-direction: column; gap: 8px; }
.field label {
  font: 600 12px/1 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}
.field input,
.field select,
.field textarea {
  width: 100%;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--text);
  font: 400 15px/1.4 var(--font-body);
  transition: border-color .25s var(--ease-out);
}
.field input, .field select {
  height: 52px;
  padding: 0 22px;
  border-radius: var(--radius-pill);
}
.field textarea {
  min-height: 128px;
  padding: 16px 22px;
  border-radius: var(--radius);
  resize: vertical;
}
.field input::placeholder,
.field textarea::placeholder { color: var(--muted); opacity: 1; }
.field input:hover,
.field select:hover,
.field textarea:hover { border-color: var(--text); }

/* ════════════════════════════════════════════════════════════════════
   10. REVEAL SYSTEM
   Hidden states are gated behind html.js so content is always visible
   without scripting. IO adds .is-visible once (one-shot).
   ════════════════════════════════════════════════════════════════════ */
.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s var(--ease-out), transform .7s var(--ease-out);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

.js .reveal-stagger > * {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .6s var(--ease-out), transform .6s var(--ease-out);
}
.js .reveal-stagger.is-visible > * { opacity: 1; transform: none; }
/* 80ms stagger steps, capped at the 8th child */
.js .reveal-stagger > :nth-child(2) { transition-delay: 80ms; }
.js .reveal-stagger > :nth-child(3) { transition-delay: 160ms; }
.js .reveal-stagger > :nth-child(4) { transition-delay: 240ms; }
.js .reveal-stagger > :nth-child(5) { transition-delay: 320ms; }
.js .reveal-stagger > :nth-child(6) { transition-delay: 400ms; }
.js .reveal-stagger > :nth-child(7) { transition-delay: 480ms; }
.js .reveal-stagger > :nth-child(n+8) { transition-delay: 560ms; }

/* ════════════════════════════════════════════════════════════════════
   11. WORD ANIMATION — .h-word (auto-split h2s) / .title-word (authored)
   .h-word spans are created by JS (with --i set), so they never exist
   without scripting. .title-word is authored by section builders, each
   with an explicit --i; the parent gets .title-in to run the entrance
   (add class .title-auto to have the skeleton apply .title-in on load).
   ════════════════════════════════════════════════════════════════════ */
.js .h-word,
.js .title-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(28px);
  filter: blur(8px);                 /* headings "focus in" — clean + futuristic */
  transition: transform .75s var(--ease-out), opacity .6s var(--ease-out), filter .6s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.js .h-visible .h-word,
.js .title-in .title-word {
  opacity: 1;
  transform: none;
  filter: blur(0);
}

/* ════════════════════════════════════════════════════════════════════
   13. NAVBAR
   ════════════════════════════════════════════════════════════════════ */
.site-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 1000;
  height: var(--nav-h);           /* shrinks via the :root.is-scrolled var swap */
  /* Liquid glass: a soft white tint + blur + saturation present even at
     rest, so the bar always reads as a premium glass layer over the hero.
     The inset top highlight is the glass sheen; the soft drop shadow gives
     it depth/layering. Deepens once scrolled (below). */
  /* Clear "liquid glass": whiter, more transparent, less frost (lower blur),
     high saturation + a touch of brightness for the macOS-style vibrancy, with a
     bright top-edge specular highlight. */
  background: rgba(255,255,255,.20);
  -webkit-backdrop-filter: blur(9px) saturate(185%) brightness(1.06);
  backdrop-filter: blur(9px) saturate(185%) brightness(1.06);
  border-bottom: 1px solid rgba(255,255,255,.28);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.6),
    inset 0 -1px 0 rgba(13,46,61,.04),
    0 6px 24px -22px rgba(13,46,61,.4);
  /* Only compositor-safe properties are transitioned. `height` and
     `backdrop-filter` used to animate here, which forced layout and a blur
     re-rasterise on every scroll threshold crossing, on every page. The 16px
     height change now snaps and the blur switches discretely. */
  transition:
    background-color .35s var(--ease-out),
    border-color .35s var(--ease-out),
    box-shadow .35s var(--ease-out);
}
:root.is-scrolled .site-nav {
  background: rgba(255,255,255,.44);
  -webkit-backdrop-filter: blur(15px) saturate(190%) brightness(1.05);
  backdrop-filter: blur(15px) saturate(190%) brightness(1.05);
  border-bottom-color: rgba(255,255,255,.32);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.72),
    0 10px 30px -24px rgba(13,46,61,.45);
}
/* Hook for a dark hero: add .on-dark to .site-nav (T4 / integrator) and
   the bar inverts until the frosted scrolled state takes over. */
:root:not(.is-scrolled) .site-nav.on-dark {
  --text: var(--text-inv);
  --muted: var(--muted-inv);
  --line: var(--line-inv);
  --line-strong: var(--line-inv-strong);
  --focus-ring: var(--color-accent);   /* deep-teal ring is 2.29:1 here; ion cyan is 7.79:1 */
  color: var(--text);
  /* Over a dark hero at rest the light glass would wash out the light text —
     go fully transparent until the frosted scrolled state takes over. */
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-bottom-color: transparent;
  box-shadow: none;
}

/* ── Liquid-glass refraction (real optical bending of the live backdrop).
   Only Chromium renders an SVG filter inside backdrop-filter — Safari and
   Firefox parse it, drop the url() token, and keep the frosted fallback
   above. So struxa.js runs a capability check and adds html.lg ONLY where
   the refraction actually paints; everyone else gets the clear-frost glass
   unchanged. The #lg-nav filter (turbulence displacement + per-channel
   chromatic aberration) is injected into <body> by struxa.js. ── */
html.lg .site-nav {
  background: rgba(255,255,255,.16);
  -webkit-backdrop-filter: blur(3px) saturate(180%) brightness(1.05);
  backdrop-filter: url(#lg-nav) blur(2px) saturate(180%) brightness(1.05);
  border-bottom-color: rgba(255,255,255,.36);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.75),
    inset 0 -1px 0 rgba(255,255,255,.16),
    inset 0 -16px 24px -20px rgba(255,255,255,.30),
    0 8px 30px -22px rgba(13,46,61,.45);
}
html.lg.is-scrolled .site-nav {
  background: rgba(255,255,255,.36);
  -webkit-backdrop-filter: blur(4px) saturate(190%) brightness(1.04);
  backdrop-filter: url(#lg-nav) blur(3px) saturate(190%) brightness(1.04);
  border-bottom-color: rgba(255,255,255,.30);
}

/* Reduced-transparency (macOS "Reduce transparency", Windows equivalent):
   honour the OS request — drop the refraction + blur and give a near-solid
   bar, mirroring how the site already respects prefers-reduced-motion. Later
   source order + equal-or-higher specificity lets it win over both the frosted
   fallback and the html.lg refraction. */
@media (prefers-reduced-transparency: reduce) {
  .site-nav,
  :root.is-scrolled .site-nav,
  html.lg .site-nav,
  html.lg.is-scrolled .site-nav {
    background: rgba(255,255,255,.94);
    -webkit-backdrop-filter: saturate(115%);
    backdrop-filter: saturate(115%);
    border-bottom-color: rgba(13,46,61,.10);
  }
}

.nav-inner {
  height: 100%;
  display: flex;
  align-items: center;
  gap: 40px;
}

/* 2px gradient scroll-progress bar. Driven by the CSS scroll timeline below
   where supported; struxa.js only paints it on engines that lack one. */
.nav-progress {
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--grad);
  transform: scaleX(0);
  transform-origin: 0 50%;
  pointer-events: none;
}
@keyframes navProgress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@supports (animation-timeline: scroll()) {
  .nav-progress {
    animation: navProgress linear both;
    animation-timeline: scroll(root block);
    animation-duration: auto;   /* scroll-linked: beats the blanket reduced-motion duration */
  }
}
@media (prefers-reduced-motion: reduce) {
  /* Purely decorative and the only thing this bar does is move. Hide it
     rather than leave a stuck-at-zero sliver. */
  .nav-progress { display: none; }
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font: 700 19px/1 var(--font-display);
  letter-spacing: .08em;
  color: var(--text);
  text-decoration: none;
  flex: none;
}
.wordmark svg { color: var(--text); }

.nav-menu {
  display: flex;
  align-items: center;
  gap: 32px;
  margin-left: auto;
}
.nav-links {
  display: flex;
  align-items: center;
  gap: 28px;
}
.nav-links a {
  position: relative;
  display: inline-block;
  padding: 8px 2px;
  font: 500 14.5px/1 var(--font-body);
  color: var(--muted);
  text-decoration: none;
  transition: color .25s var(--ease-out);
}
.nav-links a:hover { color: var(--color-primary-dark); }
/* Solid deep-teal underline marks the active / hovered nav item */
.nav-links a::after {
  content: "";
  position: absolute;
  left: 2px; right: 2px; bottom: 2px;
  height: 2px;
  border-radius: 1px;
  background: var(--color-primary);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform .3s var(--ease-out);
}
.nav-links a:hover::after,
.nav-links a[aria-current="true"]::after { transform: scaleX(1); }

/* Hamburger — hidden on desktop, 44px touch target on mobile */
.nav-toggle {
  display: none;
  flex: none;   /* never shrink below 44px once the cart icon reveals in the right cluster */
  width: 44px;
  height: 44px;
  margin-left: auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  border-radius: var(--radius-sm);
  color: var(--text);
}
.nav-toggle span {
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
  transition: transform .3s var(--ease-out), opacity .2s var(--ease-out);
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ════════════════════════════════════════════════════════════════════
   14. MOBILE NAV DRAWER (≤1024px)
   Raised 820px → 1024px: the nav gained the cart + account icons, so the full
   horizontal row (wordmark + 6 links + Shop + cart + account) stops fitting
   below ~1000px. It now collapses to the hamburger at ≤1024 so those trailing
   icons never overflow off-screen. If nav items change, re-check the fit width.
   Kept in sync with mqlMobileLive in struxa.js.
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 1024px) {
  .nav-toggle { display: inline-flex; }
  .nav-inner { gap: 12px; }   /* tighter than the 40px desktop gap so wordmark + toggle + cart + account never crowd/clip once the cart reveals */
  /* At 320px even 12px gaps overflowed once the cart icon revealed, pushing
     .nav-toggle off-screen. Free ~61px by dropping the wordmark TEXT; the 20px
     lattice mark still carries the brand and stays the home link.
     "STRUXA" is a bare text node with no element of its own, so it is collapsed
     with font-size:0 on the parent rather than display:none on a span. The <img>
     has explicit width/height so it is unaffected, and the link keeps its
     aria-label="Struxa home", so the accessible name never depends on the text. */
  @media (max-width: 360px) {
    .nav-inner { gap: 6px; }
    .site-nav .wordmark { font-size: 0; gap: 0; }
  }
  .nav-menu {
    /* The panel surface is always light, so pin its palette back to the
       light tokens even under .site-nav.on-dark. */
    --text: #11232C;
    --muted: #52656E;
    --line: rgba(13,46,61,.10);
    --line-strong: rgba(13,46,61,.18);
    position: fixed;
    top: var(--nav-h);
    left: 0; right: 0;
    margin-left: 0;
    max-height: calc(100dvh - var(--nav-h));
    overflow: auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 14px 20px 28px;
    background: rgba(250,251,252,.94);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    backdrop-filter: blur(18px) saturate(140%);
    border-bottom: 1px solid var(--line);
    color: var(--text);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-10px);
    transition:
      transform .4s var(--ease-out),
      opacity .3s var(--ease-out),
      visibility 0s .3s;
  }
  .nav-menu.is-open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
    transition:
      transform .45s var(--ease-out),
      opacity .3s var(--ease-out);
  }
  .nav-links { flex-direction: column; align-items: stretch; gap: 0; }
  .nav-links a {
    display: block;
    padding: 15px 4px;
    font-size: 17px;
    color: var(--text);
    border-bottom: 1px solid var(--line);
  }
  .nav-links a::after { display: none; } /* underline is a hover affordance; no hover here */
  .nav-cta { margin-top: 18px; justify-content: center; }
}

/* ════════════════════════════════════════════════════════════════════
   15. SKIP LINK
   ════════════════════════════════════════════════════════════════════ */
.skip-link {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 2000;
  padding: 12px 20px;
  border-radius: var(--radius-pill);
  background: var(--ink);
  color: var(--text-inv);
  font: 600 14px/1 var(--font-body);
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform .2s var(--ease-out);
}
.skip-link:focus,
.skip-link:focus-visible { transform: none; }

/* ════════════════════════════════════════════════════════════════════
   16. FOOTER
   ════════════════════════════════════════════════════════════════════ */
.site-footer { padding: 80px 0 40px; }
.footer-top {
  display: grid;
  grid-template-columns: 1.4fr 2fr;
  gap: 56px;
  padding-bottom: 56px;
  border-bottom: 1px solid var(--line);
}
.footer-tagline {
  margin-top: 18px;
  max-width: 320px;
  font-size: 14.5px;
  color: var(--muted);
}
.footer-cols {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
}
.footer-col h3 {
  font: 600 11.5px/1 var(--font-body);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 18px;
}
.footer-col ul { display: flex; flex-direction: column; gap: 12px; list-style: none; padding: 0; }
.footer-col li { list-style: none; }
.footer-col li::marker { content: ""; }
.footer-col a {
  font-size: 14.5px;
  color: var(--text);
  text-decoration: none;
  overflow-wrap: anywhere;   /* the contact email can't overflow its column on narrow phones */
  transition: color .25s var(--ease-out);
}
.footer-col a:hover { color: var(--muted); }
.footer-disclaimer {
  margin-top: 32px;
  max-width: none;          /* full container width → wider, fewer lines, shorter footer */
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--muted);
}
.footer-legal {
  margin-top: 36px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 28px;
  font-size: 12.5px;
  color: var(--muted);
}
.footer-legal a { color: var(--text); text-decoration: none; }
.footer-legal a:hover { text-decoration: underline; }
@media (max-width: 900px) {
  .site-footer { padding: 60px 0 34px; }
  .footer-top { grid-template-columns: 1fr; gap: 34px; padding-bottom: 38px; }
  .footer-disclaimer { margin-top: 30px; }
  .footer-legal { margin-top: 26px; }
}

/* ════════════════════════════════════════════════════════════════════
   18. REDUCED MOTION — exhaustive; must stay last so it wins.
   Every reveal forced visible, every animation/transition removed,
   marquee halted. Mirrors the house pattern.
   ════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto !important; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: .01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
  .js .reveal,
  .js .reveal-stagger > * {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .js .h-word,
  .js .title-word {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
  }
  .grad-word { animation: none !important; }
  .btn, .btn-arrow, .card, .nav-links a::after, .nav-toggle span, .skip-link {
    transition: none !important;
  }
  .btn:hover, .card:hover { transform: none !important; }
  .btn:hover .btn-arrow { transform: none !important; }
  .site-nav, .nav-menu, .nav-progress { transition: none !important; }
}


/* ==== hero ==== */

/* ═══ HERO — dark "orbit" stage (Cyrclo rings + Robotflow center) ═══
   Full-viewport ink stage: a faint dot grid, two counter-rotating rings of
   product tiles, and — at the center — the splint itself as a live 3D model
   (transparent canvas, slow auto-rotate, black lattice + white straps).
   Copy + CTA sit in the center column, Robotflow-style. Rings are built by
   the hero-rings module in struxa.js and are purely decorative; the splint
   and copy are real HTML. All orbit/spin motion is gated off under
   prefers-reduced-motion. Placeholder tile art = the existing splint renders;
   swap for per-model / per-colorway renders later (see the future task). */
#hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--bg);               /* light stage — matches the rest of the home page */
  isolation: isolate;
}
@supports not (height: 100svh) { #hero { min-height: 100vh; } }

/* Dot grid — faint, masked to fade out toward the center */
.hero-dots {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(#C8D8DE 1px, transparent 1.4px);
  background-size: 30px 30px;
  opacity: .35;
  -webkit-mask-image: radial-gradient(ellipse 62% 62% at 50% 50%, transparent 10%, #000 62%);
  mask-image: radial-gradient(ellipse 62% 62% at 50% 50%, transparent 10%, #000 62%);
}

/* ── Orbiting rings (JS-built; decorative) ── */
.hero-rings { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.hero-ring {
  position: absolute; top: 50%; left: 50%; width: 0; height: 0;
  animation: heroSpin var(--dur, 90s) linear infinite;
  will-change: transform;
}
.hero-ring.ccw { animation-direction: reverse; }
.hero-tile-pos { position: absolute; top: 0; left: 0; width: 0; height: 0; }
.hero-tile {
  position: absolute; top: 0; left: 0;
  width: var(--sz, 88px); height: var(--sz, 88px);
  margin-top: calc(var(--sz, 88px) / -2);
  margin-left: calc(var(--sz, 88px) / -2);
  animation: heroSpin var(--dur, 90s) linear infinite reverse;  /* keeps tiles upright while orbiting */
}
.hero-ring.ccw .hero-tile { animation-direction: normal; }
/* Transparent splint renders float freely — no box, no shadow. The tile art is
   still the legacy purple/blue render set (pending a deep-ocean rerender), so no
   recolor filter is applied. */
.hero-tile img { width: 100%; height: 100%; object-fit: contain; }
@keyframes heroSpin { to { transform: rotate(360deg); } }

/* Center vignette — keeps copy legible over any tile that orbits near it */
.hero-veil {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: radial-gradient(ellipse 50% 56% at 50% 50%, rgba(250,251,252,.80) 30%, rgba(250,251,252,0) 72%);
}

/* ── Center column: splint + copy (Robotflow layout) ── */
.hero-center {
  position: relative; z-index: 3;
  width: 100%; max-width: 760px;
  padding: 20px 24px;
  margin: 0 auto; text-align: center;
  color: var(--text);
}
.hero-title {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(2.05rem, 5vw, 3.8rem);
  line-height: 1.04; letter-spacing: -0.03em;
  color: var(--text);
  margin-top: 0;
}
/* Typing headline (GSAP TextPlugin). JS reserves min-height so nothing shifts. */
.hero-type { display: inline; }
.hero-type-caret {
  display: inline-block; width: 3px; height: 0.9em; margin-left: 6px;
  vertical-align: -0.06em; border-radius: 2px; background: var(--grad);
}
.hero-type-caret.is-idle { animation: heroCaretBlink 1.05s steps(1, end) infinite; }
@keyframes heroCaretBlink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .hero-type-caret { display: none; } }
/* Copy sits above the 3D canvas (z-index:1) so it stays readable over the splint */
.hero-title, .hero-lead, .hero-actions { position: relative; z-index: 2; }
/* .grad-word "moves" uses the solid deep technical teal set in the base rules */
.hero-lead {
  max-width: 40em; margin: 16px auto 0;
  font-size: clamp(1.02rem, 1.4vw, 1.18rem); line-height: 1.6;
  color: var(--muted);
}
.hero-actions {
  display: flex; align-items: center; justify-content: center;
  gap: 22px; flex-wrap: wrap; margin-top: 26px;
}
.hero-price {
  display: inline-flex; align-items: center; gap: 8px;
  font: 500 15px/1 var(--font-body); color: var(--text);
  text-decoration: none;
}
.hero-price b { font-weight: 600; }

.hero-lead.reveal { transition-delay: .30s; }
.hero-actions.reveal { transition-delay: .44s; }

@media (max-width: 620px) {
  /* Rings stay visible on phones — they orbit around the copy instead of being
     hidden. Slightly smaller tiles + a stronger center veil keep the headline
     crisp where a tile passes behind it. (Tiles are vmin-sized, so they already
     scale to the narrow viewport; JS sets --sz inline, so override with !important.) */
  .hero-ring:not(.ccw) .hero-tile { --sz: 11vmin !important; }   /* outer ring */
  .hero-ring.ccw .hero-tile { --sz: 9vmin !important; }          /* inner ring */
  .hero-veil { background: radial-gradient(ellipse 66% 58% at 50% 50%, rgba(250,251,252,.95) 42%, rgba(250,251,252,0) 82%); }
  .hero-center { padding: 16px 20px; }
  /* Zoomed-in default on phones (GSAP starts its scroll-zoom from here; this is
     the fallback when GSAP is absent). */
  .hero-rings { transform: scale(1.35); transform-origin: 50% 50%; }
}
@media (max-width: 380px) {
  /* On the narrowest phones, tuck the rings out a touch more so tiles clear the copy. */
  .hero-ring:not(.ccw) .hero-tile { --sz: 10vmin !important; }
  .hero-ring.ccw .hero-tile { --sz: 8vmin !important; }
}

@media (prefers-reduced-motion: reduce) {
  /* Release the compositor layers too. Killing the animation without resetting
     will-change left reduced-motion users paying full GPU layer cost for
     elements that never move. */
  .hero-ring, .hero-ring .hero-tile {
    animation: none !important;
    will-change: auto !important;
  }
}


/* ==== problem ==== */

/* ════════════════════════════════════════════════════════════════════
   T6 — PROBLEM → SOLUTION SECTION (scoped: .problem-)
   Light band: header → split row (pain-point stack | rack-focus video)
   → centered answer band → 3-up benefit card trio.
   All shared behavior (reveals, h2 split, card tilt, video nets) comes
   from the skeleton; only .problem- layout lives here. Gradient appears
   ONLY in the automatic eyebrow tick — no gradient text in this section.
   ════════════════════════════════════════════════════════════════════ */
.problem-head { max-width: 640px; }

/* ── SPLIT ROW — pain points (left) / rack-focus video (right) ──────────
   Stacks to one column at ≤900px. */
.problem-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
  margin-top: clamp(44px, 5.5vw, 64px);
}
@media (max-width: 900px) {
  .problem-split { grid-template-columns: 1fr; gap: 36px; }
}

/* Pain-point stack: bold lead word + one line of copy, divided by hairline
   separators. The ghosted index numerals (01/02/03) were removed 2026-08-14 -
   the three items are not a sequence, so the numbering encoded nothing. */
.problem-pains { display: block; }
.problem-pain {
  display: flex;
  align-items: baseline;
  gap: clamp(16px, 2vw, 22px);
  padding: clamp(18px, 2.4vw, 24px) 0;
  border-top: 1px solid var(--line);
}
.problem-pain:last-child { padding-bottom: 0; }
.problem-pain-copy {
  font-size: 16.5px;
  line-height: 1.55;
  color: var(--muted);
}
.problem-pain-copy strong {
  color: var(--text);
  font-weight: 600;
}

/* Rack-focus video in a rounded, hairline-bordered 16:9 panel. */
.problem-media {
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  overflow: hidden;
  background: var(--bg-alt); /* graceful surface while the poster resolves */
  aspect-ratio: 16 / 9;
}
.problem-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ── ANSWER BAND — the turn from problem to solution ──────────────────
   Centered, narrow measure, generous top margin. */
.problem-answer {
  max-width: 720px;
  margin: clamp(72px, 9vw, 120px) auto 0;
  text-align: center;
}
.problem-answer h3 {
  font-size: clamp(1.45rem, 2.6vw, 2rem);
  letter-spacing: -0.015em;
  line-height: 1.2;
}
.problem-answer-body {
  margin-top: 16px;
  font-size: 17px;
  color: var(--muted);
}

/* ── BENEFIT CARD TRIO — 3-up, one column on mobile ───────────────────
   .card supplies surface/border/hover-lift plus the skeleton's GSAP
   tilt hook; only the grid lives here. */
.problem-benefits {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  margin-top: clamp(40px, 5vw, 56px);
}
@media (min-width: 760px) {
  .problem-benefits { grid-template-columns: repeat(3, 1fr); }
}


/* ==== technology ==== */

/* ════════════════════════════════════════════════════════════════════
   T5 — TECHNOLOGY SECTION (scoped: .tech-)
   Dark ink band: StruxaMesh™ header → cinematic feature panel →
   3-up video card trio → manufacturing sub-panel band.
   All shared behavior (reveals, h2 split, card tilt, video nets)
   comes from the skeleton; only .tech- layout lives here.
   ════════════════════════════════════════════════════════════════════ */
#technology { overflow: hidden; } /* contains the corner lattice motif bleed */
#technology > .container { position: relative; z-index: 1; }

/* Faint rhombus-lattice motif, top-right corner of the band. Decorative
   only — masked to fade out, ≤0.04 opacity, no pointer events. */
.tech-lattice-bg {
  position: absolute;
  top: -60px;
  right: -80px;
  width: min(620px, 75vw);
  height: 560px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='56' viewBox='0 0 56 56'%3E%3Cpath d='M28 2 54 28 28 54 2 28Z' fill='none' stroke='%23F4F5F7' stroke-width='1'/%3E%3C/svg%3E");
  background-size: 56px 56px;
  opacity: .04;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(closest-side at 65% 35%, #000 30%, transparent 95%);
  mask-image: radial-gradient(closest-side at 65% 35%, #000 30%, transparent 95%);
}

.tech-head { max-width: 720px; }

/* ── FEATURE PANEL — full-container cinematic fly-through ──────────────
   Gradient hairline via the 1px-padding wrapper trick (the sanctioned
   low-opacity gradient accent); inner panel clips the video. */
.tech-feature {
  margin-top: 56px;
  padding: 1px;
  border-radius: var(--radius-lg);
  background: linear-gradient(135deg,
    rgba(35,211,227,.40) 0%,
    rgba(0,107,120,.30) 52%,
    rgba(13,46,61,.40) 100%);
}
/* Spec: feature panel rises 24px + fades (skeleton default is 22px).
   :not(.is-visible) keeps this from outliving the reveal at equal
   specificity; the reduced-motion block still wins via !important. */
.js .tech-feature.reveal:not(.is-visible) { transform: translateY(24px); }

.tech-feature-inner {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--ink-2);
}
.tech-feature-media {
  aspect-ratio: 16 / 9;
  background: #0A2733; /* graceful surface while the poster resolves */
}
.tech-feature-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Bottom scrim keeps the overlaid copy readable over any video frame. */
.tech-feature-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top,
    rgba(10,12,15,.88) 0%,
    rgba(10,12,15,.46) 34%,
    rgba(10,12,15,0) 64%);
}
.tech-feature-copy {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 30px 36px 34px;
  max-width: 640px;
}
.tech-feature-copy h3 {
  font-size: clamp(1.3rem, 2.2vw, 1.65rem);
  color: var(--text-inv);
}
.tech-feature-copy p {
  margin-top: 8px;
  font-size: 15.5px;
  max-width: 56ch;
  color: #C8D8DE; /* lighter than --muted-inv: must clear 4.5:1 over the scrim */
}
@media (max-width: 719px) {
  /* Overlay would crowd a ~200px-tall video — stack the copy below it. */
  .tech-feature-scrim { display: none; }
  .tech-feature-copy {
    position: static;
    max-width: none;
    padding: 20px 22px 24px;
  }
}

/* ── CARD TRIO — video top (16:9), copy below ────────────────────────
   .card supplies surface/border/hover-lift and the skeleton's GSAP
   tilt hook; only the media ratio and dark placeholder change here. */
.tech-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  margin-top: 24px;
}
@media (min-width: 900px) {
  .tech-grid { grid-template-columns: repeat(3, 1fr); }
}
.tech-card .card-media {
  aspect-ratio: 16 / 9;
  background: #0A2733;
}
.tech-card .card-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Deepen the hover shadow so the lift reads on the ink background. */
.tech-card:hover { box-shadow: 0 24px 48px -24px rgba(0,0,0,.55); }

/* ── STRUXAFORM BAND — distinct sub-panel on --ink-2 ────────────────── */
.tech-form {
  margin-top: 72px;
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: clamp(32px, 4.5vw, 56px);
  align-items: center;
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(30px, 4.5vw, 60px);
}
.tech-form-copy h3 {
  margin-top: 16px;
  font-size: clamp(1.45rem, 2.6vw, 2rem);
  letter-spacing: -0.015em;
}
.tech-form-body {
  margin-top: 14px;
  max-width: 54ch;
  font-size: 16.5px;
  color: var(--muted);
}
.tech-form-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 28px;
}
.tech-form-media { align-self: stretch; }
.tech-form-media img {
  width: 100%;
  height: 100%;
  min-height: 280px;
  object-fit: cover;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
}
@media (max-width: 899px) {
  .tech-form { grid-template-columns: 1fr; }
  .tech-form-media img { min-height: 0; aspect-ratio: 16 / 10; }
}
@media (max-width: 820px) {
  .tech-feature { margin-top: 44px; }
  .tech-form { margin-top: 56px; }
}

/* ═══ EXPLORE THE SPLINT — relocated interactive 3D viewer ═══ */
.tech-explore { margin-top: clamp(72px, 9vw, 120px); }
.tech-explore-head { max-width: 640px; margin-bottom: 28px; }
.tech-explore-head h3 {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.5rem, 2.6vw, 2rem); letter-spacing: -0.02em;
  margin: 0 0 10px;
}
.tech-explore-head p { color: var(--muted); margin: 0; }
.tech-explore-panel {
  /* Light lab-bench panel inside the ink band: restore the light-scheme
     vars so the relocated stage/swatch/caption components style
     themselves exactly as they did on the light hero. */
  --text: #11232C; --muted: #52656E; --surface: #FFFFFF;
  --line: rgba(13,46,61,.10); --line-strong: rgba(13,46,61,.18);
  --focus-ring: var(--color-primary);  /* light panel inside .ink: restore the teal ring (5.9:1) */
  background: #F7FAFB;
  border: 1px solid rgba(244,250,251,.14);
  border-radius: var(--radius-lg);
  padding: clamp(18px, 3vw, 36px);
}


/* ── 3D stage ── */
.explore-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 32 / 26;
  /* min-height + aspect-ratio sets an implicit WIDTH floor (360 * 32/26 = 443px),
     which overflowed the viewport below ~443px. Clamp it against the viewport. */
  min-height: min(360px, 78vw);
  max-height: min(62vh, 560px);
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, #F7FAFB 0%, #EAF4F6 100%);
  border: 1px solid var(--line);
  overflow: hidden;
  cursor: grab;
  touch-action: pan-y; /* horizontal touch-drag rotates; vertical still scrolls */
}

.explore-stage:active { cursor: grabbing; }


.explore-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity .6s var(--ease-out);
}

.explore-stage canvas {
  position: absolute;
  inset: 0;
  width: 100% !important;
  height: 100% !important;
  opacity: 0;
  transition: opacity .6s var(--ease-out);
}

/* Cross-fade: canvas in, poster out, once the model is ready */
.explore-stage.is-3d canvas { opacity: 1; }

.explore-stage.is-3d .explore-poster { opacity: 0; }


.explore-fallback-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}


.explore-hint {
  position: absolute;
  left: 16px;
  bottom: 12px;
  font: 500 12px/1 var(--font-body);
  color: rgba(28,32,38,.72);
  pointer-events: none;
  opacity: 0;
  transition: opacity .5s var(--ease-out);
}

.explore-stage.is-3d .explore-hint { opacity: 1; }

.explore-stage .explore-hint.is-out { opacity: 0 !important; }


/* ── colorway swatches ── */
.explore-swatches {
  display: none; /* interactive control: only shown when scripting is live */
  margin-top: 16px;
  flex-wrap: wrap;
  gap: 10px;
}

.js .explore-swatches { display: flex; }

.explore-swatch {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 9px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  font: 500 13px/1.2 var(--font-body);
  color: var(--text);
  transition: border-color .25s var(--ease-out), transform .25s var(--ease-out);
}

.explore-swatch:hover { transform: translateY(-1px); border-color: var(--text); }

.explore-swatch[aria-checked="true"] {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ink);
}

.explore-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1px solid rgba(13,46,61,.18);
  flex: none;
}


.explore-caption {
  display: none; /* describes the interactive model: only shown when scripting is live */
  margin-top: 10px;
  font-size: 12.5px;
  color: var(--muted);
}

.js .explore-caption { display: block; }


/* The fallback path hides these via the hidden attribute — it must win
   over the .js display rules above. */
.explore-swatches[hidden],
.explore-caption[hidden],
.explore-hint[hidden] { display: none !important; }

/* ── Tap-to-load control ────────────────────────────────────────────────
   Shown instead of auto-initialising the 3D stack when #explore-stage carries
   data-tap-to-load (see struxa.js). Sits over the poster; the drag hint is
   suppressed until the viewer is actually live, or it would promise an
   interaction the stage cannot yet honour. */
.explore-stage.is-tap-gated { cursor: default; }
.explore-stage.is-tap-gated .explore-hint { display: none; }
.explore-tap {
  position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 3;
  display: inline-flex; align-items: center; gap: 9px;
  padding: 11px 18px; border-radius: var(--radius-pill);
  border: 1px solid var(--color-primary); background: var(--color-primary); color: #FFFFFF;
  font: 600 14px/1 var(--font-body); cursor: pointer;
  box-shadow: var(--shadow-soft);
}
.explore-tap:hover { background: var(--color-primary-hover); border-color: var(--color-primary-hover); }
.explore-tap:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.explore-tap-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; opacity: .9; }


/* ==== products ==== */

/* ════════════════════════════════════════════════════════════════════
   T7 — PRODUCTS SECTION (scoped: .products-)
   Light band: lineup header → three family groups (2-up / 3-up / wide)
   → reserved reviews placeholder band.
   All shared behavior (reveals, h2 split, card hover-lift + GSAP tilt)
   comes from the skeleton; only .products- layout lives here. No JS.
   Gradient budget: eyebrow tick + Buy buttons only (both from skeleton).
   Product renders are 16:9 or square on light backgrounds, so media uses
   object-fit:contain over a --bg-alt letterbox — the splint is never
   cropped and the square green renders sit cleanly.
   ════════════════════════════════════════════════════════════════════ */
#products > .container { position: relative; }

.products-head { max-width: 720px; }

/* ── FAMILY GROUP — slim header row + card grid ──────────────────────── */
.products-group { margin-top: 68px; }
.products-group:first-of-type { margin-top: 52px; }

.products-group-head {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-bottom: 26px;
}
.products-group-head h3 {
  flex: none;
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
/* Hairline rule fills the space between the family name and the count. */
.products-rule {
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}
.products-count { flex: none; }

/* ── GRIDS ───────────────────────────────────────────────────────────
   Family 1: 2-up. Family 2: 3-up (2-up tablet, 1-up mobile). */
.products-grid {
  display: grid;
  gap: 24px;
  grid-template-columns: 1fr;
}
@media (min-width: 600px) {
  .products-grid-2 { grid-template-columns: repeat(2, 1fr); }
  .products-grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
  .products-grid-3 { grid-template-columns: repeat(3, 1fr); }
}

/* ── CARD ────────────────────────────────────────────────────────────
   .card supplies surface/border/radius/hover-lift + the skeleton's GSAP
   tilt hook. Flex column so the price/Buy footer pins to the bottom and
   cards in a row keep their footers aligned. */
.products-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.products-card .card-media {
  aspect-ratio: 4 / 3;
  background: #FFFFFF;
}
/* Studio photography fills the tile edge-to-edge (its own soft-gray set
   reads as the photo); white-background technical renders sit contained
   on white so the tile stays seamless. */
.products-card .card-media img {
  object-fit: cover;
}
.products-card.media-contain .card-media img {
  object-fit: contain;
  padding: 18px;
}
.products-card .card-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

/* Name (h4) left, SKU chip pinned top-right of the content. */
.products-card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}
.products-name {
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.25;
}
.products-card-top .chip-sku {
  flex: none;
  margin-top: 2px;
}
.products-oneliner {
  margin-top: 10px;
  font-size: 14.5px;
  color: var(--muted);
}
.products-sizes {
  margin-top: 14px;
  font-size: 13px;
  color: var(--muted);
}
.products-sizes a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--line-strong);
  transition: text-decoration-color .25s var(--ease-out);
}
.products-sizes a:hover { text-decoration-color: var(--text); }

.products-footer {
  margin-top: auto;          /* pin to the bottom of the card */
  padding-top: 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.products-price {
  font-weight: 500;          /* muted, medium weight */
  font-size: 14.5px;
  color: var(--muted);
}

/* ── FAMILY 3 — single WIDE card (image left 40% / content right) ────── */
.products-wide .card-media {
  aspect-ratio: 4 / 3;
  background: #FFFFFF;
}
@media (min-width: 720px) {
  .products-wide {
    display: grid;                          /* overrides the .products-card flex column */
    grid-template-columns: 40% 1fr;
    align-items: stretch;
  }
  .products-wide .card-media {
    aspect-ratio: auto;
    height: 100%;
    min-height: 340px;
  }
  .products-wide .card-body { padding: clamp(28px, 3.5vw, 44px); }
}

@media (max-width: 820px) {
  .products-group { margin-top: 56px; }
}

/* Screen-reader-only utility — the skeleton ships none; star ratings and
   the aggregate depend on it for their text equivalents. */
.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ==== fit ==== */

/* ════════════════════════════════════════════════════════════════════
   T8 — FIT & SIZING (scoped: .fit-)
   Light-alt band: header → three numbered step cards → split row with
   a sizing-table placeholder (left) and a snap-on video (right).
   Reveals, h2 split and card tilt come from the skeleton; only .fit-
   layout lives here. Video is routed through STRUXA.registerVideo.
   ════════════════════════════════════════════════════════════════════ */
.fit-head { max-width: 640px; }

/* ── STEP CARDS — numbered 01/02/03, .card supplies surface + tilt ───── */
.fit-steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  margin-top: 48px;
}
@media (min-width: 760px) {
  .fit-steps { grid-template-columns: repeat(3, 1fr); }
}
.fit-step-inner { padding: 28px 26px 30px; }
.fit-step-num {
  display: block;
  margin-bottom: 16px;
  font: 700 13px/1 var(--font-body);
  letter-spacing: .16em;
  /* Step number: solid deep technical teal (no gradient behind text). */
  color: var(--color-primary);
  -webkit-text-fill-color: currentColor;
}
.fit-step-inner h3 { font-size: 1.15rem; }
.fit-step-inner p {
  margin-top: 8px;
  font-size: 14.5px;
  color: var(--muted);
}

/* ── SPLIT ROW — sizing-table placeholder | snap-on video ────────────── */
.fit-detail {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
  margin-top: 28px;
  align-items: stretch;
}
@media (min-width: 901px) {
  .fit-detail { grid-template-columns: 1fr 1fr; }
}

/* Sizing-table placeholder: dashed hairline, centered "coming soon" copy. */
.fit-table {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 12px;
  min-height: 100%;
  padding: 44px 32px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
}
.fit-table h3 { font-size: 1.2rem; }
.fit-table p {
  max-width: 38ch;
  font-size: 14.5px;
  color: var(--muted);
}

/* Video panel: 16:9 rounded frame + muted caption below. */
.fit-video { margin: 0; }
.fit-video-frame {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  background: var(--bg-alt); /* graceful surface while the poster resolves */
}
.fit-video-frame video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.fit-video figcaption {
  margin-top: 12px;
  font-size: 12.5px;
  color: var(--muted);
}
@media (max-width: 820px) {
  .fit-steps { margin-top: 40px; }
}

/* ════════════════════════════════════════════════════════════════════
   INTERACTIVE SIZING TOOL (.fit-tool) — replaces the placeholder panel.
   Surface + hairline card matching .card; all data-driven from JS.
   ════════════════════════════════════════════════════════════════════ */
.fit-tool {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px 26px 30px;
}
.fit-tool h3 { font-size: 1.2rem; }
.fit-tool-instr {
  margin-top: 8px;
  font-size: 14.5px;
  color: var(--muted);
}

/* Input + unit toggle */
.fit-inputrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 20px;
}
.fit-input {
  flex: 1 1 140px;
  min-width: 120px;
  height: 52px;
  padding: 0 20px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  font: 500 16px/1.4 var(--font-body);
  transition: border-color .25s var(--ease-out);
}
.fit-input:hover { border-color: var(--text); }
.fit-unit {
  display: inline-flex;
  flex: none;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--bg-alt);
}
.fit-unit-btn {
  min-width: 46px;
  height: 44px;
  padding: 0 16px;
  border-radius: var(--radius-pill);
  font: 600 14px/1 var(--font-body);
  color: var(--muted);
  transition: color .2s var(--ease-out), background-color .2s var(--ease-out);
}
.fit-unit-btn.is-active { color: #fff; background-image: none; background-color: var(--color-primary); }

/* Live result readout */
.fit-readout {
  min-height: 26px;
  margin-top: 18px;
  font-size: 16px;
  color: var(--text);
}
.fit-readout b { font-weight: 700; }
.fit-readout-note {
  display: block;
  margin-top: 2px;
  font-size: 13.5px;
  color: var(--muted);
}
.fit-readout-msg { display: block; font-size: 14.5px; color: var(--text); }
.fit-readout a { color: var(--color-primary); text-decoration: underline; }

/* Size table (Size | mm | in) */
.fit-table-wrap {
  margin-top: 20px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.fit-sizes {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.fit-sizes th,
.fit-sizes td {
  text-align: left;
  padding: 10px 12px;
  white-space: nowrap;
  border-bottom: 1px solid var(--line);
}
.fit-sizes thead th {
  font: 600 11.5px/1.2 var(--font-body);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.fit-sizes tbody th {
  font-weight: 600;
  border-left: 3px solid transparent;
}
.fit-sizes tbody td { color: var(--muted); }
.fit-size-key {
  display: inline-block;
  margin-left: 4px;
  font-size: 11.5px;
  color: var(--muted);
}
.fit-sizes tbody tr.fit-row-active { background: rgba(0,107,120,.08); }
.fit-sizes tbody tr.fit-row-active th { border-left-color: var(--color-primary); }
.fit-sizes tbody tr.fit-row-active th,
.fit-sizes tbody tr.fit-row-active td { color: var(--text); }

/* Notes + print action */
.fit-note { margin-top: 16px; font-size: 13px; color: var(--muted); }
.fit-note-demo { font-weight: 600; color: var(--text); }
.fit-actions { margin-top: 20px; }
.fit-print-help { margin-top: 10px; font-size: 12.5px; color: var(--muted); }

/* ════════════════════════════════════════════════════════════════════
   PRINTABLE TO-SCALE SIZING CHART (.fit-print-guide)
   Hidden on screen; revealed only under @media print when the Print
   button adds body.fit-printing. Widths use mm so the ruler is to scale.
   ════════════════════════════════════════════════════════════════════ */
.fit-print-guide { display: none; }
.fit-pg-inner { color: #000; font-family: var(--font-body); }
.fit-pg-title { font-size: 20px; color: #000; }
.fit-pg-demo {
  margin-top: 4px;
  font: 700 12px/1.3 var(--font-body);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #000;
}
.fit-pg-block { margin-top: 16px; }
.fit-pg-block h3 { font-size: 13px; color: #000; }
.fit-pg-instr,
.fit-cal-label { margin-top: 4px; font-size: 11px; color: #000; }
/* Calibration bar — box-sizing:border-box (skeleton reset) makes 50mm the
   outer tick-to-tick width. Bracket shape via bottom + side borders. */
.fit-cal-bar {
  width: 50mm;
  height: 6mm;
  margin-top: 6px;
  border: 0.4mm solid #000;
  border-top: none;
}
.fit-pg-strip { margin-top: 6px; }
.fit-strip-svg { overflow: visible; }
.fit-zone { fill: #DCE7EB; stroke: #000; stroke-width: 0.2; }
.fit-zone-letter { font: 700 4px var(--font-body); fill: #000; }
.fit-axis { stroke: #000; stroke-width: 0.3; }
.fit-tick-major { stroke: #000; stroke-width: 0.35; }
.fit-tick-minor { stroke: #000; stroke-width: 0.18; }
.fit-tick-label { font: 400 2.6px var(--font-body); fill: #000; }
.fit-pg-table {
  width: 100%;
  margin-top: 6px;
  border-collapse: collapse;
  font-size: 11px;
  color: #000;
}
.fit-pg-table th,
.fit-pg-table td {
  text-align: left;
  padding: 3px 8px;
  border: 0.2mm solid #000;
}
.fit-pg-table thead th { background: #E3EDF0; }
.fit-pg-footer { margin-top: 14px; font-size: 9.5px; color: #000; }

/* ── PRINT ISOLATION ─────────────────────────────────────────────────
   Normal print (Cmd+P without the button): guide stays hidden.
   body.fit-printing (set by the Print button): hide the whole site and
   show only the to-scale guide. print-color-adjust keeps ruler ticks. */
@page { margin: 12mm; }
@media print {
  .fit-print-guide { display: none; }
  body.fit-printing {
    background: #fff;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  body.fit-printing .site-nav,
  body.fit-printing .site-footer,
  body.fit-printing .skip-link,
  body.fit-printing #main > section:not(#fit) { display: none !important; }
  body.fit-printing #fit { padding: 0 !important; background: #fff !important; }
  body.fit-printing #fit > .container {
    max-width: none !important;
    padding: 0 !important;
  }
  body.fit-printing #fit > .container > *:not(.fit-print-guide) { display: none !important; }
  body.fit-printing .fit-print-guide {
    display: block !important;
    position: static !important;
    left: auto !important;
    color: #000;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  body.fit-printing .fit-zone,
  body.fit-printing .fit-pg-table thead th {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}


/* ==== faq ==== */

/* ════════════════════════════════════════════════════════════════════
   T8 — FAQ (scoped: .faq-)
   Light band: header → seven native <details>/<summary> items.
   No JavaScript — open/close is native. Hairline dividers, question in
   Inter 600 with a rotating chevron, muted answer body. Focus ring and
   reveal/stagger entrance come from the skeleton.
   ════════════════════════════════════════════════════════════════════ */
.faq-head { max-width: 640px; }

.faq-list {
  margin-top: 44px;
  border-top: 1px solid var(--line);
}
.faq-item { border-bottom: 1px solid var(--line); }

/* Summary = the question row. Native marker removed; chevron added. */
.faq-q {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 4px;
  font: 600 16.5px/1.4 var(--font-body);
  letter-spacing: -0.005em;
  color: var(--text);
  cursor: pointer;
}
.faq-q::-webkit-details-marker { display: none; } /* Safari default triangle */
.faq-q::after {
  content: "";
  flex: none;
  width: 15px;
  height: 15px;
  background-color: var(--muted);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform .3s var(--ease-out);
}
.faq-item[open] .faq-q::after { transform: rotate(180deg); }
.faq-item[open] .faq-q { color: var(--text); }
.faq-q:hover { color: var(--text); }
.faq-q:hover::after { background-color: var(--text); }

.faq-a { padding: 0 4px 24px; }
.faq-a p {
  max-width: 68ch;
  font-size: 15px;
  color: var(--muted);
}
.faq-a p + p { margin-top: 12px; }
.faq-a ul {
  max-width: 68ch;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.faq-a li {
  position: relative;
  padding-left: 18px;
  font-size: 15px;
  color: var(--muted);
  line-height: 1.6;
}
/* Gradient tick marker — sanctioned small accent (light section). */
.faq-a li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .62em;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--color-primary);
}
.faq-a li b, .faq-a li strong { color: var(--text); font-weight: 600; }
.faq-a a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
}


/* ==== about ==== */

/* ════════════════════════════════════════════════════════════════════
   T8 — ABOUT (scoped: .about-)
   Quiet ink strip (~60% of normal section padding) over a dimmed
   hand-closeup photo. The scrim is opaque enough (≥.82) that light text
   clears 4.5:1 over any frame of the image. Content is centered and
   capped at 680px. No JavaScript.
   ════════════════════════════════════════════════════════════════════ */
/* ==== contact ==== */

.contact-head { margin-bottom: 44px; }
/* ════════════════════════════════════════════════════════════════════
   T8 — NEWSLETTER + CONTACT (scoped: .contact-)
   Light band, split into a newsletter sign-up (left) and a get-in-touch
   block (right); stacks ≤900px. The form is inert until wired — the
   handler only prevents the default submit and swaps in a success note.
   Field styling (pill input, btn) comes from the skeleton.
   ════════════════════════════════════════════════════════════════════ */
.contact-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
}
@media (min-width: 901px) {
  .contact-grid {
    grid-template-columns: 1.1fr 0.9fr;
    gap: 64px;
    align-items: start;
  }
}
.contact-col h2,
.contact-col h3 {
  font-size: clamp(1.4rem, 2.4vw, 1.9rem);
  letter-spacing: -0.015em;
}
.contact-body {
  margin-top: 14px;
  max-width: 46ch;
  font-size: 16.5px;
  color: var(--muted);
}

/* Newsletter form: pill email input beside the submit; wraps on mobile. */
.contact-form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 24px;
}
.contact-form .field { flex: 1 1 240px; }

/* Web3Forms honeypot. It has to stay in the DOM and be submitted, but it had no
   rule anywhere, so the bare checkbox rendered beside the email label. */
.cform-hp {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

/* The submit sits beside a label+input column, so the flex default of
   align-items:stretch made it as tall as label AND input together. Bottom-align
   it and pin it to the input's own 52px so the two pills read as one control. */
.contact-form { align-items: flex-end; }
.contact-form .btn { flex: none; height: 52px; padding-top: 0; padding-bottom: 0; }

.contact-success {
  margin-top: 24px;
  font: 500 16.5px/1.5 var(--font-body);
  color: var(--text);
}
.contact-success[hidden] { display: none; }

/* Consent line under the signup field. Required by CAN-SPAM/GDPR practice: say what
   they're subscribing to, and that leaving is one click. */
.contact-consent {
  margin-top: 12px;
  font: 400 13.5px/1.55 var(--font-body);
  color: var(--muted);
  max-width: 52ch;
}
.contact-consent a { color: inherit; text-decoration: underline; }
.contact-consent a:hover { color: var(--color-primary); }

.contact-error {
  margin-top: 24px;
  font: 500 16.5px/1.5 var(--font-body);
  color: var(--color-error, #A8321F);
}
.contact-error[hidden] { display: none; }
.contact-error a { color: inherit; }

/* Submit button while the request is in flight. */
.contact-form .btn[aria-busy="true"] { opacity: .65; pointer-events: none; }

.contact-get a {
  color: var(--text);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 2px;
}



/* ==== multi-page nav/footer additions ==== */
.wordmark-logo { flex: none; width: 20px; height: auto; display: block; }
.site-footer .wordmark-logo { width: 22px; }
@media (min-width: 901px) { .footer-top { grid-template-columns: 1.2fr 3fr; } } /* desktop only, so the ≤900 stack wins */
.footer-brand { max-width: 320px; }
.footer-cols { grid-template-columns: repeat(4, minmax(0,1fr)); gap: 24px; }
.footer-addr { font-style: normal; font-size: 14.5px; line-height: 1.7; color: var(--text); margin-top: 14px; }
@media (max-width: 900px) { .footer-cols { grid-template-columns: repeat(2, minmax(0,1fr)); gap: 28px 22px; } }
@media (max-width: 520px) {
  .site-footer { padding: 46px 0 28px; }
  .footer-cols { gap: 22px 16px; }          /* stays 2-up — no full-width single-column stacking */
  .footer-col h3 { margin-bottom: 12px; }
  .footer-col ul { gap: 9px; }
  .footer-tagline { margin-top: 14px; }
  .footer-brand { max-width: none; }
}
.nav-links a { white-space: nowrap; }
/* active nav link */
.nav-links a[aria-current="page"] { color: var(--text); }
.nav-links a[aria-current="page"]::after { transform: scaleX(1); }

/* ════════════════════════════════════════════════════════════════════
   BLOG — listing (/blog/index.html) + article pages (/blog/<slug>.html)
   ════════════════════════════════════════════════════════════════════ */
.blog-head { max-width: 60ch; }
.blog-head .section-intro { margin-top: 16px; }

/* ── listing grid ── */
.blog-grid {
  margin-top: clamp(32px, 5vw, 56px);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 2.4vw, 30px);
}
@media (max-width: 900px) { .blog-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .blog-grid { grid-template-columns: 1fr; } }

.blog-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: transform .5s var(--ease-out), box-shadow .5s var(--ease-out), border-color .5s var(--ease-out);
}
.blog-card:hover {
  transform: translateY(-4px);
  border-color: var(--line-strong);
  box-shadow: 0 18px 40px -30px rgba(13,46,61,.5);
}
.blog-card-media { aspect-ratio: 16 / 10; overflow: hidden; background: var(--bg-alt); }
.blog-card-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .6s var(--ease-out); }
.blog-card:hover .blog-card-media img { transform: scale(1.04); }
.blog-card-body { padding: 20px 22px 24px; display: flex; flex-direction: column; flex: 1; }
.blog-card-title { font: 600 1.18rem/1.28 var(--font-display); color: var(--ink); margin: 12px 0 8px; letter-spacing: -.01em; }
.blog-card-dek { color: var(--muted); font-size: .95rem; line-height: 1.55; margin: 0 0 16px; }
.blog-card-meta { margin-top: auto; font-size: .8rem; color: var(--muted); display: flex; gap: 8px; align-items: center; }
.blog-card-meta .dot { width: 3px; height: 3px; border-radius: var(--radius-pill); background: currentColor; opacity: .5; }

/* category chip (shared listing + article) */
.blog-cat {
  display: inline-flex; align-self: flex-start; align-items: center;
  font: 600 .7rem/1 var(--font-body); letter-spacing: .1em; text-transform: uppercase;
  color: var(--color-primary-dark); background: var(--color-primary-light);
  padding: 5px 10px; border-radius: var(--radius-pill);
}

/* featured (first) card spans full width, horizontal on desktop */
.blog-card.is-featured { grid-column: 1 / -1; }
@media (min-width: 760px) {
  .blog-card.is-featured { flex-direction: row; }
  .blog-card.is-featured .blog-card-media { flex: 0 0 52%; aspect-ratio: auto; }
  .blog-card.is-featured .blog-card-body { justify-content: center; padding: clamp(28px, 4vw, 48px); }
  .blog-card.is-featured .blog-card-title { font-size: clamp(1.5rem, 2.4vw, 2rem); }
  .blog-card.is-featured .blog-card-dek { font-size: 1.02rem; }
}

/* ── article page ── */
.post-wrap { max-width: 760px; margin: 0 auto; }
.post-back { display: inline-flex; align-items: center; gap: 7px; font-size: .9rem; color: var(--muted); text-decoration: none; margin-bottom: 22px; transition: color .3s var(--ease-out); }
.post-back:hover { color: var(--ink); }
/* Nudge the arrow with a transform, not `gap` - gap animation forces layout. */
.post-back .post-back-arrow, .post-back svg { transition: transform .3s var(--ease-out); }
.post-back:hover .post-back-arrow, .post-back:hover svg { transform: translateX(-3px); }
.post-header { margin-bottom: clamp(24px, 3vw, 34px); }
.post-title { font: 700 clamp(1.9rem, 4.2vw, 3rem) / 1.1 var(--font-display); letter-spacing: -.02em; color: var(--ink); margin: 16px 0 0; }
.post-dek { font-size: clamp(1.05rem, 1.6vw, 1.28rem); line-height: 1.5; color: var(--muted); margin: 16px 0 0; max-width: 62ch; }
.post-byline { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin-top: 20px; font-size: .86rem; color: var(--muted); }
.post-byline .dot { width: 3px; height: 3px; border-radius: var(--radius-pill); background: currentColor; opacity: .5; }
.post-hero { margin: clamp(24px, 3.5vw, 40px) 0; border-radius: var(--radius); overflow: hidden; background: var(--bg-alt); border: 1px solid var(--line); }
.post-hero img { width: 100%; height: auto; display: block; }
.post-hero figcaption { padding: 10px 16px; font-size: .8rem; color: var(--muted); background: var(--surface); border-top: 1px solid var(--line); }

/* Measure cap. .post-wrap stays 760px for the header, hero figure and footer;
   only the running text is held to a readable line length, matching .post-dek. */
.post-body { font-size: 1.06rem; line-height: 1.72; color: var(--text); max-width: 65ch; }
.post-body > p { margin: 0 0 1.25em; }
.post-body > p:first-child { font-size: 1.14rem; color: var(--ink); }        /* lede */
.post-h2 { font: 600 clamp(1.3rem, 2.2vw, 1.6rem)/1.25 var(--font-display); color: var(--ink); letter-spacing: -.01em; margin: 1.8em 0 .6em; }
.post-list { margin: 0 0 1.25em; padding-left: 1.25em; }
.post-list li { margin: 0 0 .5em; padding-left: .25em; }
.post-list li::marker { color: var(--color-primary); }
.post-pull {
  margin: 1.6em 0; padding: 4px 0 4px 22px;
  border-left: 3px solid transparent; border-image: var(--grad) 1;
  font: 500 clamp(1.15rem, 2vw, 1.4rem)/1.4 var(--font-display); color: var(--ink);
}
.post-note { margin-top: 2.2em; padding: 16px 18px; background: var(--bg-alt); border: 1px solid var(--line); border-radius: var(--radius); font-size: .92rem; color: var(--muted); }

.post-end { margin-top: clamp(36px, 5vw, 56px); padding-top: 28px; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 18px; align-items: center; justify-content: space-between; }
.post-end .post-cta-text { font: 600 1.1rem/1.3 var(--font-display); color: var(--ink); margin: 0; }
.post-end .post-cta-sub { font-size: .9rem; color: var(--muted); margin: 4px 0 0; }

/* homepage "From the journal" teaser head (heading left, All-posts link right) */
.home-journal-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 18px 24px; flex-wrap: wrap; margin-bottom: clamp(28px, 4vw, 44px); }
.home-journal-head > div { min-width: 0; }
.home-journal-head .section-h { margin-bottom: 0; }
.home-journal-all { flex: none; margin-bottom: 4px; }
#home-journal .blog-grid { margin-top: 0; }
@media (max-width: 560px) { .home-journal-all { width: 100%; justify-content: center; } }

/* ════════════════════════════════════════════════════════════════════
   SHOP / CART (Shopify Buy Button SDK integration — struxa-shop.js)
   The nav cart icon + badge, the product-card add-to-cart mount, and the
   overrides for the SDK's light-DOM parts (product selects + toggle). The
   cart button ships hidden (attribute) and is revealed by JS only once the
   SDK cart is live — pure progressive enhancement.
   ════════════════════════════════════════════════════════════════════ */
.nav-cart {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  flex: none;
  border: 0;
  background: transparent;
  color: var(--text);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color .3s var(--ease-out), transform .15s var(--ease-out);
}
.nav-cart[hidden] { display: none; }
.nav-cart svg { width: 22px; height: 22px; }
.nav-cart:hover { color: var(--ink); }
.nav-cart:active { transform: translateY(1px); }
.nav-cart:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* count badge — gradient pill, top-right, only shown when the cart has items */
.nav-cart-count {
  position: absolute;
  top: 1px; right: -1px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  display: none;
  align-items: center; justify-content: center;
  font: 600 11px/1 var(--font-body);
  color: #fff;
  background: var(--color-primary);
  border-radius: var(--radius-pill);
  box-shadow: 0 0 0 2px var(--surface);
}
.nav-cart.has-items .nav-cart-count { display: inline-flex; }

/* Mobile (≤820px): the nav-menu is off-canvas, so group the cart + hamburger
   on the right as [cart][hamburger] (cart to the left). margin-left:auto sits
   on the cart (moved off the toggle); order puts the cart before the toggle. */
@media (max-width: 1024px) {
  .nav-cart   { order: 1; margin-left: auto; }
  .nav-toggle { order: 2; margin-left: 0; }
}

/* Product-card add-to-cart mount. Empty (pre-render) → collapse so the footer
   shows only the fallback Shop link + price. Once the SDK renders, is-sdk-live
   hides the fallback and the mount (now non-empty) takes over. */
.products-footer { flex-wrap: wrap; }
.shop-mount { flex: 1 0 100%; margin-top: 2px; }
.shop-mount:empty { display: none; }
/* Once the SDK is live the standalone 'Shop' fallback link is redundant, so it
   is hidden. Scoped to that link specifically: it used to hide EVERY <a class=btn>
   in the footer, which silently swallowed the 'View product page' button added
   2026-08-18. */
.products-footer.is-sdk-live > a.products-fallback-link { display: none; }
/* Keep the authored "From $X" price visible even when the SDK card renders —
   the card is mounted with price:false, so this static span is the only price. */

/* ════════════════════════════════════════════════════════════════════
   QUICK-SHOP — "Select options" reveal on the catalog cards.
   Clean card by default (no selectors, no static variant preview); the SDK's
   own option <select>s + Add-to-cart live inside an animated panel that the
   "Select options" button expands. Progressive enhancement: with JS off the
   static "Shop" link stays; the button + panel are JS-revealed by
   assets/struxa-quickshop.js.
   ════════════════════════════════════════════════════════════════════ */

/* Clean card: never show the static, non-interactive variant preview. */
.products-card .products-variants { display: none; }

/* Default → fallback "Shop" link visible; the "Select options" button is
   [hidden] in markup. quickshop.js adds .qs-ready → swap link for button. */
.products-select-btn { margin-right: auto; }               /* push price to the right, like the link */
.products-footer.qs-ready > .products-fallback-link { display: none; }
.products-footer.qs-ready > .products-select-btn[hidden] { display: none; } /* honour [hidden] until JS clears it */

/* Caret flips when the panel is open. */
.products-select-caret { display: inline-block; font-size: .85em; line-height: 1; transition: transform .3s var(--ease-out); }
.products-footer.is-open .products-select-caret { transform: rotate(180deg); }

/* The animated panel — collapsed by default. visibility:hidden takes the
   revealed <select>s out of the tab order while closed. */
.products-quickshop {
  flex: 1 0 100%;
  overflow: hidden;
  max-height: 0;
  margin-top: 0;
  opacity: 0;
  visibility: hidden;
  transition:
    max-height .42s var(--ease-out),
    margin-top .42s var(--ease-out),
    opacity .28s var(--ease-out),
    visibility 0s linear .42s;
}
.products-footer.is-open .products-quickshop {
  max-height: 40rem;
  margin-top: 14px;
  opacity: 1;
  visibility: visible;
  transition:
    max-height .42s var(--ease-out),
    margin-top .42s var(--ease-out),
    opacity .3s var(--ease-out) .06s,
    visibility 0s;
}

/* Brief loading affordance while the SDK mounts its selects into the panel. */
.products-quickshop.is-loading::before {
  content: "Loading options…";
  display: block;
  font: 500 13px/1.6 var(--font-body);
  color: var(--muted);
}
.products-quickshop-pdp {
  display: inline-block;
  margin-top: 10px;
  font: 500 13px/1.5 var(--font-body);
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--line-strong);
  position: relative; z-index: 2;
  transition: text-decoration-color .25s var(--ease-out);
}
.products-quickshop-pdp:hover { text-decoration-color: var(--text); }

/* No-option products: nothing to configure → drop the toggle and show the
   SDK's Add-to-cart inline (panel stays open, un-clipped). */
.products-footer.qs-no-options > .products-select-btn { display: none; }
.products-footer.qs-no-options > .products-fallback-link { display: none; }
.products-footer.qs-no-options .products-quickshop {
  max-height: none; margin-top: 12px; opacity: 1; visibility: visible; overflow: visible;
  transition: none;
}

/* Reduced motion: no height/opacity animation — just show/hide instantly. */
@media (prefers-reduced-motion: reduce) {
  .products-quickshop { transition: none !important; }
  .products-footer.is-open .products-quickshop { transition: none !important; }
  .products-select-caret { transition: none !important; }
}


/* Style the SDK product's light-DOM variant <select>s + button (product uses
   iframe:false). The cart's own Checkout button lives inside frame-cart (an
   iframe) and is styled via the SDK options, so these rules can't reach it. */
.shopify-buy__product { margin: 0 !important; }
.shopify-buy__product .shopify-buy__btn,
.products-footer .shopify-buy__btn {
  background: var(--color-primary) !important;
  background-color: var(--color-primary) !important;   /* solid teal, no gradient behind text */
  color: #fff !important;
  border: 0 !important;
  border-radius: var(--radius-pill) !important;
  font: 600 14px/1.1 var(--font-body) !important;
  padding: 12px 22px !important;
  cursor: pointer;
  transition: transform .25s var(--ease-out) !important;
}
.shopify-buy__product .shopify-buy__btn:hover,
.products-footer .shopify-buy__btn:hover { transform: translateY(-2px) !important; }
/* Tactile press on the most important control on the site. Without this the
   button stays lifted through the click, so the primary purchase action is the
   one control with no press feedback. */
.shopify-buy__product .shopify-buy__btn:active,
.products-footer .shopify-buy__btn:active {
  transform: translateY(0) !important;
  background-color: var(--color-primary-pressed) !important;
}
.shopify-buy__btn-wrapper { margin-top: 6px !important; }
.shopify-buy__option-select { margin-bottom: 10px !important; }
.shopify-buy__option-select__label {
  font-family: var(--font-body) !important;
  font-size: 12.5px !important;
  color: var(--muted) !important;
  letter-spacing: .01em;
}
.shopify-buy__option-select__select {
  font-family: var(--font-body) !important;
  font-size: 14px !important;
  color: var(--text) !important;
  background-color: var(--surface) !important;
  border: 1px solid rgba(13,46,61,.18) !important;
  border-radius: var(--radius-sm) !important;
  padding: 9px 12px !important;
  -webkit-appearance: menulist !important;   /* use the native dropdown arrow */
  appearance: menulist !important;
  height: auto !important;
}
/* With iframe:false the SDK doesn't inject its caret-sizing CSS, so its custom
   dropdown-caret SVG renders full-size — hide it; the native arrow (above) is used. */
.shopify-buy__option-select-wrapper svg,
.shopify-buy__select-icon-wrapper,
.shopify-buy__select-icon { display: none !important; }
.shopify-buy__option-select-wrapper { position: relative; }

/* Off-screen host for the hidden bootstrap product (which spins up the shared
   cart + toggle). Rendered, just parked out of view. */
.struxa-cart-host {
  position: absolute !important;
  width: 1px; height: 1px;
  left: -9999px; top: auto;
  overflow: hidden;
}
/* Hide the SDK's floating cart tab (its main-doc wrapper, frame-toggle) — we
   drive the cart from the nav icon. Kept RENDERED (not display:none) so its
   inner toggle button stays clickable as the open trigger. */
.shopify-buy-frame--toggle,
.shopify-buy__cart-toggle {
  position: fixed !important;
  left: -9999px !important;
  top: 0 !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* ════════════════════════════════════════════════════════════════════
   NAV — account icon (person). Sits at the far right of .nav-inner, after
   the cart. Always visible (unlike the cart, which reveals with the SDK).
   ════════════════════════════════════════════════════════════════════ */
.nav-account {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: none;
  color: var(--text); border-radius: var(--radius-sm);
  text-decoration: none;
  transition: color .3s var(--ease-out), transform .15s var(--ease-out);
}
.nav-account svg { width: 22px; height: 22px; }
.nav-account:hover { color: var(--ink); }
.nav-account:active { transform: translateY(1px); }
.nav-account:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
@media (min-width: 1025px) {
  /* Desktop: group the trailing account + cart into one cohesive cluster.
     The 40px .nav-inner gap keeps the cluster clearly separated from the nav;
     this pulls the pair tight together (≈10px) only while both are present. */
  .nav-cart:not([hidden]) + .nav-account { margin-left: -30px; }
}
@media (max-width: 1024px) {
  /* Always-visible account icon anchors the right cluster: [account][cart][hamburger] */
  .nav-account { order: 1; margin-left: auto; }
  .nav-cart    { order: 2; margin-left: 0; }
  .nav-toggle  { order: 3; margin-left: 0; }
}

/* ════════════════════════════════════════════════════════════════════
   PRODUCT CARDS — make the whole card (except Add-to-cart) open the PDP.
   A stretched-link overlay covers the card; interactive children sit above.
   ════════════════════════════════════════════════════════════════════ */
.products-card.is-linked { position: relative; }
.products-card .products-cardlink {
  position: absolute; inset: 0; z-index: 1;
  border-radius: inherit;
  text-indent: -9999px; overflow: hidden; white-space: nowrap;
}
.products-card.is-linked .card-media,
.products-card.is-linked .products-name { cursor: pointer; }
.products-card.is-linked .card-media img { transition: transform .5s var(--ease-out); }
.products-card.is-linked:hover .card-media img { transform: scale(1.03); }
.products-card.is-linked .products-name { transition: color .25s var(--ease-out); }
.products-card.is-linked:hover .products-name { color: #006B78; }
/* keep the buy controls above the stretched link; everything else (media,
   name, one-liner, variant swatches) sits under it → clicking there opens the PDP */
.products-card .products-footer { position: relative; z-index: 2; }

/* ════════════════════════════════════════════════════════════════════
   PRODUCT DETAIL PAGE (.pdp-*) — sticky gallery (left) + buy box (right),
   then full-width Overview / Technical / In-The-Box tabs.
   ════════════════════════════════════════════════════════════════════ */
#pdp { padding-top: calc(var(--nav-h) + 24px); }
.pdp-breadcrumb {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-size: .85rem; color: var(--muted); margin-bottom: 22px;
}
.pdp-breadcrumb a { color: var(--muted); text-decoration: none; }
.pdp-breadcrumb a:hover { color: var(--ink); }
.pdp-breadcrumb .sep { opacity: .5; }
.pdp-breadcrumb .cur { color: var(--text); }

.pdp-top { display: grid; grid-template-columns: 1fr; gap: clamp(28px, 4vw, 56px); align-items: start; }
@media (min-width: 900px) { .pdp-top { grid-template-columns: minmax(0,1.15fr) minmax(340px,.85fr); } }

/* ── Gallery (left) ── */
.pdp-gallery { position: relative; min-width: 0; } /* min-width:0 or this grid child refuses to shrink and the PDP scrolls sideways */
@media (min-width: 900px) { .pdp-gallery { position: sticky; top: calc(var(--nav-h) + 20px); } }
.pdp-stage {
  position: relative; aspect-ratio: 4 / 3; width: 100%;
  background: #FFFFFF; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden;
}
.pdp-panel { position: absolute; inset: 0; opacity: 0; visibility: hidden; transition: opacity .4s var(--ease-out); }
.pdp-panel.is-active { opacity: 1; visibility: visible; }
.pdp-panel img, .pdp-panel video { width: 100%; height: 100%; object-fit: contain; display: block; }
.pdp-stage.media-cover .pdp-panel img { object-fit: cover; }
/* the 3D stage panel reuses .explore-stage inside */
.pdp-panel--3d .explore-stage { width: 100%; height: 100%; background: #FFFFFF; }
/* variant render gallery — tasteful crossfade when the colourway/fit swaps the
   main image in place (view-to-view switches already crossfade via the panel). */
.pdp-panel img { transition: opacity .35s var(--ease-out); }
.pdp-panel img.is-swapping { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .pdp-panel, .pdp-panel img { transition: none; }
  .pdp-panel img.is-swapping { opacity: 1; }
}

/* Hotspot callouts (the "1080W …" bubbles) */
.pdp-hotspot { position: absolute; z-index: 3; }
.pdp-hotspot-dot {
  width: 14px; height: 14px; border-radius: var(--radius-pill);
  background: var(--color-primary); box-shadow: 0 0 0 4px rgba(35,211,227,.35);
  cursor: pointer; border: 0; padding: 0;
  position: relative;
}
/* The dot stays 14px for the visual design, but a bare 14px target fails the
   44px minimum. This pseudo-element enlarges the HIT AREA only. */
.pdp-hotspot-dot::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.pdp-hotspot-card {
  position: absolute; width: 220px; max-width: 60vw;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 18px 40px -26px rgba(13,46,61,.5);
  padding: 14px 16px; opacity: 0; transform: translateY(4px); pointer-events: none;
  transition: opacity .3s var(--ease-out), transform .3s var(--ease-out);
}
/* right-half hotspots open their card leftward so it can't clip off the stage
   (the stage is overflow:hidden). Add .pdp-hotspot--left to any dot past ~50%. */
.pdp-hotspot--left .pdp-hotspot-card { left: auto !important; right: 22px; }
.pdp-hotspot:hover .pdp-hotspot-card,
.pdp-hotspot:focus-within .pdp-hotspot-card,
.pdp-hotspot.is-open .pdp-hotspot-card { opacity: 1; transform: none; pointer-events: auto; }
.pdp-hotspot-card h4,
.pdp-hotspot-card .pdp-hotspot-title { font: 600 .95rem/1.3 var(--font-display); color: var(--ink); margin: 0 0 4px; }
.pdp-hotspot-card p { font-size: .85rem; line-height: 1.5; color: var(--muted); margin: 0; }
/* Narrow phones: a 220px card can't sit beside a near-centre dot on a ~320-440px
   stage (either side clips). Center the callout on its dot and cap the width so it
   always stays inside the stage — for any hotspot, regardless of left/right side. */
@media (max-width: 480px) {
  .pdp-hotspot-card {
    left: 50% !important; right: auto !important;
    transform: translateX(-50%) translateY(4px);
    width: 54vw; max-width: 240px; padding: 12px 14px;
  }
  .pdp-hotspot:hover .pdp-hotspot-card,
  .pdp-hotspot:focus-within .pdp-hotspot-card,
  .pdp-hotspot.is-open .pdp-hotspot-card { transform: translateX(-50%); }
  .pdp-hotspot-card h4,
  .pdp-hotspot-card .pdp-hotspot-title { font-size: .9rem; }
  .pdp-hotspot-card p { font-size: .8rem; }
}

/* feature caption row under the stage */
.pdp-featurerow {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 18px;
  margin-top: 18px; font-size: .82rem; color: var(--muted); text-align: center;
}
.pdp-featurerow span { position: relative; }
.pdp-featurerow span + span::before { content: "·"; position: absolute; left: -11px; opacity: .5; }
/* Config readout: muted nudge shown until the shopper actively picks a colour.
   No opacity - compositing .82rem --muted at .65 dropped it to 2.79:1, and this
   is the only prompt telling the shopper a colourway is still unselected.
   Italic alone carries "not yet chosen" at the full 6.09:1. */
.pdp-featurerow .is-placeholder { font-style: italic; }

/* photo / 3D toggle */
.pdp-toggle {
  display: inline-flex; gap: 2px; margin: 16px auto 0; padding: 4px;
  background: var(--bg-alt); border: 1px solid var(--line); border-radius: var(--radius-pill);
  width: fit-content;
}
.pdp-toggle-row { display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; }
/* .pdp-toggle centers itself with `margin: 16px auto 0` when it stands alone. Inside
   the flex row those auto side margins would eat all the free space before
   justify-content ran, spreading the view and roll groups apart instead of keeping
   them one centered cluster — so drop them here only. */
.pdp-toggle-row .pdp-toggle { margin-inline: 0; }
/* The toggles are script-driven; without JS they would be dead controls. */
html:not(.js) .pdp-toggle-row { display: none; }
.pdp-toggle-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  min-height: 44px; padding: 7px 14px; border-radius: var(--radius-pill);
  font: 600 .82rem/1 var(--font-body);
  transition: background .3s var(--ease-out), color .3s var(--ease-out);
}
.pdp-toggle-btn svg { width: 18px; height: 18px; }
.pdp-toggle-btn.is-active { background: var(--ink); color: #fff; }

/* thumbnail strip */
.pdp-thumbs { display: flex; gap: 10px; margin-top: 16px; overflow-x: auto; padding-bottom: 4px; -webkit-overflow-scrolling: touch; }
.pdp-thumb {
  flex: 0 0 auto; width: 72px; height: 62px; padding: 0;
  border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden;
  background: #FFFFFF; cursor: pointer; transition: border-color .25s var(--ease-out);
}
.pdp-thumb img, .pdp-thumb video { width: 100%; height: 100%; object-fit: cover; display: block; }
.pdp-thumb.is-active { border-color: var(--ink); }
.pdp-thumb.is-video { position: relative; }
.pdp-thumb.is-video::after { content: "▶"; position: absolute; inset: 0; display: grid; place-items: center; color: #fff; font-size: 12px; text-shadow: 0 1px 3px rgba(0,0,0,.5); }

/* ── Buy box (right) ── */
.pdp-buy { min-width: 0; }
.pdp-title { font: 700 clamp(1.7rem, 3vw, 2.4rem)/1.08 var(--font-display); letter-spacing: -.02em; color: var(--ink); margin: 0; }
/* Flagship support-tier eyebrow + translated clinical descriptor */
.pdp-tier { margin-bottom: 10px; }
.pdp-clinical { margin-top: 10px; font-size: 14.5px; line-height: 1.6; color: var(--color-text-secondary); }

.pdp-sku { font-family: ui-monospace,"SF Mono",Menlo,Consolas,monospace; font-size: .82rem; color: var(--muted); margin: 6px 0 0; }
.pdp-price { font: 600 1.5rem/1 var(--font-display); color: var(--ink); margin: 16px 0 0; }
.pdp-price small { font-size: .95rem; font-weight: 500; color: var(--muted); }
.pdp-desc { margin: 18px 0 0; font-size: 1rem; line-height: 1.6; color: var(--text); max-width: 46ch; }
.pdp-hr { height: 1px; background: var(--line); border: 0; margin: 22px 0; }

/* care / add-on info card */
.pdp-care { border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; margin: 22px 0 0; background: var(--surface); }
.pdp-care-head { display: flex; align-items: center; gap: 10px; }
.pdp-care-head strong { font: 600 1rem/1.2 var(--font-display); color: var(--ink); }
.pdp-care-badge { font: 600 .68rem/1 var(--font-body); letter-spacing: .08em; text-transform: uppercase; color: var(--color-primary-dark); background: var(--color-primary-light); padding: 4px 9px; border-radius: var(--radius-pill); }
.pdp-care ul { margin: 12px 0 0; padding-left: 18px; }
.pdp-care li { font-size: .9rem; color: var(--muted); margin: 0 0 4px; }

/* the SDK add-to-cart mount + fallback */
.pdp-buybox { margin: 22px 0 0; }
.pdp-buybox .pdp-fallback { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.pdp-buybox.is-sdk-live .pdp-fallback { display: none; }
.pdp-buybox .shop-mount:empty { display: none; }
/* "Coming soon" state — replaces the buy box for a paused product */
.pdp-comingsoon { margin: 22px 0 0; padding: 18px 20px; border: 1px solid var(--line-strong); border-radius: var(--radius); background: var(--bg-alt); }
.pdp-comingsoon-lead { margin: 0; font-size: 1.05rem; }
.pdp-comingsoon-sub { margin: 8px 0 0; color: var(--muted); font-size: 0.95rem; }
.products-comingsoon-chip { display: inline-flex; align-items: center; padding: 6px 12px; border-radius: var(--radius-pill); background: var(--bg-alt); border: 1px solid var(--line-strong); color: var(--muted); font: 600 13px/1 var(--font-display); }
.home-lineup-soon { position: absolute; top: 12px; left: 12px; padding: 4px 10px; border-radius: var(--radius-pill); background: rgba(13,46,61,.82); color: #fff; font: 600 11px/1 var(--font-display); letter-spacing: .04em; }

/* ── Two-tone colour swatch dots (assets/pdp-swatches.js) ──────────────────
   A radiogroup of dots that drives the SDK's native Color <select>. Each dot
   shows the lattice hex with the strap hex as a diagonal accent (set inline in
   JS) so two-tone colourways (Ember vs Onyx, Frost vs Sand) stay distinct. */
.pdp-swatches { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0 4px; }
.pdp-swatch {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  /* 34px visual, 44px hit area: the extra 5px is transparent border, so the dots
     still read at 34px and sit on the same 10px rhythm. */
  width: 34px; height: 34px; padding: 3px; margin: 0;
  position: relative;
  border-radius: 50%; border: 1px solid var(--line);
  background: var(--surface);
  display: inline-flex; align-items: center; justify-content: center;
  transition: box-shadow .2s var(--ease-out), transform .2s var(--ease-out);
}
.pdp-swatch__dot {
  width: 100%; height: 100%; border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(13,46,61,.14);
}
.pdp-swatch.is-light .pdp-swatch__dot { box-shadow: inset 0 0 0 1px var(--line-strong); }
.pdp-swatch::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.pdp-swatch:hover { transform: translateY(-1px); border-color: var(--line-strong); }
/* Selected colourway: deep-ocean ring. Selection is never colour-alone — the
   ring is a shape change and the control also exposes aria-checked. */
.pdp-swatch.is-active { border-color: var(--color-secondary); box-shadow: 0 0 0 2px var(--color-secondary); }
.pdp-swatch:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .pdp-swatch { transition: none; } }

/* related products / accessories */
.pdp-accessories { margin: 30px 0 0; }
.pdp-accessories h3 { font: 600 1rem/1.3 var(--font-display); color: var(--ink); margin: 0 0 14px; }
/* One cell per item. Both PDPs currently ship a single accessory, so a hard
   1fr 1fr left a permanent empty half; the :has() rule restores two columns
   the moment a second child exists. */
.pdp-acc-grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
.pdp-acc-grid:has(> :nth-child(2)) { grid-template-columns: 1fr 1fr; }
.pdp-acc {
  display: flex; gap: 12px; align-items: center; padding: 12px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
  text-decoration: none; color: inherit; transition: border-color .25s var(--ease-out), transform .3s var(--ease-out);
}
.pdp-acc:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.pdp-acc img { width: 54px; height: 54px; object-fit: cover; border-radius: var(--radius-sm); flex: none; background: var(--bg-alt); }
.pdp-acc-name { font: 600 .9rem/1.25 var(--font-body); color: var(--ink); }
.pdp-acc-price { font-size: .82rem; color: var(--muted); margin-top: 2px; }

/* ── Tabs (full width) ── */
.pdp-tabs { margin-top: clamp(48px, 6vw, 84px); }
.pdp-tabnav {
  display: flex; gap: clamp(20px, 4vw, 44px); justify-content: center;
  border-bottom: 1px solid var(--line); position: sticky; top: var(--nav-h); background: var(--bg); z-index: 4;
  overflow-x: auto;
}
.pdp-tab {
  border: 0; background: transparent; cursor: pointer;
  padding: 16px 2px; font: 600 1rem/1 var(--font-body); color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
  transition: color .25s var(--ease-out), border-color .25s var(--ease-out);
}
.pdp-tab:hover { color: var(--text); }
.pdp-tab.is-active { color: var(--ink); border-bottom-color: var(--color-primary); }
.pdp-tabpanel { display: none; padding-top: clamp(32px, 5vw, 56px); }
.pdp-tabpanel.is-active { display: block; }

/* Overview panel — stacked hero blocks */
.pdp-ov-hero { border-radius: var(--radius); overflow: hidden; background: var(--bg-alt); border: 1px solid var(--line); margin-bottom: 20px; }
.pdp-ov-hero img, .pdp-ov-hero video { width: 100%; height: auto; display: block; }
.pdp-ov-duo { display: grid; grid-template-columns: 1fr; gap: 20px; }
@media (min-width: 720px) { .pdp-ov-duo { grid-template-columns: 1fr 1fr; } }
.pdp-ov-cap { max-width: 640px; margin: 0 auto 30px; text-align: center; }
.pdp-ov-cap h3 { font: 600 clamp(1.4rem,2.4vw,1.9rem)/1.2 var(--font-display); color: var(--ink); }
.pdp-ov-cap p { margin-top: 10px; color: var(--muted); line-height: 1.6; }

/* The caption block is centred, and this list had no rules at all, so the
   browser default put disc markers at the far left of the 640px column while
   each item's text sat centred, leaving the bullets stranded from their lines.
   The list is now a left-aligned block that centres as a unit under the centred
   heading, with a hanging indent so wrapped lines align to the text, not the
   marker. */
.pdp-ov-cap ul {
  display: inline-block;
  text-align: left;
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  color: var(--muted);
  line-height: 1.6;
}
.pdp-ov-cap li { position: relative; padding-left: 20px; }
.pdp-ov-cap li + li { margin-top: 8px; }
.pdp-ov-cap li::before {
  content: "";
  position: absolute;
  left: 3px;
  top: .62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-primary);
}

/* Technical panel — spec table with collapsible groups */
.pdp-spec-wrap { max-width: 900px; margin: 0 auto; }
.pdp-spec-note { font-size: .85rem; color: var(--muted); margin: 0 0 22px; padding: 12px 14px; background: var(--bg-alt); border: 1px dashed var(--line-strong); border-radius: var(--radius-sm); }
.pdp-spec-group { border-top: 1px solid var(--line); }
.pdp-spec-group > summary { list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; padding: 18px 2px; font: 600 1.05rem/1.2 var(--font-display); color: var(--ink); }
.pdp-spec-group > summary::-webkit-details-marker { display: none; }
.pdp-spec-group > summary::after { content: "＋"; color: var(--muted); font-weight: 400; }
.pdp-spec-group[open] > summary::after { content: "−"; }
.pdp-spec-row { display: grid; grid-template-columns: 1fr 1.4fr; gap: 16px; padding: 12px 2px; border-top: 1px solid var(--line); font-size: .95rem; }
.pdp-spec-rows .pdp-spec-row:first-child { border-top: 0; }
.pdp-spec-k { color: var(--muted); }
.pdp-spec-v { color: var(--text); }
.pdp-spec-v .todo { color: #A85B00; background: rgba(245,132,42,.10); padding: 1px 7px; border-radius: var(--radius-sm); font-size: .85em; }
.pdp-spec-group .pdp-spec-rows { padding-bottom: 14px; }
.pdp-dim-figs { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; padding: 4px 2px 16px; }
.pdp-dim-figs.is-single { grid-template-columns: minmax(0, 340px); }
.pdp-dim-fig { margin: 0; border: 1px solid var(--line); border-radius: var(--radius); background: #F7FAFB; padding: 10px; }
.pdp-dim-fig img { display: block; width: 100%; height: auto; border-radius: var(--radius-sm); }
.pdp-dim-fig figcaption { margin-top: 8px; font-size: .8rem; color: var(--muted); text-align: center; letter-spacing: .01em; }
.pdp-dim-note { padding: 0 2px 14px; font-size: .82rem; color: var(--muted); }

/* In The Box panel */
.pdp-box { display: grid; grid-template-columns: 1fr; gap: clamp(24px,4vw,48px); align-items: center; max-width: 980px; margin: 0 auto; }
@media (min-width: 760px) { .pdp-box { grid-template-columns: 1.3fr .7fr; } }
.pdp-box-media { border-radius: var(--radius); overflow: hidden; background: var(--bg-alt); border: 1px solid var(--line); }
.pdp-box-media img { width: 100%; height: auto; display: block; }
.pdp-box-list h3 { font: 600 1.15rem/1.2 var(--font-display); color: var(--ink); margin: 0 0 14px; }
.pdp-box-list ul { list-style: none; padding: 0; margin: 0; }
.pdp-box-list li { display: flex; gap: 10px; padding: 11px 0; border-bottom: 1px solid var(--line); font-size: .95rem; color: var(--text); }
.pdp-box-list li:last-child { border-bottom: 0; }
.pdp-box-list li b { font-weight: 600; color: var(--ink); flex: none; }

@media (max-width: 600px) { .pdp-acc-grid { grid-template-columns: 1fr; } }

/* ════════════════════════════════════════════════════════════════════
   ACCOUNT LOADING OVERLAY — frosted-glass scrim + animated hex-lattice
   Raised on account-icon click while the hosted portal loads. Markup + the
   GSAP radial wave are injected by struxa.js; CSS owns the glass, the "comes
   up" entrance, the gradient, and a keyframe fallback when GSAP is absent.
   ════════════════════════════════════════════════════════════════════ */
.acct-loader {
  position: fixed; inset: 0; z-index: 2147483647;
  display: grid; place-items: center;
  background: rgba(16, 19, 23, .58);
  -webkit-backdrop-filter: blur(20px) saturate(1.15);
  backdrop-filter: blur(20px) saturate(1.15);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .4s var(--ease-out), visibility 0s linear .4s;
}
.acct-loader.is-active { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity .4s var(--ease-out); }
.acct-loader-inner {
  display: flex; flex-direction: column; align-items: center; gap: 28px;
  transform: translateY(18px); opacity: 0;
  transition: transform .55s var(--ease-out), opacity .45s var(--ease-out);
}
.acct-loader.is-active .acct-loader-inner { transform: none; opacity: 1; }
.struxa-lattice { width: 140px; height: 140px; overflow: visible; }
.struxa-lattice polygon { opacity: .18; }
.acct-loader-text {
  margin: 0; font: 600 .72rem/1 var(--font-body);
  letter-spacing: .22em; text-transform: uppercase; color: #DCE7EB;
}
/* Fallback radial pulse when GSAP is unavailable — per-cell delay via inline --d. */
.struxa-lattice.css-pulse polygon { animation: acctLatticePulse 1.5s ease-in-out infinite; animation-delay: var(--d, 0s); }
@keyframes acctLatticePulse { 0%, 100% { opacity: .18; } 45% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .acct-loader-inner { transition: opacity .2s linear; transform: none; }
  .struxa-lattice polygon { animation: none !important; opacity: .82; }
}

/* ── Inline lattice loaders (share the .struxa-lattice engine) ── */
/* 3D viewer: a small lattice over the model stage while it downloads/parses. */
.explore-loading {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  background: rgba(16, 19, 23, .30);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  transition: opacity .4s var(--ease-out);
}
.explore-loading.is-done { opacity: 0; pointer-events: none; }
.explore-loading .struxa-lattice { width: 62px; height: 62px; }
/* Contact Send button: a tiny white lattice inline with the label while posting. */
.cf-btn-lattice { display: inline-flex; vertical-align: middle; margin-right: 9px; }
.cf-btn-lattice .struxa-lattice { width: 18px; height: 18px; }
.cf-btn-lattice .struxa-lattice polygon { stroke: #fff; opacity: .35; }

/* ==========================================================================
   Your Struxa Fit — on-device fit profile (struxa-fit.js)
   ========================================================================== */
/* The hidden attribute must always win, even over display:grid/flex rules. */
[hidden] { display: none !important; }
.myfit { max-width: 760px; }
.myfit-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(24px, 4vw, 40px);
  box-shadow: 0 1px 2px rgba(13,46,61,.04), 0 12px 32px -18px rgba(13,46,61,.18);
}
.myfit-head { margin-bottom: 26px; }
.myfit-title { font: 600 clamp(1.3rem, 2.4vw, 1.7rem)/1.1 var(--font-display); letter-spacing: -0.02em; margin: 8px 0 10px; }
.myfit-sub { font-size: 15px; line-height: 1.6; color: var(--muted); max-width: 52ch; margin: 0; }

.myfit-saved {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px;
  margin-bottom: 24px; padding: 12px 16px;
  border-radius: var(--radius-sm);
  background: var(--bg-alt);
  border-left: 3px solid transparent; border-image: var(--grad) 1;
}
.myfit-saved-label { font-size: 12px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
.myfit-saved-val { font-weight: 600; color: var(--text); font-size: 15px; }

.myfit-form { display: flex; flex-direction: column; gap: 22px; }
.myfit-field { border: 0; padding: 0; margin: 0; min-width: 0; }
.myfit-field > legend,
.myfit-field > label {
  display: block; font-size: 13px; font-weight: 600; color: var(--text);
  letter-spacing: -0.005em; margin-bottom: 10px; padding: 0;
}
.myfit-opt { font-weight: 400; color: var(--muted); font-size: 12px; }
.myfit-row { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; align-items: start; }
@media (max-width: 560px) { .myfit-row { grid-template-columns: 1fr; } }

/* chips (fit type + hand) */
.myfit-chips { display: flex; flex-wrap: wrap; gap: 10px; }
.myfit-chip {
  appearance: none; cursor: pointer;
  font: 500 14px/1 var(--font-body); color: var(--text);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill); padding: 11px 18px; min-height: 44px;
  transition: border-color .2s var(--ease-out), background .2s var(--ease-out), color .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.myfit-chip:hover { border-color: var(--text); }
/* Selected control: ice fill, deep-ocean boundary, teal label — plus a
   checkmark glyph so selection never reads by colour alone. */
.myfit-chip.is-active {
  color: var(--color-primary);
  border-color: var(--color-secondary);
  background-image: none; background-color: var(--color-primary-light);
  box-shadow: 0 6px 16px -8px rgba(13,46,61,.35);
}
.myfit-chip.is-active::before { content: "\2713"; margin-right: 6px; font-weight: 700; }
.myfit-chip:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* measurement input */
.myfit-measure { position: relative; display: flex; align-items: center; max-width: 200px; }
.myfit-input {
  width: 100%; font: 400 15px/1.4 var(--font-body); color: var(--text);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); padding: 12px 14px; min-height: 44px;
  transition: border-color .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.myfit-measure .myfit-input { padding-right: 42px; }
.myfit-input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px rgba(0,107,120,.20); }
.myfit-unit { position: absolute; right: 14px; color: var(--muted); font-size: 14px; pointer-events: none; }
.myfit-hint { font-size: 12.5px; line-height: 1.55; color: var(--muted); margin: 8px 0 0; max-width: 42ch; }
.myfit-notes { resize: vertical; min-height: 64px; }
/* strip native number spinners for a cleaner look */
.myfit-input[type=number]::-webkit-outer-spin-button,
.myfit-input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.myfit-input[type=number] { -moz-appearance: textfield; }

/* color swatches */
.myfit-swatches { display: flex; flex-wrap: wrap; gap: 10px; }
.myfit-swatch {
  appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 9px;
  font: 500 14px/1 var(--font-body); color: var(--text);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill); padding: 8px 16px 8px 9px; min-height: 44px;
  transition: border-color .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.myfit-swatch:hover { border-color: var(--text); }
.myfit-swatch-dot { width: 20px; height: 20px; border-radius: 50%; flex: none; box-shadow: inset 0 0 0 1px rgba(13,46,61,.12); }
.myfit-swatch.is-light .myfit-swatch-dot { box-shadow: inset 0 0 0 1px var(--line-strong); }
.myfit-swatch.is-active { border-color: var(--text); box-shadow: 0 0 0 1px var(--text); }
.myfit-swatch:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* actions */
.myfit-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; margin-top: 2px; }
.myfit-status { font-size: 14px; font-weight: 600; color: #1B7F5A; opacity: 0; transform: translateY(2px); transition: opacity .3s var(--ease-out), transform .3s var(--ease-out); }
.myfit-status.is-on { opacity: 1; transform: none; }
.myfit-privacy { font-size: 12px; line-height: 1.6; color: var(--muted); margin: 4px 0 0; }

/* compact saved-fit chip (product pages) */
.fitchip {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 14px; border-radius: var(--radius-pill);
  background: var(--bg-alt); border: 1px solid var(--line);
  font-size: 13.5px; color: var(--text);
}
.fitchip-mark { display: inline-flex; color: var(--color-primary); }
.fitchip-text strong { font-weight: 600; }
.fitchip-edit { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; margin-left: 2px; }
.fitchip-edit:hover { color: var(--text); }
.pdp-buy .fitchip { margin-top: 16px; }

@media (prefers-reduced-motion: reduce) {
  .myfit-chip, .myfit-swatch, .myfit-input, .myfit-status { transition: none; }
}

/* ==========================================================================
   Account page (account.html + struxa-account.js)
   ========================================================================== */
/* ---- Signed-out account: matches the elevated-clinical dashboard ---- */
.acctp-signedout { display: block; }
.acctp-so-hero {
  position: relative; overflow: hidden;
  background: linear-gradient(180deg, var(--surface), var(--bg-alt) 140%);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: clamp(30px, 4.5vw, 56px);
}
.acctp-so-hero::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 2px; background: var(--grad); }
.acctp-so-lattice { position: absolute; top: -52px; right: -44px; width: 290px; opacity: .07; pointer-events: none; }
.acctp-so-lattice .struxa-lattice { width: 100%; height: auto; }
.acctp-so-inner { position: relative; max-width: 600px; }
.acctp-so-title { font: 600 clamp(1.9rem, 4vw, 2.75rem)/1.05 var(--font-display); letter-spacing: -0.025em; margin: 12px 0 14px; }
.acctp-so-sub { font-size: clamp(15px, 1.5vw, 17px); line-height: 1.6; color: var(--muted); max-width: 48ch; margin: 0; }
.acctp-cta { margin-top: 30px; display: flex; flex-direction: column; gap: 14px; align-items: flex-start; }
.acctp-note { font-size: 12.5px; line-height: 1.6; color: var(--muted); max-width: 46ch; margin: 0; font-family: var(--acct-mono); }
[data-acct-login].is-disabled { opacity: .55; cursor: not-allowed; }

.acctp-benefits { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 18px; }
@media (max-width: 760px) { .acctp-benefits { grid-template-columns: 1fr; } }
.acctp-benefit {
  position: relative; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 24px 22px 26px;
  display: flex; flex-direction: column; gap: 12px; align-items: flex-start;
  transition: border-color .2s var(--ease-out), transform .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.acctp-benefit:hover { border-color: var(--line-strong); transform: translateY(-3px); box-shadow: 0 22px 44px -30px rgba(13,46,61,.32); }
.acctp-benefit-ic { flex: none; width: 40px; height: 40px; border-radius: var(--radius-sm); display: grid; place-items: center; color: var(--color-primary); background: var(--color-primary-light); }
.acctp-benefit-ic svg { width: 20px; height: 20px; }
.acctp-benefit h3 { font-size: 1.05rem; font-weight: 600; letter-spacing: -0.01em; margin: 0; }
.acctp-benefit p { font-size: 14px; color: var(--muted); line-height: 1.6; margin: 0; }
@media (prefers-reduced-motion: reduce) { .acctp-benefit { transition: none; } }

/* ---- Signed-in account: elevated-clinical dashboard ---- */
:root { --acct-mono: ui-monospace, 'SF Mono', 'SFMono-Regular', Menlo, Consolas, monospace; }
.acctp { display: block; }
.acctp > * { animation: acctpIn .5s var(--ease-out) both; }
.acctp > *:nth-child(2) { animation-delay: .05s; }
.acctp > *:nth-child(3) { animation-delay: .1s; }
.acctp > *:nth-child(4) { animation-delay: .15s; }
.acctp > *:nth-child(5) { animation-delay: .2s; }
@keyframes acctpIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* hero */
.acctp-hero {
  position: relative; overflow: hidden;
  background: linear-gradient(180deg, var(--surface), var(--bg-alt) 140%);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: clamp(26px, 3.6vw, 44px);
}
.acctp-hero::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 2px; background: var(--grad); }
.acctp-hero-lattice { position: absolute; top: -46px; right: -40px; width: 250px; opacity: .07; pointer-events: none; }
.acctp-hero-lattice .struxa-lattice { width: 100%; height: auto; }
.acctp-hero-inner { position: relative; display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.acctp-title { margin: 8px 0 6px; letter-spacing: -0.02em; }
.acctp-email { font-size: 14px; color: var(--muted); margin: 0; font-family: var(--acct-mono); }
.acctp-signout { flex: none; }

/* status readout strip */
.acctp-status { position: relative; margin-top: clamp(22px, 3vw, 30px); display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 12px; }
.acctp-stat { position: relative; overflow: hidden; padding: 14px 16px 14px 20px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); display: flex; flex-direction: column; gap: 7px; }
.acctp-stat::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--grad); opacity: .85; }
.acctp-stat-k { font: 600 10.5px/1 var(--font-body); text-transform: uppercase; letter-spacing: .12em; color: var(--muted); }
.acctp-stat-v { font: 500 15px/1.2 var(--acct-mono); color: var(--text); font-variant-numeric: tabular-nums; }

/* sticky sub-nav */
.acctp-nav {
  position: sticky; top: calc(var(--nav-h-shrunk) + 8px); z-index: 6;
  display: flex; gap: 4px; width: fit-content; max-width: 100%; margin: 20px 0; padding: 5px;
  border: 1px solid var(--line); border-radius: var(--radius-pill);
  background: rgba(255,255,255,.72); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  box-shadow: 0 10px 30px -22px rgba(13,46,61,.4); overflow-x: auto;
}
.acctp-nav a { flex: none; padding: 8px 16px; border-radius: var(--radius-pill); font: 500 13.5px/1 var(--font-body); color: var(--muted); text-decoration: none; transition: color .2s var(--ease-out), background .2s var(--ease-out); }
.acctp-nav a:hover { color: var(--text); }
.acctp-nav a.is-active { color: #fff; background-image: none; background-color: var(--color-primary); }
.acctp-nav a:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* quick actions */
.acctp-quick { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 22px; }
.acctp-action { display: flex; align-items: center; gap: 11px; padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); color: var(--text); text-decoration: none; font: 500 14px/1.2 var(--font-body); transition: border-color .2s var(--ease-out), transform .2s var(--ease-out), box-shadow .2s var(--ease-out); }
.acctp-action:hover { border-color: var(--line-strong); transform: translateY(-2px); box-shadow: 0 16px 34px -24px rgba(13,46,61,.32); }
.acctp-action:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.acctp-action-ic { flex: none; width: 34px; height: 34px; border-radius: var(--radius-sm); display: grid; place-items: center; color: var(--color-primary); background: var(--color-primary-light); }
.acctp-action-ic svg { width: 18px; height: 18px; }

/* panels */
.acctp-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: 20px; align-items: start; }
@media (max-width: 980px) { .acctp-grid { grid-template-columns: 1fr; } }
.acctp-panel {
  position: relative; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: clamp(22px, 3vw, 32px); scroll-margin-top: 132px;
}
.acctp-profile { margin-top: 20px; }
.acctp-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--line); }
.acctp-panel-head h2 { font: 600 1.15rem/1.2 var(--font-display); letter-spacing: -0.015em; margin: 0; }
/* 10px bold uppercase needs headroom, not less: #1B7F5A on this tint measured
   4.44:1. Darkened to clear AA with margin at this size. */
.acctp-panel-tag { flex: none; font: 600 10px/1 var(--font-body); text-transform: uppercase; letter-spacing: .1em; color: #14664A; padding: 5px 10px; border-radius: var(--radius-pill); background: rgba(31,157,87,.1); border: 1px solid rgba(31,157,87,.24); }

/* clinical spec list (profile, etc.) */
.acctp-spec { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0 24px; margin: 0; }
.acctp-spec > div { display: flex; flex-direction: column; gap: 6px; padding: 13px 0; border-bottom: 1px solid var(--line); }
.acctp-spec dt { font: 600 10.5px/1 var(--font-body); text-transform: uppercase; letter-spacing: .12em; color: var(--muted); }
.acctp-spec dd { margin: 0; font: 500 15px/1.35 var(--acct-mono); color: var(--text); word-break: break-word; }
.acctp-profile-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 22px; }

/* fit editor, reskinned to sit natively inside the panel */
.acctp-panel .myfit-card { background: transparent; border: 0; box-shadow: none; padding: 0; }
.acctp-panel .myfit-head { display: none; }
.acctp-panel .myfit { max-width: none; }
.acctp-sync { font-size: 12.5px; color: var(--muted); margin: 16px 0 0; font-family: var(--acct-mono); }

/* orders */
.acctp-muted { font-size: 14.5px; color: var(--muted); line-height: 1.6; }
.acctp-empty { display: flex; flex-direction: column; gap: 16px; align-items: flex-start; }
.acctp-orderlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.acctp-order { padding: 16px 0; border-top: 1px solid var(--line); }
.acctp-order:first-child { border-top: 0; padding-top: 2px; }
.acctp-order-top { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.acctp-order-name { font-weight: 600; font-size: 15px; font-family: var(--acct-mono); }
.acctp-order-date { font-size: 13px; color: var(--muted); }
.acctp-order-total { margin-left: auto; font-weight: 600; font-size: 14px; font-family: var(--acct-mono); font-variant-numeric: tabular-nums; }
.acctp-order-items { font-size: 13.5px; color: var(--muted); margin: 6px 0 0; line-height: 1.5; }
.acctp-order-actions { display: flex; gap: 18px; margin-top: 10px; }
.acctp-order-link { font-size: 13px; font-weight: 500; color: var(--text); text-decoration: none; border-bottom: 1px solid var(--line-strong); padding-bottom: 1px; transition: color .2s var(--ease-out), border-color .2s var(--ease-out); }
.acctp-order-link:hover { color: var(--color-primary); border-color: var(--color-primary); }

.acctp-retry { display: flex; flex-direction: column; gap: 14px; align-items: flex-start; max-width: 52ch; }
.acctp-retry .acctp-muted { margin: 0; }

@media (max-width: 620px) {
  .acctp-hero-inner { flex-direction: column; }
  .acctp-signout { order: -1; align-self: flex-end; }
}
@media (prefers-reduced-motion: reduce) {
  .acctp > * { animation: none; }
  .acctp-action, .acctp-nav a, .acctp-order-link { transition: none; }
}

/* ── Judge.me reviews (PDP "Reviews" tab) ──────────────────────────
   The widget is Judge.me's own markup, so it arrives carrying Judge.me's default
   styling. These rules re-point it at the site's tokens. It sits inside a tab
   panel, which already supplies the width and top padding, so there is no band
   or border here. Scoped under .pdp-reviews so nothing can leak into the rest of
   the page if Judge.me changes its class names. */
.pdp-reviews { max-width: 1100px; margin: 0 auto; }
.pdp-reviews .jdgm-widget { font-family: var(--font-body); color: var(--text); }
.pdp-reviews .jdgm-widget * { font-family: inherit; }

/* STARS ARE DRAWN HERE, ON PURPOSE.
   Judge.me's stylesheet sets .jdgm-star{font-family:'JudgemeStar' !important} but
   ships no @font-face for that family: the glyph is injected by Judge.me's JS
   bundle, which this page deliberately does not load (see assets/judgeme.js).
   Left alone the stars are empty 0x0 elements. The server-rendered markup still
   tells us the rating through jdgm--on / --half / --off, so the stars are drawn
   from those classes with a normal character. Gold, because a teal star does not
   read as a rating. */
.pdp-reviews .jdgm-star { font-family: inherit !important; width: auto !important; }
.pdp-reviews .jdgm-star::before { content: "\2605"; }
.pdp-reviews .jdgm-star.jdgm--on { color: #E8A33D; }
.pdp-reviews .jdgm-star.jdgm--off { color: #C6D4D9; }
.pdp-reviews .jdgm-star.jdgm--half {
  background: linear-gradient(90deg, #E8A33D 50%, #C6D4D9 50%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
/* The panel supplies its own site-styled heading, so Judge.me's internal title
   would be a second one immediately under it. */
.pdp-reviews .jdgm-rev-widg__title { display: none; }
.pdp-reviews .jdgm-rev__title,
.pdp-reviews .jdgm-widget h2,
.pdp-reviews .jdgm-widget h3 { font-family: var(--font-display); color: var(--text); }
.pdp-reviews .jdgm-rev,
.pdp-reviews .jdgm-rev__body { color: var(--text); }
.pdp-reviews .jdgm-rev__timestamp,
.pdp-reviews .jdgm-rev__author { color: var(--muted); }
.pdp-reviews .jdgm-write-rev-link,
.pdp-reviews .jdgm-btn,
.pdp-reviews .jdgm-submit-rev {
  background: var(--color-primary) !important;
  border-color: var(--color-primary) !important;
  color: #fff !important;
  border-radius: 999px !important;
}
.pdp-reviews .jdgm-rev { border-color: var(--line); }
/* Shown only if the fetch fails, so the tab is never a dead end. */
.pdp-reviews-fallback { color: var(--muted); font-size: 15px; margin-top: 18px; }
.pdp-reviews-fallback[hidden] { display: none !important; }
}

/* Shown only when Add to cart is pressed with no colour chosen (assets/struxa-shop.js).
   Sits under the swatch row so the fix is where the eye already is. */
.pdp-color-hint {
  margin: 10px 0 0;
  font: 600 13.5px/1.5 var(--font-body);
  color: #A8321F;
}
.pdp-color-hint[hidden] { display: none !important; }

/* The homepage's one product card carries the main Shop CTA but showed no price,
   so the first number a shopper attached to the flagship was the hero's "From
   $13.99" (the cheaper product). */
.home-spotlight-price { font: 600 1.05rem/1.3 var(--font-display); color: var(--ink); margin: 0; }
.home-spotlight-price span { font-weight: 500; font-size: .82rem; color: var(--muted); }

/* ── Quick-shop: colour swatches beside the SDK select, and the PDP button ──
   The Buy SDK only renders a native <select>, so the card offered no colour
   affordance while the PDP had swatches. These sit to the right of the select
   and drive it, so keyboard users keep the native control and everyone else
   gets the swatch row. */
.products-qs-swatches { display: inline-flex; align-items: center; gap: 8px; margin-left: 12px; vertical-align: middle; }
.products-qs-swatch {
  width: 22px; height: 22px; padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(13,46,61,.22);
  cursor: pointer;
  transition: transform .18s var(--ease-out), box-shadow .18s var(--ease-out);
}
.products-qs-swatch.is-light { border-color: rgba(13,46,61,.38); }
.products-qs-swatch:hover { transform: scale(1.12); }
.products-qs-swatch[aria-pressed="true"] {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--color-primary);
}
.products-qs-swatch:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 3px; }

/* Sits beside "Quick add to cart" so the route to the full page stays obvious. */
.products-pdp-btn { white-space: nowrap; }
@media (max-width: 560px) {
  .products-qs-swatches { margin-left: 0; margin-top: 10px; }
}

/* ── Journal: "Keep reading" ────────────────────────────────────────────────
   Posts used to dead-end, so a reader who finished one had nowhere to go and the
   16-post cluster passed almost no authority to the rest of the site. Three
   siblings, same-category first. */
.post-related { margin-top: clamp(40px, 6vw, 68px); padding-top: 30px; border-top: 1px solid var(--line); }
.post-related-h { font: 600 1.15rem/1.3 var(--font-display); color: var(--ink); margin: 0 0 18px; }
.post-related-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.blog-card--sm {
  display: block; padding: 16px 18px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface);
  text-decoration: none; color: inherit;
  transition: border-color .22s var(--ease-out), transform .22s var(--ease-out);
}
.blog-card--sm:hover { border-color: var(--color-primary); transform: translateY(-2px); }
.blog-card--sm .blog-cat { font-size: 11px; }
.blog-card--sm .blog-card-title { font: 600 .95rem/1.35 var(--font-display); color: var(--ink); margin-top: 8px; }
@media (max-width: 760px) { .post-related-grid { grid-template-columns: 1fr; } }
