/* ============================================================
   VOXEL — design system
   Palette locked to the brand deck (Mirette Wadee, 2026)
   ============================================================ */

:root {
  /* ---- Brand constants: identical in both themes ---- */
  --blue:        #195cf1;
  --blue-bright: #4d84ff;
  --blue-deep:   #0b3ec0;
  --navy:        #041131;
  --navy-deep:   #020a1f;
  --black:       #000000;
  --paper:       #f4f7fe;
  --white:       #ffffff;

  /* ---- Theme channels ----
     Held as bare "r g b" triples so every translucent variant in the
     sheet can be written rgb(var(--x-rgb) / .5) and flip with the
     theme automatically, instead of hand-maintaining two of each. */
  --deep-rgb:    2 10 31;      /* deepest surface: overlays, insets   */
  --surface-rgb: 4 17 49;      /* raised surface: cards, panels       */
  --text-rgb:    244 247 254;  /* foreground                          */
  --accent-rgb:  25 92 241;
  --accent-bright-rgb: 77 132 255;
  --accent-deep-rgb:   11 62 192;

  /* ---- Semantic, derived from the channels ---- */
  --bg:        rgb(var(--deep-rgb));
  --bg-alt:    rgb(var(--surface-rgb));
  --text:      rgb(var(--text-rgb));
  --dim:       rgb(var(--text-rgb) / 0.62);
  --line-dark: rgb(var(--text-rgb) / 0.14);
  --line-light: rgb(var(--surface-rgb) / 0.12);
  --dim-ink:   rgb(var(--surface-rgb) / 0.64);
  --footer-bg: var(--black);
  --shadow:    rgba(0, 0, 0, .45);
  --grain-blend: overlay;
  --grain-opacity: .14;
  --aura-a: .62;
  --aura-b: .34;
  --danger:    #7f1d1d;

  /* Accent that sits on the page background. The brand blue is legible
     on navy but thin against near-white, so light mode darkens it for
     body-sized text while buttons keep the true brand colour. */
  --accent-on-bg: var(--blue-bright);

  color-scheme: dark;

  /* Type — three faces, each doing one job.
     Anton is a single-weight poster face: enormous impact at headline
     size, illegible below about 1.2rem. It is therefore restricted to
     .display, and Archivo carries every mid-level heading and all body
     copy. Plex Mono still carries every number and label. */
  --font-display: 'Anton', 'Archivo', 'IBM Plex Sans Arabic', system-ui, sans-serif;
  --font-body:    'Archivo', 'IBM Plex Sans Arabic', system-ui, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, monospace;

  /* Rhythm */
  --gut: clamp(1.25rem, 4vw, 3rem);
  --wrap: 1240px;
  --cut: 14px; /* corner cut, echoes the logo's angular terminals */

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ============================================================
   LIGHT THEME
   Only the channels and a handful of semantics change; every
   translucent value in the sheet follows from them.
   ============================================================ */
:root[data-theme='light'] {
  --deep-rgb:    244 247 254;  /* page      */
  --surface-rgb: 255 255 255;  /* cards     */
  --text-rgb:    4 17 49;      /* navy ink  */

  --dim:        rgb(var(--text-rgb) / 0.66);
  --line-dark:  rgb(var(--text-rgb) / 0.13);
  --line-light: rgb(var(--text-rgb) / 0.13);
  --dim-ink:    rgb(var(--text-rgb) / 0.66);
  --footer-bg:  var(--navy);
  --shadow:     rgba(4, 17, 49, .18);
  /* overlay blend on a pale ground washes out; multiply keeps the tooth */
  --grain-blend: multiply;
  --grain-opacity: .06;
  /* a wash, not a blob — the same alphas would read as solid on paper */
  --aura-a: .17;
  --aura-b: .12;
  --danger:     #b42318;
  --accent-on-bg: var(--blue-deep);

  color-scheme: light;
}

/* Islands that stay dark in light mode, each for its own reason:
   the footer as a deliberate anchor, and the 3D stages because a white
   or clear filament lit against a white page would simply disappear —
   a dark stage reads every colour the shop sells. Re-declaring the
   channels here means their nested text and borders follow along. */
:root[data-theme='light'] .footer,
:root[data-theme='light'] .hero__stage,
:root[data-theme='light'] .viewer {
  --deep-rgb: 2 10 31;
  --surface-rgb: 4 17 49;
  --text-rgb: 244 247 254;
  /* The derived tokens must be restated, not just the channels: --text
     is substituted where it is declared (:root), so overriding only
     --text-rgb here would leave --text as the page's navy ink and make
     footer links invisible against the dark panel. */
  --text: rgb(var(--text-rgb));
  --bg: rgb(var(--deep-rgb));
  --bg-alt: rgb(var(--surface-rgb));
  --dim: rgb(var(--text-rgb) / 0.62);
  --line-dark: rgb(var(--text-rgb) / 0.14);
  --line-light: rgb(var(--text-rgb) / 0.14);
  --accent-on-bg: var(--blue-bright);
  color: var(--text);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
/* Any author `display` beats the UA rule for [hidden], which silently
   un-hides anything given a display value (.done is display:grid). */
[hidden] { display: none !important; }
img, canvas, svg { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--blue-bright); outline-offset: 3px; }

html[dir='rtl'] body { font-family: 'IBM Plex Sans Arabic', var(--font-body); }
html[dir='rtl'] h1, html[dir='rtl'] h2, html[dir='rtl'] h3,
html[dir='rtl'] .display { font-family: 'IBM Plex Sans Arabic', var(--font-display); }
/* Arabic needs its own metrics: the tight Latin leading collides
   ascenders with the descenders of the line above, and negative
   tracking damages the joins between letters. */
html[dir='rtl'] .display,
html[dir='rtl'] h1, html[dir='rtl'] h2, html[dir='rtl'] h3 {
  line-height: 1.32;
  letter-spacing: 0;
  font-stretch: normal;
  /* Anton covers no Arabic, and casing is meaningless in the script */
  font-weight: 700;
  text-transform: none;
}
html[dir='rtl'] .hero h1 .accent { font-stretch: normal; -webkit-text-stroke-width: 1px; }

/* ---------- primitives ---------- */
.wrap { width: min(100% - (var(--gut) * 2), var(--wrap)); margin-inline: auto; }

.display {
  font-family: var(--font-display);
  font-weight: 400;          /* Anton ships a single weight */
  font-stretch: normal;      /* and no width axis to vary */
  letter-spacing: 0.005em;   /* condensed caps need a hair of air */
  line-height: 0.88;
  text-transform: uppercase;
}
/* Deliberately steep: the jump from headline to body is what carries
   hierarchy, so the page needs no decoration to feel structured. */
h1.display { font-size: clamp(3.1rem, 8.2vw, 7rem); }
h2.display { font-size: clamp(2.2rem, 5.4vw, 4rem); }
h3 { font-family: var(--font-body); font-weight: 700; font-stretch: 105%;
     letter-spacing: -0.02em; line-height: 1.1; }

/* A catalogue index mark, not a decorated pill. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
  display: block;
}
.lede { font-size: clamp(1.05rem, 1.35vw, 1.24rem); line-height: 1.5; color: var(--dim); max-width: 54ch; }

/* angular cut — the logo's signature terminal */
.cut {
}

/* ---------- buttons ----------
   Square and flat. The bevel was applied to every surface on the page,
   which turns a brand detail into wallpaper; it is now used once, large,
   on the hero stage. No hover lift either — a translateY on every
   element is the tell that motion is standing in for hierarchy. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7rem;
  padding: 0.9rem 1.5rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid transparent;
  transition: background .16s linear, color .16s linear, border-color .16s linear;
}
.btn--primary { background: var(--blue); color: #fff; border-color: var(--blue); }
.btn--primary:hover { background: transparent; color: var(--accent-on-bg); border-color: var(--accent-on-bg); }
.btn--ghost { border-color: var(--line-dark); color: var(--text); }
.btn--ghost:hover { border-color: var(--text); background: var(--text); color: var(--bg); }
.btn--onlight { border-color: var(--line-light); color: var(--text); }
.btn--onlight:hover { border-color: var(--text); }
.btn--lg { padding: 1.05rem 1.9rem; font-size: 0.86rem; }
.btn--block { width: 100%; }
.btn[disabled] { opacity: .38; pointer-events: none; }
.btn__arrow { transition: transform .16s linear; }
.btn:hover .btn__arrow { transform: translateX(4px); }
html[dir='rtl'] .btn__arrow { transform: scaleX(-1); }
html[dir='rtl'] .btn:hover .btn__arrow { transform: scaleX(-1) translateX(4px); }

/* ---------- logo ---------- */
.logo { display: inline-flex; align-items: center; gap: 0.65rem; }
.logo__mark {
  width: 30px; aspect-ratio: 4 / 3;
  background: currentColor;
  -webkit-mask: url('../img/voxel-mark.png') center / contain no-repeat;
          mask: url('../img/voxel-mark.png') center / contain no-repeat;
  flex: none;
}
.logo__word {
  width: 104px; aspect-ratio: 1600 / 405;
  background: currentColor;
  -webkit-mask: url('../img/voxel-wordmark.png') center / contain no-repeat;
          mask: url('../img/voxel-wordmark.png') center / contain no-repeat;
}

/* ============================================================
   NAV
   ============================================================ */
.nav {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 100;
  transition: background .3s var(--ease), border-color .3s var(--ease), backdrop-filter .3s;
  border-block-end: 1px solid transparent;
}
/* Opaque, with a hairline. Frosted-glass headers are the same borrowed
   vocabulary as the gradient blob. */
.nav--stuck {
  background: var(--bg);
  border-block-end-color: var(--line-dark);
}
.nav__in {
  display: flex; align-items: center; gap: 2rem;
  height: 74px;
}
.nav__links { display: flex; align-items: center; gap: 1.9rem; margin-inline-start: auto; }
.nav__link {
  font-family: var(--font-mono);
  font-size: 0.78rem; font-weight: 400; letter-spacing: 0.02em;
  color: var(--dim);
  position: relative; padding-block: 4px;
  transition: color .16s linear;
}
.nav__link::after {
  content: ''; position: absolute; inset-block-end: 0; inset-inline-start: 0;
  width: 0; height: 1px; background: currentColor;
  transition: width .18s linear;
}
.nav__link:hover, .nav__link[aria-current='page'] { color: var(--text); }
.nav__link:hover::after, .nav__link[aria-current='page']::after { width: 100%; }
.nav__actions { display: flex; align-items: center; gap: 0.85rem; }

.lang {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.75rem;
  letter-spacing: 0.06em;
  padding: 0.5rem 0.8rem;
  border: 1px solid var(--line-dark);
  color: var(--dim);
  transition: color .2s, border-color .2s;
}
.lang:hover { color: var(--text); border-color: var(--blue); }

/* theme toggle — shows the mode you'd switch TO */
.lang--icon { display: grid; place-content: center; padding: 0.4rem; }
.lang--icon svg { width: 17px; height: 17px; }
.icon-moon { display: none; }
:root[data-theme='light'] .icon-sun { display: none; }
:root[data-theme='light'] .icon-moon { display: block; }

.nav__burger { display: none; width: 40px; height: 40px; position: relative; }
.nav__burger span {
  position: absolute; inset-inline: 9px; height: 2px; background: var(--text);
  transition: transform .28s var(--ease), opacity .2s;
}
.nav__burger span:nth-child(1) { top: 14px; }
.nav__burger span:nth-child(2) { top: 20px; }
.nav__burger span:nth-child(3) { top: 26px; }
body.menu-open .nav__burger span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
body.menu-open .nav__burger span:nth-child(2) { opacity: 0; }
body.menu-open .nav__burger span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

@media (max-width: 900px) {
  .nav__in { height: 62px; gap: 0.6rem; }
  .logo__word { width: 88px; }
  /* Exactly one auto margin, on the group — putting it on the burger
     too would push a gap between the two and strand the ع button. */
  .nav__actions { order: 2; margin-inline-start: auto; gap: 0.5rem; }
  .nav__burger { display: block; order: 3; width: 34px; height: 34px; }
  .nav__burger span { inset-inline: 6px; }
  .nav__burger span:nth-child(1) { top: 11px; }
  .nav__burger span:nth-child(2) { top: 16px; }
  .nav__burger span:nth-child(3) { top: 21px; }
  .lang { padding: 0.35rem 0.55rem; font-size: 0.74rem; }
  .nav__links {
    position: fixed; inset: 62px 0 auto 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--bg-alt);
    border-block-end: 1px solid var(--line-dark);
    padding: 0.5rem var(--gut) 1.5rem;
    transform: translateY(-120%);
    transition: transform .38s var(--ease);
    margin: 0;
  }
  body.menu-open .nav__links { transform: translateY(0); }
  .nav__link { padding: 0.95rem 0; border-block-end: 1px solid var(--line-dark); font-size: 1.05rem; }
  .nav__link::after { display: none; }
}
/* On a phone the header CTA wraps and crowds the burger — the hero
   and the sticky WhatsApp button already cover the same action. */
@media (max-width: 560px) { .nav__actions .btn { display: none; } }

/* ============================================================
   SECTIONS
   ============================================================ */
.section { padding-block: clamp(4rem, 8vw, 7rem); position: relative; }
/* Alternating surfaces are gone. A single ground with hairline rules
   between sections reads as one continuous document rather than a
   stack of unrelated marketing panels. */
.section--light, .section--navy { background: transparent; }
.section + .section { border-block-start: 1px solid var(--line-dark); }

/* Label left, argument right — the spec-sheet split. This asymmetry is
   what stops every section opening with the same centred stack. */
.section__head {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 7fr);
  gap: clamp(1rem, 4vw, 3rem);
  margin-block-end: clamp(2.5rem, 5vw, 4rem);
  align-items: start;
}
.section__head .eyebrow { padding-block-start: 0.55rem; }
.section__head > :not(.eyebrow) { grid-column: 2; }
.section__head .lede { margin-block-start: 1.1rem; }
@media (max-width: 780px) {
  .section__head { grid-template-columns: 1fr; gap: 0.9rem; }
  .section__head > :not(.eyebrow) { grid-column: 1; }
}

/* No gradient blobs and no noise overlay. Depth comes from hairline
   rules, real spacing and type scale — the ambient-glow backdrop is
   the single most recognisable generated-template signature. */
.aura { position: relative; }
.grain { display: none; }

/* ============================================================
   HERO
   ============================================================ */
.hero {
  position: relative;
  padding-block: clamp(6rem, 13vw, 9.5rem) clamp(3rem, 6vw, 5rem);
  overflow: hidden;
}
/* Type-led: the headline takes the larger share and the render sits
   beside it as evidence, rather than the two splitting the page evenly. */
.hero__in {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: end;
}
.hero__copy { display: grid; gap: 1.5rem; justify-items: start; }
.hero h1 > span { display: block; }
/* Anton has neither a weight nor a width axis, so the old light-and-narrow
   contrast is impossible here — the second clause is separated by an
   outline instead, which is the poster-face way of doing it and keeps the
   accent colour free for actions. */
.hero h1 .accent {
  color: transparent;
  -webkit-text-stroke: 1.5px var(--dim);
  text-stroke: 1.5px var(--dim);
}
/* Fallback: without text-stroke support the clause would vanish entirely. */
@supports not (-webkit-text-stroke: 1px black) {
  .hero h1 .accent { color: var(--dim); -webkit-text-stroke: 0; }
}
.hero__cta { display: flex; flex-wrap: wrap; gap: 0.9rem; }

.hero__stage {
  position: relative;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line-dark);
  /* Opaque, not tinted: this is a dark island in light mode, so any
     transparency lets the pale page through and turns it grey. */
  background:
    radial-gradient(ellipse at 50% 104%, rgb(var(--text-rgb) / .07), transparent 60%),
    rgb(var(--surface-rgb));
  /* The one place the logo's angular terminal is used — once, large. */
  --cut: 26px;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.hero__stage canvas { width: 100%; height: 100%; }
.hero__badge {
  position: absolute; inset-block-end: 16px; inset-inline-start: 18px;
  display: flex; align-items: center; gap: 0.5rem;
  font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--dim);
}
.hero__badge .dot { width: 6px; height: 6px; background: var(--blue); }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .25; } }

@media (max-width: 900px) {
  .hero__in { grid-template-columns: 1fr; }
  /* Copy leads on a phone too. Putting the render first pushed the
     headline below the fold, which undercuts a type-led page. */
  .hero__stage { aspect-ratio: 4 / 3; }
}

/* ---------- marquee strip ---------- */
.strip { display: none; } /* ticker of adjectives — pure filler */
.strip--unused {
  border-block: 1px solid var(--line-dark);
  background: var(--bg-alt);
  overflow: hidden;
  padding-block: 1.05rem;
}
.strip__track {
  display: flex; gap: 3.5rem; width: max-content;
  animation: slide 34s linear infinite;
  font-family: var(--font-body); font-weight: 700; font-size: 0.82rem;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--dim);
}
.strip__track span { display: flex; align-items: center; gap: 3.5rem; }
.strip__track em {
  font-style: normal; white-space: nowrap;
  display: flex; align-items: center; gap: 3.5rem;
}
.strip__track em::after { content: '◆'; color: var(--blue); font-size: 0.6rem; }
@keyframes slide { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .strip__track { animation: none; } }

/* ============================================================
   CARDS
   ============================================================ */
/* ---------- cells ----------
   Not floating cards: each item hangs off a hairline rule, the way a
   printed catalogue sets a column. No box, no shadow, no lift. */
.cards { display: grid; gap: 0; }
.cards--3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.cards--4 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

.card {
  position: relative;
  padding: 1.5rem 2rem 2.5rem 0;
  border-block-start: 1px solid var(--text);
  display: grid; gap: 0.7rem; align-content: start;
  background: none;
}
.card h3 { font-size: 1.18rem; }
.card p { color: var(--dim); font-size: 0.95rem; max-width: 40ch; }
.section--light .card { background: none; border-block-start-color: var(--text); }

/* An index number, not a decorative watermark. */
.card__num {
  font-family: var(--font-mono);
  font-size: 0.72rem; font-weight: 500; letter-spacing: 0.1em;
  color: var(--dim);
  margin-block-end: 0.2rem;
}

/* ---------- spec table ----------
   The materials list is data, so it is set as data: tabular figures,
   monospace, hairline rows. */
.spec { width: 100%; border-collapse: collapse; }
.spec thead th {
  font-family: var(--font-mono); font-size: 0.68rem; font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--dim);
  text-align: start; padding: 0 1rem 0.8rem 0;
  border-block-end: 1px solid var(--text);
  white-space: nowrap;
}
.spec tbody td {
  padding: 1.15rem 1rem 1.15rem 0;
  border-block-end: 1px solid var(--line-dark);
  vertical-align: baseline;
  font-size: 0.95rem;
}
.spec tbody tr:last-child td { border-block-end: none; }
.spec__name {
  font-family: var(--font-body); font-weight: 700; font-stretch: 105%;
  font-size: 1.05rem; letter-spacing: -0.01em; white-space: nowrap;
}
.spec__use { color: var(--dim); }
.spec__num {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.spec__num b { font-weight: 600; }
.spec__num span { color: var(--dim); font-size: 0.82rem; }
.spec__dots { display: flex; gap: 5px; }
.spec__dots i { width: 11px; height: 11px; display: block; outline: 1px solid var(--line-dark); }
@media (max-width: 720px) {
  .spec, .spec tbody, .spec tr, .spec td { display: block; width: 100%; }
  .spec thead { display: none; }
  .spec tbody tr { border-block-end: 1px solid var(--line-dark); padding-block: 1.1rem; }
  .spec tbody tr:last-child { border-block-end: none; }
  .spec tbody td { border: none; padding: 0.15rem 0; }
  .spec__name { font-size: 1.15rem; }
}

/* ============================================================
   STUDIO
   ============================================================ */
.studio { padding-block: 6.5rem 4rem; min-height: 100vh; }
.studio__head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 1.5rem; margin-block-end: 2rem; }

.tabs { display: flex; border: 1px solid var(--line-dark); }
.tab {
  padding: 0.8rem 1.4rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.78rem;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--dim);
  transition: background .16s linear, color .16s linear;
}
.tab[aria-selected='true'] { background: var(--text); color: var(--bg); }

.studio__grid { display: grid; grid-template-columns: 1.35fr 1fr; gap: 1.5rem; align-items: start; }
@media (max-width: 1000px) { .studio__grid { grid-template-columns: 1fr; } }

.viewer {
  position: relative;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line-dark);
  /* A faint floor bounce stages the object; it is photographic, not
     decorative, so it stays — just far weaker than the old glow. */
  background:
    radial-gradient(ellipse at 50% 112%, rgb(var(--text-rgb) / .07), transparent 58%),
    var(--bg-alt);
  overflow: hidden;
  position: sticky; top: 92px;
}
/* relative, never static — the tools, readouts and drop zone are
   absolutely positioned and need .viewer to stay their containing block */
@media (max-width: 1000px) { .viewer { position: relative; top: auto; aspect-ratio: 4 / 3; } }
.viewer canvas { width: 100%; height: 100%; touch-action: none; }

.viewer__drop {
  position: absolute; inset: 0; z-index: 3;
  display: grid; place-content: center; justify-items: center; gap: 1rem;
  text-align: center; padding: 2rem;
  background: rgb(var(--deep-rgb) / .9);
  transition: opacity .25s, visibility .25s;
}
.viewer__drop[hidden] { display: none; }
.viewer.is-dragging .viewer__drop { background: rgb(var(--accent-rgb) / .22); }
.viewer__drop svg { width: 54px; height: 54px; stroke: var(--accent-on-bg); }
.viewer__drop h3 { font-size: 1.3rem; }
.viewer__drop p { color: var(--dim); font-size: 0.9rem; max-width: 34ch; }
.viewer__hint {
  position: absolute; inset-block-end: 12px; inset-inline-start: 14px; z-index: 2;
  font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--dim); pointer-events: none;
}
.viewer__dims {
  position: absolute; inset-block-start: 12px; inset-inline-start: 14px; z-index: 2;
  display: grid; gap: 2px;
  font-family: var(--font-mono); font-size: 0.7rem; color: var(--dim);
  font-variant-numeric: tabular-nums; pointer-events: none;
}
.viewer__dims b { color: var(--text); font-weight: 600; }
.viewer__tools {
  position: absolute; inset-block-start: 12px; inset-inline-end: 12px; z-index: 4;
  display: flex; gap: 6px;
}
.viewer__tool {
  width: 34px; height: 34px; display: grid; place-content: center;
  border: 1px solid var(--line-dark); background: rgb(var(--deep-rgb) / .7);
  color: var(--dim); font-size: 0.9rem;
  transition: color .2s, border-color .2s;
}
.viewer__tool:hover { color: var(--text); border-color: var(--blue); }
.viewer__tool[aria-pressed='true'] { color: var(--accent-on-bg); border-color: var(--blue); }

.hint--touch { display: none; }
@media (pointer: coarse) {
  .hint--mouse { display: none; }
  .hint--touch { display: inline; }
  /* A full-width square canvas that swallows every swipe is a scroll
     dead-end. Handing vertical pans back to the page leaves horizontal
     drags for the orbit controls — which is the axis the model spins on. */
  .viewer canvas { touch-action: pan-y; }
}

/* Nothing loaded yet: the orbit hint and the rotate/wireframe/reset
   tools have nothing to act on, and they overlap the drop panel. */
.viewer:has([data-drop]:not([hidden])) .viewer__tools,
.viewer:has([data-drop]:not([hidden])) .viewer__hint { display: none; }

.viewer__err {
  position: absolute; inset-block-end: 0; inset-inline: 0; z-index: 5;
  padding: 0.85rem 1.1rem;
  background: var(--danger); color: #fff; font-size: 0.88rem;
}
.viewer__err[hidden] { display: none; }

/* options panel */
.panel { display: grid; gap: 1.25rem; }
.field { display: grid; gap: 0.55rem; }
.field__label {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  font-family: var(--font-mono); font-size: 0.7rem; font-weight: 500;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--dim);
}
.field__val { color: var(--text); letter-spacing: 0; font-variant-numeric: tabular-nums; }

.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.chip {
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--line-dark);
  font-family: var(--font-mono); font-size: 0.78rem; color: var(--dim);
  transition: border-color .16s linear, color .16s linear, background .16s linear;
  display: flex; align-items: center; gap: 0.45rem;
}
.chip:hover { border-color: var(--text); color: var(--text); }
.chip[aria-pressed='true'] { border-color: var(--text); background: var(--text); color: var(--bg); }
.chip small { color: var(--dim); font-size: 0.76rem; }

.swatches { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.swatch {
  width: 38px; height: 38px; border: 2px solid transparent; outline: 1px solid var(--line-dark);
  transition: transform .2s var(--ease), border-color .2s;
  position: relative;
}
.swatch:hover { outline-color: var(--text); }
.swatch[aria-pressed='true'] { border-color: var(--accent-on-bg); outline-color: var(--accent-on-bg); }

input[type='range'] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 3px; background: var(--line-dark); cursor: pointer;
}
input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px; background: var(--blue); border: 3px solid var(--bg);
  cursor: pointer; transition: transform .15s;
}
input[type='range']::-webkit-slider-thumb:hover { transform: scale(1.15); }
input[type='range']::-moz-range-thumb {
  width: 18px; height: 18px; background: var(--blue); border: 3px solid var(--bg);
  border-radius: 0; cursor: pointer;
}

.input, select.input, textarea.input {
  width: 100%;
  padding: 0.8rem 1rem;
  background: rgb(var(--deep-rgb) / .6);
  border: 1px solid var(--line-dark);
  color: var(--text);
  transition: border-color .2s;
}
.input:focus { border-color: var(--blue); outline: none; }
.input::placeholder { color: rgb(var(--text-rgb) / .35); }
textarea.input { resize: vertical; min-height: 84px; }
select.input { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--dim) 50%), linear-gradient(135deg, var(--dim) 50%, transparent 50%); background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%; background-size: 5px 5px; background-repeat: no-repeat; }
html[dir='rtl'] select.input { background-position: 13px 50%, 18px 50%; }

.stepper { display: flex; border: 1px solid var(--line-dark); width: max-content; }
.stepper button { width: 42px; height: 42px; color: var(--dim); font-size: 1.1rem; transition: color .2s, background .2s; }
.stepper button:hover { color: var(--text); background: rgb(var(--accent-rgb) / .16); }
.stepper input { width: 58px; text-align: center; background: none; border: none; border-inline: 1px solid var(--line-dark); font-family: var(--font-body); font-weight: 700; }
.stepper input::-webkit-outer-spin-button, .stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* quote card */
.quote {
  border: 1px solid rgb(var(--accent-rgb) / .45);
  background: linear-gradient(160deg, rgb(var(--accent-rgb) / .16), rgb(var(--surface-rgb) / .7));
  padding: 1.5rem;
  display: grid; gap: 1rem;
}
.quote__total { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.quote__total .n { font-family: var(--font-body); font-weight: 800; font-stretch: 112%;
  font-size: clamp(2.1rem, 5vw, 2.9rem); line-height: 1; letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums; }
.quote__total .n small { font-size: 0.9rem; color: var(--dim); font-weight: 500; margin-inline-start: .35rem; }
.quote__rows { display: grid; gap: 0.45rem; font-family: var(--font-mono); font-size: 0.78rem;
  font-variant-numeric: tabular-nums; }
.quote__row { display: flex; justify-content: space-between; gap: 1rem; color: var(--dim); }
.quote__row b { color: var(--text); font-weight: 500; }
.quote__row--sep { border-block-start: 1px solid var(--line-dark); padding-block-start: 0.45rem; margin-block-start: 0.25rem; }
.quote__note { font-size: 0.78rem; color: var(--dim); line-height: 1.5; }
.quote.is-stale { opacity: .5; }

/* ============================================================
   PRESETS
   ============================================================ */
.presets { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.9rem; }
.preset {
  border: 1px solid var(--line-dark);
  background: rgb(var(--deep-rgb) / .5);
  padding: 0.9rem;
  display: grid; gap: 0.5rem; text-align: start;
  transition: border-color .2s, transform .2s var(--ease);
}
.preset:hover { border-color: var(--text); }
.preset[aria-pressed='true'] { border-color: var(--text); background: rgb(var(--text-rgb) / .06); }
.preset__thumb {
  aspect-ratio: 1; width: 100%;
  background: rgb(var(--text-rgb) / .04);
  /* flex, not grid: a centred grid area is content-sized, so a
     percentage width on the SVG would resolve against nothing */
  display: flex; align-items: center; justify-content: center;
}
.preset__thumb svg { width: 62%; height: 62%; stroke: var(--text); fill: none; stroke-width: 2.4; }
.preset__name { font-family: var(--font-body); font-weight: 700; font-size: 0.92rem; letter-spacing: -0.01em; }
.preset__meta { font-family: var(--font-mono); font-size: 0.7rem; color: var(--dim); }

/* ============================================================
   GALLERY
   ============================================================ */
.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-block-end: 2rem; }
.gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.1rem; }
.gal__item {
  border: 1px solid var(--line-dark);
  background: rgb(var(--surface-rgb) / .5);
  overflow: hidden; text-align: start;
  display: grid; grid-template-rows: auto 1fr;
  transition: border-color .25s, transform .25s var(--ease);
  animation: rise .45s var(--ease) backwards;
}
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }
.gal__item:hover .gal__title { color: var(--accent-on-bg); }
.gal__media {
  aspect-ratio: 4 / 3; position: relative; overflow: hidden;
  background: var(--bg);
}
.gal__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease); }
.gal__item:hover .gal__media img { transform: scale(1.05); }
.gal__ph { position: absolute; inset: 0; }
.gal__body { padding: 1.1rem 1.2rem 1.3rem; display: grid; gap: 0.4rem; align-content: start; }
.gal__title { font-family: var(--font-body); font-weight: 700; font-size: 1.05rem;
  letter-spacing: -0.015em; transition: color .16s linear; }
.gal__meta { font-family: var(--font-mono); font-size: 0.72rem; color: var(--dim); display: flex; flex-wrap: wrap; gap: 0.45rem; }
.gal__meta span { display: flex; align-items: center; gap: 0.35rem; }
.tag {
  position: absolute; inset-block-start: 10px; inset-inline-start: 10px;
  padding: 0.28rem 0.55rem; background: rgb(var(--deep-rgb) / .82);
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--text);
}
.gal__empty { grid-column: 1 / -1; padding: 3rem 1rem; text-align: center; color: var(--dim); }

/* lightbox */
.lb {
  position: fixed; inset: 0; z-index: 200;
  background: rgb(var(--deep-rgb) / .94);
  backdrop-filter: blur(10px);
  display: grid; place-items: center;
  padding: var(--gut);
  opacity: 0; visibility: hidden;
  transition: opacity .28s, visibility .28s;
}
.lb.is-open { opacity: 1; visibility: visible; }
.lb__box {
  position: relative;
  width: min(100%, 940px); max-height: 88vh; overflow: auto;
  background: var(--bg-alt); border: 1px solid var(--line-dark);
  display: grid; grid-template-columns: 1.1fr 1fr;
  transform: translateY(16px); transition: transform .32s var(--ease);
}
.lb.is-open .lb__box { transform: none; }
@media (max-width: 760px) { .lb__box { grid-template-columns: 1fr; } }
.lb__media { position: relative; min-height: 260px; background: var(--bg); }
.lb__media img { width: 100%; height: 100%; object-fit: cover; }
.lb__body { padding: 2rem; display: grid; gap: 1rem; align-content: start; }
.lb__specs { display: grid; gap: 0.5rem; font-size: 0.9rem; }
.lb__spec { display: flex; justify-content: space-between; gap: 1rem; padding-block: 0.5rem; border-block-end: 1px solid var(--line-dark); }
.lb__spec span { color: var(--dim); }
.lb__close {
  position: fixed; inset-block-start: 18px; inset-inline-end: 18px; z-index: 3;
  width: 38px; height: 38px; display: grid; place-content: center;
  background: rgb(var(--deep-rgb) / .8); border: 1px solid var(--line-dark); color: var(--text);
}
.lb__close:hover { border-color: var(--blue); color: var(--accent-on-bg); }

/* ============================================================
   ORDER SHEET
   ============================================================ */
.sheet {
  position: fixed; inset: 0; z-index: 210;
  background: rgb(var(--deep-rgb) / .94); backdrop-filter: blur(10px);
  display: grid; place-items: center; padding: var(--gut);
  opacity: 0; visibility: hidden; transition: opacity .28s, visibility .28s;
  overflow-y: auto;
}
.sheet.is-open { opacity: 1; visibility: visible; }
.sheet__box {
  width: min(100%, 560px);
  background: var(--bg-alt); border: 1px solid var(--line-dark);
  padding: clamp(1.5rem, 4vw, 2.4rem);
  display: grid; gap: 1.15rem;
  transform: translateY(16px); transition: transform .32s var(--ease);
}
.sheet.is-open .sheet__box { transform: none; }
.sheet__row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.9rem; }
@media (max-width: 520px) { .sheet__row { grid-template-columns: 1fr; } }
.sheet__summary {
  padding: 0.9rem 1.1rem; border: 1px solid var(--line-dark);
  background: rgb(var(--deep-rgb) / .5); font-size: 0.86rem; display: grid; gap: 0.3rem;
}
.sheet__summary b { color: var(--accent-on-bg); }

.done { display: grid; gap: 1rem; justify-items: center; text-align: center; padding: 1rem 0; }
.done__code {
  font-family: var(--font-mono); font-weight: 600; font-size: 1.5rem;
  letter-spacing: 0.08em; color: var(--text);
  padding: 0.7rem 1.3rem; border: 1px solid var(--line-dark);
}

/* ============================================================
   BANDS + FOOTER
   ============================================================ */
.band {
  border-block-start: 1px solid var(--text);
  background: none;
  padding: clamp(1.8rem, 4vw, 2.6rem) 0 0;
  display: grid; grid-template-columns: 1.4fr auto; gap: 2rem; align-items: center;
}
@media (max-width: 820px) { .band { grid-template-columns: 1fr; } }
.band h2 { margin-block-end: 0.6rem; }

/* Full-bleed like the spec table: across the page the rule is that
   section heads are indented and their content runs the full measure. */
.faq { display: grid; gap: 0; border-block-start: 1px solid var(--text); }
.faq__q {
  width: 100%; text-align: start;
  padding: 1.4rem 0; border-block-end: 1px solid var(--line-dark);
  display: flex; justify-content: space-between; align-items: center; gap: 1.5rem;
  font-family: var(--font-body); font-weight: 700; font-size: 1.15rem;
  letter-spacing: -0.015em; transition: color .16s linear;
}
.faq__q:hover { color: var(--dim); }
.faq__q i { font-style: normal; font-family: var(--font-mono); color: var(--dim); font-size: 1.1rem; transition: transform .22s linear; flex: none; }
.faq__q[aria-expanded='true'] i { transform: rotate(45deg); }
.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .32s var(--ease); border-block-end: 1px solid var(--line-dark); }
.faq__a[data-open='true'] { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { color: var(--dim); padding-block: 0 1.4rem; max-width: 62ch; }

.footer { background: var(--footer-bg); padding-block: clamp(3rem, 7vw, 5rem) 2rem; }
.footer__grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr; gap: 2.5rem; margin-block-end: 3rem; }
@media (max-width: 760px) { .footer__grid { grid-template-columns: 1fr 1fr; } .footer__brand { grid-column: 1 / -1; } }
.footer__brand p { color: var(--dim); font-size: 0.92rem; max-width: 38ch; margin-block-start: 1rem; }
.footer h4 { font-family: var(--font-mono); font-size: 0.68rem; font-weight: 500; letter-spacing: 0.09em; text-transform: uppercase; color: var(--dim); margin-block-end: 1.1rem; }
.footer ul { list-style: none; padding: 0; display: grid; gap: 0.65rem; }
.footer a { color: var(--text); font-size: 0.92rem; opacity: .78; transition: opacity .16s linear; }
.footer a:hover { opacity: 1; }
.footer__bottom {
  border-block-start: 1px solid rgb(var(--text-rgb) / .12); padding-block-start: 1.6rem;
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem;
  font-family: var(--font-mono); font-size: 0.72rem; color: var(--dim);
}

/* whatsapp float */
.wa {
  position: fixed; inset-block-end: 22px; inset-inline-end: 22px; z-index: 90;
  width: 54px; height: 54px; border-radius: 50%;
  background: #25d366; display: grid; place-content: center;
  box-shadow: 0 10px 30px var(--shadow);
  transition: transform .25s var(--ease);
}
.wa:hover { filter: brightness(1.08); }
.wa svg { width: 28px; height: 28px; fill: #fff; }

/* ---------- utils ---------- */
/* Deliberately no scroll-reveal. Fade-and-rise on every block is one of
   the loudest generated-template signals, and it delays the content for
   no benefit. Class kept so the markup stays valid. */
.reveal { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
.sr { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ============================================================
   PHONE
   Everything below is layout that only makes sense on a small,
   one-thumb screen — not just shrunken desktop.
   ============================================================ */
@media (max-width: 640px) {
  :root { --cut: 10px; }

  /* --- type: the desktop clamps bottom out too large at 375px --- */
  h1.display { font-size: clamp(2.1rem, 9.5vw, 2.9rem); }
  h2.display { font-size: clamp(1.7rem, 7vw, 2.2rem); }
  .lede { font-size: 0.98rem; }
  .eyebrow { font-size: 0.66rem; letter-spacing: 0.18em; }

  /* --- hero: 3D first, then the pitch --- */
  .hero { min-height: 0; padding-block: 6rem 3rem; }
  .hero__in { gap: 2rem; }
  .hero__stage { aspect-ratio: 1 / 1; }
  .hero__cta { width: 100%; gap: 0.7rem; }
  .hero__cta .btn { flex: 1 1 100%; }
  .hero__badge {
    font-size: 0.58rem; letter-spacing: 0.1em;
    inset-inline-start: 14px; inset-inline-end: 14px;
    inset-block-end: 12px;
  }

  .section { padding-block: 3.5rem; }
  .section__head { margin-block-end: 2rem; }
  .card { padding: 1.5rem 1.35rem; }
  .stat { padding: 1.35rem 1.1rem; }
  .band { padding: 1.75rem 1.4rem; gap: 1.4rem; }
  .band .btn { width: 100%; }

  /* --- studio --- */
  .studio { padding-block-start: 5.25rem; }
  .studio__head { gap: 1.1rem; }
  .tabs { width: 100%; }
  .tab {
    flex: 1; padding: 0.75rem 0.4rem;
    font-size: 0.84rem; white-space: nowrap; text-align: center;
  }
  /* The drop panel already carries a "Choose a file" button — the one
     in the options column is a duplicate with no drag affordance. */
  [data-pane='upload'] { display: none; }

  .viewer { aspect-ratio: 1 / 1; }
  .viewer__drop { padding: 1.25rem; gap: 0.7rem; }
  .viewer__drop svg { width: 40px; height: 40px; }
  .viewer__drop h3 { font-size: 1.05rem; }
  .viewer__drop p { font-size: 0.84rem; }
  .viewer__dims { font-size: 0.68rem; }

  .presets { grid-template-columns: repeat(2, 1fr); }
  .chip { padding: 0.55rem 0.8rem; font-size: 0.84rem; }
  .swatch { width: 34px; height: 34px; }

  /* Room for the sticky total bar so it never covers the last field */
  .panel { padding-block-end: 4.5rem; }

  /* --- order sheet: full-bleed sheet reads better than a floating card --- */
  /* overflow hidden on the overlay so only the sheet body scrolls —
     otherwise the two compete and the sheet sits past the fold.
     dvh keeps it honest when a phone's URL bar collapses. */
  /* Pinned to the bottom edge rather than grid-aligned: with a capped
     height the auto row sizes off the uncapped content and pushes the
     sheet past the fold. dvh keeps it right when the URL bar collapses. */
  .sheet { display: block; padding: 0; overflow: hidden; }
  .sheet__box {
    position: absolute; inset-inline: 0; inset-block-end: 0;
    width: 100%;
    max-height: 90vh; max-height: 90dvh;
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    clip-path: none; border-inline: none; border-block-end: none;
  }

  .lb__body { padding: 1.4rem; }
  .footer__grid { gap: 1.75rem; }

  /* The floating WhatsApp button sits over the last row of content */
  .wa { width: 48px; height: 48px; inset-block-end: 16px; inset-inline-end: 16px; }
  .wa svg { width: 24px; height: 24px; }
}

/* ============================================================
   Sticky total — phone only.
   On a narrow screen the price sits far below the controls you are
   changing, so it gets pinned where your thumb already is.
   ============================================================ */
.totalbar { display: none; }

@media (max-width: 640px) {
  .totalbar {
    position: fixed; inset-inline: 0; inset-block-end: 0; z-index: 80;
    display: flex; align-items: center; gap: 0.9rem;
    padding: 0.7rem 1rem calc(0.7rem + env(safe-area-inset-bottom));
    background: rgb(var(--deep-rgb) / .93);
    backdrop-filter: blur(16px) saturate(140%);
    border-block-start: 1px solid var(--line-dark);
    transform: translateY(110%);
    transition: transform .3s var(--ease);
  }
  .totalbar.is-on { transform: none; }
  .totalbar__n {
    font-family: var(--font-body); font-weight: 800; font-stretch: 112%;
    font-size: 1.35rem; line-height: 1.1; letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
  }
  .totalbar__n small { display: block; font-size: 0.64rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim); font-weight: 500; }
  .totalbar .btn { margin-inline-start: auto; padding-block: 0.8rem; }
  /* Keep the floating WhatsApp button clear of the bar */
  body:has(.totalbar.is-on) .wa { inset-block-end: 78px; }
}

/* ============================================================
   THE PRINT — scroll-driven centrepiece
   A tall track with a sticky viewport inside it. Scroll distance
   is the build; the object, the nozzle and the readout are all
   driven from the same progress value.
   ============================================================ */
.printer {
  position: relative;
  height: 380vh;                 /* the track: this IS the build time */
  border-block-start: 1px solid var(--line-dark);
  background: var(--bg);
}
.printer__sticky {
  position: sticky; top: 0;
  height: 100vh; height: 100dvh;
  overflow: hidden;
}
/* Dark in both themes: molten blue against a pale page loses the
   glow entirely, and the layer shadows stop reading. */
.printer__sticky {
  --deep-rgb: 2 10 31;
  --surface-rgb: 4 17 49;
  --text-rgb: 244 247 254;
  /* --bg and --bg-alt must be restated as well, not just the channels:
     they were substituted at :root, so leaving them out paints white
     text onto the light page. Same trap as the footer and the stages. */
  --bg: rgb(var(--deep-rgb));
  --bg-alt: rgb(var(--surface-rgb));
  --text: rgb(var(--text-rgb));
  --dim: rgb(var(--text-rgb) / 0.6);
  --line-dark: rgb(var(--text-rgb) / 0.14);
  background: var(--bg);
  color: var(--text);
}
.printer__stage { position: absolute; inset: 0; }
.printer__stage canvas { width: 100%; height: 100%; }

.printer__ui {
  position: relative; z-index: 2;
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding-block: clamp(5rem, 11vh, 7rem) clamp(2rem, 5vh, 3.5rem);
  pointer-events: none;
}
.printer__head { display: grid; gap: 0.9rem; max-width: 20ch; }
.printer__h2 { font-size: clamp(1.9rem, 3.6vw, 3.1rem); }

/* Captions sit low-left, out of the object's way, and cross-fade as
   the build passes each third. */
/* The captions are absolutely stacked so they cross-fade in place;
   the container therefore has no natural height and would collide with
   the readout below it. Reserve the space explicitly. */
.printer__captions { position: relative; align-self: end; max-width: 34ch; min-height: 9.5rem; }
.printer__caption {
  position: absolute; inset-inline-start: 0; inset-block-end: 0;
  display: grid; gap: 0.5rem;
  opacity: 0; transform: translateY(8px);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.printer__caption.is-on { opacity: 1; transform: none; }
.printer__caption h3 { font-size: 1.45rem; }
.printer__caption p { color: var(--dim); font-size: 0.95rem; }
.printer__step {
  font-family: var(--font-mono); font-size: 0.7rem;
  letter-spacing: 0.1em; color: var(--dim);
}

/* The readout — the detail that makes it feel like a machine. */
.printer__hud {
  display: flex; gap: clamp(1.5rem, 4vw, 3rem);
  align-self: end; justify-self: end;
  margin: 0; text-align: end;
}
.printer__hud div { display: grid; gap: 0.3rem; }
.printer__hud dt {
  font-family: var(--font-mono); font-size: 0.64rem;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim);
}
.printer__hud dd {
  margin: 0;
  font-family: var(--font-mono); font-size: clamp(1rem, 1.6vw, 1.3rem);
  font-variant-numeric: tabular-nums; color: var(--text);
}

@media (max-width: 780px) {
  .printer { height: 320vh; }
  .printer__ui { padding-block: 5rem 2rem; position: relative; isolation: isolate; }
  .printer__head { max-width: 14ch; }
  .printer__captions { max-width: none; min-height: 8.5rem; }
  .printer__caption h3 { font-size: 1.15rem; }
  .printer__caption p { font-size: 0.88rem; }
  .printer__hud { justify-self: start; text-align: start; margin-block-start: 1.25rem; }
  /* A scrim keeps the copy legible where it crosses the object. */
  .printer__ui::after {
    content: ''; position: absolute; inset-inline: 0; inset-block-end: 0;
    height: 46%; z-index: -1; pointer-events: none;
    background: linear-gradient(to top, rgb(var(--deep-rgb) / .92), transparent);
  }
}

/* Without scroll-linked motion the track is pointless — collapse it
   to a single screen showing the finished object. */
@media (prefers-reduced-motion: reduce) {
  .printer { height: auto; }
  .printer__sticky { position: relative; height: 88vh; }
  .printer__caption { position: relative; opacity: 1; transform: none; margin-block-start: 1.25rem; }
  .printer__captions { display: grid; }
}
