/* =============================================================
   HyperPrints — styles.css
   v0.2 · Dark by default with a working light theme
   Colour tokens live in :root — change them here, nowhere else.
   Sections 1–17 are shared; 18+ are v0.2 additions.
   ============================================================= */

/* ---------- 1. TOKENS ---------- */
:root {
  /* brand */
  --accent:        #22e0ff;   /* graphics, fills, glows */
  --accent-ink:    #22e0ff;   /* the same accent used as small TEXT — see light theme */
  --accent-2:      #7c5cff;
  --accent-warm:   #ff8a3d;
  --accent-ok:     #3ddc97;
  --brand-nozzle:  #fe993a;   /* the logo's hot end — a fixed brand colour */

  /* dark surfaces (default) */
  --bg:            #07090d;
  --bg-alt:        #0b0f15;
  --surface:       #0f141c;
  --surface-2:     #141b25;
  --line:          #1e2833;
  --line-soft:     #18202a;
  --line-strong:   #2a3644;   /* form controls — a touch firmer than --line */

  /* dark type */
  --text:          #e8eef7;
  --text-dim:      #9aa8bb;
  --text-faint:    #7a8699;   /* tuned for WCAG AA at small sizes — don't darken */

  --shadow:        0 18px 50px -20px rgba(0,0,0,.85);
  --glow:          0 0 40px -6px rgba(34,224,255,.35);

  /* type */
  --font-display: 'Space Grotesk', system-ui, sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'SF Mono', monospace;

  /* layout */
  --wrap:   1180px;
  --radius: 14px;
  --radius-lg: 22px;
  --ease: cubic-bezier(.22,.8,.3,1);
  /* Motion system (v0.9.2). One set of curves and durations for everything
     that moves, so hovers, reveals and page changes feel like one machine.
       ease-out    things arriving (reveals, panels)
       ease-spring a touch of overshoot for things you push (buttons, chips, cards)
       t-fast / t-med / t-slow  micro-feedback / hovers / entrances */
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  --t-fast: .18s;
  --t-med: .32s;
  --t-slow: .6s;
  --hot: #ffb35a;          /* the colour of freshly extruded filament */
}

:root[data-theme="light"] {
  --bg:         #f6f8fb;
  --bg-alt:     #eef2f7;
  --surface:    #ffffff;
  --surface-2:  #f4f7fb;
  /* Light borders were 1.1-1.3:1 against their backgrounds, so cards on the
     tinted sections all but vanished. Now 1.5-1.7:1 for edges, and 3:1 for
     anything you type into (WCAG 1.4.11, non-text contrast). */
  --line:        #bcc7d5;
  --line-soft:   #d3dbe6;
  --line-strong: #7d8a9e;
  --shadow-card: 0 1px 2px rgba(16,32,56,.05), 0 8px 22px -14px rgba(16,32,56,.22);

  --text:       #0d1620;
  --text-dim:   #4e5d73;
  --text-faint: #5f6c80;   /* tuned for WCAG AA at small sizes — don't lighten */

  --accent:     #0091b5;
  --accent-ink: #00768c;   /* darker so small accent text stays legible on white */
  --accent-2:   #6142e0;
  /* status colours also need darkening for white backgrounds */
  --accent-warm: #a34c00;
  --accent-ok:   #0b7a53;
  --brand-nozzle: #e07a16;   /* a shade deeper so the hot end holds on white */

  --shadow:     0 16px 40px -22px rgba(15,30,55,.35);
  --glow:       0 0 34px -10px rgba(0,145,181,.35);
}

/* ---------- 1b. MATERIAL HUES ----------
   One hue per filament, used for the card's rail, bars and line art (--mat)
   and for its name in text (--mat-ink). These were inline colours in v0.2 and
   the dark-theme values washed out to ~1.7:1 on a white card, so the light
   theme now darkens them. Every pair clears 4.5:1 against its own surface. */
.mat-pla    { --mat: #22e0ff; --mat-ink: #22e0ff; }
.mat-petg   { --mat: #7c5cff; --mat-ink: #9b83ff; }
.mat-tpu    { --mat: #ff8a3d; --mat-ink: #ff8a3d; }
.mat-placf  { --mat: #3ddc97; --mat-ink: #3ddc97; }
.mat-petgcf { --mat: #ff5d8f; --mat-ink: #ff5d8f; }
.mat-abs    { --mat: #ffd166; --mat-ink: #ffd166; }
.mat-asa    { --mat: #5cc8ff; --mat-ink: #5cc8ff; }
.mat-pc     { --mat: #b28dff; --mat-ink: #b28dff; }
.mat-pa     { --mat: #4ade80; --mat-ink: #4ade80; }

:root[data-theme="light"] .mat-pla    { --mat: #00768c; --mat-ink: #00768c; }
:root[data-theme="light"] .mat-petg   { --mat: #5b3cd4; --mat-ink: #5b3cd4; }
:root[data-theme="light"] .mat-tpu    { --mat: #a34c00; --mat-ink: #a34c00; }
:root[data-theme="light"] .mat-placf  { --mat: #0b7a53; --mat-ink: #0b7a53; }
:root[data-theme="light"] .mat-petgcf { --mat: #b81d54; --mat-ink: #b81d54; }
:root[data-theme="light"] .mat-abs    { --mat: #845200; --mat-ink: #845200; }
:root[data-theme="light"] .mat-asa    { --mat: #0069a8; --mat-ink: #0069a8; }
:root[data-theme="light"] .mat-pc     { --mat: #6636cc; --mat-ink: #6636cc; }
:root[data-theme="light"] .mat-pa     { --mat: #12703c; --mat-ink: #12703c; }

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

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background .35s var(--ease), color .35s var(--ease);
}

img, svg, canvas { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }

h1, h2, h3, h4 { font-family: var(--font-display); line-height: 1.12; letter-spacing: -.02em; font-weight: 600; }

::selection { background: var(--accent); color: #06121a; }

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

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--accent); color: #06121a; padding: 10px 16px; border-radius: 8px; font-weight: 600;
  transition: top .2s var(--ease);
}
.skip-link:focus { top: 12px; }

.hp { position: absolute; left: -9999px; opacity: 0; height: 0; width: 0; }

/* ---------- 3. LAYOUT PRIMITIVES ---------- */
.wrap { width: min(100% - 40px, var(--wrap)); margin-inline: auto; }

.section { padding: clamp(72px, 9vw, 130px) 0; position: relative; }
.section--alt { background: var(--bg-alt); border-block: 1px solid var(--line-soft); }

.sec-head { max-width: 640px; margin-bottom: clamp(36px, 5vw, 60px); }
.sec-head h2 { font-size: clamp(30px, 4.4vw, 46px); margin-block: 10px 14px; }
.sec-head__sub { color: var(--text-dim); font-size: 17px; }

.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent-ink);
}
.eyebrow .dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 18%, transparent);
  animation: pulse 2.4s var(--ease) infinite;
}
@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1);} 50% { opacity: .45; transform: scale(.8);} }

.grad {
  background: linear-gradient(100deg, var(--accent), var(--accent-2) 70%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
/* The headline's gradient line catches a single sweep of light as the page
   lands, in step with the print starting behind it. Once, not a loop: a
   looping shimmer is a repaint every frame for the life of the page. */
.hero__title .grad {
  background:
    linear-gradient(100deg, transparent 38%, rgba(255,255,255,.85) 50%, transparent 62%) 150% 0 / 250% 100% no-repeat,
    linear-gradient(100deg, var(--accent), var(--accent-2) 70%);
  -webkit-background-clip: text; background-clip: text;
  animation: title-sweep 1.8s .5s var(--ease) both;
}
@keyframes title-sweep { from { background-position: 150% 0, 0 0; } to { background-position: -60% 0, 0 0; } }
@media (prefers-reduced-motion: reduce) { .hero__title .grad { animation: none; background-position: -60% 0, 0 0; } }

/* Page to page, the browser cross-fades instead of flashing white-then-page.
   Chrome, Edge and Safari 18+; everywhere else it is simply ignored. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }

/* ---------- 4. BUTTONS ---------- */
.btn {
  --btn-bg: transparent;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 12px 22px; border-radius: 999px;
  font-family: var(--font-display); font-weight: 600; font-size: 15px;
  border: 1px solid var(--line);
  background: var(--btn-bg);
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), background .25s var(--ease), border-color .25s var(--ease);
  will-change: transform;
}
.btn--lg { padding: 15px 30px; font-size: 16px; }
.btn--sm { padding: 9px 18px; font-size: 14px; }
.btn--block { width: 100%; }

.btn--primary {
  background: linear-gradient(100deg, var(--accent), var(--accent-2));
  color: #04121a; border-color: transparent;
  box-shadow: 0 10px 30px -12px color-mix(in srgb, var(--accent) 70%, transparent);
}
.btn--primary:hover { transform: translateY(-2px); box-shadow: 0 16px 38px -12px color-mix(in srgb, var(--accent) 80%, transparent); }
.btn--primary:active { transform: translateY(0); }

.btn--ghost { color: var(--text); background: color-mix(in srgb, var(--surface) 70%, transparent); }
.btn--ghost:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-2px); }

.btn__arrow { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform .25s var(--ease); }
.btn:hover .btn__arrow { transform: translateX(4px); }

.btn[disabled] { opacity: .6; pointer-events: none; }

/* ---------- 5. NAV ---------- */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  padding-top: env(safe-area-inset-top, 0px);   /* clear the notch on phones */
  /* backdrop-filter is not transitioned: animating a blur radius re-renders it
     every frame of the fade. The colour fades; the blur just switches on. */
  transition: background-color .3s var(--ease), border-color .3s var(--ease);
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: var(--line-soft);
}
/* On a phone the bar sits over the hero animation, and a live blur re-renders
   on every frame it draws. Nearly opaque looks the same at that size. */
@media (max-width: 760px) {
  .nav.is-stuck { background: color-mix(in srgb, var(--bg) 95%, transparent); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: 20px; height: 70px; }

.brand { display: inline-flex; align-items: center; gap: 10px; font-family: var(--font-display); font-weight: 700; font-size: 19px; letter-spacing: -.02em; }
/* The mark's ink is wider than it is tall (48 x 44 on a 64 grid), so it needs
   a slightly bigger box than a square glyph would to read at the same weight. */
.brand__mark { width: 34px; height: 34px; flex: none; }
.brand__accent { color: var(--accent-ink); }

/* ---------- inline page links (wide screens) ----------
   The burger stays at every width; these are the shortcut, not the only way in. */
.nav__pages { display: none; align-items: center; gap: 4px; }
.nav__link {
  position: relative; padding: 8px 13px; border-radius: 9px;
  font-size: 14.5px; font-weight: 500; color: var(--text-dim);
  white-space: nowrap;
  transition: color .2s var(--ease), background-color .2s var(--ease);
}
.nav__link:hover { color: var(--text); background: color-mix(in srgb, var(--surface) 70%, transparent); }
.nav__link::after {
  content: ''; position: absolute; left: 13px; right: 13px; bottom: 2px; height: 2px;
  border-radius: 2px; background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transform: scaleX(0); transform-origin: left; transition: transform .25s var(--ease);
}
.nav__link[aria-current="page"] { color: var(--text); }
.nav__link[aria-current="page"]::after { transform: scaleX(1); }

@media (min-width: 960px) { .nav__pages { display: flex; } }   /* five pages + Contact + quote fit from ~900px */

/* Driven by transform, not width: a width change re-lays-out the header on
   every scroll frame; a transform is composited and costs nothing. */
.nav__progress { height: 2px; width: 100%; transform: scaleX(0); transform-origin: 0 50%; background: linear-gradient(90deg, var(--accent), var(--accent-2)); }

/* ---------- 6. HERO ---------- */
.hero { position: relative; padding: clamp(110px, 14vw, 170px) 0 clamp(60px, 7vw, 90px); overflow: hidden; }

.hero__grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, var(--line-soft) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line-soft) 1px, transparent 1px);
  background-size: 62px 62px;
  mask-image: radial-gradient(ellipse 85% 62% at 50% 22%, #000 25%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 85% 62% at 50% 22%, #000 25%, transparent 78%);
  opacity: .8;
}
.hero__glow {
  position: absolute; top: -18%; left: 50%; translate: -50% 0;
  width: 900px; height: 620px; pointer-events: none;
  background:
    radial-gradient(circle at 30% 40%, color-mix(in srgb, var(--accent) 22%, transparent), transparent 60%),
    radial-gradient(circle at 72% 30%, color-mix(in srgb, var(--accent-2) 20%, transparent), transparent 62%);
}

.hero__inner {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(30px, 5vw, 64px); align-items: center;
}

.hero__title {
  /* bigger in v0.9.2: the headline is the other half of the hook */
  font-size: clamp(40px, 5.9vw, 72px); font-weight: 700; margin: 16px 0 22px; line-height: 1.02;
  letter-spacing: -.04em; text-wrap: balance;
}
.hero__sub { color: var(--text-dim); font-size: clamp(16px, 1.5vw, 18.5px); max-width: 52ch; }
.hero__cta { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 30px; }

.hero__pills { display: flex; flex-wrap: wrap; gap: 10px; list-style: none; padding: 0; margin-top: 36px; }
.hero__pills li {
  display: flex; flex-direction: column; gap: 1px;
  padding: 11px 17px; border: 1px solid var(--line); border-radius: 12px;
  background: color-mix(in srgb, var(--surface) 55%, transparent);
}
.hero__pills strong { font-family: var(--font-mono); font-size: 14px; color: var(--text); font-weight: 500; }
.hero__pills span { font-size: 12px; color: var(--text-faint); letter-spacing: .02em; }

/* --- The build chamber (hero.js) ---
   One self-contained machine on the right of the headline: a status strip
   along the top, the part printing in the middle, what to print next along
   the bottom. v0.9.1 spread these across the hero (a full-bleed canvas, a
   floating HUD, chips and a caption under the copy), which read as a widget
   bolted onto the page. No backdrop-filter anywhere in here: the canvas
   redraws every frame, and a blur over it would be recomputed every frame. */
.hero { min-height: min(100svh, 980px); display: flex; flex-direction: column; justify-content: center; }
.hero__copy { position: relative; }

.chamber {
  position: relative; display: grid; grid-template-rows: auto 1fr auto; grid-template-columns: minmax(0, 1fr); min-width: 0;
  border-radius: 22px; overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% 110%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 60%),
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 92%, transparent), color-mix(in srgb, var(--bg) 96%, transparent));
  border: 1px solid var(--line);
  box-shadow: 0 40px 90px -40px rgba(0, 0, 0, .75), inset 0 1px 0 color-mix(in srgb, #fff 6%, transparent);
  isolation: isolate;
}
/* a thin light that runs round the frame edge once the page has landed */
.chamber::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none; z-index: 3;
  background: conic-gradient(from var(--edge, 0deg), transparent 0 70%, var(--accent) 80%, var(--accent-2) 88%, transparent 96%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; animation: edge-run 2.4s 1.1s var(--ease-out) forwards;
}
@property --edge { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
@keyframes edge-run { 0% { opacity: 0; --edge: 0deg; } 15% { opacity: 1; } 85% { opacity: 1; } 100% { opacity: 0; --edge: 360deg; } }

.chamber__bar {
  position: relative; display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--line-soft);
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .12em; color: var(--text-faint);
}
.chamber__status { display: inline-flex; align-items: center; gap: 7px; color: var(--accent-ok); }
.chamber__name { color: var(--text); margin-right: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chamber__layer { font-variant-numeric: tabular-nums; white-space: nowrap; }
.chamber__progress {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
  transform-origin: 0 50%; transform: scaleX(0);
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}
.led { width: 7px; height: 7px; border-radius: 50%; background: var(--accent-ok); box-shadow: 0 0 8px var(--accent-ok); animation: pulse 1.6s infinite; }

.hero__stage { position: relative; min-height: clamp(340px, 50vh, 520px); cursor: grab; touch-action: pan-y; user-select: none; -webkit-user-select: none; }
.hero__stage.is-dragging { cursor: grabbing; }
.hero__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; }
.hero__static { display: none; position: absolute; inset: 0; margin: auto; width: min(52%, 240px); height: auto;
  filter: drop-shadow(0 18px 40px color-mix(in srgb, var(--accent) 30%, transparent)); }
.hero--static .hero__static { display: block; }
/* registration marks in the chamber corners */
.chamber__corner { position: absolute; width: 14px; height: 14px; border-color: color-mix(in srgb, var(--accent) 55%, transparent); border-style: solid; border-width: 0; pointer-events: none; }
.chamber__corner--tl { top: 12px; left: 12px; border-top-width: 1.5px; border-left-width: 1.5px; }
.chamber__corner--tr { top: 12px; right: 12px; border-top-width: 1.5px; border-right-width: 1.5px; }
.chamber__corner--bl { bottom: 12px; left: 12px; border-bottom-width: 1.5px; border-left-width: 1.5px; }
.chamber__corner--br { bottom: 12px; right: 12px; border-bottom-width: 1.5px; border-right-width: 1.5px; }

.chamber__foot { padding: 10px 10px 11px; border-top: 1px solid var(--line-soft); }
/* Wraps rather than scrolling sideways: every model is always in view, and
   there is no masked scroller (iOS Safari has form for dropping taps inside
   a masked overflow container). */
.hero-models { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; }
.hero-chip {
  flex: 0 1 auto; display: inline-flex; justify-content: center; align-items: baseline; gap: 7px; padding: 7px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: color-mix(in srgb, var(--surface) 80%, transparent);
  font-size: 12.5px; white-space: nowrap;
  touch-action: manipulation;              /* no double-tap-zoom delay on phones */
  -webkit-tap-highlight-color: transparent;
  transition: border-color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-spring);
}
.hero-chip:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); transform: translateY(-1px); }
.hero-chip:active { transform: scale(.96); }
.hero-chip.is-active { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, var(--surface)); }
.hero-chip b { font-family: var(--font-display); font-weight: 600; letter-spacing: -.01em; }
.hero-chip span { display: none; }      /* the names say enough; tags pushed the row onto two lines */

@media (max-width: 880px) {
  .hero__inner { grid-template-columns: 1fr; gap: 26px; }
  /* Chamber first on a phone: a short band above the headline, so the
     machine and the words both land in the first screen. */
  .chamber { order: -1; }
  .hero__stage { min-height: clamp(250px, 56vw, 380px); }
  .hero { justify-content: flex-start; }
}
/* ---------- 7. TICKER ---------- */
.ticker {
  border-block: 1px solid var(--line-soft);
  background: var(--bg-alt);
  overflow: hidden; padding: 13px 0;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.ticker__track {
  display: flex; align-items: center; gap: 22px; white-space: nowrap; width: max-content;
  animation: slide 38s linear infinite;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .16em; color: var(--text-faint);
}
.ticker__track i { color: var(--accent); font-style: normal; font-size: 8px; }
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ---------- 8. CARDS (services) ---------- */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); gap: 20px; }

.card {
  position: relative; padding: 28px 26px 26px;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
  transition: transform .35s var(--ease), border-color .35s var(--ease), box-shadow .35s var(--ease);
}
.card::before {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(360px circle at var(--mx, 50%) var(--my, 0%), color-mix(in srgb, var(--accent) 12%, transparent), transparent 62%);
  transition: opacity .35s var(--ease);
}
.card:hover { transform: translateY(-5px); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); box-shadow: var(--shadow); }
.card:hover::before { opacity: 1; }

.card__icon {
  width: 46px; height: 46px; border-radius: 13px; display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
  margin-bottom: 18px;
}
.card__icon svg { width: 22px; height: 22px; fill: none; stroke: var(--accent); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.card h3 { font-size: 19px; margin-bottom: 9px; }
.card p { color: var(--text-dim); font-size: 14.8px; }
.card__list { list-style: none; padding: 0; margin-top: 16px; display: grid; gap: 7px; }
.card__list li { position: relative; padding-left: 18px; font-size: 13.4px; color: var(--text-faint); font-family: var(--font-mono); }
.card__list li::before { content: '▸'; position: absolute; left: 0; color: var(--accent); }

/* ---------- 9. PRODUCT GRID ---------- */
.prod-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(218px, 1fr)); gap: 16px; }

.prod {
  display: flex; flex-direction: column; gap: 8px; text-align: left;
  padding: 22px 20px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); width: 100%;
  transition: transform .3s var(--ease), border-color .3s var(--ease), background .3s var(--ease);
}
.prod:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); background: var(--surface-2); }
.prod__top { display: flex; align-items: center; justify-content: space-between; }
.prod__tag { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .12em; color: var(--accent-ink); text-transform: uppercase; }
.prod__plus { width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--line); display: grid; place-items: center; color: var(--text-faint); font-size: 14px; line-height: 1; transition: all .3s var(--ease); }
.prod:hover .prod__plus { background: var(--accent); border-color: var(--accent); color: #04121a; transform: rotate(90deg); }
.prod h3 { font-size: 16.5px; }
.prod p { font-size: 13.6px; color: var(--text-dim); }
.prod__price { margin-top: auto; padding-top: 12px; font-family: var(--font-mono); font-size: 12.5px; color: var(--text-faint); }
.prod__price b { color: var(--text); font-weight: 500; }

/* ---------- 10. GALLERY ---------- */
.filters { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 26px; }
.chip {
  padding: 8px 17px; border-radius: 999px; border: 1px solid var(--line);
  font-size: 13.5px; color: var(--text-dim); background: var(--surface);
  transition: all .25s var(--ease);
}
.chip:hover { color: var(--text); border-color: var(--accent); }
.chip.is-active { background: var(--accent); border-color: var(--accent); color: #04121a; font-weight: 600; }

.gal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 16px; }

/* v0.9.7: the photo has its own 4:3 frame and the caption sits under it, so a
   two-line title no longer covers half the part (the masks were showing only
   their horns). Photos are fitted whole, on a backdrop sampled from the
   photo's own edges (script.js photoBackdrop), so a portrait shot gets no bars. */
.gal {
  position: relative; border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--line); background: var(--surface);
  display: flex; flex-direction: column;
  transition: transform .4s var(--ease), border-color .4s var(--ease), opacity .3s var(--ease);
}
.gal.is-hidden { display: none; }
.gal:hover { transform: translateY(-5px); border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); }
.gal__media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--photo-bg, var(--surface-2)); transition: background-color .4s var(--ease); }
/* .photo is an <img>, or a <picture> wrapping one. A picture is inline by
   default, so it has to be told to fill the tile the way the img would. */
.gal__media .photo { position: absolute; inset: 0; display: block; }
.gal__media img { width: 100%; height: 100%; object-fit: contain; transition: transform .6s var(--ease); }
.gal:hover .gal__media img { transform: scale(1.035); }
/* The photo sits on top of the placeholder while it loads, so nothing shifts
   when it arrives and nothing flashes when the file is not there yet. */
.photo { opacity: 0; transition: opacity .35s var(--ease); }
.photo.is-loaded { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .photo { transition: none; } }

.gal__ph {
  position: absolute; inset: 0; display: grid; place-items: center;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--accent) 9%, transparent), transparent 55%),
    repeating-linear-gradient(0deg, var(--line-soft) 0 1px, transparent 1px 13px),
    var(--surface-2);
}
.gal__ph svg { width: 58%; height: 58%; opacity: .5; }
/* Placeholder and label share the centre cell; the label sits just above the
   caption scrim so it is never covered by a two-line title. */
.gal__ph > * { grid-area: 1 / 1; }
.gal__ph svg { align-self: center; }
.gal__soon {
  align-self: center;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--accent-ink);
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  background: color-mix(in srgb, var(--bg) 70%, transparent);
}
.lb__stage .gal__soon { margin-top: 10%; font-size: 13px; }

.gal__cap {
  position: relative; flex: 1; padding: 13px 16px 15px;
  background: var(--surface); border-top: 1px solid var(--line);
  display: flex; align-items: flex-end; justify-content: space-between; gap: 12px;
}
.gal__cap > div { min-width: 0; }
.gal__cap h3 { font-size: 15.5px; }
.gal__cap p { font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); letter-spacing: .05em; margin-top: 3px; }
.gal__badge {
  flex: none; font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase;
  padding: 4px 9px; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  color: var(--accent-ink); background: color-mix(in srgb, var(--accent) 10%, transparent);
}

.gal-note { margin-top: 30px; text-align: center; color: var(--text-dim); font-size: 15px; }

/* A print with more than one photo (v0.9.5). The second photo waits on top of
   the first, hidden, and fades in while the tile is hovered or focused; the
   tag in the corner says there is more to see, for touch screens too. */
.gal--multi .photo--alt.is-loaded { opacity: 0; }
.gal--multi:hover .photo--alt.is-loaded,
.gal--multi:focus-visible .photo--alt.is-loaded { opacity: 1; }
.gal__views {
  position: absolute; top: 12px; left: 12px; z-index: 2;
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  padding: 5px 9px 5px 7px; border-radius: 999px;
  color: var(--text); background: color-mix(in srgb, var(--bg) 82%, transparent);
  border: 1px solid var(--line-soft);
}
.gal__views svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; }
.gal-note a { color: var(--accent-ink); border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); }

/* ---------- 11. ESTIMATOR ---------- */
.est {
  display: grid; grid-template-columns: 1.15fr .85fr; gap: 0;
  border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden;
  background: var(--surface); box-shadow: var(--shadow);
}
.est__controls { padding: clamp(24px, 3.5vw, 38px); display: grid; gap: 28px; align-content: start; }
.est__out {
  padding: clamp(24px, 3.5vw, 38px);
  background: linear-gradient(165deg, var(--surface-2), var(--bg-alt));
  border-left: 1px solid var(--line);
  display: grid; gap: 20px; align-content: start;
}

.field label { display: flex; align-items: baseline; gap: 8px; font-size: 14px; font-weight: 500; margin-bottom: 12px; }
.field__hint { font-size: 12px; color: var(--text-faint); font-weight: 400; }
.field label b { font-family: var(--font-mono); color: var(--accent-ink); font-weight: 500; }
.field--row { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }

.dims { display: grid; gap: 13px; }
.dim { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 14px; }
.dim__val { font-family: var(--font-mono); font-size: 12px; color: var(--text-faint); min-width: 58px; text-align: right; }
.dim__val b { color: var(--text); font-weight: 500; }

input[type="range"] {
  -webkit-appearance: none; appearance: none; width: 100%; height: 4px; border-radius: 3px;
  background: var(--line); cursor: pointer; outline-offset: 6px;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 17px; height: 17px; border-radius: 50%;
  background: var(--accent); border: 3px solid var(--surface);
  box-shadow: 0 0 0 1px var(--accent), 0 2px 8px rgba(0,0,0,.4);
  transition: transform .2s var(--ease);
}
input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.18); }
input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%; background: var(--accent);
  border: 3px solid var(--surface); box-shadow: 0 0 0 1px var(--accent); cursor: pointer;
}

.seg { display: flex; gap: 6px; padding: 5px; border: 1px solid var(--line-strong); border-radius: 12px; background: var(--bg-alt); }
.seg__btn {
  flex: 1; padding: 9px 4px; border-radius: 8px; font-size: 13.5px; font-weight: 500; color: var(--text-dim);
  font-family: var(--font-mono); letter-spacing: .04em;
  transition: all .25s var(--ease);
}
.seg__btn:hover { color: var(--text); }
.seg__btn.is-active { background: var(--accent); color: #04121a; font-weight: 600; }
.mat-note { margin-top: 11px; font-size: 13px; color: var(--text-faint); min-height: 2.6em; }

.est__price { padding-bottom: 20px; border-bottom: 1px solid var(--line); }
.est__label { font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-faint); }
.est__amount { display: flex; align-items: baseline; gap: 4px; margin-top: 6px; font-family: var(--font-display); }
.est__amount .cur { font-size: 26px; color: var(--accent-ink); }
.est__amount #estPrice { font-size: clamp(42px, 5.5vw, 56px); font-weight: 700; letter-spacing: -.03em; line-height: 1; }
.est__amount .cad { font-family: var(--font-mono); font-size: 12px; color: var(--text-faint); margin-left: 6px; }
.est__range { font-family: var(--font-mono); font-size: 12px; color: var(--text-faint); }

.est__stats { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.est__stats > div { display: flex; flex-direction: column; gap: 2px; }
.est__stats span { font-size: 11.5px; color: var(--text-faint); font-family: var(--font-mono); letter-spacing: .07em; }
.est__stats b { font-size: 16px; font-weight: 500; font-family: var(--font-display); }

.est__viz {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 10px 0 2px;
}
/* The 3D preview. Every box is a .cube of six faces sized by --cw (X), --ch (Z,
   up) and --cd (Y, depth), all in px; --coy drops it onto the floor of the build
   volume. Registered as lengths so a slider change glides instead of jumping. */
@property --cw  { syntax: '<length>'; inherits: true; initial-value: 0px; }
@property --ch  { syntax: '<length>'; inherits: true; initial-value: 0px; }
@property --cd  { syntax: '<length>'; inherits: true; initial-value: 0px; }
@property --coy { syntax: '<length>'; inherits: false; initial-value: 0px; }
.est__plate.est3d {
  position: relative; width: 250px; height: 220px; max-width: 100%;
  perspective: 760px; perspective-origin: 50% 40%;
  cursor: grab; touch-action: pan-y; user-select: none;
}
.est3d.is-dragging { cursor: grabbing; }
.est3d__scene {
  position: absolute; inset: 0; transform-style: preserve-3d;
  transform: rotateX(var(--rx, -24deg)) rotateY(var(--ry, -34deg));
}
.cube {
  position: absolute; left: 50%; top: 50%; transform-style: preserve-3d;
  width: var(--cw); height: var(--ch);
  margin-left: calc(var(--cw) / -2); margin-top: calc(var(--ch) / -2);
  transform: translateY(var(--coy));
  transition: --cw .35s var(--ease), --ch .35s var(--ease), --cd .35s var(--ease), --coy .35s var(--ease);
}
.cube .f { position: absolute; left: 0; top: 0; box-sizing: border-box; backface-visibility: visible; }
.cube .fr, .cube .bk { width: var(--cw); height: var(--ch); }
.cube .fr { transform: translateZ(calc(var(--cd) / 2)); }
.cube .bk { transform: rotateY(180deg) translateZ(calc(var(--cd) / 2)); }
.cube .lf, .cube .rt { width: var(--cd); height: var(--ch); left: calc((var(--cw) - var(--cd)) / 2); }
.cube .lf { transform: rotateY(-90deg) translateZ(calc(var(--cw) / 2)); }
.cube .rt { transform: rotateY(90deg) translateZ(calc(var(--cw) / 2)); }
.cube .tp, .cube .bt { width: var(--cw); height: var(--cd); top: calc((var(--ch) - var(--cd)) / 2); }
.cube .tp { transform: rotateX(90deg) translateZ(calc(var(--ch) / 2)); }
.cube .bt { transform: rotateX(-90deg) translateZ(calc(var(--ch) / 2)); }

/* the H2S volume: hairline walls, a gridded build plate */
.est3d__vol .f { border: 1px solid color-mix(in srgb, var(--text-faint) 45%, transparent); }
.est3d__vol .tp { border-style: dashed; }
.est3d__vol .bt {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background:
    linear-gradient(to right, color-mix(in srgb, var(--accent) 22%, transparent) 1px, transparent 1px) 0 0 / 12.5% 12.5%,
    linear-gradient(to bottom, color-mix(in srgb, var(--accent) 22%, transparent) 1px, transparent 1px) 0 0 / 12.5% 12.5%,
    color-mix(in srgb, var(--accent) 7%, transparent);
}
/* the A1 volume, dashed inside it */
.est3d__a1 .f { border: 1px dashed color-mix(in srgb, var(--accent-2) 55%, transparent); }
.est3d__a1 .tp { display: none; }
/* the part itself */
.est__box .f {
  border: 1.5px solid color-mix(in srgb, var(--accent) 80%, transparent);
  background: color-mix(in srgb, var(--accent) 20%, transparent);
}
.est__box .tp { background: color-mix(in srgb, var(--accent) 34%, transparent); }
.est__box .fr { box-shadow: inset 0 0 18px -6px color-mix(in srgb, var(--accent) 80%, transparent); }
.est__box.is-h2s .f { border-color: color-mix(in srgb, var(--accent-2) 85%, transparent);
                      background: color-mix(in srgb, var(--accent-2) 20%, transparent); }
.est__box.is-h2s .tp { background: color-mix(in srgb, var(--accent-2) 34%, transparent); }
.est__fits {
  display: inline-flex; align-items: center; gap: 7px; padding: 4px 10px; border-radius: 999px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .03em;
  color: var(--accent-ink); border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.est__fits::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.est__fits.is-h2s { color: var(--accent-2); border-color: color-mix(in srgb, var(--accent-2) 45%, var(--line));
                    background: color-mix(in srgb, var(--accent-2) 9%, transparent); }
:root[data-theme="light"] .est__fits.is-h2s { color: #4a2fc0; }
@media (prefers-reduced-motion: reduce) { .cube { transition: none; } }
.est__vizhint {
  font-size: 10.5px; color: var(--text-faint); font-family: var(--font-mono);
  letter-spacing: .03em;
}
.est__boxlabel {
  font-family: var(--font-mono); font-size: 11px; color: var(--accent-ink);
  white-space: nowrap; letter-spacing: .04em;
}

.est__disclaimer { font-size: 11.5px; color: var(--text-faint); line-height: 1.5; }

@media (max-width: 860px) {
  .est { grid-template-columns: 1fr; }
  .est__out { border-left: 0; border-top: 1px solid var(--line); }
}

/* ---------- 12. MATERIALS ---------- */
.mat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; }
.mat {
  padding: 26px 24px; border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); position: relative; overflow: hidden;
  transition: transform .35s var(--ease), border-color .35s var(--ease);
}
.mat::after { content: ''; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--mat); opacity: .8; }
.mat:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--mat) 50%, var(--line)); }
.mat h3 { font-size: 22px; color: var(--mat-ink, var(--mat)); font-family: var(--font-mono); letter-spacing: .02em; }
.mat__for { font-size: 13.4px; color: var(--text-dim); margin-top: 6px; min-height: 3em; }
.mat__specs { margin: 18px 0 14px; display: grid; gap: 9px; }
.mat__specs > div { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.mat__specs dt { font-size: 12.5px; color: var(--text-faint); }
.mat__specs dd { margin: 0; }
.bars { display: flex; gap: 3px; }
.bars span { width: 13px; height: 5px; border-radius: 2px; background: var(--line); }
.bars span.on { background: var(--mat); }
.mat__warn { font-size: 12.3px; color: var(--text-faint); border-top: 1px solid var(--line-soft); padding-top: 12px; line-height: 1.55; }

/* ---------- 13. PROCESS ---------- */
.steps { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 22px; counter-reset: s; }
.step { position: relative; padding-top: 26px; border-top: 1px solid var(--line); }
.step::before {
  content: ''; position: absolute; top: -1px; left: 0; width: 0; height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width .9s var(--ease) .15s;
}
.step.is-in::before { width: 100%; }
.step__num { font-family: var(--font-mono); font-size: 12px; color: var(--accent-ink); letter-spacing: .12em; }
.step h3 { font-size: 18px; margin: 10px 0 8px; }
.step p { font-size: 14.4px; color: var(--text-dim); }

/* ---------- 14. QUOTE ---------- */
.quote { display: grid; grid-template-columns: .85fr 1.15fr; gap: clamp(30px, 5vw, 64px); align-items: start; }
.quote__intro h2 { font-size: clamp(30px, 4.2vw, 44px); margin-block: 10px 14px; }
.quote__intro > p { color: var(--text-dim); }
.quote__points { list-style: none; padding: 0; margin-top: 26px; display: grid; gap: 12px; }
.quote__points li { display: flex; align-items: flex-start; gap: 11px; font-size: 14.6px; color: var(--text-dim); }
.quote__points svg { flex: none; width: 19px; height: 19px; margin-top: 2px; fill: none; stroke: var(--accent); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }

.quote__social { margin-top: 34px; padding-top: 26px; border-top: 1px solid var(--line); }
.quote__social p { font-size: 13px; color: var(--text-faint); margin-bottom: 12px; font-family: var(--font-mono); letter-spacing: .08em; text-transform: uppercase; }
.socials { display: flex; gap: 10px; flex-wrap: wrap; }
.social {
  display: inline-flex; align-items: center; gap: 9px; padding: 10px 18px;
  border: 1px solid var(--line); border-radius: 999px; font-size: 14px; color: var(--text-dim);
  transition: all .25s var(--ease);
}
.social svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.social:hover { color: var(--accent); border-color: var(--accent); transform: translateY(-2px); }
.socials--sm .social { width: 42px; height: 42px; padding: 0; justify-content: center; }
.quote__soon {
  font-size: 13.5px; color: var(--text-dim); text-transform: none !important;
  letter-spacing: 0 !important; font-family: var(--font-body) !important; max-width: 40ch;
}

.quote__form {
  padding: clamp(24px, 3.4vw, 36px);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); box-shadow: var(--shadow);
  display: grid; gap: 18px;
}
.f-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.f-field { display: grid; gap: 7px; align-content: start; }   /* fields without an error line were stretching taller than their neighbours */
.f-field label { font-size: 13.6px; font-weight: 500; display: flex; align-items: baseline; gap: 7px; }
.req { color: var(--accent-ink); }

.f-field input, .f-field select, .f-field textarea {
  width: 100%; padding: 12px 14px; border-radius: 11px;
  border: 1px solid var(--line-strong); background: var(--bg-alt); color: var(--text);
  font-size: 14.6px; font-family: var(--font-body);
  transition: border-color .22s var(--ease), background .22s var(--ease), box-shadow .22s var(--ease);
}
.f-field textarea { resize: vertical; min-height: 110px; }
.f-field select { appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237b8aa0' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 17px; padding-right: 38px;
}
.f-field input:focus, .f-field select:focus, .f-field textarea:focus {
  outline: none; border-color: var(--accent); background: var(--surface-2);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}
.f-field input::placeholder, .f-field textarea::placeholder { color: var(--text-faint); }

.f-field.has-err input, .f-field.has-err select, .f-field.has-err textarea { border-color: #ff6b6b; }

/* flash when a catalogue card drops its product into the form */
.is-flash { animation: flash 1.5s var(--ease); }
@keyframes flash {
  0%, 100% { box-shadow: 0 0 0 0 transparent; border-color: var(--line-strong); }
  15%, 65% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 24%, transparent); border-color: var(--accent); }
}
.f-err { font-size: 12.2px; color: #ff8080; min-height: 0; }

.custom-needs {
  padding: 12px 15px; border-radius: 12px; font-size: 13.5px; color: var(--text-dim);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.custom-needs b { color: var(--text); font-weight: 600; }
.custom-needs[hidden] { display: none; }
.f-status { font-size: 14px; text-align: center; min-height: 1.2em; }
.f-status.is-ok { color: var(--accent-ok); }
.f-status.is-bad { color: #ff8080; }
.f-fineprint { font-size: 11.8px; color: var(--text-faint); text-align: center; }

.quote__sent { text-align: center; display: grid; gap: 14px; place-items: center; padding: 26px 0; }
.quote__sent .tick {
  width: 62px; height: 62px; border-radius: 50%; display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent-ok) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent-ok) 45%, transparent);
}
.quote__sent .tick svg { width: 28px; height: 28px; fill: none; stroke: var(--accent-ok); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.quote__sent h3 { font-size: 24px; }
.quote__sent p { color: var(--text-dim); max-width: 38ch; }

@media (max-width: 880px) {
  .quote { grid-template-columns: 1fr; }
  .f-row, .field--row { grid-template-columns: 1fr; }
}

/* ---------- 14b. QUOTE PAGE (quote.html) ----------
   The form got a page of its own in v0.2.1: every CTA on the site leads here,
   and it is one URL that can go in a social bio. Form first on the page grid
   (it is why people came), reassurance beside it. */
.section--tight { padding-top: clamp(28px, 4vw, 48px); }
.phead--short { padding-bottom: clamp(18px, 3vw, 30px); }
.quote--page { grid-template-columns: 1.2fr .8fr; }
.quote--page .quote__form { order: -1; }
.quote__steps { list-style: none; padding: 0; margin-top: 16px; display: grid; gap: 14px; counter-reset: step; }
.quote__steps li {
  position: relative; padding-left: 42px; font-size: 14.6px; color: var(--text-dim); line-height: 1.55;
  counter-increment: step;
}
.quote__steps li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute; left: 0; top: 1px; width: 28px; height: 28px; border-radius: 8px;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 11px; color: var(--accent-ink);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.quote__steps b { color: var(--text); font-weight: 600; }
.quote--page .quote__points { margin-top: 14px; }
@media (max-width: 880px) {
  .quote--page { grid-template-columns: 1fr; }
}

/* the quote band that closes the home page — the one CTA that matters most,
   so it carries an accent edge the learn band above it doesn't */
.band + .band { margin-top: 18px; }
.band--quote { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.band--quote .eyebrow { margin-bottom: 8px; }

/* the header CTA doubles as the "you are here" marker on the quote page */
.nav__cta[aria-current="page"] { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent); }

/* ---------- 15. FOOTER ---------- */
.footer { border-top: 1px solid var(--line); background: var(--bg-alt); padding-top: clamp(48px, 6vw, 72px); }
.footer__inner { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.2fr; gap: 34px; padding-bottom: 46px; }
.footer__brand p { color: var(--text-dim); font-size: 14px; margin: 14px 0 18px; max-width: 34ch; }
.footer__col { display: flex; flex-direction: column; gap: 10px; }
.footer__col h4 { font-size: 12px; font-family: var(--font-mono); letter-spacing: .13em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 4px; }
.footer__col a { font-size: 14.4px; color: var(--text-dim); transition: color .2s var(--ease); width: fit-content; }
.footer__col a:hover { color: var(--accent); }
.footer__loc { font-size: 13px; color: var(--text-faint); margin-top: 6px; line-height: 1.6; }

.footer__bottom {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px;
  padding: 20px 0 26px; border-top: 1px solid var(--line-soft);
  font-size: 12.8px; color: var(--text-faint);
}
.footer__made { font-family: var(--font-mono); letter-spacing: .06em; }

@media (max-width: 800px) { .footer__inner { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .footer__inner { grid-template-columns: 1fr 1fr; gap: 28px 20px; } .footer__brand, .footer__col:last-child { grid-column: 1 / -1; } }

/* ---------- 16. BACK TO TOP ---------- */
.to-top {
  position: fixed; right: 22px; z-index: 90;
  bottom: calc(22px + env(safe-area-inset-bottom, 0px));
  width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--line); background: var(--surface); color: var(--text-dim);
  opacity: 0; pointer-events: none; transform: translateY(12px);
  transition: opacity .3s var(--ease), transform .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.to-top.is-on { opacity: 1; pointer-events: auto; transform: translateY(0); }
.to-top:hover { color: var(--accent); border-color: var(--accent); }
.to-top svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- 17. SCROLL REVEAL ---------- */
.reveal { opacity: 0; transform: translateY(22px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; } }

/* =============================================================
   18. OVERLAY MENU (v0.2)
   One menu on every page, opened by the button in the header.
   ============================================================= */
.nav__links { display: flex; align-items: center; gap: 10px; }   /* header right side */
.nav__cta { color: #04121a !important; }

.icon-btn {
  width: 40px; height: 40px; flex: none; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 11px;
  background: color-mix(in srgb, var(--surface) 60%, transparent);
  color: var(--text);
  transition: border-color .2s var(--ease), color .2s var(--ease), transform .2s var(--ease);
}
.icon-btn:hover { border-color: var(--accent); color: var(--accent-ink); transform: translateY(-1px); }
.icon-btn svg {
  width: 19px; height: 19px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
/* The icon shows what the button DOES, not what the theme currently is.
   It used to show a moon while already dark, which reads as "click for dark
   mode" — so people clicked it expecting dark and got light. In dark you now
   see a sun (click for light); in light you see a moon (click for dark). The
   aria-label and tooltip say it in words, and are kept in step by script.js. */
:root[data-theme="dark"] .icon-moon,
:root:not([data-theme="light"]) .icon-moon { display: none; }
:root[data-theme="light"] .icon-sun { display: none; }

/* .icon-btn centres with grid/place-items; overriding display here drops that,
   so the bars have to be re-centred explicitly or they sit top-left in the box. */
.nav__burger { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; }
.nav__burger span {
  width: 17px; height: 1.8px; background: currentColor; border-radius: 2px;
  transition: transform .28s var(--ease), opacity .2s;
}
.nav__burger.is-open span:nth-child(1) { transform: translateY(5.8px) rotate(45deg); }
.nav__burger.is-open span:nth-child(2) { opacity: 0; }
.nav__burger.is-open span:nth-child(3) { transform: translateY(-5.8px) rotate(-45deg); }

.menu {
  position: fixed; inset: 0; z-index: 150;
  display: grid; grid-template-rows: auto 1fr;
  /* Solid, no backdrop-filter: at 97% opacity the blur was invisible, but it
     still made the GPU re-blur the whole screen on every frame of the fade —
     and on the home page that was over a live animation. */
  background: var(--bg);
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity .3s var(--ease), visibility 0s linear .3s;
  padding-top: env(safe-area-inset-top, 0px);
}
.menu.is-open {
  opacity: 1; pointer-events: auto; visibility: visible;
  transition: opacity .3s var(--ease), visibility 0s;
}
.menu:focus { outline: none; }   /* it takes focus as a dialog, not as a control */
.menu__head { display: flex; align-items: center; justify-content: space-between; height: 70px; }
.menu__body { overflow-y: auto; padding-bottom: 40px; }
.menu__inner { display: grid; gap: 34px; padding-top: clamp(20px, 5vh, 54px); }

.menu__list { list-style: none; padding: 0; display: grid; gap: 2px; }
.menu__link {
  display: grid; grid-template-columns: auto 1fr auto; align-items: baseline; gap: 16px;
  padding: 16px 4px; border-bottom: 1px solid var(--line-soft);
  transition: padding-left .3s var(--ease), border-color .3s var(--ease);
}
.menu__link:hover, .menu__link:focus-visible { padding-left: 14px; border-color: var(--accent); }
.menu__num {
  font-family: var(--font-mono); font-size: 11px; color: var(--accent-ink);
  letter-spacing: .1em; width: 24px;
}
.menu__name {
  font-family: var(--font-display); font-weight: 600; letter-spacing: -.025em;
  font-size: clamp(26px, 5vw, 44px); line-height: 1.05;
}
.menu__blurb { font-size: 13.5px; color: var(--text-faint); justify-self: end; text-align: right; max-width: 30ch; }
.menu__link[aria-current="page"] .menu__name { color: var(--accent-ink); }
.menu__link[aria-current="page"] { border-color: var(--accent); }
/* the last item's rule and the footer's rule were stacking into a double line */
.menu__list li:last-child .menu__link:not([aria-current="page"]) { border-bottom-color: transparent; }

.menu__foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 18px; padding-top: 22px; border-top: 1px solid var(--line-soft);
}
.menu__contact { display: grid; gap: 4px; font-size: 14px; color: var(--text-dim); }
.menu__contact a:hover { color: var(--accent-ink); }

@media (max-width: 720px) {
  .menu__link { grid-template-columns: auto 1fr; }
  .menu__blurb { grid-column: 2; justify-self: start; text-align: left; font-size: 12.5px; }
}
/* seven pages on a phone: tighter rows, and on short screens (a folded
   phone, landscape) the one-line descriptions step aside so every page
   stays reachable without scrolling */
@media (max-width: 720px) {
  .menu__inner { gap: 22px; padding-top: 10px; }
  .menu__link { padding: 10px 4px; gap: 2px 14px; }
  .menu__name { font-size: 25px; }
  .menu__blurb { font-size: 12px; line-height: 1.4; }
}
@media (max-width: 720px) and (max-height: 760px) {
  .menu__blurb { display: none; }
  .menu__link { padding: 9px 4px; }
}

/* =============================================================
   19. PAGE HEADERS (inner pages)
   ============================================================= */
.phead { position: relative; padding: clamp(104px, 13vw, 150px) 0 clamp(34px, 5vw, 56px); overflow: hidden; }
.phead__grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, var(--line-soft) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line-soft) 1px, transparent 1px);
  background-size: 62px 62px;
  mask-image: radial-gradient(ellipse 80% 90% at 30% 0%, #000 10%, transparent 72%);
  -webkit-mask-image: radial-gradient(ellipse 80% 90% at 30% 0%, #000 10%, transparent 72%);
}
/* The header column used to be the .wrap itself capped at 760px, which
   centred it — so every inner page's title sat indented from the content
   below it. Keep the reading measure, but on the children, so the header
   lines up with the page grid. */
.phead__inner { position: relative; }
.phead__inner > * { max-width: 760px; }
.phead h1 { font-size: clamp(34px, 5.4vw, 58px); margin-block: 14px 16px; letter-spacing: -.035em; text-wrap: balance; }
.phead p { color: var(--text-dim); font-size: clamp(16px, 1.5vw, 18px); max-width: 60ch; }
.crumb { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .12em; color: var(--text-faint); text-transform: uppercase; }
.crumb a:hover { color: var(--accent-ink); }

/* =============================================================
   21. LIGHTBOX
   ============================================================= */
.gal { cursor: zoom-in; }
.gal__zoom {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  /* eight of these on the gallery page — eight backdrop roots for a 30px circle */
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  border: 1px solid var(--line-soft); color: var(--text);
  opacity: 0; transform: scale(.85); transition: all .3s var(--ease);
}
.gal:hover .gal__zoom, .gal:focus-within .gal__zoom { opacity: 1; transform: scale(1); }
.gal__zoom svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

.lb {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center; padding: clamp(14px, 4vw, 44px);
  /* No backdrop-filter. A full-screen blur is re-computed on every frame that
     anything underneath changes, and it was the main cost of opening a photo.
     A dense scrim reads the same with the panel on top of it. */
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity .28s var(--ease), visibility 0s linear .28s;
}
.lb.is-open { opacity: 1; pointer-events: auto; visibility: visible; transition: opacity .28s var(--ease), visibility 0s; }

.lb__panel {
  position: relative; width: min(100%, 980px); max-height: 100%;
  display: grid; grid-template-rows: 1fr auto auto;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); box-shadow: 0 40px 90px -30px rgba(0,0,0,.7);
  overflow: hidden;
  transform: scale(.94) translateY(10px); opacity: .6;
  transition: transform .34s var(--ease), opacity .34s var(--ease);
}
.lb.is-open .lb__panel { transform: none; opacity: 1; }

.lb__stage {
  position: relative; display: grid; place-items: center;
  background: var(--bg-alt); min-height: min(52vh, 420px); max-height: 66vh; overflow: hidden;
}
/* Placeholder and photo share one grid cell so the photo fades in over it
   rather than landing underneath it. */
.lb__stage > * { grid-area: 1 / 1; }
.lb__stage .photo { display: block; width: 100%; }
.lb__stage img { width: 100%; height: 100%; max-height: 66vh; object-fit: contain; }
.lb__stage .gal__ph { position: static; width: 100%; min-height: min(52vh, 420px); }

/* The photos of one print: a button for each, under the big photo. */
.lb__views {
  display: flex; gap: 10px; padding: 12px clamp(18px, 3vw, 28px) 0;
  border-top: 1px solid var(--line); overflow-x: auto;
}
.lb__views[hidden] { display: none; }
.lb__views + .lb__meta { border-top: 0; padding-top: 14px; }
.lb__view {
  display: inline-flex; align-items: center; gap: 10px; flex: none;
  padding: 5px 12px 5px 5px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text-dim);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  transition: border-color .22s var(--ease), color .22s var(--ease);
}
.lb__view:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); color: var(--text); }
.lb__view[aria-pressed="true"] { border-color: var(--accent); color: var(--accent-ink); }
.lb__thumb {
  position: relative; display: block; width: 56px; aspect-ratio: 4 / 3; border-radius: 8px; overflow: hidden;
  background: var(--bg-alt);
}
.lb__thumb .photo { position: absolute; inset: 0; display: block; }
.lb__thumb img { width: 100%; height: 100%; object-fit: cover; }

.lb__meta { display: grid; gap: 8px; padding: 20px clamp(18px, 3vw, 28px) 22px; border-top: 1px solid var(--line); }
.lb__meta h3 { font-size: clamp(19px, 2.4vw, 24px); }
.lb__spec { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .07em; color: var(--accent-ink); }
.lb__story { font-size: 14.5px; color: var(--text-dim); max-width: 68ch; }
.lb__count { font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); }

/* These sit ON TOP of the blurred overlay. A backdrop-filter here is a second
   blur of an already-blurred layer — invisible, and one more backdrop root for
   the compositor. An opaque background gives the same look for nothing.
   `transition: all` also animated the filter on every hover; name the
   properties instead. */
.lb__x, .lb__nav {
  position: absolute; z-index: 3; display: grid; place-items: center;
  border-radius: 50%; border: 1px solid var(--line);
  background: var(--surface); color: var(--text);
  transition: border-color .22s var(--ease), color .22s var(--ease), transform .22s var(--ease);
}
.lb__x { top: 12px; right: 12px; width: 40px; height: 40px; }
.lb__nav { top: calc(min(52vh, 420px) / 2); translate: 0 -50%; width: 44px; height: 44px; }
.lb__nav--prev { left: 12px; }
.lb__nav--next { right: 12px; }
/* The arrows are centred with the `translate` property, not `transform`, so a
   hover rule that re-applied translateY(-50%) in `transform` stacked on top of
   it and threw them half their height up the screen — then back down on
   unhover. Hover only scales; the centring is left alone. */
.lb__x:hover, .lb__nav:hover { border-color: var(--accent); color: var(--accent-ink); transform: scale(1.06); }
.lb__x svg, .lb__nav svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* Scroll lock for the menu and the lightbox. overflow:hidden on the root, not
   position:fixed on body: pinning body re-lays-out the whole page on every
   open and close, which was the stall people felt on a phone. */
html.is-locked, body.is-locked { overflow: hidden; }
html.is-locked { overscroll-behavior: none; }

@media (max-width: 560px) {
  .lb__nav { width: 38px; height: 38px; }
  .lb__nav--prev { left: 6px; } .lb__nav--next { right: 6px; }
}

/* =============================================================
   22. MATERIALS PAGE
   ============================================================= */
.matx-grid { display: grid; gap: 20px; }
.matx {
  display: grid; grid-template-columns: 250px 1fr; gap: 0;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); overflow: hidden;
  transition: border-color .35s var(--ease);
}
.matx:hover { border-color: color-mix(in srgb, var(--mat) 45%, var(--line)); }
.matx__art {
  display: grid; place-items: center; padding: 24px;
  background:
    radial-gradient(circle at 50% 40%, color-mix(in srgb, var(--mat) 14%, transparent), transparent 68%),
    var(--bg-alt);
  border-right: 1px solid var(--line);
}
.matx__art svg { width: 100%; max-width: 210px; height: auto; overflow: visible; }

/* Isometric part illustrations (isoArt in script.js). Three tones of the
   material colour: top faces catch the light, left faces are the true
   colour, right faces are in shade. Edges get a thin darker line so the
   form still reads when two faces are close in tone. */
.matx__art svg * { stroke-linejoin: round; }
.iso-t, .iso-l, .iso-m, .iso-r, .iso-c, .iso-f {
  stroke: color-mix(in srgb, var(--mat) 40%, #05070b); stroke-width: .7; vector-effect: non-scaling-stroke;
}
.iso-t { fill: color-mix(in srgb, var(--mat) 72%, #fff); }
.iso-l, .iso-c { fill: var(--mat); }
.iso-m { fill: color-mix(in srgb, var(--mat) 82%, #05070b); }
.iso-r { fill: color-mix(in srgb, var(--mat) 58%, #05070b); }
.iso-f { fill: color-mix(in srgb, var(--mat) 45%, #05070b); }            /* a floor in shadow */
.iso-dim { fill: color-mix(in srgb, var(--mat) 38%, #05070b); }          /* far inner walls */
.iso-h { fill: color-mix(in srgb, var(--mat) 14%, #05070b); stroke: none; }  /* holes */
.iso-w { fill: color-mix(in srgb, var(--mat) 40%, #05070b); stroke: none; }  /* inside a hole */
.iso-rib { stroke: color-mix(in srgb, var(--mat) 45%, #05070b); stroke-width: .9; vector-effect: non-scaling-stroke; }
.iso-txt { fill: color-mix(in srgb, var(--mat) 35%, #05070b); font-family: var(--font-mono); font-weight: 500; }
/* things that are not printed: steel bushings and shafts, rubber grips, the machine */
.iso-steel.iso-t { fill: #d9dfe6; } .iso-steel.iso-l, .iso-steel.iso-c { fill: #9aa4b0; } .iso-steel.iso-r { fill: #6b7580; }
.iso-steel { stroke: #3a424c; }
.iso-grip.iso-t { fill: #3b4552; } .iso-grip.iso-c { fill: #242b34; }
.iso-grip { stroke: #11161c; }
.iso-machine.iso-t { fill: #3a4450; } .iso-machine.iso-l { fill: #2a323c; } .iso-machine.iso-r { fill: #1d242c; }
.iso-machine { stroke: #11161c; }
.iso-led { fill: #3ddc97; }
/* the sign's raised border and numerals, with a darker copy behind as their depth */
.iso-raise { stroke: color-mix(in srgb, var(--mat) 72%, #fff); }
.iso-raise-lo { stroke: color-mix(in srgb, var(--mat) 50%, #05070b); }
.iso-raise-txt { fill: color-mix(in srgb, var(--mat) 72%, #fff); font-family: var(--font-display); font-weight: 700; }
.iso-raise-lo-txt { fill: color-mix(in srgb, var(--mat) 50%, #05070b); font-family: var(--font-display); font-weight: 700; }
/* the guard's polycarbonate window */
.iso-glass { fill: color-mix(in srgb, var(--mat) 22%, transparent); stroke: color-mix(in srgb, var(--mat) 70%, #fff); stroke-width: .8; vector-effect: non-scaling-stroke; }
.iso-glint { fill: rgba(255,255,255,.16); }
.iso-warn { fill: #f5c542; stroke: #6b4e00; stroke-width: .6; vector-effect: non-scaling-stroke; }
.iso-warn-txt { fill: #3a2a00; font-weight: 700; font-family: var(--font-display); }
.matx__body { padding: clamp(20px, 3vw, 28px); display: grid; gap: 14px; align-content: start; }

.matx__top { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; }
.matx__name { font-family: var(--font-mono); font-size: 26px; color: var(--mat-ink, var(--mat)); letter-spacing: .01em; }
.matx__full { font-size: 13px; color: var(--text-faint); }
.pill {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  padding: 4px 10px; border-radius: 999px; border: 1px solid currentColor;
}
.pill--ok   { color: var(--accent-ok); }
.pill--warn { color: var(--accent-warm); }
.pill--soon { color: var(--accent-ink); }

.matx__best { font-size: 15px; }
.matx__best b { color: var(--text); }
.matx__why, .matx__watch { font-size: 14px; color: var(--text-dim); }
.matx__watch { padding-left: 14px; border-left: 2px solid color-mix(in srgb, var(--accent-warm) 55%, transparent); }

.matx__specs { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px 20px; }
.matx__specs > div { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.matx__specs dt, .matx__specs .k { font-size: 12.5px; color: var(--text-faint); }
.matx__specs dd, .matx__specs .v { margin: 0; font-family: var(--font-mono); font-size: 12px; }

.matx__foot { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; padding-top: 4px; }

@media (max-width: 760px) {
  .matx { grid-template-columns: 1fr; }
  .matx__art { border-right: 0; border-bottom: 1px solid var(--line); padding: 20px; }
  .matx__art svg { max-width: 150px; }
}

/* learn blocks */
.learn-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); gap: 18px; }
.learn {
  padding: 22px 20px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--surface);
}
.learn h3 { font-size: 16px; margin-bottom: 8px; }
.learn p { font-size: 14px; color: var(--text-dim); }

/* =============================================================
   23. LASER SECTION
   ============================================================= */
.laser {
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background:
    radial-gradient(ellipse 60% 100% at 85% 0%, color-mix(in srgb, var(--accent-warm) 12%, transparent), transparent 70%),
    var(--surface);
  padding: clamp(24px, 4vw, 40px);
  display: grid; gap: 26px;
}
.laser__top { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.laser__top h2 { font-size: clamp(26px, 3.4vw, 38px); }
.badge-soon {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  padding: 6px 13px; border-radius: 999px;
  color: var(--accent-warm); border: 1px solid color-mix(in srgb, var(--accent-warm) 45%, transparent);
  background: color-mix(in srgb, var(--accent-warm) 10%, transparent);
}
.badge-soon::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--accent-warm);
  animation: pulse 2.4s var(--ease) infinite;
}
.laser__intro { color: var(--text-dim); max-width: 62ch; font-size: 16px; }

.laser__specs { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; }
.laser__spec {
  display: grid; gap: 3px; padding: 15px 16px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--bg-alt);
}
.laser__spec span { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint); }
.laser__spec b { font-size: 15px; font-weight: 500; font-family: var(--font-display); }

.laser__mats { display: flex; flex-wrap: wrap; gap: 8px; }
.laser__mats span {
  font-size: 13px; padding: 7px 14px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--text-dim); background: var(--bg-alt);
}
.laser__jobs { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 16px; }
.laser__job { padding-top: 16px; border-top: 1px solid var(--line); }
.laser__job h3 { font-size: 16px; margin-bottom: 6px; }
.laser__job p { font-size: 13.8px; color: var(--text-dim); }
.laser__note { font-size: 13px; color: var(--text-faint); }

/* =============================================================
   24. FAQ
   ============================================================= */
.faq { display: grid; gap: 0; border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__q {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 20px 4px; text-align: left; font-family: var(--font-display); font-weight: 600;
  font-size: clamp(16px, 2vw, 18px); transition: color .22s var(--ease);
}
.faq__q:hover { color: var(--accent-ink); }
.faq__sign { flex: none; width: 22px; height: 22px; position: relative; }
.faq__sign::before, .faq__sign::after {
  content: ''; position: absolute; inset: 50% 0 auto 0; height: 1.6px; background: currentColor;
  transition: transform .3s var(--ease);
}
.faq__sign::after { transform: rotate(90deg); }
.faq__item.is-open .faq__sign::after { transform: rotate(0deg); }
.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .34s var(--ease); }
.faq__item.is-open .faq__a { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { padding: 0 4px 22px; color: var(--text-dim); font-size: 15px; max-width: 70ch; }

/* =============================================================
   25. CTA BAND + MISC
   ============================================================= */
.band {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 22px;
  padding: clamp(26px, 4vw, 40px);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background:
    radial-gradient(ellipse 70% 130% at 100% 50%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 70%),
    var(--surface);
}
.band h2 { font-size: clamp(23px, 3vw, 30px); margin-bottom: 6px; }
/* About's "At a glance" card. .band's space-between shrank the list to its
   content width, leaving the values stranded mid-card; stretch it instead. */
.band--facts { display: grid; gap: 14px; justify-content: stretch; }
.band p { color: var(--text-dim); font-size: 15px; max-width: 52ch; }

.feature-row { display: flex; align-items: baseline; justify-content: space-between; gap: 18px; flex-wrap: wrap; margin-bottom: 26px; }
.link-more { display: inline-flex; align-items: center; gap: 7px; color: var(--accent-ink); font-size: 14.5px; font-weight: 500; }
.link-more svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform .25s var(--ease); }
.link-more:hover svg { transform: translateX(4px); }

.mini-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 18px; }
.mini {
  display: grid; gap: 9px; padding: 24px 22px;
  border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface);
  transition: transform .32s var(--ease), border-color .32s var(--ease);
}
.mini:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.mini__icon { width: 42px; height: 42px; border-radius: 12px; display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent); }
.mini__icon svg { width: 20px; height: 20px; fill: none; stroke: var(--accent); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.mini h3 { font-size: 17.5px; }
.mini p { font-size: 14px; color: var(--text-dim); }

/* machines list (about page) */
.machines { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 18px; }
.machine {
  padding: 24px 22px; border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); display: grid; gap: 12px; align-content: start;
}
.machine__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.machine h3 { font-size: 18px; }
.machine__list { list-style: none; padding: 0; display: grid; gap: 7px; }
.machine__list li { display: flex; justify-content: space-between; gap: 14px; font-size: 13.4px; }
.machine__list span { color: var(--text-faint); }
.machine__list b { font-family: var(--font-mono); font-size: 12.2px; font-weight: 500; }

/* prose (about story) */
.prose { max-width: 66ch; display: grid; gap: 16px; }
.prose p { color: var(--text-dim); font-size: 16px; }
.prose strong { color: var(--text); font-weight: 600; }

/* about page split */
.about-split {
  display: grid; grid-template-columns: 1.1fr .9fr;
  gap: clamp(30px, 5vw, 60px); align-items: start;
}
@media (max-width: 860px) { .about-split { grid-template-columns: 1fr; } }


/* =============================================================
   26. TOUCH & SMALL-SCREEN CORRECTIONS
   ============================================================= */

/* iOS Safari zooms in on focus when a form control is under 16px.
   Bumping these to 16px on touch devices stops the page jumping. */
@media (max-width: 900px), (pointer: coarse) {
  .f-field input, .f-field select, .f-field textarea { font-size: 16px; }
}

/* Hover effects are meaningless on touch and leave elements stuck in a
   hovered state after a tap, so they only apply to real pointers. */
@media (hover: none) {
  .card:hover, .prod:hover, .mini:hover, .mat:hover, .gal:hover { transform: none; }
  .gal__zoom { opacity: 1; transform: scale(1); }
}

/* Narrow phones: the header row (brand + CTA + theme + menu) does not fit
   below ~440px, and body overflow-x:hidden was quietly clipping the menu
   button off the right edge. The theme switch now has to survive here — it is
   the only one on the page — so the CTA shortens and everything tightens
   instead. Below 370px the wordmark steps aside and the mark carries it. */
.cta-short { display: none; }
.nav__cta { white-space: nowrap; }
/* The page links join the header at 1040px (seven pages), where the CTA's
   full label still fits beside them, so it no longer needs the short one there. */
@media (max-width: 440px) {
  .nav__inner { gap: 8px; }
  .nav__links { gap: 6px; }
  .cta-long  { display: none; }
  .cta-short { display: inline; }
  .nav__cta { padding: 9px 14px; }
  .brand { gap: 8px; }
  .brand__text { font-size: 16.5px; }
  .brand__mark { width: 29px; height: 29px; }
  .icon-btn { width: 36px; height: 36px; }
  .icon-btn svg { width: 17px; height: 17px; }
}
@media (max-width: 370px) {
  .brand__text { display: none; }
}

/* Phone in landscape: the hero would otherwise be taller than the screen. */
@media (max-height: 520px) and (orientation: landscape) {
  .hero { padding-block: 92px 40px; }
  .hero__stage { max-width: 420px; }
  .menu__inner { padding-top: 14px; gap: 18px; }
  .menu__link { padding-block: 10px; }
  .menu__name { font-size: clamp(20px, 3.4vw, 28px); }
}

/* Foldable inner screens and small tablets land in an awkward middle
   width — give the print bay and the lightbox room there. */
@media (min-width: 620px) and (max-width: 900px) {
  .hero__stage { max-width: 560px; }
  .lb__panel { width: min(100%, 620px); }
}


/* =============================================================
   27. LIGHT THEME — EDGES AND ELEVATION
   On white, a hairline alone doesn't separate a white card from a
   near-white page. Every surface block gets a soft two-layer shadow
   under its border. :where() keeps this at zero specificity so hover
   states and components with their own shadow still win.
   ============================================================= */
:where(:root[data-theme="light"]) :where(
  .card, .prod, .gal, .mat, .matx, .learn, .mini, .machine, .laser, .band,
  .hero-chip, .hero-hud, .hero__pills li, .laser__spec, .chip, .seg,
  .glance, .lb__panel, .est, .quote__form
) { box-shadow: var(--shadow-card); }

/* the tinted sections get a firm edge top and bottom, not just a tint */
:root[data-theme="light"] .section--alt { border-block-color: var(--line); }

/* the "this is a solid brick" warning on oversized estimator boxes */
.est__big {
  border-left: 2px solid var(--accent-warm);
  padding-left: 10px; margin-bottom: 8px;
}
.est__big b { color: var(--text); }

/* ---------- CONTACT ROUTES (v0.2.2) ----------
   A quote form is a commitment. Some people just have a question, and if the
   only thing on the page is a form they leave instead of asking. */
.band__aside { font-size: 13.5px; color: var(--text-faint); margin-top: 10px; }
.band__aside a { color: var(--accent-ink); border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); }

.ask-first {
  margin-top: 30px; padding: 20px 20px 18px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
}
.ask-first h3, .ask-first .ask-first__h { font-size: 16.5px; margin-bottom: 8px; }
.ask-first p { font-size: 14.2px; color: var(--text-dim); line-height: 1.6; }
.ask-first__alt { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line-soft); font-size: 13.6px; }
.ask-first a { color: var(--accent-ink); border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); }

/* ---------- SHOP (Shopify Buy Button) ---------- */
.shop__lede { color: var(--text-dim); max-width: 60ch; margin-bottom: 26px; }
.shop__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 16px; }
.shop__item {
  display: grid; gap: 8px; align-content: start;
  padding: 22px 20px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface);
}
.shop__item h3 { font-size: 16px; }
.shop__item p { font-size: 14px; color: var(--text-dim); }
.shop__buy { margin-top: 8px; }
/* the Buy Button renders un-iframed so it can inherit the site's buttons */
.shopify-buy__product__variant-selectors { margin-bottom: 10px; }
.shopify-buy__btn, .shopify-buy__btn--cart-checkout {
  font-family: var(--font-body); font-weight: 600; border-radius: 999px;
  padding: 11px 20px; border: 0; cursor: pointer;
  background: linear-gradient(120deg, var(--accent), var(--accent-2));
  color: #04121a;
}
.shopify-buy__btn:hover { filter: brightness(1.06); }
.shopify-buy__product__price { color: var(--text); font-family: var(--font-mono); }

/* ---------- LEGAL PAGES ---------- */
.legal { max-width: 74ch; display: grid; gap: 14px; }
.legal__meta { font-family: var(--font-mono); font-size: 12px; color: var(--text-faint); letter-spacing: .04em; }
.legal h2 { font-size: clamp(19px, 2.4vw, 23px); margin-top: 22px; }
.legal p, .legal li { color: var(--text-dim); font-size: 15.2px; line-height: 1.7; }
.legal ul { display: grid; gap: 8px; padding-left: 20px; }
.legal b { color: var(--text); }
.legal a { color: var(--accent-ink); border-bottom: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); }
.footer__legal a { color: var(--text-faint); }
.footer__legal a:hover { color: var(--accent-ink); }

/* ---------- LEGAL PAGES: summary box, tables, sub-headings ---------- */
.legal h3 { font-size: 16.5px; margin-top: 16px; color: var(--text); }
.legal__tldr {
  margin: 8px 0 14px; padding: 20px 22px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.legal__tldr h2 { margin-top: 0; font-size: 17px; }
.legal__tldr ul { margin-top: 10px; }
.legal__table { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 14.6px; }
.legal__table th, .legal__table td {
  text-align: left; padding: 11px 12px; border-bottom: 1px solid var(--line-soft);
  color: var(--text-dim); vertical-align: top;
}
.legal__table th { color: var(--text); font-weight: 600; border-bottom-color: var(--line); }
.legal__table td:first-child { color: var(--text); width: 42%; }
.legal__foot {
  margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--line);
  font-size: 14px; color: var(--text-faint);
}
@media (max-width: 560px) {
  .legal__table, .legal__table tbody, .legal__table tr, .legal__table td { display: block; width: 100%; }
  .legal__table thead { display: none; }
  .legal__table tr { padding: 10px 0; border-bottom: 1px solid var(--line-soft); }
  .legal__table td { border: 0; padding: 2px 0; }
  .legal__table td:first-child { font-weight: 600; width: auto; }
}

/* ---------- 28. BLUR BUDGET ----------
   Each backdrop-filter makes the compositor snapshot and blur everything behind
   it. Stacked, full-screen, on a desktop-sized window, that is what made the
   gallery lightbox drag on a PC while staying smooth on a phone (fewer pixels).
   The site now keeps at most two live at a time, and none behind an open
   overlay, where nobody can see through to them anyway. */
body.is-locked .nav,
body.is-locked .nav.is-stuck {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Some machines and settings ask for cheaper compositing outright. */
@media (prefers-reduced-transparency: reduce) {
  .lb, .menu, .nav.is-stuck {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .lb   { background: color-mix(in srgb, var(--bg) 97%, transparent); }
  .menu { background: var(--bg); }
  .nav.is-stuck { background: var(--bg); }
}

/* =============================================================
   29. MOTION (v0.9.2)
   The site's signature is the thing the business does: things get
   PRINTED. Titles print in layer by layer from the bottom, with the
   hot line of the nozzle at the front; cards stand on a stack of
   layers when you touch them; pages sweep in from the bottom.
   Everything here is either a one-shot entrance or a hover — nothing
   loops except the gallery placeholders' sheen, which only moves a
   transform. All of it switches off for reduced motion.
   ============================================================= */

/* ---- entrances ---- */
.rise { animation: rise var(--t-slow) var(--ease-out) var(--d, 0s) both; }
@keyframes rise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }

/* Printed in: revealed bottom-up in 16 discrete layers, a hot nozzle line
   at the front and the freshly laid layers glowing under it. */
/* sized to the words, so the glowing layer line spans the text, not the column */
.print-in { position: relative; width: fit-content; max-width: 100%; }
.print-in--load, .print-in.is-in { animation: print-reveal 1.3s steps(22, end) var(--d, .25s) both; }
/* waiting to be scrolled to: hidden by opacity, which (unlike a clip-path) the
   IntersectionObserver still sees, so it can tell when the title comes into view */
.print-wait { opacity: 0; }
@keyframes print-reveal {
  from { clip-path: inset(100% -4% -12% -4%); }
  to   { clip-path: inset(-12% -4% -12% -4%); }
}
.print-in::after {
  content: ''; position: absolute; left: -3%; right: -3%; top: 0; height: 100%; pointer-events: none;
  background:
    linear-gradient(to bottom, #fff3e0 0 1px, var(--hot) 1px 3px, color-mix(in srgb, var(--hot) 34%, transparent) 3px, transparent 24px);
  opacity: 0; transform: translateY(100%);
}
.print-in--load::after, .print-in.is-in::after { animation: print-scan 1.3s steps(22, end) var(--d, .25s) both; }
@keyframes print-scan {
  0%   { opacity: 1; transform: translateY(100%); }
  94%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(0); }
}
/* the headline's gradient line catches its light sweep after the print lands */
.hero__title .grad { animation-delay: 1.55s; }

/* inner-page headers land the same way as the home page */
.phead__inner > :not(h1) { animation: rise var(--t-slow) var(--ease-out) both; }
.phead__inner > :nth-child(1) { animation-delay: .05s; }
.phead__inner > :nth-child(3) { animation-delay: .8s; }
.phead__inner > :nth-child(n+4) { animation-delay: .9s; }

/* scroll reveals: a little quicker and crisper than v0.2 */
.reveal { transition: opacity .55s var(--ease-out), transform .55s var(--ease-out); transform: translateY(18px); }

/* ---- touch: cards stand on printed layers ----
   .tilt is added by script.js to cards, catalogue tiles, gallery tiles and
   machine cards. The pointer tilts them a few degrees towards itself (fine
   pointers only), and on hover they lift onto a stack of offset outlines —
   the layer lines of a print, in the accent colour. */
.tilt {
  --rx: 0deg; --ry: 0deg; --lift: 0px;
  transform: perspective(900px) rotateX(var(--rx)) rotateY(var(--ry)) translateY(var(--lift));
  transition: transform var(--t-med) var(--ease-out), box-shadow var(--t-med) var(--ease-out),
              border-color var(--t-med) var(--ease-out), opacity .55s var(--ease-out);
}
/* a tilting card is usually also a scroll reveal: keep its rise */
.tilt.reveal:not(.is-in) { transform: perspective(900px) translateY(18px); }
.tilt.reveal.is-in:not(:hover) { transform: perspective(900px) rotateX(var(--rx)) rotateY(var(--ry)) translateY(var(--lift)); }
.tilt.is-tracking { transition: transform .1s linear, box-shadow var(--t-med) var(--ease-out), border-color var(--t-med) var(--ease-out), opacity .55s var(--ease-out); }
@media (hover: hover) {
  .tilt:hover {
    --lift: -6px;
    border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
    box-shadow:
      0 2px 0 -1px color-mix(in srgb, var(--accent) 45%, transparent),
      0 5px 0 -2px color-mix(in srgb, var(--accent) 30%, transparent),
      0 8px 0 -3px color-mix(in srgb, var(--accent-2) 22%, transparent),
      0 11px 0 -4px color-mix(in srgb, var(--accent-2) 12%, transparent),
      0 30px 50px -24px rgba(0, 0, 0, .7);
  }
  /* v0.2 hovers did their own translateY; the tilt owns transform now, on every item card alike */
  .tilt.tilt:hover { transform: perspective(900px) rotateX(var(--rx)) rotateY(var(--ry)) translateY(var(--lift)); }
}
:root[data-theme="light"] .tilt:hover {
  box-shadow:
    0 2px 0 -1px color-mix(in srgb, var(--accent) 55%, transparent),
    0 5px 0 -2px color-mix(in srgb, var(--accent) 38%, transparent),
    0 8px 0 -3px color-mix(in srgb, var(--accent-2) 28%, transparent),
    0 11px 0 -4px color-mix(in srgb, var(--accent-2) 16%, transparent),
    0 26px 40px -24px rgba(15, 30, 55, .35);
}

/* ---- buttons: a magnetic pull, a press, a sheen ---- */
.btn { transition: transform var(--t-fast) var(--ease-spring), box-shadow var(--t-med) var(--ease-out),
                   background-color var(--t-med) var(--ease-out), border-color var(--t-med) var(--ease-out), color var(--t-med) var(--ease-out); }
.btn:active { transform: translate(var(--mx-btn, 0px), var(--my-btn, 0px)) scale(.97); }
.btn.magnetic { transform: translate(var(--mx-btn, 0px), var(--my-btn, 0px)); }
.btn.magnetic:hover { transform: translate(var(--mx-btn, 0px), calc(var(--my-btn, 0px) - 2px)); }
.btn.magnetic:active { transform: translate(var(--mx-btn, 0px), var(--my-btn, 0px)) scale(.97); }
.btn.magnetic.is-tracking { transition: transform .12s linear, box-shadow var(--t-med) var(--ease-out); }
.btn--primary { position: relative; overflow: hidden; isolation: isolate; }
.btn--primary::after {
  content: ''; position: absolute; inset: -2px; z-index: -1; pointer-events: none;
  background: linear-gradient(105deg, transparent 35%, rgba(255, 255, 255, .45) 50%, transparent 65%);
  transform: translateX(-120%);
}
@media (hover: hover) {
  .btn--primary:hover::after { transform: translateX(120%); transition: transform .7s var(--ease-out); }
}

/* ---- nav: one highlight glides to whichever link you point at ---- */
.nav__pages { position: relative; }
.nav__glide {
  position: absolute; top: 50%; left: 0; height: 34px; margin-top: -17px; border-radius: 9px; pointer-events: none; z-index: -1;
  width: var(--gw, 0px); transform: translateX(var(--gx, 0px));
  background: color-mix(in srgb, var(--accent) 11%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
  opacity: 0;
  transition: transform var(--t-med) var(--ease-out), width var(--t-med) var(--ease-out), opacity var(--t-fast) var(--ease-out);
}
.nav__pages.is-gliding .nav__glide { opacity: 1; }

/* ---- links in running text: the underline draws itself ---- */
.legal a, .gal-note a, .band__aside a, .ask-first a, .lb__story a {
  background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition: background-size var(--t-med) var(--ease-out);
}
.legal a:hover, .gal-note a:hover, .band__aside a:hover, .ask-first a:hover { background-size: 100% 1px; }

/* ---- loading: empty gallery slots breathe with a travelling sheen ---- */
.gal__ph { overflow: hidden; }
.gal__ph::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 30%, color-mix(in srgb, var(--accent) 10%, transparent) 50%, transparent 70%);
  transform: translateX(-100%);
  animation: sheen 2.6s var(--ease-out) infinite;
}
@keyframes sheen { 60%, 100% { transform: translateX(100%); } }

/* ---- page to page: the next page sweeps in from the bottom ----
   The header keeps its own transition name, so it stays perfectly still
   while the page under it changes — the app-like part. */
.nav { view-transition-name: site-nav; }
::view-transition-old(root) { animation: vt-out .26s var(--ease-out) both; }
::view-transition-new(root) { animation: vt-in .5s var(--ease-out) both; }
@keyframes vt-out { to { opacity: 0; transform: translateY(-10px) scale(.995); } }
@keyframes vt-in  { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }

@media (prefers-reduced-motion: reduce) {
  .rise, .print-in--load, .print-in.is-in, .print-in::after, .phead__inner > *, .gal__ph::after, .chamber::before { animation: none !important; }
  .print-wait { opacity: 1; }
  .tilt, .magnetic { transform: none !important; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none !important; }
}
/* ---- parallax: the hero's backdrop drifts slower than the page ---- */
/* (the parallax transforms are set by script.js, see initMotion) */
.hero__grid, .hero__glow { will-change: transform; }

/* ---- the menu: links arrive one after another, and fill in on hover ----
   The page names are set big and hollow (an outline), and fill with the
   accent from the left when pointed at, like a layer being laid down. */
.menu__list li { opacity: 0; transform: translateY(14px); transition: opacity var(--t-med) var(--ease-out), transform var(--t-med) var(--ease-out); }
.menu.is-open .menu__list li { opacity: 1; transform: none; }
.menu.is-open .menu__list li:nth-child(1) { transition-delay: .06s; }
.menu.is-open .menu__list li:nth-child(2) { transition-delay: .11s; }
.menu.is-open .menu__list li:nth-child(3) { transition-delay: .16s; }
.menu.is-open .menu__list li:nth-child(4) { transition-delay: .21s; }
.menu.is-open .menu__list li:nth-child(5) { transition-delay: .26s; }
.menu__foot { opacity: 0; transition: opacity var(--t-med) var(--ease-out) .3s; }
.menu.is-open .menu__foot { opacity: 1; }
@media (hover: hover) {
  .menu__name {
    background: linear-gradient(90deg, var(--accent), var(--accent-2)) 0 0 / 0% 100% no-repeat, linear-gradient(var(--text), var(--text));
    -webkit-background-clip: text; background-clip: text; color: transparent;
    transition: background-size .45s var(--ease-out);
  }
  .menu__link:hover .menu__name, .menu__link:focus-visible .menu__name,
  .menu__link[aria-current="page"] .menu__name {
    background-size: 100% 100%, 100% 100%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .menu__list li, .menu__foot { opacity: 1; transform: none; transition: none; }
}
/* =============================================================
   30. THE SHOP FLOOR (v0.9.2)
   One reveal everywhere gets old, so each kind of thing is revealed by
   a different machine from the shop:
     titles    FDM print  — a nozzle lays the text down layer by layer
     cards     laser cut  — the H2S's blue laser cuts round the outline
     drawings  slicer     — wireframe preview first, then solid
     figures   AMS swap   — the numbers flick through filament colours
   ============================================================= */

/* ---- FDM: the nozzle that prints the titles (built by script.js) ----
   Its origin is the tip, so a translate puts the tip exactly on the
   glowing layer line under it. */
.nozzle {
  position: absolute; left: 0; top: 0; width: 0; height: 0; z-index: 60; pointer-events: none;
}
.nozzle svg {
  position: absolute; left: -13px; bottom: 0; width: 26px; height: 42px; max-width: none; overflow: visible;
  transform: scale(var(--nz, 1)); transform-origin: 50% 100%;
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, .45));
}
h2.print-in { --d: .45s; }

/* ---- laser cut: a blue-white point runs round a card's outline ---- */
@property --cut { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.laser-in { position: relative; --laser: #6e86ff; }
.laser-in::after {
  content: ''; position: absolute; inset: 0; z-index: 4; pointer-events: none;
  border-radius: inherit; padding: 2px;
  background:
    conic-gradient(from -90deg, transparent 0 calc(var(--cut) - 26deg), color-mix(in srgb, var(--laser) 70%, transparent) calc(var(--cut) - 10deg), #fff calc(var(--cut) - 1deg), #fff var(--cut), transparent var(--cut)),
    conic-gradient(from -90deg, color-mix(in srgb, var(--laser) 75%, transparent) 0 var(--cut), transparent var(--cut));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0;
}
.laser-in.is-in::after { animation: laser-cut .95s cubic-bezier(.45, 0, .55, 1) var(--ld, .08s) both; }
@keyframes laser-cut {
  0%   { --cut: 0deg; opacity: 1; }
  82%  { --cut: 360deg; opacity: 1; }
  100% { --cut: 360deg; opacity: 0; }
}
:root[data-theme="light"] .laser-in { --laser: #3a55e8; }

/* ---- slicer preview: the drawing is traced as a wireframe, then goes solid ----
   script.js gives every shape pathLength="1", so a dash of 1 is the whole
   outline whatever its size. */
.slice-in :is(polygon, rect, circle, ellipse, path) { stroke-dasharray: 1 1; stroke-dashoffset: 1; }
.slice-in :is(polygon, rect, circle, ellipse, path, text) { fill-opacity: 0; }
.is-in .slice-in :is(polygon, rect, circle, ellipse, path, text) { animation: slice-draw 1.1s var(--ease-out) .15s both; }
@keyframes slice-draw {
  0%   { stroke-dashoffset: 1; fill-opacity: 0; stroke: var(--accent); }
  55%  { stroke-dashoffset: 0; fill-opacity: 0; stroke: var(--accent); }
  100% { stroke-dashoffset: 0; fill-opacity: 1; }
}

/* ---- AMS: key figures swap through filament colours, then settle ---- */
/* the hero's figures change colour as the page lands; the laser specs when they scroll in */
.hero__pills .ams-in, .is-in .ams-in { animation: ams-swap .9s steps(1, end) var(--ad, .15s) both; }
@keyframes ams-swap {
  0%   { color: #22e0ff; }
  18%  { color: #ff7a1a; }
  36%  { color: #6fe03a; }
  54%  { color: #8b6cff; }
  72%  { color: #ece6d8; }
  90%, 100% { color: var(--text); }
}
.hero__pills li:nth-child(1) strong { --ad: 1.25s; }
.hero__pills li:nth-child(2) strong { --ad: 1.4s; }
.hero__pills li:nth-child(3) strong { --ad: 1.55s; }

@media (prefers-reduced-motion: reduce) {
  .nozzle { display: none; }
  .laser-in::after { animation: none !important; opacity: 0; }
  .slice-in :is(polygon, rect, circle, ellipse, path, text) { animation: none !important; fill-opacity: 1; stroke-dashoffset: 0; }
  .ams-in { animation: none !important; }
}
/* ---- one feel for every control ----
   Buttons, filter chips, the estimator's material toggles and the hero's
   model buttons all lift a pixel on hover and give on press, on the same
   curve and timing (v0.9.4 audit: each had grown its own). */
.chip, .seg__btn, .hero-chip {
  transition: color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-spring);
}
@media (hover: hover) {
  .chip:hover, .seg__btn:hover, .hero-chip:hover, .btn--ghost:hover, .btn--primary:hover:not(.magnetic) { transform: translateY(-1px); }
}
.chip:active, .seg__btn:active, .hero-chip:active { transform: scale(.96); }
.btn:not(.magnetic):active { transform: scale(.97); }
@media (prefers-reduced-motion: reduce) {
  .chip, .seg__btn, .hero-chip { transition: none; }
}

/* ---------- HOW IT'S MADE (slicer.js) ----------
   A tall section with a sticky stage inside it: the scroll through the
   extra height is what drives the 3D scene. Reduced motion and the
   no-WebGL photo get a normal, unpinned section. */
.slicer { position: relative; height: 340vh; }
.slicer__pin {
  position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden;
  display: flex; align-items: center;
  background:
    radial-gradient(60% 55% at 70% 50%, color-mix(in srgb, var(--accent) 10%, transparent), transparent 70%),
    radial-gradient(40% 40% at 78% 70%, color-mix(in srgb, var(--accent-2) 9%, transparent), transparent 70%);
}
.slicer__grid {
  position: absolute; inset: 0; pointer-events: none; opacity: .5;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 56px 56px;
  -webkit-mask-image: radial-gradient(70% 70% at 70% 55%, #000 10%, transparent 75%);
          mask-image: radial-gradient(70% 70% at 70% 55%, #000 10%, transparent 75%);
}
.slicer__canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.slicer__still { display: none; }
.slicer__inner { position: relative; z-index: 1; pointer-events: none; }
.slicer__copy { max-width: 430px; pointer-events: auto; }
.slicer__copy h2 { font-size: clamp(30px, 4.4vw, 48px); margin-block: 12px 28px; }

.slicer__steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.slicer__step {
  display: grid; grid-template-columns: 34px 1fr; gap: 12px; padding: 12px 14px 12px 12px;
  border-radius: var(--radius); border: 1px solid transparent;
  opacity: .38; transform: translateX(0);
  transition: opacity .45s var(--ease), border-color .45s var(--ease), background .45s var(--ease), transform .45s var(--ease);
}
.slicer__step.is-active {
  opacity: 1; transform: translateX(6px);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.slicer__num { font-family: var(--font-mono); font-size: 12px; color: var(--accent-ink); padding-top: 3px; letter-spacing: .08em; }
.slicer__step h3 { font-size: 18px; margin-bottom: 3px; }
.slicer__step p { color: var(--text-dim); font-size: 14.5px; line-height: 1.55; }
.slicer__step:not(.is-active) p { display: none; }

.slicer__hud {
  display: inline-flex; align-items: center; gap: 9px; margin-top: 22px;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .06em; color: var(--text-dim);
  padding: 7px 12px; border: 1px solid var(--line); border-radius: 999px;
  background: color-mix(in srgb, var(--bg) 70%, transparent);
  font-variant-numeric: tabular-nums;
}
.slicer__track {
  position: absolute; right: clamp(16px, 3vw, 40px); top: 22%; bottom: 22%; width: 2px;
  background: var(--line); border-radius: 2px; overflow: hidden;
}
.slicer__track i {
  position: absolute; inset: 0; transform-origin: top; transform: scaleY(0);
  background: linear-gradient(var(--accent), var(--accent-2));
}
.slicer__hint {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .3em; text-transform: uppercase; color: var(--text-dim);
  animation: slicer-hint 2.2s var(--ease) infinite;
}
@keyframes slicer-hint { 0%,100% { opacity: .35; transform: translate(-50%, 0); } 50% { opacity: .9; transform: translate(-50%, 5px); } }

@media (max-width: 760px) {
  .slicer { height: 300vh; }
  .slicer__pin { align-items: flex-start; padding-top: 84px; }
  .slicer__copy h2 { margin-bottom: 14px; }
  .slicer__step { padding: 9px 10px; }
  /* a phone has room for one step at a time; the part sits under it */
  .slicer:not(.slicer--reduced):not(.slicer--still) .slicer__step:not(.is-active) { display: none; }
  .slicer__step.is-active { transform: none; }
  .slicer__step p { font-size: 13.5px; }
  .slicer__hud { margin-top: 12px; }
  .slicer__hint { display: none; }
}

/* Reduced motion: no pin; the finished part sits beside all three steps. */
.slicer--reduced { height: auto; }
.slicer--reduced .slicer__pin { position: relative; height: auto; min-height: 640px; padding-block: clamp(72px, 9vw, 130px); }
.slicer--reduced .slicer__step { opacity: 1; transform: none; }
.slicer--reduced .slicer__step p { display: block; }
.slicer--reduced .slicer__hint, .slicer--reduced .slicer__track { display: none; }

/* No WebGL (or no mesh): a photo of the real mask, and the steps as text. */
.slicer--still { height: auto; }
.slicer--still .slicer__pin { position: relative; height: auto; padding-block: clamp(72px, 9vw, 130px); }
.slicer--still .slicer__canvas, .slicer--still .slicer__hint, .slicer--still .slicer__track, .slicer--still .slicer__hud { display: none; }
.slicer--still .slicer__step { opacity: 1; transform: none; }
.slicer--still .slicer__step p { display: block; }
.slicer--still .slicer__still {
  display: block; position: absolute; right: max(20px, calc((100% - var(--wrap)) / 2)); top: 50%;
  width: min(44%, 520px); transform: translateY(-50%); border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--line);
}
@media (max-width: 760px) {
  .slicer--still .slicer__still { position: relative; right: auto; top: auto; transform: none; width: auto; margin: 28px 20px 0; }
  .slicer--still .slicer__pin { flex-direction: column; }
}
.slicer.is-done .slicer__hint { opacity: 0; animation: none; transition: opacity .4s var(--ease); }

/* ---------- MATERIAL COMPARE (materials.html, initCompare) ---------- */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.cmp {
  border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface);
  padding: clamp(16px, 2.4vw, 28px);
}
.cmp__bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 22px; }
.cmp__picker { display: flex; flex-wrap: wrap; gap: 8px; }
.cmp__chip {
  display: inline-flex; align-items: center; gap: 8px; padding: 8px 13px; border-radius: 999px;
  font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .04em; cursor: pointer;
  border: 1px solid var(--line); background: transparent; color: var(--text-dim);
  transition: background .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease), transform .2s var(--ease);
}
.cmp__chip i { width: 9px; height: 9px; border-radius: 50%; border: 1.5px solid var(--mat); transition: background .25s var(--ease), box-shadow .25s var(--ease); }
.cmp__chip:hover { border-color: color-mix(in srgb, var(--mat) 60%, var(--line)); color: var(--text); }
.cmp__chip.is-on {
  color: var(--text); border-color: var(--mat);
  background: color-mix(in srgb, var(--mat) 13%, transparent);
}
.cmp__chip.is-on i { background: var(--mat); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mat) 22%, transparent); }
.cmp__chip:active { transform: scale(.95); }
.cmp__chip.is-nope { animation: cmp-nope .4s var(--ease); }
@keyframes cmp-nope { 20%, 60% { transform: translateX(-4px); } 40%, 80% { transform: translateX(4px); } }
.cmp__tools { display: flex; align-items: center; gap: 8px; }
.cmp__count { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-faint); margin-right: 4px; }

.cmp__body { display: grid; grid-template-columns: minmax(240px, 340px) 1fr; gap: clamp(18px, 3vw, 36px); align-items: start; }
.cmp__radar { margin: 0; position: sticky; top: 92px; }
.cmp__radar svg { width: 100%; height: auto; overflow: visible; }
.cmp__ring { fill: none; stroke: var(--line); stroke-width: 1; }
.cmp__ring:last-of-type { stroke: color-mix(in srgb, var(--text-faint) 50%, transparent); }
.cmp__spoke { stroke: var(--line); stroke-width: 1; }
.cmp__axis { fill: var(--text-dim); font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; }
.cmp__shape polygon {
  fill: color-mix(in srgb, var(--mat) 14%, transparent); stroke: var(--mat); stroke-width: 2; stroke-linejoin: round;
  transition: opacity .25s var(--ease), stroke-width .25s var(--ease);
}
.cmp__dots circle { fill: var(--mat); }
.cmp__shape { transition: opacity .25s var(--ease); }
.cmp__shape.is-dim { opacity: .14; }
.cmp__legend { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 14px; margin-top: 8px; font-family: var(--font-mono); font-size: 11.5px; color: var(--mat-ink, var(--text-dim)); }
.cmp__key { display: inline-flex; align-items: center; gap: 6px; color: var(--mat-ink); transition: opacity .25s var(--ease); }
.cmp__key i { width: 14px; height: 3px; border-radius: 2px; background: var(--mat); }
.cmp__key.is-dim { opacity: .35; }

.cmp__tablewrap { overflow-x: auto; border-radius: var(--radius); border: 1px solid var(--line); outline-offset: 3px; }
.cmp__table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13.5px; min-width: max-content; }
.cmp__table th, .cmp__table td { padding: 10px 14px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line-soft, var(--line)); }
.cmp__table tbody tr:last-child th, .cmp__table tbody tr:last-child td { border-bottom: 0; }
.cmp__table tbody th, .cmp__table tfoot th {
  position: sticky; left: 0; z-index: 1; background: var(--surface);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 500; white-space: nowrap;
}
.cmp__table thead th { position: sticky; top: 0; background: var(--surface); border-bottom: 2px solid var(--mat, var(--line)); min-width: 150px; max-width: 230px; }
.cmp__table thead th:first-child { left: 0; z-index: 2; min-width: 0; border-bottom-color: var(--line); }
.cmp__name { display: block; font-family: var(--font-display); font-size: 17px; font-weight: 600; color: var(--mat-ink); }
.cmp__full { display: block; font-size: 11.5px; color: var(--text-faint); }
.cmp__table td { color: var(--text-dim); max-width: 230px; transition: opacity .25s var(--ease), background .25s var(--ease); }
.cmp__table td b { color: var(--text); font-weight: 600; }
.cmp__table td span { color: var(--text-faint); font-size: 12px; }
.cmp__table td.is-best { background: color-mix(in srgb, var(--mat) 9%, transparent); }
.cmp__table td.is-best::after {
  content: 'Best'; display: inline-block; margin-left: 7px; padding: 1px 6px; border-radius: 999px; vertical-align: 1px;
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--mat-ink); border: 1px solid color-mix(in srgb, var(--mat) 50%, transparent);
}
.cmp__table .is-dim { opacity: .35; }
.cmp__meter { display: inline-block; width: 56px; height: 6px; margin-right: 8px; border-radius: 3px; vertical-align: 1px;
  background: linear-gradient(90deg, var(--mat) calc(var(--v) * 100%), color-mix(in srgb, var(--mat) 14%, transparent) 0); }
.cmp__table tfoot td { border-bottom: 0; }
.cmp__table .is-new { animation: cmp-in .45s var(--ease) both; }
@keyframes cmp-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

@media (max-width: 900px) {
  .cmp__body { grid-template-columns: 1fr; }
  .cmp__radar { position: static; max-width: 340px; margin-inline: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .cmp__table .is-new, .cmp__chip.is-nope { animation: none; }
}
.cmp__tools .btn { white-space: nowrap; }
.cmp__table thead th { min-width: 140px; max-width: 200px; }
.cmp__table td { max-width: 200px; }
/* more columns off to the side: a fade and a nudge on that edge */
.cmp__tablewrap { position: relative; }
.cmp__scroller { position: relative; }
.cmp__more {
  position: absolute; top: 1px; right: 1px; bottom: 1px; width: 56px; pointer-events: none;
  border-radius: 0 var(--radius) var(--radius) 0; opacity: 0; transition: opacity .25s var(--ease);
  background: linear-gradient(90deg, transparent, var(--surface) 85%);
  display: flex; align-items: center; justify-content: flex-end; padding-right: 8px;
  font-family: var(--font-mono); font-size: 16px; color: var(--accent-ink);
}
.cmp__scroller.has-more .cmp__more { opacity: 1; }
@media (max-width: 620px) {
  .cmp__bar { gap: 10px; }
  .cmp__tools { width: 100%; }
  .cmp__count { margin-right: auto; }
  .cmp__table { font-size: 12.5px; }
  .cmp__table th, .cmp__table td { padding: 9px 10px; }
  .cmp__table thead th { min-width: 118px; }
  .cmp__table tbody th, .cmp__table tfoot th { font-size: 9.5px; letter-spacing: .04em; white-space: normal; max-width: 72px; }
  .cmp__meter { width: 34px; margin-right: 5px; }
  .cmp__name { font-size: 15px; }
}
.cmp__body > * { min-width: 0; }
.cmp__table { min-width: 0; table-layout: auto; }
.cmp__table thead th { min-width: 0; }
@media (max-width: 620px) { .cmp__table thead th { min-width: 0; } }

/* ---------- LIGHTBOX ZOOM (lbZoom in script.js) ---------- */
.lb__stagewrap { position: relative; display: grid; overflow: hidden; }
.lb__stage { background: var(--photo-bg, var(--bg-alt)); touch-action: none; cursor: zoom-in; transition: background-color .35s var(--ease); }
.lb__stage.is-zoomed { cursor: grab; }
.lb__stage.is-panning { cursor: grabbing; }
.lb__stage img { transform-origin: 50% 50%; will-change: transform; user-select: none; -webkit-user-drag: none; }
.lb__zoom {
  position: absolute; right: 14px; bottom: 14px; z-index: 3;
  display: flex; align-items: center; gap: 2px; padding: 4px;
  border-radius: 999px; border: 1px solid var(--line);
  background: color-mix(in srgb, var(--surface) 94%, transparent);   /* no blur: RG-085 keeps the lightbox free of live blur layers */
}
.lb__zoom button {
  width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%;
  border: 0; background: transparent; color: var(--text); cursor: pointer;
  transition: background .2s var(--ease), opacity .2s var(--ease);
}
.lb__zoom button:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.lb__zoom button:disabled { opacity: .35; cursor: default; }
.lb__zoom svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.lb__zoom span { min-width: 44px; text-align: center; font-family: var(--font-mono); font-size: 11px; color: var(--text-dim); }
.lb__zoomhint {
  position: absolute; left: 14px; bottom: 18px; z-index: 3; pointer-events: none;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .04em; color: var(--text-dim);
  padding: 5px 10px; border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 78%, transparent);
  transition: opacity .3s var(--ease);
}
.lb__stage.is-zoomed ~ .lb__zoomhint { opacity: 0; }
@media (max-width: 620px) { .lb__zoomhint { display: none; } }

/* ---------- LAYER RAIL (initSectionNav) ----------
   Fixed down the left edge on wide screens: one print layer per stop, the
   nozzle riding to the one you are on. Under 1100px: a pill bottom-left that
   opens the same list. */
.layers {
  position: fixed; left: clamp(10px, 1.6vw, 26px); top: 50%; z-index: 80;
  transform: translate(-14px, -50%); opacity: 0; pointer-events: none;
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.layers.is-shown { opacity: 1; transform: translate(0, -50%); pointer-events: auto; }
.layers.is-away { opacity: 0 !important; pointer-events: none !important; }
.layers__pill { display: none; }
.layers__list { list-style: none; margin: 0; padding: 6px 0 6px 18px; display: flex; flex-direction: column; gap: 2px; position: relative; }
.layers__item {
  position: relative; display: flex; align-items: center; height: 18px; gap: 12px;
  color: var(--text-dim); text-decoration: none; outline: none;
}
.layers__line {
  display: block; width: 18px; height: 3px; border-radius: 2px;
  background: color-mix(in srgb, var(--text-faint) 55%, transparent);
  transition: width .3s var(--ease), background .3s var(--ease), box-shadow .3s var(--ease);
}
.layers__item:hover .layers__line, .layers__item:focus-visible .layers__line { width: 28px; background: var(--text-dim); }
.layers__item.is-here .layers__line {
  width: 34px; background: linear-gradient(90deg, var(--accent), var(--accent-2));
  box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 70%, transparent);
}
.layers__label {
  white-space: nowrap; font-family: var(--font-mono); font-size: 11px; letter-spacing: .05em;
  padding: 4px 9px; border-radius: 8px; border: 1px solid var(--line);
  background: color-mix(in srgb, var(--surface) 92%, transparent); color: var(--text);
  box-shadow: 0 8px 24px -12px rgba(0,0,0,.5);
  opacity: 0; transform: translateX(-6px); pointer-events: none;
  transition: opacity .2s var(--ease), transform .2s var(--ease);
}
.layers__item:hover .layers__label, .layers__item:focus-visible .layers__label { opacity: 1; transform: none; }
.layers__item:focus-visible .layers__label { outline: 2px solid var(--accent); outline-offset: 2px; }
/* the nozzle: a small hot-end that rides along to the layer you are on */
.layers__nozzle {
  position: absolute; left: 0; top: 0; width: 12px; height: 12px; margin-top: -6px;
  transition: transform .45s var(--ease);
}
.layers__nozzle::before {
  content: ''; position: absolute; inset: 0 1px 4px; border-radius: 2px 2px 0 0; background: var(--text-dim);
}
.layers__nozzle::after {
  content: ''; position: absolute; left: 3px; right: 3px; bottom: 0; height: 5px;
  background: var(--accent); clip-path: polygon(0 0, 100% 0, 50% 100%);
  filter: drop-shadow(0 0 4px var(--accent));
}
:root[data-theme="light"] .layers__item.is-here .layers__line { box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 45%, transparent); }

@media (max-width: 1100px) {
  .layers { top: auto; left: 16px; bottom: calc(22px + env(safe-area-inset-bottom, 0px)); transform: translateY(14px); }
  .layers.is-shown { transform: none; }
  .layers__nozzle { display: none; }
  .layers__pill {
    display: inline-flex; align-items: center; gap: 8px; height: 44px; max-width: min(64vw, 280px); padding: 0 16px 0 13px;
    border-radius: 999px; border: 1px solid var(--line); cursor: pointer;
    background: color-mix(in srgb, var(--surface) 90%, transparent); color: var(--text);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
    box-shadow: 0 10px 30px -14px rgba(0,0,0,.55);
    font-family: var(--font-mono); font-size: 12px; letter-spacing: .03em;
  }
  .layers__pill svg { width: 16px; height: 16px; flex: none; fill: none; stroke: var(--accent); stroke-width: 2; stroke-linecap: round; }
  .layers__here { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .layers__list {
    position: absolute; left: 0; bottom: 54px; min-width: 230px; max-height: 60vh; overflow-y: auto;
    padding: 8px; gap: 0; border-radius: 16px; border: 1px solid var(--line);
    background: var(--surface); box-shadow: 0 24px 50px -20px rgba(0,0,0,.6);
    opacity: 0; transform: translateY(8px) scale(.98); transform-origin: bottom left; pointer-events: none;
    transition: opacity .22s var(--ease), transform .22s var(--ease);
  }
  .layers.is-open .layers__list { opacity: 1; transform: none; pointer-events: auto; }
  .layers__item { height: auto; padding: 10px 10px; border-radius: 10px; }
  .layers__item:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
  .layers__label { opacity: 1; transform: none; padding: 0; border: 0; background: none; box-shadow: none; font-size: 12.5px; }
  .layers__item.is-here .layers__label { color: var(--accent-ink); }
}
@media (prefers-reduced-motion: reduce) {
  .layers, .layers__nozzle, .layers__line, .layers__label, .layers__list { transition: none; }
}

/* ---------- CONTACT PAGE ---------- */
.contact-ways { list-style: none; margin: 14px 0 26px; padding: 0; display: grid; gap: 1px; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--line); }
.contact-ways li { display: flex; justify-content: space-between; gap: 16px; padding: 13px 16px; background: var(--surface); }
.contact-ways span { font-family: var(--font-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint); padding-top: 2px; }
.contact-ways a { color: var(--accent-ink); }
.contact-ways b { font-weight: 500; }
.f-opt { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint); margin-left: 6px; font-weight: 400; }

/* ---------- INDUSTRIAL PAGE ---------- */
.ind-cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
.mini__mat { margin-top: auto; padding-top: 10px; font-family: var(--font-mono); font-size: 11px !important; letter-spacing: .04em; color: var(--accent-ink) !important; }
.who-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 18px; }
.who { padding: 22px; border-radius: var(--radius-lg); border: 1px solid var(--line); background: var(--surface); position: relative; overflow: hidden; }
.who::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: linear-gradient(var(--accent), var(--accent-2)); }
.who h3 { font-size: 17px; margin-bottom: 6px; }
.who p { font-size: 14px; color: var(--text-dim); }
.cap { display: grid; grid-template-columns: 1.3fr 1fr; gap: clamp(18px, 3vw, 36px); align-items: start; }
.cap__list { border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); padding: 6px 20px; }
.cap__list li { gap: 18px; }
.cap__list b { text-align: right; }
.cap__note { padding: 22px; border-radius: var(--radius-lg); border: 1px dashed color-mix(in srgb, var(--text-faint) 60%, transparent); }
.cap__note h3 { font-size: 17px; margin-bottom: 10px; }
.cap__note ul { margin: 0; padding-left: 18px; display: grid; gap: 8px; color: var(--text-dim); font-size: 14px; }
@media (max-width: 860px) { .cap { grid-template-columns: 1fr; } .cap__list b { text-align: left; } .cap__list li { flex-direction: column; gap: 2px; } }

/* ---------- HEADER + FOOTER (v0.9.7 structure) ----------
   Wide screens: logo · five pages · Contact · quote button · theme. The burger
   is only for narrower screens, where the menu lists all six pages. */
.nav__util {
  display: none; padding: 8px 10px; font-size: 14.5px; font-weight: 500; color: var(--text-dim);
  border-radius: 9px; transition: color .2s var(--ease);
}
.nav__util:hover, .nav__util[aria-current="page"] { color: var(--text); }
@media (min-width: 960px) {
  .nav__util { display: inline-flex; }
  .nav__inner .nav__burger { display: none; }
}
.footer__cta { width: fit-content; margin-bottom: 4px; color: #04121a !important; }
.footer__legal { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.footer__bottom { align-items: center; }

/* ---------- LAYER RAIL: hover only on the layer itself (v0.9.7 fix) ----------
   The whole row (line + hidden label) used to be the link, so an invisible
   200px strip over the left edge caught hovers and scrolls meant for the cards
   beside it. Now only the short line is the target; the label floats beside
   it, ignores the pointer, and appears only while that line is hovered. */
@media (min-width: 1101px) {
  .layers { pointer-events: none; }
  .layers.is-shown .layers__item { pointer-events: auto; }
  .layers__list { padding-left: 16px; width: 56px; }
  .layers__item { width: 40px; height: 16px; gap: 0; }
  .layers__line { flex: none; }
  .layers__label {
    position: absolute; left: 46px; top: 50%; translate: 0 -50%;
    pointer-events: none !important; font-size: 10.5px; padding: 3px 8px;
  }
}
/* the rail and its pill step aside once the footer is in view */
.layers.is-footer { opacity: 0 !important; pointer-events: none !important; }
.layers.is-footer * { pointer-events: none !important; }
@media (max-width: 1100px) {
  .menu__foot .btn { width: 100%; justify-content: center; }
}

/* =============================================================
   HOME ON A PHONE (v0.9.7 review): value first, details on demand.
   The page was ten screens long and opened on the printer, with the
   headline and the quote button below the fold. Now: headline, one line,
   the quote button, then a shorter printer; compact stats; no ticker; a
   shorter "How it's made"; services as a 2x2 grid; recent work as a strip.
   ============================================================= */
@media (max-width: 760px) {
  .hero { min-height: 0; padding-block: 88px 28px; }
  .hero__inner { gap: 22px; }
  .chamber { order: 0; }                               /* words and the button come first */
  .hero__title { font-size: clamp(34px, 10vw, 44px); }
  .hero__sub { font-size: 15.5px; margin-top: 12px; }
  .hero__cta { margin-top: 20px; gap: 10px; }
  .hero__cta .btn { flex: 1 1 auto; justify-content: center; padding-inline: 18px; }
  .hero__cta .btn--lg { min-height: 50px; font-size: 15px; }
  .hero__pills { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 20px; }
  .hero__pills li { padding: 9px 10px; }
  .hero__pills strong { font-size: 12px; }
  .hero__pills span { font-size: 10.5px; }
  .hero__stage { min-height: clamp(210px, 52vw, 300px); }
  .hero-models { flex-wrap: nowrap; justify-content: flex-start; overflow-x: auto; scroll-snap-type: x mandatory;
                 padding: 0 2px 4px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .hero-models::-webkit-scrollbar { display: none; }
  .hero-chip { flex: none; scroll-snap-align: start; }
  .ticker { display: none; }

  .slicer { height: 230vh; }

  #services { padding-block: 48px; }
  #services .feature-row { margin-bottom: 18px; }
  #services .mini-cards { grid-template-columns: 1fr 1fr; gap: 10px; }
  #services .mini { padding: 15px 14px; gap: 6px; }
  #services .mini__icon { width: 34px; height: 34px; border-radius: 10px; }
  #services .mini h3 { font-size: 15px; }
  #services .mini p { font-size: 12.5px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

  #work { padding-block: 48px; }
  #work .gal-grid[data-limit] { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; gap: 12px;
                    margin-inline: -20px; padding: 0 20px 8px; scrollbar-width: none; }
  #work .gal-grid[data-limit]::-webkit-scrollbar { display: none; }
  #work .gal-grid[data-limit] .gal { flex: 0 0 76%; scroll-snap-align: start; }
}
#work .gal-grid[data-limit] { scroll-padding-inline: 20px; }

/* ---------- INNER PAGES ON A PHONE (v0.9.7 review) ----------
   Materials: each card shows name, best use and the ratings; "Details" opens
   the why / watch-out / temperatures. Services: the cards drop their bullet
   lists, and the product tiles go two to a row. */
.matx__more { display: none; }
@media (max-width: 760px) {
  .matx__art { max-height: 130px; }
  .matx__art svg { max-height: 120px; }
  .matx__body { gap: 10px; padding: 16px 18px 18px; }
  .matx:not(.is-open) .matx__why, .matx:not(.is-open) .matx__watch { display: none; }
  .matx__more {
    display: inline-flex; margin-left: auto; padding: 7px 12px; border-radius: 999px; cursor: pointer;
    border: 1px solid var(--line); background: transparent; color: var(--text-dim);
    font-family: var(--font-mono); font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  }
  .matx__foot .matx__full { display: none; }

  #printing .card__list { display: none; }
  #printing .card { padding: 18px; }
  .prod-grid { grid-template-columns: 1fr 1fr !important; gap: 10px !important; }
  .prod { padding: 14px !important; }
  .prod h3 { font-size: 15px; }
  .prod p { font-size: 12.5px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
}

@media (max-width: 760px) {
  .matx__art { max-height: 96px; }
  .matx__art svg { max-height: 88px; }
  .matx__specs { grid-template-columns: 1fr 1fr; gap: 6px 14px; }
  .matx__best { font-size: 14px; }
}

/* Light mode: the build chamber was near-white, so white and bone-white
   parts vanished into it. It now reads as the lit inside of an enclosure:
   a cool mid-grey that a white part stands out against. */
:root[data-theme="light"] .chamber {
  background:
    radial-gradient(110% 70% at 50% 105%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 62%),
    linear-gradient(180deg, #b9c4d3 0%, #a3b0c2 55%, #96a3b6 100%);
  border-color: #8f9cb0;
  box-shadow: 0 30px 70px -36px rgba(20, 35, 60, .55), inset 0 1px 0 rgba(255, 255, 255, .35);
}
:root[data-theme="light"] .chamber__bar { background: color-mix(in srgb, #ffffff 82%, #c9d3e0); }

/* "How it works" steps as cards, like every other card on the site: they
   were bare text under a 1px rule that all but vanished on the light page. */
.step {
  padding: 24px 22px 22px; border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); overflow: hidden;
}
.step::before { top: 0; height: 3px; }
:root[data-theme="light"] .step { border-color: #c3ccd9; box-shadow: 0 10px 28px -22px rgba(20, 35, 60, .35); }

/* Lightbox: the photo was sized to the panel's width, so a 4:3 shot came out
   ~735px tall in a stage capped at 66vh and lost its bottom. The stage now
   has a set height and the photo is fitted whole inside it. */
.lb__stage { height: min(64vh, 620px); min-height: 260px; max-height: none; }
.lb__stage .photo { width: 100%; height: 100%; }
.lb__stage img { width: 100%; height: 100%; max-height: none; object-fit: contain; }
.lb__stage .gal__ph { min-height: 0; height: 100%; }
.lb__zoomhint { display: none !important; }        /* the tip now sits with the counter, off the photo */
.lb__tip { color: var(--text-faint); }
@media (max-width: 620px) { .lb__stage { height: min(52vh, 440px); } .lb__tip { display: none; } }
.lb__countrow { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 16px; font-family: var(--font-mono); font-size: 11.5px; }
.lb__countrow .lb__count { margin: 0; }
.lb__stage { display: block; position: relative; }
.lb__stage > .photo, .lb__stage > .gal__ph { position: absolute; inset: 0; width: auto; height: auto; }
.lb__stage > .photo img { position: absolute; inset: 0; }
.footer__brand .footer__made { margin-top: -8px; color: var(--accent-ink); font-size: 12.5px; }

/* ---------- RESERVED SPACE FOR SCRIPT-DRAWN GRIDS (v0.9.7, CLS) ----------
   These grids are built by script.js after the HTML has painted, so on a slow
   phone everything under them jumped down when they arrived (gallery CLS 0.43,
   materials 0.12). Each now holds a floor a little under its measured height,
   so the page below starts roughly where it ends up. A floor, not a size: the
   content can always grow past it. */
.filters[hidden] { display: none !important; }
#galGrid { min-height: 290px; }
#matxGrid { min-height: 3000px; }
#learnGrid { min-height: 380px; }
#prodGrid { min-height: 520px; }
#servicesGrid { min-height: 880px; }
#laserSection { min-height: 250px; }
#faqList { min-height: 440px; }
@media (max-width: 620px) {
  #galGrid { min-height: 650px; }
  #galGrid[data-limit] { min-height: 300px; }
  #matxGrid { min-height: 3350px; }
  #learnGrid { min-height: 920px; }
  #prodGrid { min-height: 960px; }
  #servicesGrid { min-height: 1560px; }
  #laserSection { min-height: 330px; }
}

/* ---------- REFLOW AT 320 px (WCAG 1.4.10) ----------
   An iPhone SE, or any phone with large text: nothing may be cut off. */
.matx, .matx__body, .est, .est__controls, .est__out, .field, .hero__copy { min-width: 0; }
.matx__best, .matx__why, .matx__watch { overflow-wrap: anywhere; }
@media (max-width: 620px) {
  /* seven materials wrap onto two rows instead of running off the side */
  .seg { flex-wrap: wrap; }
  .seg__btn { flex: 1 0 calc(25% - 6px); min-width: 0; }
  .dim { gap: 10px; }
  .dim__val { min-width: 48px; }
}
@media (max-width: 380px) {
  .hero__cta .btn { flex: 1 1 100%; white-space: normal; }
  .hero__pills { grid-template-columns: 1fr 1fr; }
  .hero__pills li:first-child { grid-column: 1 / -1; }
  .eyebrow { letter-spacing: .1em; }
  .matx__specs { grid-template-columns: 1fr; }
}

/* ---------- ACCESSIBILITY FIXES (v0.9.7 audit) ---------- */
.footer__col .footer__h { font-size: 12px; font-family: var(--font-mono); letter-spacing: .13em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 4px; font-weight: 600; }
/* small grey text inside a highlighted "Best" cell measured 4.23:1 in the dark theme */
.cmp__table td.is-best span { color: var(--text-dim); }
/* nothing under 11px: these labels were 9.5-10.5px */
.gal__badge, .cmp__table td.is-best::after, .hero__pills span, .lb__zoomhint, .layers__label,
.est__vizhint, .est__fits, .f-opt, .matx__more, .gal__views { font-size: 11px !important; }
.chamber__bar, .prod__tag, .pill, .laser__spec span, .cmp__axis { font-size: 11px !important; }
@media (max-width: 620px) { .cmp__table tbody th, .cmp__table tfoot th, .hero__pills span { font-size: 11px !important; } }

/* floating controls slide away while reading down on phones (initFloatAway) */
@media (max-width: 1100px) {
  .to-top, .layers { transition: transform .3s var(--ease), opacity .3s var(--ease); }
  body.is-reading .to-top { transform: translateY(140%); opacity: 0; pointer-events: none; }
  body.is-reading .layers:not(.is-open) { transform: translateY(140%); opacity: 0; pointer-events: none; }
}
@media (prefers-reduced-motion: reduce) { .to-top, .layers { transition: none; } }
