@charset "UTF-8";
/* ==========================================================================
   Layerform Labels — design system
   ==========================================================================

   CONCEPT — "optical laminate".
   A multi-layer label is a stack of translucent planes that light passes
   through. So depth on this page comes from LUMINOSITY, not from swapping
   background colours: one deep ground throughout, and surfaces that rise out
   of it by getting lighter, catching a hairline, and casting a soft contact
   shadow. Sections never flip to a cream band — that striping is what made
   the page read as choppy rather than considered.

   RESTRAINT — one accent. The generated product photography is charcoal with
   a warm-orange spot rule, so the interface is built around exactly that:
   warm off-white type, near-black ground, one orange. A cool cyan exists but
   is reserved for coding the layer anatomy; it is never UI chrome.

   TYPE — Fraunces (variable, with its SOFT and WONK axes) set LIGHT and LARGE
   for display, against a neutral grotesk and a technical mono. Weight-light
   at size is what reads as expensive; heavy display type at small size is
   what reads as a template.
   ========================================================================== */

/* --- 1. Fonts ------------------------------------------------------------ */

@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/archivo-latin.woff2") format("woff2");
  font-weight: 400 900; font-stretch: 75% 125%; font-display: swap;
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/archivo-latin-ext.woff2") format("woff2");
  font-weight: 400 900; font-stretch: 75% 125%; font-display: swap;
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+1AB0-1ACE,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "Instrument";
  src: url("/assets/fonts/instrument-latin-n3.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Instrument";
  src: url("/assets/fonts/instrument-latin-ext-n2.woff2") format("woff2");
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+1AB0-1ACE,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "Instrument";
  src: url("/assets/fonts/instrument-latin-i1.woff2") format("woff2");
  font-weight: 400 700; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "SpaceMono";
  src: url("/assets/fonts/spacemono-latin-n1.woff2") format("woff2");
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: "SpaceMono";
  src: url("/assets/fonts/spacemono-latin-n3.woff2") format("woff2");
  font-weight: 700; font-display: swap;
}

/* CJK and Arabic ride on system faces — shipping a 6 MB webfont to a phone in
   a warehouse is worse design than using the excellent face already installed.
   The CJK display stack is a HEAVY GOTHIC, never a Mincho/Song serif: at
   headline sizes a Song face renders thin and elongated, which is the opposite
   of what an industrial manufacturer should look like. Weight, not contrast,
   is what carries a Chinese headline. */
:root {
  --f-cjk:  "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans SC", sans-serif;
  --f-jp:   "Hiragino Kaku Gothic ProN", "Yu Gothic", "Meiryo", "Source Han Sans", "Noto Sans JP", sans-serif;
  --f-kr:   "Apple SD Gothic Neo", "Malgun Gothic", "Source Han Sans KR", "Noto Sans KR", sans-serif;
  --f-ar:   "SF Arabic", "Geeza Pro", "Segoe UI", "Noto Naskh Arabic", "Traditional Arabic", sans-serif;

  --f-display: "Archivo", system-ui, sans-serif;
  --f-body:    "Instrument", system-ui, -apple-system, "Segoe UI", sans-serif;
  --f-mono:    "SpaceMono", ui-monospace, "SFMono-Regular", Consolas, monospace;

  /* Archivo axes. Display type is set heavy and slightly EXPANDED so a headline
     has real presence instead of relying on size alone. */
  --dsp-wght: 800;
  --dsp-wdth: 112;
}
.lang-zh { --f-display: "Archivo", var(--f-cjk); --f-body: "Instrument", var(--f-cjk); }
.lang-ja { --f-display: "Archivo", var(--f-jp);  --f-body: "Instrument", var(--f-jp); }
.lang-ko { --f-display: "Archivo", var(--f-kr);  --f-body: "Instrument", var(--f-kr); }
.lang-ar { --f-display: var(--f-ar); --f-body: var(--f-ar); --f-mono: var(--f-ar); }

/* --- 2. Tokens ----------------------------------------------------------- */

:root {
  /* One ground family. Each step is a real elevation, not a new colour. */
  --ink:    #07080A;
  --ink-2:  #0B0D11;
  --ink-3:  #10131A;
  --ink-4:  #171B24;
  --ink-5:  #212632;

  /* Warm off-white, tuned to the warm cast of the product photography.
     A pure #FFF here reads clinical and fights the images. */
  --fg:     #F4F2EE;
  --fg-2:   #A2A8B4;
  --fg-3:   #79808D;   /* 5.1:1 on --ink — the floor for anything readable */

  /* THE accent. One. Taken from the orange spot rule in the photography. */
  --spot:      #FF5C35;
  --spot-lift: #FF7E5A;
  --spot-deep: #C4340F;
  /* Reserved for coding layer anatomy — never used as interface chrome. */
  --cool:      #6FD5E8;

  --line:      rgb(255 255 255 / .09);
  --line-2:    rgb(255 255 255 / .16);
  --glow:      rgb(255 92 53 / .16);

  /* semantic */
  --bg:      var(--ink);
  --bg-2:    var(--ink-2);
  --card:    var(--ink-3);
  --card-up: var(--ink-4);

  /* Type scale. The previous values were roughly one step too small at every
     level — 11.5px labels and a 14px nav are unreadable on a desktop monitor at
     arm's length, which is exactly how a buyer looks at a supplier site. Every
     step below is set for that distance, not for a screenshot. */
  /*
   * HARD FLOOR: nothing on this site renders below 15px, and no CJK text below
   * 16px. Earlier passes checked contrast and overflow but never set a minimum
   * legible size, so 11-13px labels kept surviving review one selector at a
   * time. The floor is the rule now; individual components may go up, never down.
   */
  --t-mono:  .9375rem;   /* 15px — labels, eyebrows, specs */
  --t-sm:    1.0000rem;  /* 16px — card copy, secondary */
  --t-base:  1.1875rem;  /* 19px — body */
  --t-lead:  clamp(1.3rem, 1.1rem + .8vw, 1.65rem);
  --t-nav:   1.0625rem;  /* 17px — navigation */
  --t-h3:    clamp(1.4rem, 1.15rem + .75vw, 1.85rem);
  --t-h2:    clamp(2.3rem, 1.5rem + 3.2vw, 4.2rem);
  --t-h1:    clamp(2.9rem, 1.7rem + 5vw, 6.2rem);
  --t-mega:  clamp(3.4rem, 1.4rem + 8.4vw, 9rem);

  /* rhythm */
  --pad-y:   clamp(5rem, 3.4rem + 6.4vw, 10rem);
  --wrap:    78rem;
  --wrap-nr: 62rem;
  --gut:     clamp(1.25rem, .7rem + 2.4vw, 2.75rem);
  --r:       14px;
  --r-lg:    22px;

  /* Slow, weighted easing. Nothing here uses `ease` — the browser default is
     what makes hand-built motion feel cheap. */
  --ease:     cubic-bezier(.16, 1, .3, 1);
  --ease-io:  cubic-bezier(.65, .01, .28, 1);
  --dur:      .62s;

  --shadow-1: 0 1px 2px rgb(0 0 0 / .5), 0 8px 24px -12px rgb(0 0 0 / .7);
  --shadow-2: 0 2px 4px rgb(0 0 0 / .5), 0 28px 60px -28px rgb(0 0 0 / .85);
  --shadow-3: 0 40px 90px -40px rgb(0 0 0 / .95);

  color-scheme: dark;
}

/* `band-paper` survives from the earlier design so the markup keeps working,
   but it no longer flips to cream. It is now a one-step ELEVATION within the
   same ground — rhythm without stripes. */
.band-paper { --bg: var(--ink-2); --card: var(--ink-4); --card-up: var(--ink-5); }

/* --- 3. Base ------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-block-start: 6rem;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  min-block-size: 100vh;
  background: var(--ink);
  color: var(--fg);
  font-family: var(--f-body);
  font-size: var(--t-base);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* A single, very quiet light source top-left, so the page has a direction.
   Without it a flat dark page looks like an unlit box. */
body::before {
  content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(70rem 50rem at 8% -8%, rgb(255 92 53 / .07), transparent 62%),
    radial-gradient(52rem 40rem at 96% 4%, rgb(111 213 232 / .045), transparent 60%);
}
main, .topbar, footer { position: relative; z-index: 1; }

img, svg, video { display: block; max-inline-size: 100%; }
img { block-size: auto; }

a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }

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

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

.sr-only {
  position: absolute; inline-size: 1px; block-size: 1px;
  padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.skip {
  position: absolute; inset-block-start: -100%; inset-inline-start: 1rem; z-index: 200;
  padding: .8rem 1.2rem; background: var(--spot); color: #fff; border-radius: 0 0 10px 10px;
  font-weight: 600;
}
.skip:focus { inset-block-start: 0; }

/* --- 4. Typography ------------------------------------------------------- */

h1, h2, h3, h4 {
  font-family: var(--f-display);
  font-weight: 800;
  line-height: 1.06;
  letter-spacing: -.02em;
  font-variation-settings: "wght" var(--dsp-wght), "wdth" var(--dsp-wdth);
  text-wrap: balance;
}
h3, h4 { font-weight: 700; --dsp-wght: 700; --dsp-wdth: 105; line-height: 1.24; letter-spacing: -.012em; }

/* CJK headlines take the system gothic at a heavy weight. They need looser
   leading than Latin (the glyphs are full-height boxes) and no negative
   tracking — squeezing Han characters together just muddies them. */
.lang-zh h1, .lang-ja h1, .lang-ko h1,
.lang-zh h2, .lang-ja h2, .lang-ko h2,
.lang-zh h3, .lang-ja h3, .lang-ko h3 {
  letter-spacing: 0;
  line-height: 1.3;
  font-variation-settings: normal;
  font-weight: 700;
}

/* Arabic must never take Latin tracking: negative letter-spacing severs the
   cursive joins that make the script legible at all. */
.lang-ar h1, .lang-ar h2, .lang-ar h3, .lang-ar h4,
.lang-ar .hero-h1, .lang-ar .sec-title, .lang-ar .mono, .lang-ar .eyebrow {
  letter-spacing: normal;
  font-variation-settings: normal;
  line-height: 1.5;
}

p { text-wrap: pretty; }

.mono, .eyebrow, .badge, .chip, .tag, .spec-row dt, .stat span, .pcard-meta, .art-meta {
  font-family: var(--f-mono);
  font-size: var(--t-mono);
  letter-spacing: .13em;
  text-transform: uppercase;
}

.eyebrow {
  display: inline-flex; align-items: center; gap: .7rem;
  color: var(--spot);
  margin-block-end: 1.5rem;
}
.eyebrow::before {
  content: ""; inline-size: 1.9rem; block-size: 1px;
  background: currentColor; opacity: .55;
}
.eyebrow-n { opacity: .5; }

.sec-title { font-size: var(--t-h2); }
.sec-lead {
  margin-block-start: 1.4rem;
  max-inline-size: 46ch;
  font-size: var(--t-lead);
  color: var(--fg-2);
  line-height: 1.55;
}
.sec-head { max-inline-size: 62rem; margin-block-end: clamp(2.5rem, 1.6rem + 3vw, 4.5rem); }
.sec-head.center { margin-inline: auto; text-align: center; }
.sec-head.center .sec-lead { margin-inline: auto; }

/* --- 5. Layout ----------------------------------------------------------- */

.wrap { inline-size: min(100% - var(--gut) * 2, var(--wrap)); margin-inline: auto; }
.wrap-nr { max-inline-size: var(--wrap-nr); }
.pad { padding-block: var(--pad-y); background: var(--bg); position: relative; }
.pad-b { padding-block-end: var(--pad-y); }

/* The seam between two elevations is a hairline, not a die-cut perforation.
   One quiet rule reads as precision; a dotted tear-line reads as clip-art. */
.pad + .pad { border-block-start: 1px solid var(--line); }

.g  { display: grid; gap: clamp(1rem, .6rem + 1.4vw, 1.8rem); }
.g2 { display: grid; gap: clamp(1rem, .6rem + 1.4vw, 1.8rem); grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
.g3 { display: grid; gap: clamp(1rem, .6rem + 1.4vw, 1.8rem); grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
.row { display: flex; flex-wrap: wrap; gap: .8rem; align-items: center; }
.sep { block-size: 1px; background: var(--line); border: 0; margin-block: 2.5rem; }

/* --- 6. Buttons ---------------------------------------------------------- */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--fg);
  --btn-bd: var(--line-2);
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .95rem 1.5rem;
  border: 1px solid var(--btn-bd); border-radius: 999px;
  background: var(--btn-bg); color: var(--btn-fg);
  font-size: 1rem; font-weight: 600; letter-spacing: .005em;
  white-space: nowrap;
  transition: color .3s var(--ease), border-color .3s var(--ease), transform .3s var(--ease);
}
/* The fill grows from the centre rather than the button changing colour —
   a small thing that makes a hover feel physical instead of switched. */
.btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  background: var(--btn-hov, var(--spot));
  transform: scale(.6); opacity: 0;
  transition: transform .45s var(--ease), opacity .35s var(--ease);
}
.btn:hover { transform: translateY(-2px); }
/* Buttons driven by the magnet get their inline transform overwritten every
   frame, so their lift is expressed as light rather than position. */
.btn-spot:hover, .btn-lg:hover { box-shadow: 0 10px 30px -10px var(--glow); }
.btn:hover::before { transform: scale(1); opacity: 1; }
.btn:active { transform: translateY(0); }

.btn-spot { --btn-bg: var(--spot); --btn-fg: #fff; --btn-bd: transparent; --btn-hov: var(--spot-lift); }
.btn-line { --btn-fg: var(--fg); }
.btn-line:hover { --btn-fg: #fff; border-color: transparent; }
.btn-ghost { --btn-bd: transparent; --btn-fg: var(--fg-2); }
.btn-ghost:hover { --btn-fg: #fff; }
.btn-sm { padding: .62rem 1.15rem; font-size: .9375rem; }
.btn-lg { padding: 1.15rem 2rem; font-size: 1.0625rem; }
.btn-block { inline-size: 100%; justify-content: center; }

.ico { inline-size: 1.05em; block-size: 1.05em; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.lang-ar .btn .ico { transform: scaleX(-1); }

/* --- 7. Topbar ----------------------------------------------------------- */

.topbar {
  position: sticky; inset-block-start: 0; z-index: 100;
  background: color-mix(in srgb, var(--ink) 72%, transparent);
  backdrop-filter: blur(18px) saturate(1.5);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
  border-block-end: 1px solid transparent;
  transition: background .4s var(--ease), border-color .4s var(--ease);
}
.topbar.is-stuck { background: color-mix(in srgb, var(--ink) 92%, transparent); border-block-end-color: var(--line); }
.topbar-in {
  inline-size: min(100% - var(--gut) * 2, var(--wrap));
  margin-inline: auto;
  display: flex; align-items: center; gap: 1.5rem;
  block-size: 4.75rem;
}
.brand { display: inline-flex; align-items: center; gap: .7rem; margin-inline-end: auto; }
.brand-mark { inline-size: 2.3rem; block-size: 2.3rem; overflow: visible; }
.bm-1 { fill: var(--fg); }
.bm-2 { fill: var(--fg); opacity: .3; }
.bm-3 { fill: var(--fg); opacity: .14; }
.bm-peel { fill: var(--spot); }
.brand:hover .bm-2 { opacity: .45; }
.brand-mark, .brand-mark * { transition: opacity .35s var(--ease), transform .45s var(--ease); }
.brand:hover .brand-mark { transform: translateY(-1px); }
.brand-txt { display: flex; flex-direction: column; line-height: 1.15; }
.brand-txt b { font-family: var(--f-display); font-weight: 800; font-size: 1.18rem; letter-spacing: -.015em; }
.brand-txt i {
  font-family: var(--f-mono); font-style: normal;
  font-size: 1rem; letter-spacing: .1em; text-transform: uppercase; color: var(--fg-3);
}

.nav ul { display: flex; gap: .3rem; list-style: none; padding: 0; }
.nav a {
  position: relative; display: block; padding: .55rem .9rem; border-radius: 8px;
  font-size: var(--t-nav); font-weight: 500; color: var(--fg-2);
  transition: color .25s var(--ease);
}
.nav a:hover, .nav a.is-on { color: var(--fg); }
/* The underline grows from the centre out — the same physical logic as the
   button fill, so the whole interface moves one way. */
.nav a::after {
  content: ""; position: absolute; inset-block-end: .15rem; inset-inline: .85rem;
  block-size: 1.5px; background: var(--spot);
  transform: scaleX(0); transform-origin: center;
  transition: transform .4s var(--ease);
}
.nav a:hover::after, .nav a.is-on::after { transform: scaleX(1); }

.topbar-end { display: flex; align-items: center; gap: .6rem; }

/* language */
.lang { position: relative; }
.lang-btn {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .5rem .75rem; border-radius: 999px;
  border: 1px solid var(--line); color: var(--fg-2);
  font-size: var(--t-mono); letter-spacing: .08em;
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.lang-btn:hover { color: var(--fg); border-color: var(--line-2); }
.lang-btn .ico { inline-size: .95rem; block-size: .95rem; }
.lang-menu {
  position: absolute; inset-block-start: calc(100% + .6rem); inset-inline-end: 0;
  min-inline-size: 12.5rem; padding: .4rem; margin: 0; list-style: none;
  background: var(--ink-3); border: 1px solid var(--line-2); border-radius: 14px;
  box-shadow: var(--shadow-2);
  opacity: 0; visibility: hidden; transform: translateY(-6px) scale(.98);
  transform-origin: top right;
  transition: opacity .28s var(--ease), transform .28s var(--ease), visibility .28s;
}
.lang-ar .lang-menu { transform-origin: top left; }
.lang.is-open .lang-menu { opacity: 1; visibility: visible; transform: none; }
.lang-opt {
  display: flex; align-items: baseline; gap: .6rem;
  padding: .55rem .75rem; border-radius: 9px; color: var(--fg-2);
  transition: background .2s, color .2s;
}
.lang-opt:hover { background: rgb(255 255 255 / .05); color: var(--fg); }
.lang-opt.is-on { color: var(--spot); }
.lang-opt b { font-size: .95rem; font-weight: 600; min-inline-size: 2.6rem; }
.lang-opt span { font-size: var(--t-sm); opacity: .7; }

.burger { display: none; inline-size: 44px; block-size: 44px; position: relative; border-radius: 10px; }
.burger i {
  position: absolute; inset-inline: 12px; block-size: 1.5px; background: var(--fg);
  transition: transform .4s var(--ease), opacity .3s var(--ease);
}
.burger i:nth-child(2) { inset-block-start: 16px; }
.burger i:nth-child(3) { inset-block-start: 21px; }
.burger i:nth-child(4) { inset-block-start: 26px; }
.burger[aria-expanded="true"] i:nth-child(2) { transform: translateY(5px) rotate(45deg); }
.burger[aria-expanded="true"] i:nth-child(3) { opacity: 0; transform: scaleX(.3); }
.burger[aria-expanded="true"] i:nth-child(4) { transform: translateY(-5px) rotate(-45deg); }

.scroll-ink {
  position: absolute; inset-block-end: -1px; inset-inline-start: 0;
  block-size: 1.5px; inline-size: var(--p, 0%);
  background: linear-gradient(90deg, var(--spot), var(--spot-lift));
}

.mnav {
  position: fixed; inset: 4.75rem 0 auto; z-index: 99;
  background: color-mix(in srgb, var(--ink) 97%, transparent);
  backdrop-filter: blur(20px);
  border-block-end: 1px solid var(--line);
  padding: 1rem var(--gut) 2rem;
}
.mnav ul { list-style: none; padding: 0; display: grid; gap: .15rem; }
.mnav a {
  display: block; padding: .95rem .25rem;
  font-family: var(--f-display); font-size: 1.5rem; font-weight: 400;
  border-block-end: 1px solid var(--line);
}
.mnav a:hover { color: var(--spot); }
.mnav-cta { color: var(--spot); }

/* --- 8. Hero ------------------------------------------------------------- */

.hero {
  position: relative; overflow: hidden;
  padding-block: clamp(4rem, 2rem + 8vw, 8rem) clamp(4rem, 2rem + 6vw, 7rem);
  background: var(--ink);
}
.hero-grid-bg {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, var(--line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line) 1px, transparent 1px);
  background-size: 5.5rem 5.5rem;
  mask-image: radial-gradient(90% 70% at 50% 0%, #000 20%, transparent 78%);
  opacity: .5;
}
.hero-in {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
  gap: clamp(2rem, 1rem + 4vw, 4.5rem); align-items: center;
}
.hero-copy { max-inline-size: 34rem; }
.hero-eyebrow { margin-block-end: 1.6rem; }

.hero-h1 {
  font-size: var(--t-h1);
  font-weight: 800;
  font-variation-settings: "wght" 800, "wdth" 115;
  line-height: 1.02;
  letter-spacing: -.028em;
}
.lang-zh .hero-h1, .lang-ja .hero-h1, .lang-ko .hero-h1 {
  font-weight: 800; line-height: 1.24; letter-spacing: 0; font-variation-settings: normal;
}
.lang-ar .hero-h1 { font-weight: 700; line-height: 1.5; letter-spacing: normal; }

/* Word-by-word reveal: each word rises out of its own clipping box. */
.hero-h1 .w { display: inline-block; overflow: hidden; vertical-align: bottom; padding-block-end: .08em; }
.hero-h1 .w-i {
  display: inline-block;
  transform: translateY(105%);
  transition: transform .95s var(--ease);
  transition-delay: var(--d, 0ms);
}


.hero-lead {
  margin-block-start: 1.8rem; max-inline-size: 34rem;
  font-size: var(--t-lead); color: var(--fg-2); line-height: 1.6;
}
.hero-cta { display: flex; flex-wrap: wrap; gap: .8rem; margin-block-start: 2.4rem; }
.hero-note {
  margin-block-start: 1.8rem; padding-block-start: 1.4rem;
  border-block-start: 1px solid var(--line);
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .06em;
  color: var(--fg-3); line-height: 1.9;
}
.hero-scroll {
  display: inline-flex; align-items: center; gap: .6rem; margin-block-start: 2rem;
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .14em;
  text-transform: uppercase; color: var(--fg-3);
}
.hero-scroll::after {
  content: ""; inline-size: 2.5rem; block-size: 1px; background: currentColor;
  transform-origin: left; animation: scrollHint 2.4s var(--ease-io) infinite;
}
@keyframes scrollHint { 0%,100% { transform: scaleX(.3); opacity: .4 } 50% { transform: scaleX(1); opacity: 1 } }

/* hero film */
.hero-film {
  position: absolute; inset: 0; overflow: hidden; z-index: 0;
  /* The still is the container background, so it is on screen from first paint
     whether or not the film is ever fetched. */
  background-size: cover; background-position: 68% center; background-repeat: no-repeat;
}
.lang-ar .hero-film { background-position: 32% center; }
.hero-film-v {
  position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
  object-fit: cover; object-position: 68% center;
  opacity: 0; transition: opacity 1.4s var(--ease);
}
.hero-film-v.is-on { opacity: 1; }
/* Two stacked gradients, not one: the headline sits over moving footage and
   the contrast underneath it changes frame by frame. This guarantees the
   floor whatever the video does. */
.hero-film-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(90deg, var(--ink) 14%, color-mix(in srgb, var(--ink) 78%, transparent) 48%, transparent 82%),
    linear-gradient(0deg, var(--ink) 1%, transparent 34%),
    color-mix(in srgb, var(--ink) 26%, transparent);
}
.lang-ar .hero-film-scrim {
  background:
    linear-gradient(270deg, var(--ink) 14%, color-mix(in srgb, var(--ink) 78%, transparent) 48%, transparent 82%),
    linear-gradient(0deg, var(--ink) 1%, transparent 34%),
    color-mix(in srgb, var(--ink) 26%, transparent);
}
.lang-ar .hero-film-v { object-position: 32% center; }
.hero.has-film .hero-in { grid-template-columns: minmax(0, 1fr); }
.hero.has-film .hero-copy { max-inline-size: 42rem; }
.hero.has-film { min-block-size: min(80vh, 720px); display: flex; align-items: center; }
.hero.has-film .hero-grid-bg { opacity: .28; }

/* --- 9. The 3D stack ----------------------------------------------------- */

.stack-wrap { position: relative; perspective: 1600px; perspective-origin: 50% 42%; }
/* The scene only holds the perspective. The ROTATION lives on .stack-plies,
   because that is the element the pointer/scroll lerp in site.js writes to —
   rotating both would compound into roughly twice the intended angle. */
.stack-scene {
  position: relative; aspect-ratio: 4 / 3.4;
  transform-style: preserve-3d;
}
.stack-plies {
  position: absolute; inset: 12% 14%;
  transform-style: preserve-3d;
  transform: rotateX(56deg) rotateZ(-34deg);
}
.lang-ar .stack-plies { transform: rotateX(56deg) rotateZ(34deg); }
/* Until the lerp takes over, CSS eases the pose; after that JS owns it frame
   by frame and a transition here would fight the animation. */
.stack-wrap:not(.is-live) .stack-plies { transition: transform 1.1s var(--ease); }

.ply {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  /* --sep is driven by scroll; each ply lifts proportionally to its index so
     the stack opens like a real laminate rather than sliding as one block. */
  transform: translateZ(calc(var(--i) * var(--gap, 18px)));
  transition: transform 1.05s var(--ease);
}
.ply-face {
  position: absolute; inset: 0; border-radius: 12px;
  background:
    linear-gradient(150deg,
      color-mix(in srgb, var(--c) 24%, var(--ink-4)) 0%,
      color-mix(in srgb, var(--c) 9%, var(--ink-3)) 58%,
      var(--ink-3) 100%);
  border: 1px solid color-mix(in srgb, var(--c) 34%, transparent);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--c) 40%, transparent),
    0 18px 40px -22px rgb(0 0 0 / .9);
  color: var(--c);
  overflow: hidden;
}
/* A travelling specular band. This is what sells the plies as physical film
   rather than as coloured rectangles. */
.ply-face::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 32%, rgb(255 255 255 / .13) 46%, transparent 60%);
  transform: translateX(-40%);
  transition: transform 1.4s var(--ease);
}
.stack-wrap:hover .ply-face::after, .stack-wrap.is-live:hover .ply-face::after { transform: translateX(40%); }

.ply-art { position: absolute; inset: 8% 6%; inline-size: 88%; block-size: 84%; opacity: .5; }
.ply-tag {
  position: absolute; inset-block-end: .55rem; inset-inline-start: .7rem;
  display: inline-flex; align-items: center; gap: .38rem;
  font-family: var(--f-mono); font-size: .9375rem; letter-spacing: .08em; text-transform: uppercase;
  color: color-mix(in srgb, var(--c) 62%, var(--fg));
  opacity: 0; transform: translateY(4px);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
  transition-delay: calc(var(--i) * 40ms);
}
.ply-tag i { inline-size: .34rem; block-size: .34rem; border-radius: 50%; background: var(--c); }
.stack-wrap:hover .ply-tag, .stack-wrap:focus-within .ply-tag { opacity: 1; transform: none; }

/* The edge is what gives a ply thickness when the stack is tilted. */
.ply-edge {
  position: absolute; inset-inline: 0; inset-block-end: -3px; block-size: 3px;
  background: color-mix(in srgb, var(--c) 46%, var(--ink));
  transform: rotateX(-90deg); transform-origin: top;
  border-radius: 0 0 3px 3px;
}
.stack-shadow {
  position: absolute; inset: 16% 12% -6%;
  background: radial-gradient(ellipse at 50% 50%, rgb(0 0 0 / .75), transparent 68%);
  filter: blur(26px); transform: translateZ(-70px);
}
.stack-rule {
  position: absolute; inset-block-end: 3%; inset-inline-end: 4%;
  display: flex; align-items: baseline; gap: .45rem;
}
.stack-rule span { font-family: var(--f-display); font-size: 3.6rem; font-weight: 800; line-height: 1; }
.stack-rule i {
  font-family: var(--f-mono); font-style: normal; font-size: var(--t-mono);
  letter-spacing: .14em; text-transform: uppercase; color: var(--fg-3);
}
.stack-inline .stack-scene { aspect-ratio: 4 / 3.1; }

/* --- 10. Stats ----------------------------------------------------------- */

.stat-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 1px; list-style: none; padding: 0;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden;
}
.stat-row li {
  background: var(--bg);
  padding: clamp(1.6rem, 1rem + 1.6vw, 2.4rem) clamp(1.1rem, .8rem + 1vw, 1.8rem);
  display: flex; flex-direction: column; gap: .5rem;
  transition: background .35s var(--ease);
}
.stat-row li:hover { background: var(--ink-3); }
.stat-n {
  font-family: var(--f-display); font-size: clamp(2.6rem, 1.7rem + 2.6vw, 4rem);
  font-weight: 800; font-variation-settings: "wght" 800, "wdth" 108;
  line-height: 1; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}
.stat-row span { color: var(--fg-3); line-height: 1.4; }
.stat-note { margin-block-start: 1.2rem; font-size: var(--t-sm); color: var(--fg-3); }

/* --- 11. Anatomy --------------------------------------------------------- */

.an-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .82fr);
  gap: clamp(2rem, 1rem + 4vw, 4.5rem); align-items: start;
}
.an-list { list-style: none; padding: 0; margin: 0; border-block-start: 1px solid var(--line); }
.an-item { border-block-end: 1px solid var(--line); }
.an-btn {
  inline-size: 100%; display: grid; grid-template-columns: 2.4rem 1fr auto;
  align-items: center; gap: 1rem; padding: 1.35rem .35rem;
  text-align: start; color: var(--fg-2);
  transition: color .3s var(--ease), padding-inline-start .35s var(--ease);
}
.an-btn:hover { color: var(--fg); padding-inline-start: .75rem; }
.an-item.is-on .an-btn { color: var(--fg); }
.an-n { font-family: var(--f-mono); font-size: var(--t-mono); color: var(--c); opacity: .8; }
.an-name { font-family: var(--f-display); font-size: var(--t-h3); font-weight: 700; letter-spacing: -.012em; }
.an-thick { font-family: var(--f-mono); font-size: var(--t-mono); color: var(--fg-3); }
.an-body {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .55s var(--ease);
}
.an-item.is-on .an-body { grid-template-rows: 1fr; }
.an-body > * { overflow: hidden; }
.an-fn {
  padding-inline-start: 3.4rem; padding-block-end: 1.5rem;
  color: var(--fg-2); max-inline-size: 48ch;
}
.an-more { margin-block-start: 2rem; }

.an-vis { position: relative; aspect-ratio: 1 / 1.05; perspective: 1300px; }
.an-stack {
  position: absolute; inset: 14% 8%;
  transform-style: preserve-3d;
  transform: rotateX(58deg) rotateZ(-36deg);
}
.an-ply {
  position: absolute; inset: 0; border-radius: 10px;
  background: linear-gradient(150deg, color-mix(in srgb, var(--c) 26%, var(--ink-4)), var(--ink-3));
  border: 1px solid color-mix(in srgb, var(--c) 30%, transparent);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--c) 42%, transparent), 0 20px 44px -26px #000;
  transform: translateZ(calc(var(--i) * 30px));
  transition: transform .7s var(--ease), opacity .5s var(--ease), box-shadow .5s var(--ease);
  display: grid; place-items: center;
}
.an-ply span {
  font-family: var(--f-mono); font-size: .9375rem; letter-spacing: .08em; text-transform: uppercase;
  color: color-mix(in srgb, var(--c) 55%, var(--fg));
  opacity: 0; transition: opacity .4s var(--ease);
}
/* The selected ply lifts clear of the stack and the others recede — the list
   and the drawing are one control, not two decorations. */
.an-ply.is-on {
  transform: translateZ(calc(var(--i) * 30px + 58px)) scale(1.035);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--c) 60%, transparent), 0 34px 60px -24px #000;
}
.an-ply.is-on span { opacity: 1; }
.an-ply.is-dim { opacity: .32; }

/* --- 12. Cards ----------------------------------------------------------- */

.pgrid { display: grid; gap: clamp(1rem, .5rem + 1.6vw, 1.6rem); grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr)); }
.pgrid-3 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr)); }

.pcard {
  position: relative; isolation: isolate;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden;
  transition: transform .55s var(--ease), border-color .45s var(--ease), box-shadow .55s var(--ease);
}
.pcard:hover { transform: translateY(-5px); border-color: var(--line-2); box-shadow: var(--shadow-2); }
/*
 * The anchor WRAPS the whole card in the markup — it is not an empty overlay
 * sitting on top of it. Styling it `position:absolute` therefore pulled every
 * child out of flow, collapsing each card to the 2px of its own borders: eight
 * cards piled on one line, their images rendered but hidden under the next
 * section. The card is the link, so the link is a normal block.
 */
.pcard-link { display: flex; flex-direction: column; block-size: 100%; }
.pcard-vis {
  position: relative; aspect-ratio: 5 / 4; overflow: hidden;
  background: var(--ink-2);
}
.pcard-vis picture, .pcard-vis img, .pcard-vis svg { inline-size: 100%; block-size: 100%; object-fit: cover; }
.pcard-vis img { transition: transform 1s var(--ease), filter .6s var(--ease); }
.pcard:hover .pcard-vis img { transform: scale(1.045); }
/* A whisper of the accent washes in on hover — enough to feel alive, not
   enough to tint the photograph. */
.pcard-vis::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(0deg, color-mix(in srgb, var(--ink) 70%, transparent), transparent 55%),
              radial-gradient(60% 50% at 80% 100%, var(--glow), transparent 70%);
  opacity: .75; transition: opacity .5s var(--ease);
}
.pcard:hover .pcard-vis::after { opacity: 1; }

.pcard-body { padding: 1.5rem 1.5rem 1.7rem; display: flex; flex-direction: column; gap: .7rem; flex: 1; }
.pcard-meta { color: var(--fg-3); display: flex; gap: .6rem; align-items: center; }
.pcard-meta b { color: var(--spot); font-weight: 400; }
.pcard-title { font-size: var(--t-h3); font-weight: 700; letter-spacing: -.012em; }
.pcard:hover .pcard-title { color: #fff; }
.pcard-sum { color: var(--fg-2); font-size: 1rem; line-height: 1.65; }
.pcard-go {
  margin-block-start: auto; padding-block-start: .5rem;
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--spot);
}
.pcard-go .ico { transition: transform .4s var(--ease); }
.pcard:hover .pcard-go .ico { transform: translateX(4px); }
.lang-ar .pcard:hover .pcard-go .ico { transform: translateX(-4px) scaleX(-1); }
/* The one piece of literal label craft that earns its place: a lifted corner,
   and only on hover. */
.pcard-peel {
  position: absolute; inset-block-start: 0; inset-inline-end: 0; z-index: 2;
  inline-size: 3rem; block-size: 3rem;
  background: linear-gradient(225deg, var(--ink-2) 48%, transparent 50%);
  clip-path: polygon(100% 0, 0 0, 100% 100%);
  opacity: 0; transform: translate(6px, -6px);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.pcard:hover .pcard-peel { opacity: 1; transform: none; }

/* generic card */
.card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: clamp(1.4rem, 1rem + 1.2vw, 2rem);
  transition: border-color .4s var(--ease), transform .5s var(--ease), background .4s var(--ease);
}
.card:hover { border-color: var(--line-2); transform: translateY(-3px); }

/* capability */
.cap-grid { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
.cap { background: var(--bg); padding: clamp(1.5rem, 1rem + 1.4vw, 2.2rem); transition: background .4s var(--ease); }
.cap:hover { background: var(--ink-3); }
.cap-n { font-family: var(--f-mono); font-size: var(--t-mono); color: var(--spot); letter-spacing: .14em; }
.cap h3 { margin-block: .8rem .7rem; font-size: var(--t-h3); font-weight: 700; }
.cap p { color: var(--fg-2); font-size: 1rem; line-height: 1.7; }
.cap-list { list-style: none; padding: 0; margin-block-start: 1rem; display: grid; gap: .45rem; }
.cap-list li {
  position: relative; padding-inline-start: 1.05rem;
  font-size: var(--t-sm); color: var(--fg-2);
}
.cap-list li::before {
  content: ""; position: absolute; inset-inline-start: 0; inset-block-start: .62em;
  inline-size: 4px; block-size: 4px; border-radius: 50%; background: var(--spot); opacity: .65;
}
.cap-lg h3 { font-size: clamp(1.35rem, 1.1rem + .8vw, 1.9rem); }

/* industries */
.ind-grid { display: grid; gap: clamp(1rem, .6rem + 1.4vw, 1.6rem); grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr)); }
.ind {
  position: relative; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: clamp(1.4rem, 1rem + 1.2vw, 2rem);
  overflow: hidden;
  transition: border-color .4s var(--ease), transform .5s var(--ease);
}
.ind::before {
  content: ""; position: absolute; inset-block-start: 0; inset-inline: 0; block-size: 2px;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
  transition: transform .6s var(--ease);
}
.lang-ar .ind::before { transform-origin: right; }
.ind:hover { border-color: var(--line-2); transform: translateY(-3px); }
.ind:hover::before { transform: scaleX(1); }
.ind-name { font-size: var(--t-h3); font-weight: 700; margin-block-end: 1rem; }
.ind-cols { display: grid; gap: 1.1rem; margin-block-end: 1.2rem; }
.ind-cols h4 {
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--fg-3); margin-block-end: .4rem; font-weight: 400;
}
.ind-cols p { font-size: 1rem; color: var(--fg-2); line-height: 1.65; }
.ind-links { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.ind-links a {
  display: inline-block; padding: .35rem .75rem; border-radius: 999px;
  border: 1px solid var(--line); font-size: var(--t-mono); letter-spacing: .06em;
  color: var(--fg-2); font-family: var(--f-mono);
  transition: border-color .3s, color .3s, background .3s;
}
.ind-links a:hover { color: #fff; border-color: transparent; background: var(--accent, var(--spot)); }
.ind-compact { display: flex; flex-direction: column; gap: .9rem; }
.ind-compact .ind-name { margin-block-end: 0; }
.ind-compact .ind-name a:hover { color: var(--accent); }
.ind-compact .ind-links { margin-block-start: auto; }

/* process */
.step-row {
  list-style: none; padding: 0; display: grid; gap: 1px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
}
.step { background: var(--bg); padding: clamp(1.4rem, 1rem + 1.2vw, 2rem); transition: background .4s var(--ease); }
.step:hover { background: var(--ink-3); }
.step-n {
  display: inline-block; margin-block-end: 1rem;
  font-family: var(--f-display); font-size: 2.6rem; font-weight: 800; line-height: 1;
  color: var(--ink-5);
  transition: color .4s var(--ease);
}
.step:hover .step-n { color: var(--spot); }
.step h3 { font-size: 1.15rem; font-weight: 600; font-family: var(--f-body); letter-spacing: 0; margin-block-end: .5rem; }
.step p { font-size: 1rem; color: var(--fg-2); line-height: 1.65; }

/* article cards */
.agrid { display: grid; gap: clamp(1rem, .6rem + 1.4vw, 1.6rem); grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr)); }
.acard {
  display: flex; flex-direction: column; gap: .8rem;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: clamp(1.3rem, 1rem + 1vw, 1.8rem);
  transition: border-color .4s var(--ease), transform .5s var(--ease), background .4s var(--ease);
}
.acard:hover { border-color: var(--line-2); transform: translateY(-3px); background: var(--card-up); }
.acard-top { display: flex; align-items: center; gap: .7rem; color: var(--fg-3); }
.acard h3 { font-size: 1.32rem; font-weight: 700; line-height: 1.3; }
.acard:hover h3 { color: #fff; }
.acard p { font-size: 1rem; color: var(--fg-2); line-height: 1.65; }
.acard-read { margin-block-start: auto; padding-block-start: .6rem; color: var(--spot); font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .1em; text-transform: uppercase; }
.acard-tags { display: flex; flex-wrap: wrap; gap: .35rem; }
.agrid-lg .acard h3 { font-size: 1.48rem; }

/* chips, tags, badges */
.chip, .tag, .badge {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .3rem .7rem; border-radius: 999px;
  border: 1px solid var(--line); color: var(--fg-3);
}
.badge { border-color: transparent; background: var(--glow); color: var(--spot-lift); }
.tag:hover, .chip:hover { color: var(--fg); border-color: var(--line-2); }

/* --- 13. Product detail -------------------------------------------------- */

.pd-top { padding-block: clamp(2.5rem, 1.5rem + 4vw, 4.5rem) 0; }
.pd-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .92fr); gap: clamp(2rem, 1rem + 4vw, 4rem); align-items: center; }
.pd-h1 { font-size: clamp(2.3rem, 1.5rem + 3.4vw, 4.1rem); font-weight: 800; letter-spacing: -.026em; }
.lang-zh .pd-h1, .lang-ja .pd-h1, .lang-ko .pd-h1 { font-weight: 800; letter-spacing: 0; }
.pd-sum { margin-block-start: 1.4rem; font-size: var(--t-lead); color: var(--fg-2); line-height: 1.55; max-inline-size: 42ch; }
.pd-chips { display: flex; flex-wrap: wrap; gap: .5rem; margin-block-start: 1.6rem; }
.pd-cta { display: flex; flex-wrap: wrap; gap: .8rem; margin-block-start: 2rem; }
.pd-stack-cap {
  margin-block-start: 1rem; text-align: center;
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--fg-3);
}
.pd-stack-cap b { color: var(--fg); font-weight: 400; }
.pd-cols { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); gap: clamp(2rem, 1rem + 4vw, 4rem); align-items: start; }
.pd-h2 { font-size: clamp(1.6rem, 1.25rem + 1.2vw, 2.2rem); font-weight: 700; margin-block-end: 1.2rem; }
.pd-body > * + * { margin-block-start: clamp(2.5rem, 1.6rem + 2.4vw, 4rem); }
.pd-side { position: sticky; inset-block-start: 6.5rem; }
.pd-gal { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }
.pd-shot { margin: 0; border-radius: var(--r); overflow: hidden; border: 1px solid var(--line); }
.pd-shot img { inline-size: 100%; block-size: auto; }

.spec { border-block-start: 1px solid var(--line); }
.spec-row {
  display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
  gap: 1rem; padding-block: .95rem;
  border-block-end: 1px solid var(--line);
}
.spec-row dt { color: var(--fg-3); }
.spec-row dd { margin: 0; color: var(--fg); font-size: 1rem; }

/* --- 14. Insights -------------------------------------------------------- */

.art-head { padding-block: clamp(2.5rem, 1.5rem + 4vw, 4.5rem) 0; }
.art-head-in { max-inline-size: 52rem; }
.art-h1 { font-size: clamp(2.1rem, 1.4rem + 2.8vw, 3.5rem); font-weight: 800; letter-spacing: -.022em; line-height: 1.12; }
.lang-zh .art-h1, .lang-ja .art-h1, .lang-ko .art-h1 { font-weight: 800; line-height: 1.32; letter-spacing: 0; }
.art-meta { display: flex; flex-wrap: wrap; gap: .9rem; align-items: center; color: var(--fg-3); margin-block-start: 1.4rem; }
.art-sum { margin-block-start: 1.6rem; font-size: var(--t-lead); color: var(--fg-2); line-height: 1.6; }
.art-body-wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 17rem); gap: clamp(2rem, 1rem + 4vw, 4rem); align-items: start; }
.art-body { max-inline-size: 68ch; }
.art-related { position: sticky; inset-block-start: 6.5rem; }
.art-source {
  margin-block-start: 2.5rem; padding: 1.2rem 1.4rem;
  background: var(--ink-2); border: 1px solid var(--line); border-radius: var(--r);
  font-size: var(--t-sm); color: var(--fg-2);
}
.art-source a { color: var(--spot); text-decoration: underline; text-underline-offset: 3px; }
.art-links { list-style: none; padding: 0; display: grid; gap: .5rem; }
.art-back { margin-block-start: 3rem; }
.src-inline a { color: var(--spot); }

.prose { color: var(--fg-2); line-height: 1.75; }
.prose > * + * { margin-block-start: 1.3rem; }
.prose h2 { font-size: clamp(1.3rem, 1.1rem + .9vw, 1.75rem); font-weight: 400; color: var(--fg); margin-block-start: 2.6rem; }
.prose h3 { font-size: 1.2rem; font-weight: 500; color: var(--fg); margin-block-start: 2rem; }
.prose a { color: var(--spot); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.prose ul, .prose ol { padding-inline-start: 1.3rem; display: grid; gap: .5rem; }
.prose hr { border: 0; block-size: 1px; background: var(--line); margin-block: 2.2rem; }
.prose strong, .prose b { color: var(--fg); font-weight: 600; }

.pager { display: flex; gap: .5rem; align-items: center; justify-content: center; margin-block-start: 3rem; }
.pager-now { padding: .5rem 1rem; font-family: var(--f-mono); font-size: var(--t-mono); color: var(--fg-3); }

/* --- 15. Factory --------------------------------------------------------- */

.fac-list { list-style: none; padding: 0; border-block-start: 1px solid var(--line); }
.fac-list li { padding-block: 1.4rem; border-block-end: 1px solid var(--line); display: flex; align-items: baseline; gap: 1.2rem; }
.fac-list h3 { font-size: var(--t-h3); font-weight: 700; }
.fac-list h3 a:hover { color: var(--spot); }
.fac-addr { display: grid; gap: .4rem; }
.fac-addr-line { color: var(--fg-2); }

/* Layer rows: see section 29. */

/* --- 16. Forms ----------------------------------------------------------- */

.iform-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }
.fld { display: flex; flex-direction: column; gap: .45rem; }
.fld-wide { grid-column: 1 / -1; }
.fld-lab {
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .11em;
  text-transform: uppercase; color: var(--fg-3);
}
.fld-lab .req { color: var(--spot); }
.fld input, .fld select, .fld textarea {
  inline-size: 100%; padding: .9rem 1.05rem;
  background: var(--ink-2); border: 1px solid var(--line); border-radius: 10px;
  color: var(--fg); font-size: 1rem;
  transition: border-color .3s var(--ease), background .3s var(--ease), box-shadow .3s var(--ease);
}
.fld textarea { min-block-size: 8rem; resize: vertical; line-height: 1.6; }
.fld input:focus, .fld select:focus, .fld textarea:focus {
  outline: none; border-color: var(--spot); background: var(--ink-3);
  box-shadow: 0 0 0 3px var(--glow);
}
.fld input::placeholder, .fld textarea::placeholder { color: var(--fg-3); opacity: .7; }
.iform-foot { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; justify-content: space-between; margin-block-start: 1.4rem; }
.iform-privacy { font-size: var(--t-sm); color: var(--fg-3); max-inline-size: 34ch; }
.iform-msg { margin-block-start: 1rem; padding: 1rem 1.2rem; border-radius: 10px; font-size: var(--t-sm); display: none; }
.iform-msg.ok { display: block; background: rgb(143 227 136 / .1); border: 1px solid rgb(143 227 136 / .3); color: #9de896; }
.iform-msg.warn { display: block; background: rgb(232 66 90 / .1); border: 1px solid rgb(232 66 90 / .3); color: #ff8a9c; }
/* honeypot */
.hp { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); }

/* --- 17. Closing CTA ----------------------------------------------------- */

.closing { position: relative; overflow: hidden; padding-block: var(--pad-y); background: var(--ink-2); }
.closing-bg {
  position: absolute; inset: 0;
  background:
    radial-gradient(56rem 34rem at 12% 110%, rgb(255 92 53 / .14), transparent 62%),
    radial-gradient(46rem 30rem at 92% -20%, rgb(111 213 232 / .07), transparent 60%);
}
.closing-in { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: clamp(2rem, 1rem + 4vw, 4.5rem); align-items: start; }
.closing-h2 { font-size: clamp(2rem, 1.4rem + 2.6vw, 3.3rem); font-weight: 800; letter-spacing: -.024em; }
.lang-zh .closing-h2, .lang-ja .closing-h2, .lang-ko .closing-h2 { font-weight: 800; letter-spacing: 0; }
.closing-lead { margin-block-start: 1.3rem; color: var(--fg-2); font-size: var(--t-lead); line-height: 1.55; max-inline-size: 40ch; }
.closing-form { background: var(--ink-3); border: 1px solid var(--line); border-radius: var(--r-lg); padding: clamp(1.4rem, 1rem + 1.4vw, 2.2rem); }

/* --- 18. Contact --------------------------------------------------------- */

.ctc-grid { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: clamp(2rem, 1rem + 4vw, 4rem); align-items: start; }
.ctc-form { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg); padding: clamp(1.5rem, 1rem + 1.6vw, 2.4rem); }
.ctc-side { display: grid; gap: 1.5rem; }
.ctc-list { list-style: none; padding: 0; display: grid; gap: 1rem; }
.ctc-list a:hover { color: var(--spot); }
.ctc-reply { font-size: var(--t-sm); color: var(--fg-3); }
.foot-kv { display: grid; gap: .25rem; }
.foot-kv dt { font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .11em; text-transform: uppercase; color: var(--fg-3); }
.foot-kv dd { margin: 0; }

/* --- 19. Page hero ------------------------------------------------------- */

.page-hero { padding-block: clamp(3rem, 2rem + 4vw, 5.5rem) clamp(2rem, 1.4rem + 2.4vw, 3.5rem); }
.page-hero-tight { padding-block-end: 0; }
.page-h1 { font-size: var(--t-h2); font-weight: 800; letter-spacing: -.026em; }
.lang-zh .page-h1, .lang-ja .page-h1, .lang-ko .page-h1 { font-weight: 800; letter-spacing: 0; }
.page-lead { margin-block-start: 1.4rem; max-inline-size: 52ch; font-size: var(--t-lead); color: var(--fg-2); line-height: 1.55; }
.crumbs { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-block-end: 1.5rem; font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .1em; text-transform: uppercase; color: var(--fg-3); }
.crumbs a:hover { color: var(--spot); }
.crumbs li { display: flex; gap: .5rem; align-items: center; }
.crumbs ol { display: flex; flex-wrap: wrap; gap: .5rem; list-style: none; padding: 0; }

.filters { display: flex; flex-wrap: wrap; gap: .5rem; margin-block-end: 2.5rem; }
.filters a {
  padding: .45rem 1rem; border-radius: 999px; border: 1px solid var(--line);
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .08em;
  color: var(--fg-2); transition: all .3s var(--ease);
}
.filters a:hover { border-color: var(--line-2); color: var(--fg); }
.filters a.on { background: var(--fg); color: var(--ink); border-color: var(--fg); }

.sec-more { margin-block-start: 2.5rem; display: flex; justify-content: center; }
.empty { padding: 3rem 0; color: var(--fg-3); text-align: center; }

/* --- 20. Root language picker -------------------------------------------- */

.root-pick { min-block-size: 100vh; display: grid; place-items: center; padding: 3rem var(--gut); }
.pick { max-inline-size: 40rem; inline-size: 100%; }
.pick-head { display: flex; align-items: center; gap: .8rem; margin-block-end: 2.5rem; }
.pick-head .brand-mark { inline-size: 2.4rem; block-size: 2.4rem; }
.pick h1 { font-size: clamp(1.9rem, 1.5rem + 1.8vw, 2.7rem); font-weight: 800; }
.pick-lead { margin-block-start: 1rem; color: var(--fg-2); }
.pick-list { list-style: none; padding: 0; margin-block-start: 2.5rem; display: grid; gap: .5rem; }
.pick-list a {
  display: flex; align-items: baseline; gap: 1rem; padding: 1.1rem 1.3rem;
  background: var(--ink-2); border: 1px solid var(--line); border-radius: 12px;
  transition: border-color .3s var(--ease), background .3s var(--ease), transform .3s var(--ease);
}
.pick-list a:hover { border-color: var(--spot); background: var(--ink-3); transform: translateX(4px); }
.lang-ar .pick-list a:hover { transform: translateX(-4px); }
.pick-list b { font-size: 1.1rem; min-inline-size: 4rem; }
.pick-list span { color: var(--fg-3); font-size: var(--t-sm); }
.is-guess { border-color: var(--spot) !important; }

/* --- 21. Footer ---------------------------------------------------------- */

footer { background: var(--ink-2); border-block-start: 1px solid var(--line); padding-block: clamp(3rem, 2rem + 3vw, 5rem) 2rem; }
.foot-grid { display: grid; grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr)); gap: clamp(1.5rem, 1rem + 2vw, 3rem); }
.foot-brand { display: flex; align-items: center; gap: .7rem; margin-block-end: 1.2rem; }
.foot-about { color: var(--fg-2); font-size: 1rem; line-height: 1.7; max-inline-size: 34ch; }
.foot-col h3 {
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--fg-3); font-weight: 400; margin-block-end: 1rem;
}
.foot-col ul { list-style: none; padding: 0; display: grid; gap: .55rem; }
.foot-col a { color: var(--fg-2); font-size: 1rem; transition: color .25s; }
.foot-col a:hover { color: var(--spot); }
.foot-contact { display: grid; gap: .8rem; }
.foot-base {
  margin-block-start: clamp(2.5rem, 2rem + 2vw, 4rem); padding-block-start: 1.5rem;
  border-block-start: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; justify-content: space-between;
  font-size: var(--t-sm); color: var(--fg-3);
}
.foot-legal-name { color: var(--fg-2); }
.foot-mini { display: flex; gap: 1.2rem; flex-wrap: wrap; }
.foot-mini a:hover { color: var(--spot); }

/* --- 22. Motion ---------------------------------------------------------- */

/* Scroll reveal. The default is VISIBLE; the observer adds the hidden state on
   init and removes it on intersect. If JS never runs — or the observer never
   fires — the content is simply there, rather than permanently invisible. */
.js [data-anim] { opacity: 0; transform: translateY(22px); }
.js [data-anim].in { opacity: 1; transform: none;
  transition: opacity .85s var(--ease), transform .85s var(--ease); }
[data-anim] { transition-delay: var(--d, 0ms); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  .js [data-anim] { opacity: 1; transform: none; }
  .hero-h1 .w-i { transform: none; }
  .hero-film-v { opacity: 1; }
}

/* Hover effects are a lie on touch: :hover sticks after a tap. */
@media (hover: none) {
  .pcard:hover { transform: none; }
  .pcard:hover .pcard-vis img { transform: none; }
  .pcard-peel { display: none; }
  .btn:hover { transform: none; }
  .card:hover, .ind:hover, .acard:hover { transform: none; }
}

/* --- 23. Responsive ------------------------------------------------------ */

@media (max-width: 1080px) {
  .an-grid, .pd-grid, .pd-cols, .closing-in, .ctc-grid, .art-body-wrap { grid-template-columns: minmax(0, 1fr); }
  .an-vis { max-inline-size: 26rem; margin-inline: auto; }
  .pd-side, .art-related { position: static; }
  .foot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .nav, .nav-cta { display: none; }
  .burger { display: block; }
  .hero-in { grid-template-columns: minmax(0, 1fr); }
  .hero.has-film { min-block-size: 0; }
  .hero.has-film .hero-film-scrim {
    background: linear-gradient(0deg, var(--ink) 16%, color-mix(in srgb, var(--ink) 80%, transparent) 62%, color-mix(in srgb, var(--ink) 52%, transparent));
  }
  .stack-wrap { max-inline-size: 24rem; margin-inline: auto; }
  .topbar-in { block-size: 4.25rem; }
  .mnav { inset-block-start: 4.25rem; }
}

@media (max-width: 640px) {
  .foot-grid { grid-template-columns: minmax(0, 1fr); }
  .spec-row, .tl-dl > div { grid-template-columns: minmax(0, 1fr); gap: .25rem; }
  .tl-row { grid-template-columns: minmax(0, 1fr); gap: .5rem; }
  .an-btn { grid-template-columns: 2rem 1fr; }
  .an-thick { grid-column: 2; font-size: .9375rem; }
  .an-fn { padding-inline-start: 0; }
  .iform-foot { flex-direction: column; align-items: stretch; }
}

/* --- 24. Print ----------------------------------------------------------- */

@media print {
  .topbar, .mnav, .hero-film, .stack-wrap, .an-vis, footer .foot-mini, .closing-form { display: none; }
  body { background: #fff; color: #000; }
  .pad { padding-block: 1rem; }
  a { text-decoration: underline; }
}


/* --- 25. CJK typographic corrections ------------------------------------- */

/*
 * The mono/label style is 13px with .13em tracking and uppercase. That is right
 * for Latin small-caps labels and wrong for Han characters in three ways:
 * uppercase does nothing, 13px is below comfortable reading size for CJK, and
 * heavy tracking pulls apart glyphs that are already on a fixed em grid — it
 * reads as a spacing bug rather than as refinement. Space Mono has no CJK
 * coverage either, so these strings were being rendered by a fallback anyway.
 */
.lang-zh, .lang-ja, .lang-ko { --t-mono: .875rem; }

.lang-zh .mono, .lang-zh .eyebrow, .lang-zh .badge, .lang-zh .chip, .lang-zh .tag,
.lang-zh .spec-row dt, .lang-zh .stat-row span, .lang-zh .pcard-meta, .lang-zh .art-meta,
.lang-zh .hero-note, .lang-zh .an-thick, .lang-zh .fld-lab, .lang-zh .foot-col h3,
.lang-zh .crumbs, .lang-zh .filters a, .lang-zh .ind-links a, .lang-zh .brand-txt i,
.lang-ja .mono, .lang-ja .eyebrow, .lang-ja .badge, .lang-ja .chip, .lang-ja .tag,
.lang-ja .spec-row dt, .lang-ja .stat-row span, .lang-ja .pcard-meta, .lang-ja .art-meta,
.lang-ja .hero-note, .lang-ja .an-thick, .lang-ja .fld-lab, .lang-ja .foot-col h3,
.lang-ja .crumbs, .lang-ja .filters a, .lang-ja .ind-links a, .lang-ja .brand-txt i,
.lang-ko .mono, .lang-ko .eyebrow, .lang-ko .badge, .lang-ko .chip, .lang-ko .tag,
.lang-ko .spec-row dt, .lang-ko .stat-row span, .lang-ko .pcard-meta, .lang-ko .art-meta,
.lang-ko .hero-note, .lang-ko .an-thick, .lang-ko .fld-lab, .lang-ko .foot-col h3,
.lang-ko .crumbs, .lang-ko .filters a, .lang-ko .ind-links a, .lang-ko .brand-txt i {
  font-family: var(--f-body);
  letter-spacing: .02em;
  text-transform: none;
}

/* Arabic: same reasoning, plus tracking would sever the cursive joins. */
.lang-ar .mono, .lang-ar .eyebrow, .lang-ar .badge, .lang-ar .chip, .lang-ar .tag,
.lang-ar .spec-row dt, .lang-ar .stat-row span, .lang-ar .pcard-meta, .lang-ar .art-meta,
.lang-ar .hero-note, .lang-ar .an-thick, .lang-ar .fld-lab, .lang-ar .foot-col h3,
.lang-ar .crumbs, .lang-ar .filters a, .lang-ar .ind-links a, .lang-ar .brand-txt i {
  font-family: var(--f-ar);
  letter-spacing: normal;
  text-transform: none;
}
.lang-ar { --t-mono: 1rem; --t-sm: 1.0625rem; }

/* Latin numerals and units inside a CJK label keep the technical mono voice —
   "23-65 µm" should still look like an instrument reading. */
.lang-zh .an-thick, .lang-ja .an-thick, .lang-ko .an-thick,
.lang-zh .stat-n, .lang-ja .stat-n, .lang-ko .stat-n { font-feature-settings: "tnum"; }

/* CJK needs more optical size than Latin at the same nominal px: a Han glyph
   packs far more stroke into the em box, so 13px Latin small-caps and 13px
   Chinese are not the same reading task. Every label size gets a step up. */
.lang-zh, .lang-ja, .lang-ko { --t-mono: 1rem; --t-sm: 1.0625rem; }          /* 15px */
.lang-zh .brand-txt i, .lang-ja .brand-txt i, .lang-ko .brand-txt i { font-size: 1rem; }
.lang-ar .brand-txt i { font-size: 1rem; }

/* Labels inside the 3D artwork. They are decorative (the figure is aria-hidden)
   but a visitor still reads them, and sub-11px Han characters are a smudge. */
.lang-zh .ply-tag, .lang-ja .ply-tag, .lang-ko .ply-tag,
.lang-zh .an-ply span, .lang-ja .an-ply span, .lang-ko .an-ply span {
  font-family: var(--f-body); font-size: 1rem; letter-spacing: .02em; text-transform: none;
}
.lang-ar .ply-tag, .lang-ar .an-ply span {
  font-family: var(--f-ar); font-size: 1rem; letter-spacing: normal; text-transform: none;
}

/* --- 26. Product detail: photo + construction drawing --------------------- */

/* The lead photograph sits above the exploded stack, so a visitor sees the real
   product and its layer count in one glance without scrolling between them. */
.pd-vis-stack { display: grid; gap: 1.5rem; }
.pd-shot-lead { border-radius: var(--r-lg); }
.pd-shot-lead img { inline-size: 100%; block-size: auto; }
.pd-vis-stack .pd-stack { margin: 0; }
.pd-vis-stack .stack-inline .stack-scene { aspect-ratio: 4 / 2.5; }
.pd-vis-stack .stack-plies { inset: 16% 18%; }

@media (max-width: 1080px) {
  .pd-vis-stack { grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); align-items: center; }
}

/* Brand tagline: 13px Han characters in the masthead are a smudge at desktop
   viewing distance, and this line names what the company actually does. */
.lang-zh .brand-txt i, .lang-ja .brand-txt i, .lang-ko .brand-txt i { font-size: 1rem; }

/* ==========================================================================
   27. Corrections
   ========================================================================== */

/* --- Product photography must survive a dark interface ------------------- */
/*
 * The generated shots are charcoal-on-charcoal by art direction, and the card
 * they sit on is rgb(23,27,36). Measured on the real page, 38.8% of an image's
 * pixels fell below luminance 51 — i.e. the same value as the card — so the
 * photo dissolved into the panel and looked like an empty box. Two changes:
 * the image area gets its own lighter ground, and the heavy dark scrim that
 * used to sit on top is reduced to a whisper.
 */
.pcard-vis { background: #05070A; }
.pcard-vis img {
  filter: brightness(1.16) contrast(1.07) saturate(1.04);
  transition: transform 1s var(--ease), filter .6s var(--ease);
}
.pcard:hover .pcard-vis img { filter: brightness(1.24) contrast(1.09) saturate(1.08); }
.pcard-vis::after {
  background:
    linear-gradient(0deg, color-mix(in srgb, var(--ink) 34%, transparent), transparent 42%),
    radial-gradient(70% 55% at 82% 104%, var(--glow), transparent 72%);
  opacity: .5;
}
.pcard:hover .pcard-vis::after { opacity: .32; }
/* <picture> is inline by default, so a block-size on it does nothing. */
.pcard-vis picture, .pd-shot picture, .acard picture { display: block; }
.pd-shot img { filter: brightness(1.12) contrast(1.05); }

/* --- Footer: the first column is a COLUMN, not a row --------------------- */
/*
 * .foot-brand wraps the logo, the description and the legal name. It was styled
 * `display:flex; align-items:center`, which laid all three side by side — the
 * description overlapped the mark and the company name was squeezed into a
 * one-character-wide column. Only the logo lockup itself should be a flex row.
 */
.foot-brand { display: block; margin-block-end: 0; }
.foot-brand .brand { display: inline-flex; align-items: center; gap: .7rem; margin-block-end: 1.2rem; }
.foot-legal-name { margin-block-start: 1rem; font-size: .9375rem; color: var(--fg-3); line-height: 1.6; }

/* --- Key/value lists: the markup emits span + a, not dt + dd ------------- */
/*
 * The old rules targeted dt/dd and matched nothing, so "邮箱" and the address
 * ran together as one string with no separator anywhere on the page.
 */
.foot-kv li, .ctc-list li {
  display: grid; gap: .2rem;
  padding-block: .55rem;
  border-block-end: 1px solid var(--line);
}
.foot-kv li:last-child, .ctc-list li:last-child { border-block-end: 0; }
.foot-kv li > span, .ctc-list li > span {
  font-family: var(--f-mono); font-size: var(--t-mono);
  letter-spacing: .1em; text-transform: uppercase; color: var(--fg-3);
}
.lang-zh .foot-kv li > span, .lang-ja .foot-kv li > span, .lang-ko .foot-kv li > span,
.lang-zh .ctc-list li > span, .lang-ja .ctc-list li > span, .lang-ko .ctc-list li > span {
  font-family: var(--f-body); letter-spacing: .02em; text-transform: none;
}
.lang-ar .foot-kv li > span, .lang-ar .ctc-list li > span {
  font-family: var(--f-ar); letter-spacing: normal; text-transform: none;
}
.foot-kv li > a, .foot-kv li > em, .ctc-list li > a, .ctc-list li > em {
  font-style: normal; font-size: 1.0625rem; color: var(--fg); line-height: 1.55;
}
.ctc-list li > a:hover, .foot-kv li > a:hover { color: var(--spot); }
.ctc-list { gap: 0; }

/* --- Grids that never leave orphan cells --------------------------------- */
/*
 * `repeat(auto-fit, minmax(N, 1fr))` fits as many equal columns as it can and
 * then leaves the remainder empty: 5 capabilities in a 4-up grid produced one
 * lonely card beside three dead cells, and 6 process steps in a 5-up grid
 * produced the same thing. Flex with `flex-grow` has no such failure mode —
 * whatever lands on the final row stretches to fill it, for ANY item count.
 */
.cap-grid, .step-row, .ind-grid, .pgrid, .pgrid-3, .agrid {
  display: flex; flex-wrap: wrap;
}
.cap-grid > *, .step-row > * { flex: 1 1 17rem; min-inline-size: 0; }
.ind-grid { gap: clamp(1rem, .6rem + 1.4vw, 1.6rem); }
.ind-grid > * { flex: 1 1 19rem; min-inline-size: 0; }
.pgrid   { gap: clamp(1rem, .5rem + 1.6vw, 1.6rem); }
.pgrid > * { flex: 1 1 21rem; min-inline-size: 0; max-inline-size: 100%; }
.pgrid-3 { gap: clamp(1rem, .5rem + 1.6vw, 1.6rem); }
.pgrid-3 > * { flex: 1 1 19rem; min-inline-size: 0; max-inline-size: 100%; }
.agrid   { gap: clamp(1rem, .6rem + 1.4vw, 1.6rem); }
.agrid > * { flex: 1 1 20rem; min-inline-size: 0; }

/* The hairline-separated blocks keep their 1px "gap" borders under flex. */
.cap-grid, .step-row { gap: 1px; }

/* A single card stretched across a whole row looks like a mistake, so cap how
   far the last one may grow when it is alone. */
.cap-grid > *:only-child, .step-row > *:only-child { flex-grow: 0; flex-basis: 24rem; }

/* A card that ends up alone on the last row grows wide. Its bullet list then
   flows into as many columns as it can hold, so the wide form looks deliberate
   instead of like one stretched card with a ragged stack of text in it. */
.cap-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: .45rem 1.6rem;
}
.cap > h3, .cap > p { max-inline-size: 62ch; }
.step p, .step h3 { max-inline-size: 46ch; }

/* --- Layer anatomy: the section this whole site is about ------------------ */

/* Labels inside the drawing were 12px Han characters — a smudge. */
.lang-zh .an-ply span, .lang-ja .an-ply span, .lang-ko .an-ply span,
.lang-zh .ply-tag, .lang-ja .ply-tag, .lang-ko .ply-tag { font-size: 1rem; }

/* The description is the payload of each row, not a caption: give it reading
   size and the primary-ish text colour rather than muted grey. */
.an-fn {
  font-size: 1.0625rem;
  color: var(--fg-2);
  line-height: 1.7;
  padding-block-end: 1.7rem;
}
.an-btn { padding-block: 1.5rem; }
.an-thick { white-space: nowrap; }

/* The stack was rendering as faint translucent rectangles. Each ply now has a
   real fill, a lit top edge and its own shadow, so the drawing reads as six
   physical films rather than a stack of glass panes. */
.an-vis { aspect-ratio: 1 / 1; }
.an-stack { inset: 10% 4%; }
.an-ply {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--c) 42%, var(--ink-4)) 0%,
    color-mix(in srgb, var(--c) 16%, var(--ink-3)) 62%,
    var(--ink-2) 100%);
  border: 1px solid color-mix(in srgb, var(--c) 55%, transparent);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--c) 75%, transparent),
    inset 0 -1px 0 rgb(0 0 0 / .5),
    0 26px 50px -28px #000;
  transform: translateZ(calc(var(--i) * 38px));
}
.an-ply span {
  color: color-mix(in srgb, var(--c) 30%, #fff);
  opacity: .55;
  text-shadow: 0 1px 3px rgb(0 0 0 / .8);
}
.an-ply.is-on {
  transform: translateZ(calc(var(--i) * 38px + 70px)) scale(1.04);
  border-color: color-mix(in srgb, var(--c) 85%, transparent);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--c) 95%, transparent),
    0 40px 70px -26px #000,
    0 0 60px -18px color-mix(in srgb, var(--c) 60%, transparent);
}
.an-ply.is-on span { opacity: 1; }
.an-ply.is-dim { opacity: .42; }

@media (max-width: 1080px) {
  .an-vis { max-inline-size: 30rem; }
}

/* The plies are rotated AND pushed along Z, so perspective projects them well
   outside their own box — an inset that looks generous in 2D is not. These
   values were measured against the live layout, not guessed. */
.an-stack { inset: 17% 15%; }
.an-ply { transform: translateZ(calc(var(--i) * 30px)); }
.an-ply.is-on { transform: translateZ(calc(var(--i) * 30px + 58px)) scale(1.03); }
/* Belt and braces: whatever the projection does, it cannot push the page wide. */
.an-vis { overflow: clip; overflow-clip-margin: 24px; }

/* ==========================================================================
   28. Rules that went missing in the redesign
   ==========================================================================
   Rewriting the stylesheet wholesale dropped these selectors, which left the
   industries page as unstyled running text and several wrappers with no layout
   at all. Inventorying class names was not enough — every class in the markup
   needs a rule, and that is now checked by scripts/audit-seo.js.
   ========================================================================== */

/* --- Industries index ---------------------------------------------------- */

.indx-list { display: grid; gap: clamp(1.25rem, .8rem + 1.6vw, 2rem); }

.indx {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  transition: border-color .45s var(--ease), transform .5s var(--ease);
}
.indx:hover { border-color: var(--line-2); transform: translateY(-3px); }
.indx::before {
  content: ""; position: absolute; inset-block-start: 0; inset-inline: 0; block-size: 3px;
  background: linear-gradient(90deg, var(--accent), transparent 72%);
  transform: scaleX(0); transform-origin: left;
  transition: transform .7s var(--ease);
}
.lang-ar .indx::before { transform-origin: right; }
.indx:hover::before { transform: scaleX(1); }

.indx-body { padding: clamp(1.6rem, 1.1rem + 1.8vw, 2.8rem); min-inline-size: 0; }
.indx-n {
  position: absolute; inset-block-start: clamp(1.2rem, 1rem + 1vw, 2rem);
  inset-inline-end: clamp(1.2rem, 1rem + 1vw, 2rem);
  font-family: var(--f-mono); font-size: var(--t-mono);
  letter-spacing: .16em; color: var(--accent); opacity: .85; z-index: 2;
}
.indx-body h2 {
  font-size: clamp(1.7rem, 1.3rem + 1.6vw, 2.4rem);
  font-weight: 800; margin-block-end: 1.6rem;
}
.lang-zh .indx-body h2, .lang-ja .indx-body h2, .lang-ko .indx-body h2 { letter-spacing: 0; }

.indx-cols { display: grid; gap: 1.5rem; margin-block-end: 1.6rem; }
.indx-cols h3 {
  font-family: var(--f-mono); font-size: var(--t-mono); font-weight: 400;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent);
  margin-block-end: .55rem;
}
.lang-zh .indx-cols h3, .lang-ja .indx-cols h3, .lang-ko .indx-cols h3 {
  font-family: var(--f-body); font-weight: 600; letter-spacing: .02em; text-transform: none;
}
.lang-ar .indx-cols h3 { font-family: var(--f-ar); letter-spacing: normal; text-transform: none; }
.indx-cols p { color: var(--fg-2); font-size: 1.0625rem; line-height: 1.75; }

/* The industry photograph. Falls back to a tinted panel when none is set, so
   the layout never depends on an image existing. */
.indx-vis {
  position: relative; min-block-size: 100%; overflow: hidden;
  background:
    radial-gradient(70% 60% at 70% 30%, color-mix(in srgb, var(--accent) 22%, transparent), transparent 70%),
    var(--ink-2);
}
.indx-vis img { inline-size: 100%; block-size: 100%; object-fit: cover; filter: brightness(1.14) contrast(1.06); }
.indx-vis::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--card) 2%, transparent 42%),
              linear-gradient(0deg, color-mix(in srgb, var(--ink) 40%, transparent), transparent 55%);
}
.lang-ar .indx-vis::after { background: linear-gradient(270deg, var(--card) 2%, transparent 42%),
              linear-gradient(0deg, color-mix(in srgb, var(--ink) 40%, transparent), transparent 55%); }

@media (max-width: 900px) {
  .indx { grid-template-columns: minmax(0, 1fr); }
  .indx-vis { min-block-size: 14rem; order: -1; }
  .indx-vis::after { background: linear-gradient(0deg, var(--card) 2%, transparent 62%); }
}

/* --- Wrappers that had no rule ------------------------------------------- */

.pd-main { display: block; }
.pd-copy { min-inline-size: 0; }
.pd-vis  { min-inline-size: 0; }
.closing-copy { min-inline-size: 0; }
.pick-body { min-inline-size: 0; }
.iform { display: block; }
.news-teaser, .constructions, .stats, .capability, .process, .industries, .anatomy { position: relative; }

/* Feature checklist on product pages */
.tick { list-style: none; padding: 0; display: grid; gap: .7rem; }
.tick li {
  position: relative; padding-inline-start: 1.9rem;
  font-size: 1.0625rem; color: var(--fg-2); line-height: 1.7;
}
.tick li::before {
  content: ""; position: absolute; inset-inline-start: 0; inset-block-start: .58em;
  inline-size: .75rem; block-size: .42rem;
  border-inline-start: 2px solid var(--spot); border-block-end: 2px solid var(--spot);
  transform: rotate(-45deg);
}
.lang-ar .tick li::before { transform: rotate(-45deg) scaleX(-1); }

.art-tags { display: flex; flex-wrap: wrap; gap: .4rem; margin-block-start: 1rem; }

/* The print-shop ornaments were removed from the design; the helpers still emit
   their markup, so make sure the leftovers occupy nothing rather than showing
   as stray dots and bars. */
.colorbar, .reg { display: none; }

/* --- Remaining unstyled hooks -------------------------------------------- */

.foot { position: relative; }

/* Article wrapper on an insight page. */
.art { min-inline-size: 0; }

/* Fallback artwork when a construction has no photograph yet: a flat SVG of
   the ply stack, drawn in the construction's own accent. */
.glyph {
  inline-size: 100%; block-size: 100%;
  display: block; object-fit: cover;
  background: linear-gradient(150deg, color-mix(in srgb, var(--accent) 16%, var(--ink-2)), var(--ink-2));
}

/* Unread-indicator dot. */
.pulse {
  display: inline-block; inline-size: .5rem; block-size: .5rem;
  border-radius: 50%; background: var(--spot);
  box-shadow: 0 0 0 0 var(--glow);
  animation: pulse 2.4s var(--ease-io) infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--spot) 60%, transparent); }
  70%  { box-shadow: 0 0 0 .7rem transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* Application-list pills on a construction page. */
.tags { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .5rem; }
.tags li {
  padding: .45rem .95rem; border-radius: 999px;
  border: 1px solid var(--line); color: var(--fg-2); font-size: 1rem;
  transition: border-color .3s var(--ease), color .3s var(--ease);
}
.tags li:hover { border-color: var(--line-2); color: var(--fg); }

/* --- Enforcing the floor on the last stragglers --------------------------- */
/* These four sat between 14 and 15.2px in CJK. The floor is 16px; a rule that
   is "nearly" met is just the old problem with a smaller number on it. */
.lang-zh .brand-txt i, .lang-ja .brand-txt i, .lang-ko .brand-txt i { font-size: 1rem; }
.lang-ar .brand-txt i { font-size: 1rem; }
.lang-zh .btn, .lang-ja .btn, .lang-ko .btn, .lang-ar .btn { font-size: 1.0625rem; }
.lang-zh .btn-sm, .lang-ja .btn-sm, .lang-ko .btn-sm, .lang-ar .btn-sm { font-size: 1rem; }
.lang-zh .foot-legal-name, .lang-ja .foot-legal-name, .lang-ko .foot-legal-name,
.lang-ar .foot-legal-name { font-size: 1rem; }
.lang-opt b { font-size: 1.0625rem; }
.lang-opt span { font-size: 1rem; }
.lang-zh .lang-opt b, .lang-ja .lang-opt b, .lang-ko .lang-opt b { font-size: 1.0625rem; }

/* The brand lockup now carries a 16px tagline, so give it room to breathe. */
.brand-txt { gap: .1rem; }
.topbar-in { block-size: 5rem; }
.mnav { inset-block-start: 5rem; }
@media (max-width: 900px) { .topbar-in { block-size: 4.5rem; } .mnav { inset-block-start: 4.5rem; } }

/* --- Ambient layer loop behind the anatomy diagram ----------------------- */
/*
 * A generated clip of film layers separating, sitting UNDER the interactive
 * stack rather than replacing it. The diagram stays the thing you can click;
 * the footage only supplies motion and depth behind it. It is heavily dimmed
 * and blurred so it never competes with the labelled plies in front.
 */
.an-loop {
  position: absolute; inset: -6%;
  inline-size: 112%; block-size: 112%;
  object-fit: cover;
  opacity: 0;
  filter: blur(2px) saturate(.75) brightness(.62);
  transition: opacity 1.6s var(--ease);
  pointer-events: none;
}
.an-loop.is-on { opacity: .5; }
.an-vis::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(64% 58% at 50% 46%, transparent 40%, var(--bg) 88%);
}
.an-stack { z-index: 2; }
@media (prefers-reduced-motion: reduce) { .an-loop { display: none; } }

/* Layer names inside the drawing: the last thing still under the floor. */
.lang-zh .an-ply span, .lang-ja .an-ply span, .lang-ko .an-ply span,
.lang-zh .ply-tag, .lang-ja .ply-tag, .lang-ko .ply-tag { font-size: 1rem; }
.lang-ar .an-ply span, .lang-ar .ply-tag { font-size: 1rem; }
.an-ply span, .ply-tag { font-size: .9375rem; }

/* --- Back control on detail pages ---------------------------------------- */

.crumbs-in { display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap; }
.crumb-back {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .5rem 1rem .5rem .8rem;
  border: 1px solid var(--line-2); border-radius: 999px;
  font-family: var(--f-body); font-size: 1rem; font-weight: 600;
  letter-spacing: normal; text-transform: none; color: var(--fg);
  white-space: nowrap;
  transition: background .3s var(--ease), border-color .3s var(--ease), transform .3s var(--ease);
}
.crumb-back:hover { background: var(--ink-4); border-color: transparent; transform: translateX(-3px); }
.crumb-back .ico { inline-size: 1.05em; block-size: 1.05em; }
/* In RTL the arrow and the motion both mirror. */
.lang-ar .crumb-back .ico { transform: scaleX(-1); }
.lang-ar .crumb-back:hover { transform: translateX(3px); }
.crumbs-in ol { margin: 0; }
@media (max-width: 640px) { .crumbs-in ol { display: none; } }

/* ==========================================================================
   29. Technology page — layer rows
   ==========================================================================
   Previously six identical stacked blocks of label + value + label + value.
   Correct information, no hierarchy: nothing told you where one layer ended
   and the next began, and the failure note — the most useful line on the page
   — was styled exactly like the thickness figure.
   ========================================================================== */

.tl { display: grid; gap: clamp(1.5rem, 1rem + 2vw, 2.75rem); }

.tl-row {
  display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  align-items: stretch;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: border-color .45s var(--ease), transform .5s var(--ease);
}
.tl-row:hover { border-color: var(--line-2); transform: translateY(-3px); }
/* Alternate which side the photograph sits on. `order` rather than a reversed
   column list, so the DOM order stays logical for screen readers. */
.tl-row.is-flip .tl-vis { order: 2; }

.tl-vis { position: relative; min-block-size: 19rem; overflow: hidden; background: var(--ink-2); }
.tl-vis picture { display: block; block-size: 100%; }
.tl-vis img {
  inline-size: 100%; block-size: 100%; object-fit: cover;
  filter: brightness(1.14) contrast(1.06);
  transition: transform 1.1s var(--ease);
}
.tl-row:hover .tl-vis img { transform: scale(1.04); }
.tl-vis::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 55%, var(--card) 99%),
              radial-gradient(75% 60% at 30% 40%, color-mix(in srgb, var(--c) 18%, transparent), transparent 72%);
}
.tl-row.is-flip .tl-vis::after { background: linear-gradient(270deg, transparent 55%, var(--card) 99%),
              radial-gradient(75% 60% at 70% 40%, color-mix(in srgb, var(--c) 18%, transparent), transparent 72%); }
/* No photograph yet: a tinted field in the layer's own colour, never a gap. */
.tl-vis-fb {
  position: absolute; inset: 0;
  background: linear-gradient(150deg, color-mix(in srgb, var(--c) 26%, var(--ink-3)), var(--ink-2));
}
.tl-badge {
  position: absolute; inset-block-start: 1.1rem; inset-inline-start: 1.2rem; z-index: 2;
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .4rem .8rem; border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 74%, transparent);
  backdrop-filter: blur(8px);
  font-family: var(--f-mono); font-size: var(--t-mono); letter-spacing: .12em; color: var(--fg);
}
.tl-swatch { inline-size: .6rem; block-size: .6rem; border-radius: 2px; background: var(--c); display: inline-block; }

.tl-body { padding: clamp(1.6rem, 1.1rem + 2vw, 2.9rem); min-inline-size: 0; }
.tl-body h3 {
  font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.1rem);
  font-weight: 800; margin-block-end: .9rem;
}
.lang-zh .tl-body h3, .lang-ja .tl-body h3, .lang-ko .tl-body h3 { letter-spacing: 0; }
.tl-fn { font-size: 1.125rem; color: var(--fg-2); line-height: 1.75; max-inline-size: 46ch; }

.tl-dl { margin-block-start: 1.8rem; border-block-start: 1px solid var(--line); }
.tl-dl > div {
  display: grid; grid-template-columns: minmax(0, .5fr) minmax(0, 1.5fr);
  gap: 1rem; padding-block: .95rem;
  border-block-end: 1px solid var(--line);
}
.tl-dl dt {
  font-family: var(--f-mono); font-size: var(--t-mono);
  letter-spacing: .1em; text-transform: uppercase; color: var(--fg-3);
}
.lang-zh .tl-dl dt, .lang-ja .tl-dl dt, .lang-ko .tl-dl dt {
  font-family: var(--f-body); letter-spacing: .02em; text-transform: none;
}
.lang-ar .tl-dl dt { font-family: var(--f-ar); letter-spacing: normal; text-transform: none; }
.tl-dl dd { margin: 0; font-size: 1.0625rem; color: var(--fg); line-height: 1.6; }

/* The failure note is the most useful line in each block, so it stops looking
   like another spec row and becomes a flagged callout. */
.tl-warn {
  margin-block-start: 1.6rem;
  padding: 1.1rem 1.3rem;
  border-radius: var(--r);
  background: color-mix(in srgb, var(--spot) 9%, transparent);
  border-inline-start: 3px solid var(--spot);
}
.lang-ar .tl-warn { border-inline-start: 0; border-inline-end: 3px solid var(--spot); }
.tl-warn-k {
  display: block; margin-block-end: .4rem;
  font-family: var(--f-mono); font-size: var(--t-mono);
  letter-spacing: .12em; text-transform: uppercase; color: var(--spot-lift);
}
.lang-zh .tl-warn-k, .lang-ja .tl-warn-k, .lang-ko .tl-warn-k {
  font-family: var(--f-body); font-weight: 600; letter-spacing: .02em; text-transform: none;
}
.lang-ar .tl-warn-k { font-family: var(--f-ar); letter-spacing: normal; text-transform: none; }
.tl-warn p { font-size: 1.0625rem; color: var(--fg); line-height: 1.7; }

@media (max-width: 900px) {
  .tl-row, .tl-row.is-flip { grid-template-columns: minmax(0, 1fr); }
  .tl-row .tl-vis, .tl-row.is-flip .tl-vis { order: -1; min-block-size: 13rem; }
  .tl-vis::after, .tl-row.is-flip .tl-vis::after {
    background: linear-gradient(0deg, var(--card) 2%, transparent 60%);
  }
  .tl-dl > div { grid-template-columns: minmax(0, 1fr); gap: .25rem; }
}

/* ==========================================================================
   30. Capability / process blocks as routes to the quote form
   ==========================================================================
   Someone reading "8-colour UV flexo, 330/450mm" is precisely the person who
   wants to ask what it costs. Each block is now a real anchor to #quote on the
   same page, so it works with JS disabled and a crawler can follow it.
   ========================================================================== */

.cap.is-link, .step-in {
  position: relative; display: flex; flex-direction: column;
  color: inherit; block-size: 100%;
  transition: background .4s var(--ease);
}
.step-in { padding: clamp(1.4rem, 1rem + 1.2vw, 2rem); }
.step { padding: 0; background: var(--bg); }
.step:hover, .cap.is-link:hover { background: var(--ink-3); }

/* The prompt only appears on hover/focus: visible at rest on eleven blocks at
   once it would be noise, and the cards still have to read as content first. */
.cap-go, .step-go {
  display: inline-flex; align-items: center; gap: .45rem;
  margin-block-start: auto; padding-block-start: 1.1rem;
  font-family: var(--f-mono); font-size: var(--t-mono);
  letter-spacing: .1em; text-transform: uppercase; color: var(--spot);
  opacity: 0; transform: translateY(6px);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.lang-zh .cap-go, .lang-ja .cap-go, .lang-ko .cap-go,
.lang-zh .step-go, .lang-ja .step-go, .lang-ko .step-go {
  font-family: var(--f-body); font-weight: 600; letter-spacing: .02em; text-transform: none;
}
.lang-ar .cap-go, .lang-ar .step-go { font-family: var(--f-ar); letter-spacing: normal; text-transform: none; }
.cap.is-link:hover .cap-go, .cap.is-link:focus-visible .cap-go,
.step-in:hover .step-go, .step-in:focus-visible .step-go { opacity: 1; transform: none; }
.cap-go .ico, .step-go .ico { transition: transform .4s var(--ease); }
.cap.is-link:hover .cap-go .ico, .step-in:hover .step-go .ico { transform: translateX(4px); }
.lang-ar .cap-go .ico, .lang-ar .step-go .ico { transform: scaleX(-1); }
.lang-ar .cap.is-link:hover .cap-go .ico, .lang-ar .step-in:hover .step-go .ico { transform: translateX(-4px) scaleX(-1); }

/* A left edge that fills in on hover, so the whole tile reads as pressable. */
.cap.is-link::before, .step-in::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: 2px;
  background: var(--spot); transform: scaleY(0); transform-origin: bottom;
  transition: transform .45s var(--ease);
}
.cap.is-link:hover::before, .step-in:hover::before,
.cap.is-link:focus-visible::before, .step-in:focus-visible::before { transform: scaleY(1); }

/* Landing on #quote from one of these should not tuck the form under the
   sticky header. */
#quote { scroll-margin-block-start: 6rem; }

@media (hover: none) {
  .cap-go, .step-go { opacity: 1; transform: none; }
}

/* --- Photograph inside a capability / process tile ------------------------ */
/*
 * The picture sits BEHIND the text as a dimmed ground, not beside it: these
 * tiles are dense with specification bullets, and a side-by-side image would
 * halve the reading width. At rest it is a faint texture; on hover it lifts
 * and saturates, which is also the hover affordance for the whole tile.
 */
.cap.has-shot, .step-in { position: relative; isolation: isolate; overflow: hidden; }
.cap-vis, .step-vis {
  position: absolute; inset: 0; z-index: -1; display: block;
  transition: opacity .55s var(--ease), transform 1.1s var(--ease);
  opacity: .16;
}
.cap-vis picture, .step-vis picture { display: block; block-size: 100%; }
.cap-vis img, .step-vis img {
  inline-size: 100%; block-size: 100%; object-fit: cover;
  filter: brightness(1.1) contrast(1.05) saturate(.85);
}
.cap-vis::after, .step-vis::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg) 55%, transparent), var(--bg) 92%);
}
.cap.has-shot:hover .cap-vis, .step-in:hover .step-vis { opacity: .34; transform: scale(1.04); }
.cap.has-shot:focus-visible .cap-vis, .step-in:focus-visible .step-vis { opacity: .34; }

/* With a photograph behind them the tiles need their own solid ground so the
   grid's hairline gaps stay visible. */
.cap.has-shot { background: var(--bg); }
