/* SIHAN · page kit (owner: kit). Shared look for every page outside the home journey: tokens, type scale, sub-page
   header and footer, text links, honesty marks, the iris transition (T1), view-transition morph (T2), the runway (T3),
   the cursor label, kinetic type and the glass fallbacks. Read /kit/KIT-API.md before using it.
   Bright silver base, ink type, blue / ice accents. No external fonts: Inter + Source Serif 4 are self-hosted. */

@font-face { font-family: Inter; src: url(/assets/fonts/InterVariable.woff2) format('woff2'); font-weight: 100 900; font-display: swap; }
@font-face { font-family: 'SIHAN Serif'; src: url(/assets/fonts/SIHANSerif-Italic.woff2) format('woff2'); font-style: italic; font-weight: 200 900; font-display: swap; }
@font-face { font-family: 'Source Serif 4'; src: url(/assets/fonts/SourceSerif4-Italic.ttf) format('truetype'); font-style: italic; font-weight: 200 900; font-display: swap; }

/* Cross-document view transitions (T2 "morph"). page.js skips them for iris routes, so only the morph links use them. */
@view-transition { navigation: auto; }

:root {
  /* Colour (same values as /journey/journey.css) */
  --silver-0: #f6f8fb; --silver-1: #eef2f6; --silver-2: #dfe6ee; --silver-3: #c6d2df; --steel: #5b7089;
  --ink: #0e1a2c; --ink-2: #1c2b42; --ink-60: rgb(14 26 44 / .6); --ink-40: rgb(14 26 44 / .4); --ink-12: rgb(14 26 44 / .12);
  --blue: #2f6fd6; --blue-deep: #173a7a; --ice: #8fd3ec; --ice-hi: #d8f3fc; --frost: #f3f8fd;
  --sans: Inter, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --serif: 'SIHAN Serif', 'Source Serif 4', 'Iowan Old Style', Georgia, serif;
  --mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  /* Space */
  --gutter: clamp(16px, 2.6vw, 48px);
  --header-h: 72px;
  --maxw: 1680px;
  /* Motion */
  --ease: cubic-bezier(.2, .7, .1, 1);          /* settle */
  --ease-io: cubic-bezier(.7, 0, .2, 1);        /* iris, morph */
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  /* Type scale */
  /* Art bible (round 5): confident display = Inter 500–600, −0.045em; HUD = --mono, uppercase 10–11 px, .12em, ink 70 % */
  --t-giant: clamp(56px, 9vw, 180px);           /* page titles ("Filters") — the bible's display size */
  --t-h1: clamp(44px, 6.4vw, 116px);            /* product name */
  --t-h2: clamp(32px, 4.6vw, 80px);             /* section lines */
  --t-h3: clamp(22px, 2vw, 32px);               /* card names */
  --hud: clamp(10px, .7vw, 11px);               /* HUD / micro labels (mono) */
  --ink-70: rgb(14 26 44 / .7);
  --t-lead: clamp(18px, 1.35vw, 24px);
  --t-body: clamp(15px, 1.05vw, 18px);
  --micro: clamp(11px, .66vw, 13px);            /* micro caps: header, labels, marks */
  color-scheme: light;
}
@media (max-width: 699px) { :root { --header-h: 60px; } }

*, *::before, *::after { box-sizing: border-box; }
html { color: var(--ink); -webkit-text-size-adjust: 100%; scrollbar-width: thin; scrollbar-color: rgb(14 26 44 / .25) transparent; }
/* The body's background is propagated to the page canvas (html has none), so z-index: -1 layers still show. */
body { margin: 0; min-height: 100vh; background-color: var(--silver-1); font: 400 var(--t-body)/1.55 var(--sans); font-feature-settings: 'ss01', 'cv11';
  background: radial-gradient(120% 70% at 50% 0%, #fbfcfe 0%, rgb(251 252 254 / 0) 60%), linear-gradient(180deg, var(--silver-0) 0%, var(--silver-1) 45%, var(--silver-2) 100%) fixed;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; overflow-x: clip; }
img { max-width: 100%; height: auto; }
a { color: inherit; }
/* No grey tap flash on phones (links, cards, the 3D models): the kit's own hover / press states are the feedback. */
a, button, [data-route], [data-gl], [data-cam], [data-study], .f-card, .f-card-link, .k-runway { -webkit-tap-highlight-color: transparent; }
p, h1, h2, h3, h4, ul, ol, dl, dd, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
::selection { background: var(--ice-hi); color: var(--ink); }
.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 4px; border-radius: 3px; }

/* ---------- Skip link ---------- */
.k-skip { position: fixed; left: var(--gutter); top: 14px; z-index: 80; padding: 12px 18px; border-radius: 999px; background: var(--silver-0); color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink-12); font: 500 14px/1 var(--sans); text-decoration: none; transform: translateY(calc(-100% - 40px)); transition: transform .3s var(--ease); }
.k-skip:focus-visible { transform: none; }

/* ---------- Stage (WebGL, behind the DOM) ---------- */
.k-stage { position: fixed; left: 0; top: 0; width: 100vw; height: 100vh; display: block; z-index: 0; pointer-events: none; transition: opacity .35s var(--ease); }
/* Morph (T2): the canvas never enters a view-transition snapshot — out: fades in 180 ms, then hidden; in: hidden until
   the transition has finished (page.js adds html.k-vt-done), then it fades in. */
html.k-vt-leave .k-stage { opacity: 0; transition-duration: .18s; }
html.vt-out .k-stage { visibility: hidden; }
html.vt-in:not(.k-vt-done) .k-stage { opacity: 0; transition: none; }
/* The shell is positioned without a z-index, so it paints above the canvas while a child with z-index: -1 (e.g. a
   giant marquee) can sit behind the WebGL glass. */
.k-shell { position: relative; }

/* ---------- Header (fixed; wordmark left, three text links right) ---------- */
.k-header { position: fixed; top: 0; left: 0; right: 0; z-index: 40; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  height: var(--header-h); padding: env(safe-area-inset-top) var(--gutter) 0; pointer-events: none; }
.k-header > * { pointer-events: auto; }
/* the frosted header band (site-wide, round 6): content and the WebGL stage pass under it blurred once the page has
   scrolled; a 1 px hairline closes it. /filters/ hides it while its own stuck bar (header + camera row) is on. */
.k-header::before { content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: rgb(242 245 249 / .74); -webkit-backdrop-filter: blur(18px) saturate(1.15); backdrop-filter: blur(18px) saturate(1.15);
  opacity: var(--hdr-bg, 0); transition: opacity .4s var(--ease);
  /* round 14: no hard bar line — the band feathers out below the header (edge-fade scroll mask) */
  bottom: -28px; -webkit-mask: linear-gradient(180deg, #000 0, #000 calc(100% - 44px), transparent); mask: linear-gradient(180deg, #000 0, #000 calc(100% - 44px), transparent); }
html.k-scrolled .k-header { --hdr-bg: 1; }
.k-wordmark { display: inline-flex; align-items: center; min-height: 44px; color: var(--ink); text-decoration: none;
  font: 520 clamp(14px, .95vw, 20px)/1 var(--sans); letter-spacing: .52em; margin-right: -.52em; }   /* = the home's .j-wordmark */
.k-nav { display: flex; align-items: center; gap: clamp(18px, 2.4vw, 40px); }
.k-nav a { position: relative; display: inline-flex; align-items: center; min-height: 44px; }
.k-nav a[aria-current="page"]::before { content: ''; position: absolute; left: -10px; top: 50%; width: 4px; height: 4px; margin-top: -2px; border-radius: 50%; background: var(--state-blue, var(--blue)); }
/* round 14: the nav is micro mono on a strict line — quiet caps, the current page in full ink with the one blue dot */
.k-nav .k-link { letter-spacing: .16em; color: var(--ink-70); transition: color .4s var(--ease); }
.k-nav .k-link[aria-current="page"], .k-nav .k-link:hover, .k-nav .k-link:focus-visible { color: var(--ink); }

/* ---------- Text links ---------- */
/* Micro caps link (header, store links, footer). The rolling duplicate row is added by type.js ([data-roll]). */
.k-link { color: var(--ink); text-decoration: none; font: 500 var(--hud)/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; white-space: nowrap; }
/* Underline sweep: grows from the left on hover, leaves to the right. */
.k-line { text-decoration: none; background: linear-gradient(currentColor, currentColor) 100% 100% / 0 1px no-repeat; padding-bottom: 3px; transition: background-size .5s var(--ease); }
.k-line:hover, .k-line:focus-visible { background-position: 0 100%; background-size: 100% 1px; }
/* Letter roll: <a data-roll> gets <span class="k-roll"><span class="k-roll-a">…letters…</span><span class="k-roll-b" aria-hidden="true">…</span></span>. */
.k-roll { position: relative; display: inline-block; overflow: hidden; vertical-align: top; line-height: 1.15; padding-bottom: .05em; }
.k-roll-a, .k-roll-b { display: block; white-space: nowrap; }
.k-roll-b { position: absolute; left: 0; top: 100%; }
.k-roll .k-c { display: inline-block; transition: transform .52s var(--ease); transition-delay: calc(var(--i, 0) * 14ms); }
a:hover > .k-roll .k-c, a:focus-visible > .k-roll .k-c, button:hover > .k-roll .k-c { transform: translateY(-100%); }
.k-ext { display: inline-block; margin-left: .3em; transition: transform .45s var(--ease); }
a:hover .k-ext, a:focus-visible .k-ext { transform: translate(2px, -2px); }
/* Big text link (store, email). */
.k-biglink { color: var(--ink); text-decoration: none; font: 300 var(--t-h2)/1 var(--sans); letter-spacing: -.03em; display: inline-flex; align-items: baseline; gap: .25em; }
.k-biglink .k-ext { font-size: .6em; }

/* ---------- Micro labels, marks ---------- */
.k-micro { font: 500 var(--hud)/1.45 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-70); }
.k-mono { font: 500 var(--hud)/1.45 var(--mono); letter-spacing: .12em; text-transform: uppercase; }
/* Honesty mark: bottom-left, shows the label of the CG on screen (page.js updates it from [data-mark-label]). */
/* A frosted mono pill; page.js hides it while the footer or a caption sits under it ([data-ducked]); on phones it docks
   below the header. */
.k-mark { position: fixed; left: var(--gutter); bottom: max(18px, env(safe-area-inset-bottom)); z-index: 30; margin: 0 0 0 -6px; pointer-events: none;
  font: 500 var(--hud)/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-70); display: flex; align-items: center; gap: 8px;
  padding: 7px 11px 7px 9px; border-radius: 999px; background: rgb(246 248 251 / .66); box-shadow: inset 0 0 0 1px rgb(255 255 255 / .7), 0 0 0 1px var(--ink-12);
  -webkit-backdrop-filter: blur(10px) saturate(1.2); backdrop-filter: blur(10px) saturate(1.2); transition: opacity .35s var(--ease), transform .35s var(--ease); }
.k-mark::before { content: ''; width: 9px; height: 9px; flex: none; opacity: .75;
  background: linear-gradient(currentColor, currentColor) 50% 0 / 1px 100% no-repeat, linear-gradient(currentColor, currentColor) 0 50% / 100% 1px no-repeat; }
.k-mark:empty, .k-mark[data-empty], .k-mark[data-ducked] { opacity: 0; transform: translateY(4px); }
@media (max-width: 699px) { .k-mark { bottom: auto; top: calc(var(--header-h) + env(safe-area-inset-top) + 2px); left: var(--gutter); } .k-mark[data-ducked] { transform: translateY(-4px); }
  /* /filters/: below the camera row once it sticks (row bottom = header-h - 8 + 70 px); the title and the row duck it
     ([data-mark-avoid]) while they scroll past. */
  body[data-page="filters"] .k-mark { top: calc(var(--header-h) + env(safe-area-inset-top) + 74px); } }
/* Scroll progress: a hairline at the right edge. */
.k-progress { position: fixed; right: 10px; top: 50%; z-index: 30; width: 1px; height: min(36vh, 280px); transform: translateY(-50%); background: var(--ink-12); pointer-events: none; }
.k-progress::after { content: ''; position: absolute; inset: 0; background: var(--ink); transform-origin: 50% 0; transform: scaleY(var(--pg, 0)); }
@media (max-width: 699px) { .k-progress { right: 6px; height: 22vh; } }

/* ---------- Layout ---------- */
.k-main { position: relative; display: block; }
.k-wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding-left: var(--gutter); padding-right: var(--gutter); }
.k-section { position: relative; }
.k-hero { position: relative; min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column; justify-content: flex-end; padding: calc(var(--header-h) + 24px) var(--gutter) clamp(28px, 6vh, 72px); }
/* round 14 (coordinator): display headlines are LIGHT site-wide — weight 300, tracking −0.03em, solid ink, no halos */
.k-giant { font: 300 var(--t-giant)/.88 var(--sans); letter-spacing: -.03em; margin-left: -.04em; color: var(--ink); }
.k-giant sup { font: 500 max(11px, .1em)/1 var(--mono); letter-spacing: .12em; vertical-align: top; position: relative; top: .5em; margin-left: .35em; color: var(--ink-70); }
.k-h1 { font: 300 var(--t-h1)/.95 var(--sans); letter-spacing: -.03em; }
.k-h2 { font: 300 var(--t-h2)/1 var(--sans); letter-spacing: -.03em; }
.k-h3 { font: 520 var(--t-h3)/1.1 var(--sans); letter-spacing: -.03em; }
.k-lead { font: 400 var(--t-lead)/1.45 var(--sans); letter-spacing: -.01em; color: var(--ink-2); max-width: 34em; }
.k-serif { font-family: var(--sans); font-style: normal; font-weight: 600; letter-spacing: -.045em; }   /* art bible: no serif italic outside the home hero */

/* Facts row: label (micro) over value. */
.k-facts { display: grid; grid-template-columns: repeat(var(--cols, 3), minmax(0, auto)); gap: 12px clamp(24px, 3vw, 56px); }
.k-facts dt { font: 500 var(--hud)/1.2 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-70); margin-bottom: 8px; }
.k-facts dd { font: 400 clamp(14px, 1vw, 17px)/1.35 var(--sans); color: var(--ink); }
@media (max-width: 699px) { .k-facts { grid-template-columns: 1fr 1fr; } }

/* ---------- Glass frame (CSS look of a slab; the WebGL stage draws over it when live) ---------- */
.k-glass { position: relative; display: block; border-radius: clamp(14px, 1.4vw, 22px); overflow: hidden; isolation: isolate;
  background: linear-gradient(155deg, rgb(255 255 255 / .75), rgb(223 230 238 / .45) 55%, rgb(198 210 223 / .55));
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .9), inset 0 -18px 40px -24px rgb(47 111 214 / .25), 0 30px 60px -30px rgb(14 26 44 / .35), 0 2px 6px -2px rgb(14 26 44 / .12); }
.k-glass::after { content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none; border-radius: inherit;
  background: linear-gradient(115deg, rgb(255 255 255 / 0) 30%, rgb(216 243 252 / .55) 46%, rgb(255 255 255 / 0) 60%) 0 0 / 260% 100% no-repeat;
  background-position: calc(110% - var(--gx, 0) * 120%) 0; opacity: .8; }
.k-glass img { position: relative; z-index: 1; display: block; width: 100%; height: 100%; object-fit: contain; padding: 10%;
  filter: drop-shadow(0 22px 26px rgb(14 26 44 / .25)); transition: opacity .5s var(--ease), transform .7s var(--ease); }
/* When the stage is live it draws the slab; the DOM image stays (for layout, view transitions and a11y) but hides. */
html.gl-live :is([data-gl="slab"], [data-gl="model"]).gl-on { background: none; box-shadow: none; }
html.gl-live :is([data-gl="slab"], [data-gl="model"]).gl-on::after { opacity: 0; }
html.gl-live :is([data-gl="slab"], [data-gl="model"]).gl-on img { opacity: 0; }
/* Morph (T2) hand-off, see page.js. Outgoing: only the clicked element's photo is shown (k-vt-leave fades it in over the
   live model while the canvas fades out; html.vt-out = the snapshot state). */
:is([data-gl="slab"], [data-gl="model"]).vt-src img { opacity: 1 !important; transition-duration: .18s; }
/* Incoming: until the transition has finished the hero shows its bare photo (no CSS glass card — the morph must not
   cross-fade into a white frame); the canvas then fades in over it and the photo fades out (.gl-on rules above). */
html.vt-in:not(.no-webgl) [data-model-hero] { background: none; box-shadow: none; }
html.vt-in:not(.no-webgl) [data-model-hero]::after { opacity: 0; }
html.vt-in:not(.k-vt-done) [data-model-hero] img { opacity: 1 !important; }
/* The photo flies at its normal size on both ends (old and new snapshots match, so the cross-fade inside the morph
   shows ONE product); once it has landed it grows to the hero model's size (outline .9 of the rect vs the photo's 80 %)
   while the canvas fades in over it. */
html.vt-in.k-vt-done:not(.no-webgl) [data-model-hero] img { transform: scale(1.125); transition-duration: .35s; }

/* ---------- Kinetic type ---------- */
/* [data-split]: type.js wraps letters in .k-c (--i index, --n count) inside words .k-w. --rv (0..1) is the element's
   reveal, a pure function of scroll (or of time for [data-split="in"], once). */
[data-split] { --rv: 1; }
html.js:not(.vt-in) [data-split]:not(.k-split-done) { visibility: hidden; }
.k-w { display: inline-block; white-space: nowrap; }
.k-mask { display: inline-block; overflow: hidden; padding: .12em .06em .16em; margin: -.12em -.06em -.16em; vertical-align: top; }
[data-split] .k-c { display: inline-block; will-change: transform;
  --ri: clamp(0, (var(--rv) * (1 + var(--n, 1) * .045) - var(--i, 0) * .045), 1);
  transform: translateY(calc((1 - var(--ri)) * 108%)) rotate(calc((1 - var(--ri)) * 8deg)); opacity: calc(.2 + var(--ri) * .8); }
/* Scramble: the text is decoded by type.js; the final text stays in the DOM for screen readers. */
[data-scramble] { font-variant-numeric: tabular-nums; }
/* Velocity skew: [data-skew] gets skewY(--skew) from scroll speed (decays in ≈ 300 ms). */
[data-skew] { transform: skewY(var(--skew, 0deg)); transform-origin: 50% 50%; }
/* Marquee: <div class="k-marquee" data-marquee><div class="k-marquee-track"><span>Name</span>…</div></div> */
.k-marquee { position: relative; overflow: hidden; white-space: nowrap; pointer-events: none; user-select: none; }
.k-marquee-track { display: inline-flex; will-change: transform; transform: translate3d(var(--mx, 0px), 0, 0); }
.k-marquee-track > * { padding-right: .35em; }
.k-outline { color: transparent; -webkit-text-stroke: 1px rgb(14 26 44 / .28); }
@supports not (-webkit-text-stroke: 1px black) { .k-outline { color: rgb(14 26 44 / .08); } }

/* ---------- Cursor label + magnet (fine pointers only; cursor.js) ---------- */
.k-cursor { position: fixed; left: 0; top: 0; z-index: 70; width: 84px; height: 84px; margin: -42px 0 0 -42px; border-radius: 50%; pointer-events: none;
  display: grid; place-items: center; transform: translate3d(var(--cx, -200px), var(--cy, -200px), 0) scale(var(--cs, 0));
  /* round 12: a thin ring with a mono label, like the home cursor — no frosted disc (owner: no bubbles) */
  background: none; color: var(--ink); border: 1px solid color-mix(in srgb, currentColor 62%, transparent);
  box-shadow: 0 0 12px -4px color-mix(in srgb, currentColor 45%, transparent); }
.k-cursor span { font: 500 10px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ink); white-space: nowrap; opacity: var(--cs, 0); }
/* round 14 (F8): cursor.js sizes the ring (--cw / --ch); over small links and tabs it is a pill hugging the hit-area */
.k-cursor { width: var(--cw, 84px); height: var(--ch, 84px); margin: calc(var(--ch, 84px) / -2) 0 0 calc(var(--cw, 84px) / -2); border-radius: 999px; }
.k-cursor.is-snap { box-shadow: none; border-color: color-mix(in srgb, currentColor 34%, transparent); }
.k-cursor.is-snap span { opacity: 0; }
html:not(.k-fine) .k-cursor { display: none; }
[data-magnet] { display: inline-block; transform: translate3d(var(--mgx, 0px), var(--mgy, 0px), 0); transition: transform .5s var(--ease); }
[data-magnet].k-magnet-on { transition: transform .12s linear; }
html.k-grab, html.k-grab * { cursor: grab; }
html.k-grabbing, html.k-grabbing * { cursor: grabbing !important; user-select: none; }

/* ---------- Iris (T1): nine silver blades; --ir 0 = closed … 1 = open ---------- */
/* Markup (in every page, first child of body):
   <div class="k-iris" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><b class="k-iris-n"></b></div> */
.k-iris { position: fixed; inset: 0; z-index: 90; pointer-events: none; overflow: hidden; visibility: hidden; --ir: 1; --tw: 0deg; }
.k-iris > i { position: absolute; left: 50%; top: 50%; width: 320vmax; height: 160vmax; margin-left: -160vmax; transform-origin: 50% 0;
  --bi: clamp(0, (var(--ir) * 1.12 - var(--k, 0) * .015), 1);
  transform: rotate(calc(var(--k, 0) * 40deg + var(--tw) + (1 - var(--bi)) * 24deg)) translateY(calc(var(--bi) * 92vmax - 1.5vmax));
  /* brushed satin aluminium: a bright chamfer glint on the leading edge, fine brushing parallel to it, a soft sheen */
  background:
    linear-gradient(180deg, rgb(255 255 255 / 1) 0, rgb(255 255 255 / .55) 2px, rgb(255 255 255 / 0) 7px),
    linear-gradient(calc(var(--k, 0) * 23deg + 100deg), rgb(255 255 255 / 0) 30%, rgb(255 255 255 / .38) 46%, rgb(255 255 255 / 0) 60%),
    repeating-linear-gradient(180deg, rgb(255 255 255 / .16) 0 1px, rgb(14 26 44 / .045) 1px 2px, rgb(255 255 255 / 0) 2px 4px),
    linear-gradient(calc(var(--k, 0) * 17deg + 180deg), #f6f8fb 0%, #dfe5ec 14%, #c4cfdb 42%, #d6dde5 60%, #aebccb 100%);
  border-top: 1px solid #fff;
  box-shadow: 0 -1px 0 rgb(14 26 44 / .18), 0 -14px 36px -6px rgb(14 26 44 / .24); will-change: transform; }
.k-iris > i:nth-child(1) { --k: 0; } .k-iris > i:nth-child(2) { --k: 1; } .k-iris > i:nth-child(3) { --k: 2; }
.k-iris > i:nth-child(4) { --k: 3; } .k-iris > i:nth-child(5) { --k: 4; } .k-iris > i:nth-child(6) { --k: 5; }
.k-iris > i:nth-child(7) { --k: 6; } .k-iris > i:nth-child(8) { --k: 7; } .k-iris > i:nth-child(9) { --k: 8; }
.k-iris-n { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font: 500 11px/1 var(--mono); letter-spacing: .12em; color: var(--ink-60);
  font-variant-numeric: tabular-nums; opacity: 0; transition: opacity .3s var(--ease); }
html.iris-load .k-iris-n { opacity: 1; }
html.iris-in .k-iris, html.iris-load .k-iris, html.iris-closing .k-iris, .k-iris.is-on { visibility: visible; }
html.iris-in .k-iris, html.iris-load .k-iris { --ir: 0; --tw: 28deg; }
/* Safety: if the kit script never runs, the iris opens on its own after 3 s. */
html.iris-in .k-iris, html.iris-load .k-iris { animation: k-iris-safety .01s 3s forwards; }
@keyframes k-iris-safety { to { visibility: hidden; } }
.k-iris.is-on { animation: none !important; }
/* The page under the iris: scales and blurs while the blades close / open (iris.js sets --iu 0..1, 1 = covered). */
html.iris-closing :is(.k-shell, .k-stage), html.iris-opening :is(.k-shell, .k-stage) { transform: scale(calc(1 - var(--iu, 0) * .03)); filter: blur(calc(var(--iu, 0) * 4px)); transform-origin: 50% 40vh; }
html.iris-in :is(.k-shell, .k-stage), html.iris-load :is(.k-shell, .k-stage) { transform: scale(1.03); filter: blur(4px); }
html.iris-in.iris-opening :is(.k-shell, .k-stage), html.iris-load.iris-opening :is(.k-shell, .k-stage) { transform: scale(calc(1 + var(--iu, 0) * .03)); filter: blur(calc(var(--iu, 0) * 4px)); }

/* ---------- View transitions (T2 morph) ---------- */
/* ONE element per page carries each name while leaving: the clicked link's (page.js marks it .vt-from). */
html.k-vt-scoped [style*="view-transition-name"]:not(.vt-from, .vt-from *) { view-transition-name: none !important; }
/* Arriving: only the hero pair morphs; the "Next" runway preview further down keeps its name out of this transition. */
html.vt-in:not(.k-vt-done) .k-runway [style*="view-transition-name"] { view-transition-name: none !important; }
/* The rest of the outgoing page steps back before the snapshot (other cards fade out first). */
html.k-vt-leave .f-card:not(:has(.vt-from)) { opacity: 0 !important; transition: opacity .18s linear; }
/* The header is the same on both pages: it stays put instead of blinking in the root cross-fade. */
.k-header { view-transition-name: k-header; }
::view-transition-group(*) { animation-duration: .8s; animation-timing-function: cubic-bezier(.7, 0, .2, 1); }
/* Models: old and new snapshots keep their aspect and stay centred in the morphing box (a square runway preview → a
   4:5 hero). Names: scaled by width (the default), the small name hands over to the big one quickly instead of a long
   double exposure. */
[data-gl="model"], [data-gl="slab"] { view-transition-class: k-shape; }
.f-card-name > span, .p-name > span, .k-runway-name > span:first-child { view-transition-class: k-name; }
::view-transition-old(*.k-shape), ::view-transition-new(*.k-shape) { height: 100%; object-fit: contain; }
::view-transition-old(*.k-name) { animation-duration: .3s; }
::view-transition-new(*.k-name) { animation-duration: .45s; animation-delay: .2s; }
::view-transition-group(root), ::view-transition-group(k-header) { animation-duration: .5s; }
::view-transition-old(root) { animation: k-vt-out .35s cubic-bezier(.4, 0, .2, 1) both; }
::view-transition-new(root) { animation: k-vt-in .5s cubic-bezier(.2, .7, .1, 1) .25s both; }
@keyframes k-vt-out { to { opacity: 0; transform: scale(.985); } }
@keyframes k-vt-in { from { opacity: 0; } }

/* ---------- Runway (T3: keep scrolling → next page) ---------- */
/* <section class="k-runway-wrap"><a class="k-runway" data-route="morph" href="…" data-cursor="Next">…</a></section>
   --run (0..1) is written by runway.js from scroll. Round 14: a composed 70 vh poster, not a screen of black — the
   label on the top hairline, the next page's name in display type on the baseline band, its object on the optical
   axis (right). The name arrives at full brightness by mid-runway; the whole block is the link. The footer follows it
   as the page's last quiet band. */
.k-runway-wrap { position: relative; height: 70vh; height: 70svh; }
.k-runway { position: relative; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); grid-template-rows: auto 1fr auto auto; column-gap: clamp(16px, 2vw, 32px);
  height: 100%; padding: clamp(22px, 4vh, 40px) var(--gutter) clamp(28px, 6vh, 64px); border-top: 1px solid var(--line, var(--ink-12));
  color: var(--ink); text-decoration: none; overflow: hidden; --run: 0; --ra: clamp(0, var(--run) * 2, 1); }
.k-runway-label { grid-column: 1 / -1; grid-row: 1; display: flex; align-items: center; gap: 14px; }
.k-runway-name { grid-column: 1 / span 8; grid-row: 3; align-self: end; position: relative; z-index: 1; font: 300 clamp(64px, 11vw, 220px)/.9 var(--sans); letter-spacing: -.03em;
  transform: translateX(calc((1 - var(--ra)) * 22vw)); opacity: calc(.12 + var(--ra) * .88); }
.k-runway-line { grid-column: 1 / -1; grid-row: 4; position: relative; height: 1px; margin-top: clamp(16px, 2.6vh, 26px); background: var(--ink-12); }
.k-runway-line::after { content: ''; position: absolute; inset: 0; transform-origin: 0 50%; transform: scaleX(var(--run)); background: linear-gradient(90deg, var(--ink), var(--blue)); }
.k-runway-preview { grid-column: 7 / -1; grid-row: 1 / 4; justify-self: center; align-self: center; width: min(40vw, 560px, 54vh); aspect-ratio: 1;
  transform: translateX(calc((1 - var(--ra)) * 30%)) scale(calc(.92 + var(--ra) * .08)); }
@media (max-width: 699px) {
  .k-runway-wrap { height: 72svh; }
  .k-runway-name { grid-column: 1 / -1; font-size: clamp(44px, 15vw, 72px); }
  .k-runway-preview { grid-column: 1 / -1; grid-row: 2; width: min(66vw, 34svh); }
}
/* Round 15: a runway with no object (About → Filters, Filters → Pocket VND, legal → next) is a compact poster, never a
   screen of black: no empty 1fr row, the label sits right above the name, the block is only as tall as its type
   (≈ 40–48 vh) and the page ends on it. No sticky travel, no extra scroll track after it. */
.k-runway-wrap:not(:has(.k-runway-preview)) { height: auto; min-height: 0; }
.k-runway-wrap:not(:has(.k-runway-preview)) .k-runway { height: auto; min-height: clamp(260px, 44svh, 480px); grid-template-rows: 1fr auto auto auto; padding-top: clamp(64px, 12vh, 140px); }
.k-runway-wrap:not(:has(.k-runway-preview)) .k-runway-label { grid-row: 2; align-self: end; margin-bottom: clamp(14px, 2.2vh, 26px); }
@media (max-width: 699px) { .k-runway-wrap:not(:has(.k-runway-preview)) .k-runway { min-height: clamp(220px, 36svh, 360px); } }

/* ---------- Footer ---------- */
/* Round 14: on the 12-column grid; the legal text is one quiet band, the links and the copy line in micro mono. */
.k-footer { position: relative; z-index: 2; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: end; column-gap: clamp(16px, 2vw, 32px); row-gap: 14px;
  padding: clamp(22px, 4vh, 36px) var(--gutter) max(24px, env(safe-area-inset-bottom)); border-top: 1px solid var(--line, var(--ink-12)); font-size: 12px; line-height: 1.6; color: var(--ink-60); }
.k-footer .k-legal { grid-column: 1 / span 7; }
.k-footer p { max-width: 70em; }
.k-legal-links { grid-column: 8 / span 3; display: flex; gap: 22px; justify-self: end; }
.k-legal-links a, .k-top { color: var(--ink); text-decoration: none; }
.k-legal-links a, .k-copy { font: 500 var(--hud)/1.6 var(--mono); letter-spacing: .14em; text-transform: uppercase; }
.k-copy { grid-column: 11 / -1; justify-self: end; white-space: nowrap; color: var(--ink-60); }
@media (max-width: 1099px) {
  .k-footer .k-legal { grid-column: 1 / -1; }
  .k-legal-links { grid-column: 1 / span 6; justify-self: start; }
  .k-copy { grid-column: 7 / -1; }
}
@media (max-width: 699px) {
  .k-footer { grid-template-columns: 1fr auto; gap: 6px 16px; }
  .k-footer .k-legal { grid-column: 1 / -1; }
  .k-legal-links { grid-column: 1; }
  .k-copy { grid-column: 2; }
  .k-legal-links a, .k-top { display: inline-block; padding: 12px 0; }
}

/* ---------- Store / text link rows ---------- */
.k-links { display: flex; flex-wrap: wrap; gap: 14px 32px; }

/* ---------- No WebGL / no JS ---------- */
html.no-js .k-iris, html.no-js .k-cursor, html.no-js .k-mark { display: none; }

/* ---------- Reduced motion: no blur/scale, no letter travel, no marquee drift, no magnet ---------- */
@media (prefers-reduced-motion: reduce) {
  html.iris-closing :is(.k-shell, .k-stage), html.iris-opening :is(.k-shell, .k-stage), html.iris-in :is(.k-shell, .k-stage), html.iris-load :is(.k-shell, .k-stage) { transform: none !important; filter: none !important; }
  .k-iris > i { transform: rotate(calc(var(--k, 0) * 40deg)) translateY(calc(var(--bi) * 92vmax - 1.5vmax)); }
  [data-split] .k-c { transform: none; opacity: calc(.35 + var(--ri) * .65); }
  [data-skew] { transform: none; }
  [data-magnet] { transform: none !important; }
  .k-roll .k-c, .k-line, .k-glass img, .k-ext { transition: none; }
  .k-runway-name, .k-runway-preview { transform: none; }
  ::view-transition-group(*), ::view-transition-old(root), ::view-transition-new(root) { animation-duration: .18s !important; animation-delay: 0s !important; }
  @keyframes k-vt-out { to { opacity: 0; } }
}

/* ==========================================================================================================
   Round 18 (2026-10-26, owner: "feel like activetheory.net"): a dark atmosphere behind every inner page (2026-10-26 b: neutral graphite like the home's night stage, no teal cast), the header
   nav as a dark-glass capsule (top right) with a hairline rule and a faint glow under it, wide-tracked mono micro
   type. CSS only; type.js gives the micro labels a one-time scramble reveal. Copy, links and stages unchanged.
   ========================================================================================================== */
:root { --k-track: .16em; --cap-h: 48px; --cap-ink: rgb(226 238 241 / .8); --cap-hi: #f4f9fa; }
@media (max-width: 699px) { :root { --cap-h: 44px; } }

/* ---------- Atmosphere: near-black ground, soft teal / ice / copper light, animated film grain ----------
   Both layers are fixed at z-index -2 inside the body (isolated, so they also sit above a body background that does
   not propagate, e.g. the 404's html.nf-dark): below the WebGL stage (z 0), below the shell's z -1 marquees and below
   all content. Long eased ramps (8+ stops) and the grain itself keep the dark gradients from banding. */
body { isolation: isolate; }
body::before { content: ''; position: fixed; inset: 0; z-index: -2; pointer-events: none;
  background:
    radial-gradient(62% 54% at 10% 4%, rgb(34 42 52 / .62) 0%, rgb(34 42 52 / .52) 12%, rgb(34 42 52 / .4) 24%, rgb(34 42 52 / .28) 36%, rgb(34 42 52 / .17) 50%, rgb(34 42 52 / .08) 66%, rgb(34 42 52 / .025) 82%, rgb(34 42 52 / 0) 100%),
    radial-gradient(44% 38% at 92% 14%, rgb(143 211 236 / .075) 0%, rgb(143 211 236 / .06) 14%, rgb(143 211 236 / .044) 28%, rgb(143 211 236 / .028) 44%, rgb(143 211 236 / .015) 60%, rgb(143 211 236 / .006) 78%, rgb(143 211 236 / 0) 100%),
    radial-gradient(58% 46% at 74% 112%, rgb(200 116 60 / .085) 0%, rgb(200 116 60 / .07) 14%, rgb(200 116 60 / .052) 28%, rgb(200 116 60 / .034) 44%, rgb(200 116 60 / .018) 60%, rgb(200 116 60 / .007) 78%, rgb(200 116 60 / 0) 100%),
    radial-gradient(70% 52% at 18% 104%, rgb(34 42 52 / .36) 0%, rgb(34 42 52 / .29) 14%, rgb(34 42 52 / .21) 28%, rgb(34 42 52 / .13) 44%, rgb(34 42 52 / .065) 60%, rgb(34 42 52 / .02) 80%, rgb(34 42 52 / 0) 100%),
    linear-gradient(180deg, #05070a 0%, #05070a 18%, #06080b 36%, #07090d 52%, #080b0f 68%, #090c11 84%, #0b0f14 100%); }
body::after { content: ''; position: fixed; inset: 0; z-index: -2; pointer-events: none; opacity: .085;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1.6 0 0 0 -.5'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E") 0 0 / 180px 180px repeat;
  animation: k-grain 1s steps(1, end) infinite; }
@keyframes k-grain {
  0% { background-position: 0 0; } 12.5% { background-position: -46px 28px; } 25% { background-position: 31px -63px; } 37.5% { background-position: -78px -17px; }
  50% { background-position: 57px 72px; } 62.5% { background-position: -12px 88px; } 75% { background-position: 84px -38px; } 87.5% { background-position: -63px 51px; } 100% { background-position: 0 0; } }
@media (prefers-reduced-motion: reduce) { body::after { animation: none; } }
html.no-js body::after { animation: none; }

/* ---------- Capsule nav: dark glass pill, top right; "FILTERS ——— ABOUT  SHOP ↗" ---------- */
.k-nav { position: relative; isolation: isolate; height: var(--cap-h); gap: clamp(14px, 1.2vw, 20px); padding: 0 clamp(18px, 1.6vw, 26px); border-radius: 999px;
  background: rgb(6 10 12 / .55); -webkit-backdrop-filter: blur(14px) saturate(1.4); backdrop-filter: blur(14px) saturate(1.4);
  /* the rim: 1 px ice hairline, a little brighter along the top edge; a soft drop into the dark */
  box-shadow: inset 0 0 0 1px rgb(170 225 230 / .22), inset 0 1px 0 rgb(214 246 250 / .16), 0 14px 34px -18px rgb(0 0 0 / .9); }
/* the hairline rule between the first two items (a flex item of its own, so the magnetic links never drag it) */
.k-nav::before { content: ''; order: 1; flex: none; width: clamp(30px, 3.4vw, 54px); height: 1px; pointer-events: none;
  background: linear-gradient(90deg, rgb(226 238 241 / .22), rgb(226 238 241 / .62) 50%, rgb(226 238 241 / .22)); }
.k-nav > a:first-child { order: 0; }
.k-nav > a:not(:first-child) { order: 2; }
/* the luminous line under the pill: a 1 px ice line fading to its ends, a faint glow and fine falling streaks below it */
.k-nav::after { content: ''; position: absolute; z-index: -1; left: 16%; right: 16%; top: calc(100% - 1px); height: 22px; pointer-events: none;
  background:
    linear-gradient(90deg, rgb(190 240 248 / 0), rgb(190 240 248 / .55) 50%, rgb(190 240 248 / 0)) 50% 0 / 100% 1px no-repeat,
    repeating-linear-gradient(90deg, rgb(170 225 230 / .14) 0 1px, rgb(170 225 230 / 0) 1px 7px),
    radial-gradient(50% 100% at 50% 0, rgb(143 211 236 / .2) 0%, rgb(143 211 236 / .12) 30%, rgb(143 211 236 / .05) 60%, rgb(143 211 236 / 0) 100%);
  -webkit-mask: radial-gradient(50% 100% at 50% 0, #000 0%, rgb(0 0 0 / .6) 45%, transparent 100%); mask: radial-gradient(50% 100% at 50% 0, #000 0%, rgb(0 0 0 / .6) 45%, transparent 100%); }
.k-nav a { justify-content: center; padding-top: 2px; }
.k-nav .k-link { font: 500 12px/1 var(--mono); letter-spacing: .14em; color: var(--cap-ink); }
.k-nav .k-link[aria-current="page"], .k-nav .k-link:hover, .k-nav .k-link:focus-visible { color: var(--cap-hi); }
/* current page: a small ice dot under the word (replaces the old dot at its left) */
.k-nav a[aria-current="page"]::before { left: 50%; top: auto; bottom: 5px; width: 4px; height: 4px; margin: 0 0 0 calc(-2px - .07em);
  background: var(--ice); box-shadow: 0 0 6px rgb(143 211 236 / .75); }
.k-nav a:focus-visible { outline: 1px solid rgb(190 240 248 / .8); outline-offset: -1px; border-radius: 999px; }
@media (max-width: 699px) {
  .k-nav { gap: 4px; padding: 0 9px; }
  .k-nav .k-link { font-size: 11px; letter-spacing: .1em; min-width: 44px; padding: 0 3px; }
  .k-nav::before { width: 16px; margin: 0 2px; }
  .k-nav::after { left: 10%; right: 10%; height: 16px; }
  .k-nav a[aria-current="page"]::before { bottom: 4px; margin-left: calc(-2px - .05em); }
}
@media (max-width: 379px) {
  .k-nav { padding: 0 6px; gap: 2px; }
  .k-nav::before { display: none; }
  .k-nav .k-link { letter-spacing: .08em; }
}

/* ---------- Micro type: wide-tracked mono caps (type.js decodes them once with a scramble as they enter) ---------- */
.k-micro, .k-mono, .k-facts dt, .k-mark { letter-spacing: var(--k-track); }
body[data-page="legal"] :is(.legal-head, .legal) .micro { letter-spacing: var(--k-track); }

/* ---------- Staff login (owner 2026-10-28: 「在批发站和零售站最下面都加上一个员工登录的按键，点进去直接跳转到后台网站」) ----------
   The last row of every footer: a small glass capsule that goes straight to the back office (Cloudflare Access + Google). */
.k-staff-row { grid-column: 1 / -1; justify-self: end; margin: 4px 0 0; }
.k-staff { display: inline-flex; align-items: center; gap: .7em; height: 36px; padding: 0 15px; border-radius: 999px; color: var(--cap-ink, var(--ink)); text-decoration: none;
  font: 500 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; background: rgb(8 12 15 / .4);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 28%, transparent); transition: color 160ms ease, box-shadow 160ms ease, background-color 160ms ease; }
.k-staff svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.1; flex: none; }
.k-staff:hover, .k-staff:focus-visible { color: var(--cap-hi, #fff); background: rgb(14 20 24 / .6); box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 55%, transparent); }
.k-staff:focus-visible { outline: 1px solid rgb(190 240 248 / .8); outline-offset: 3px; }
@media (max-width: 699px) { .k-staff-row { justify-self: start; } .k-staff { height: 44px; padding: 0 17px; } }
@media (prefers-reduced-motion: reduce) { .k-staff { transition: none; } }

/* 2026-10-29 · Shared liquid-glass controls. Only the nav and staff capsule;
   page palettes, product stages and document layout keep their own styles. */
body[data-page] .k-header .k-nav,
body[data-page] .k-footer .k-staff {
  isolation: isolate;
  border: 1px solid #d8cdd42e;
  border-radius: 999px;
  background: linear-gradient(145deg, #3b343fd9 0%, #17131bc7 37%, #29212fcf 72%, #16121ae0);
  -webkit-backdrop-filter: blur(18px) saturate(1.08);
  backdrop-filter: blur(18px) saturate(1.08);
  box-shadow: 0 12px 28px #00000026, 0 2px 5px #0000001a,
    inset 0 2px 2px #ffffff2e, inset 0 -2px 4px #00000052;
}
body[data-page] .k-header .k-nav {
  height: auto;
  min-height: 54px;
  gap: 2px;
  padding: 4px;
}
body[data-page] .k-header .k-nav::before,
body[data-page] .k-footer .k-staff::before {
  position: absolute;
  z-index: -1;
  inset: 1px;
  display: block;
  width: auto;
  height: auto;
  margin: 0;
  border: 1px solid #ffffff24;
  border-radius: inherit;
  background: linear-gradient(170deg, #ffffff17, #ffffff00 35% 71%, #ffffff12);
  box-shadow: inset 0 1px 1px #ffffff2e;
  -webkit-mask: none;
  mask: none;
  content: '';
  pointer-events: none;
}
body[data-page] .k-header .k-nav::after { display: none; content: none; }
body[data-page] .k-header .k-nav .k-link {
  min-width: 44px;
  min-height: 44px;
  justify-content: center;
  padding: 10px 16px;
  border-radius: 999px;
  color: #eae5ea;
  font: 500 11px/1.2 var(--sans);
  letter-spacing: .015em;
  text-transform: none;
  transition: color .2s, background .2s, box-shadow .2s, border-color .2s;
}
body[data-page] .k-header .k-nav .k-link:hover,
body[data-page] .k-header .k-nav .k-link[aria-current='page'] {
  color: #fff6f8;
  background-color: #ffffff08;
}
body[data-page] .k-header .k-nav a[aria-current='page']::before {
  background: #d99eae;
  box-shadow: none;
}
body[data-page] .k-header .k-nav > a[href^='https://shop.sihanoptics.com'] {
  margin-left: 4px;
  padding: 10px 17px;
  border: 1px solid #d5a5b28f;
  color: #72172a;
  background: linear-gradient(145deg, #fff7f9ed 0%, #f4dbe3eb 25%, #e4b9c9e8 65%, #faeaf0eb);
  box-shadow: 0 5px 15px #58182c21, inset 0 2px 2px #ffffffbd, inset 0 -2px 5px #84223d24;
}
body[data-page] .k-header .k-nav > a[href^='https://shop.sihanoptics.com']:hover {
  color: #641225;
  border-color: #e1b2c0bd;
  box-shadow: 0 7px 18px #58182c30, inset 0 2px 2px #ffffffeb, inset 0 -2px 6px #84223d30;
}
body[data-page] .k-footer .k-staff {
  position: relative;
  min-height: 44px;
  height: auto;
  padding: 12px 18px;
  color: #eae5ea;
  font: 500 11px/1.2 var(--sans);
  letter-spacing: .025em;
  text-transform: none;
  transition: color .2s, border-color .2s, box-shadow .2s, background .2s;
}
body[data-page] .k-footer .k-staff:hover,
body[data-page] .k-footer .k-staff:focus-visible {
  color: #fff6f8;
  border-color: #c794a566;
  background: linear-gradient(145deg, #49404dd9, #211924d9 45%, #332536db);
  box-shadow: 0 12px 28px #00000026, inset 0 2px 2px #ffffff38, inset 0 -2px 4px #00000052;
}
body[data-page] .k-header .k-nav a:focus-visible,
body[data-page] .k-footer .k-staff:focus-visible { outline: 2px solid #e0abba; outline-offset: 3px; }
body[data-page] .k-header .k-nav > a[href^='https://shop.sihanoptics.com']:focus-visible { outline-color: #a51f38; outline-offset: 2px; }
@media (max-width: 699px) {
  body[data-page] .k-header .k-nav { min-height: 54px; gap: 1px; padding: 4px; }
  body[data-page] .k-header .k-nav .k-link { padding: 10px; font-size: 10px; letter-spacing: .01em; }
  body[data-page] .k-header .k-nav > a[href^='https://shop.sihanoptics.com'] { margin-left: 2px; padding: 10px 13px; }
}
@media (prefers-reduced-motion: reduce) {
  body[data-page] .k-header .k-nav .k-link,
  body[data-page] .k-footer .k-staff { transition: none; }
}
