/* WST visual system v2 — tokens, base, components. Prototype; ported to the site once approved. */
@import url("./fonts/noto-serif-sc-900.css");
@import url("https://fonts.googleapis.com/css2?family=Manrope:wght@200;300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap");

:root {
  /* One canvas, lit from within. Every colour comes from the clew's own light; nothing changes the canvas.
     See docs/restructure/2026-10-23-clew-site-rebuild-spec.md §2. */
  --void: #0A0B0C;          /* the only canvas */
  --void-1: #131416;        /* a row or plate under the pointer */
  --void-2: #1B1D20;        /* floating notes */
  --fiber: #ECE4D6;         /* text, 15.6:1 */
  --fiber-2: #A39C90;       /* secondary text, 7.2:1 */
  --fiber-3: #8A847A;       /* labels and meta, 5.3:1, 12px and up */
  --hair: rgba(236, 228, 214, .12);
  --ember: #F2A05E;         /* current, selected, you — and nothing else */
  --ember-deep: #C4622D;    /* fills only: knots, a pressed button, the core's rim */
  --glow: #FFE3C4;          /* light itself: the core, the pointer */
  --accent: var(--ember);
  /* Older names, kept so page styles read the same tokens. */
  --paper: var(--fiber); --paper-2: var(--void-1); --ink: var(--void); --ink-2: var(--void-1);
  --grey: var(--fiber-2); --grey-d: var(--fiber-2); --hair-d: var(--hair);
  --fg: var(--fiber); --fg2: var(--fiber-2); --line: var(--hair); --card: var(--void-1); --fg-inv: var(--void);
  --grain: 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='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .5 0 0 0 0 .5 0 0 0 0 .5 0 0 0 1.6 -.6'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  --hw: 1px;                /* hairline: a true half pixel on dense screens */

  --serif: "Noto Serif SC", "Songti SC", "STSong", serif;
  --latin: "Manrope", "Avenir Next", "Helvetica Neue", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --sans: "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", system-ui, sans-serif;

  /* Type scale */
  --fs-display: clamp(36px, 9.6vw, 156px);
  --fs-h1: clamp(38px, 5vw, 72px);
  --fs-h1s: clamp(34px, 4vw, 56px);    /* headlines inside a column: product names, essay titles */
  --fs-h2: clamp(24px, 2.6vw, 36px);
  --fs-h3: clamp(19px, 1.8vw, 26px);   /* list and card titles */
  --fs-lede: clamp(16px, 1.3vw, 19px); /* lead paragraphs and reading prose */
  --fs-body: clamp(16px, 1.15vw, 18px);
  --fs-small: 14px;
  --fs-note: 13px;
  --fs-micro: 12px;                    /* labels, credits, captions */

  /* Space */
  --gutter: clamp(16px, 6.6vw, 96px);
  --section: clamp(96px, 16vh, 180px);
  --maxw: 1440px;

  /* Motion */
  --ease: cubic-bezier(.22, 1, .36, 1);
  --t1: .6s;
  --t2: .9s;
  --t3: 1.2s;
}
@media (min-resolution: 2dppx) { :root { --hw: .5px; } }

*, *::before, *::after { box-sizing: border-box; margin: 0; }
html { background: var(--void); color-scheme: dark; scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body { color: var(--fiber); background: var(--void); font: 400 var(--fs-body)/1.85 var(--sans); -webkit-font-smoothing: antialiased; overflow-x: hidden; }
img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
:focus-visible { outline: 1px solid var(--ember); outline-offset: 3px; border-radius: 2px; }

/* ---------- type ---------- */
/* Chinese setting: strict line-breaking (no punctuation at a line start), automatic space between Chinese and
   Latin/numerals where none was typed, and paragraphs that avoid a lone character on their last line. Headlines
   set punctuation half-width ("halt"), so a comma or full stop never leaves a hole in large type. */
html { line-break: strict; text-autospace: normal; }
p, li, .lede { text-wrap: pretty; }
:where(h1, h2, h3, .display, .h1, .h2, .join .big, .film-card, .film-shot p) { font-feature-settings: "halt"; }
:where(h1, h2, h3, .display, .h1, .h2, .join .big, .ph) { word-break: keep-all; overflow-wrap: break-word; text-wrap: balance; }
.nw { white-space: nowrap; }
.display { font: 900 var(--fs-display)/1.1 var(--serif); letter-spacing: -.01em; text-wrap: balance; }
.h1 { font: 900 var(--fs-h1)/1.22 var(--serif); text-wrap: balance; }
.h2 { font: 900 var(--fs-h2)/1.35 var(--serif); }
.lede { font-size: var(--fs-lede); line-height: 1.9; color: var(--grey-d); max-width: 34em; text-wrap: pretty; }
.label { font: 500 var(--fs-micro)/1.4 var(--latin); letter-spacing: .28em; text-transform: uppercase; color: var(--grey-d); }
.num { font-family: var(--latin); font-variant-numeric: tabular-nums; }
.note { font-size: var(--fs-note); color: var(--grey-d); }
.on-ink .lede, .on-ink .note, .on-ink .label { color: var(--grey); }

/* ---------- components ---------- */
/* Primary: a pill of fibre. Under the pointer it fills with light from where the pointer came in; pressed, it
   glows ember. One per screen at most. */
.btn { position: relative; display: inline-flex; align-items: center; gap: 12px; padding: 15px 26px; border-radius: 999px; color: var(--fiber); box-shadow: inset 0 0 0 var(--hw) rgba(236, 228, 214, .5); background: radial-gradient(160px circle at var(--bx, 50%) var(--by, 50%), rgba(242, 160, 94, .2), transparent 70%) no-repeat; background-size: 0 0; font: 500 var(--fs-small)/1 var(--sans); letter-spacing: .06em; transition: gap var(--t1) var(--ease), box-shadow .3s, transform .18s; }
.btn:hover { gap: 18px; background-size: 100% 100%; box-shadow: inset 0 0 0 var(--hw) var(--fiber); }
.btn:active { background: var(--ember-deep); color: var(--fiber); transform: translateX(1.5px); }
.btn .arr { font-family: var(--latin); }
.btn-line { display: inline-flex; align-items: center; gap: 8px; padding: 9px 18px; border-radius: 999px; box-shadow: inset 0 0 0 var(--hw) rgba(236, 228, 214, .5); background: radial-gradient(120px circle at var(--bx, 50%) var(--by, 50%), rgba(242, 160, 94, .22), transparent 70%) no-repeat; background-size: 0 0; font: 500 var(--fs-small)/1 var(--sans); letter-spacing: .1em; transition: gap var(--t1) var(--ease), box-shadow .3s, transform .18s; }
.btn-line:hover { gap: 14px; background-size: 100% 100%; box-shadow: inset 0 0 0 var(--hw) var(--fiber); }
.btn-line:active { background: var(--ember-deep); transform: translateX(1.5px); }
.link { position: relative; display: inline-block; }
.link::after { content: ""; position: absolute; left: 0; right: 0; bottom: -6px; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: left; transition: transform var(--t2) var(--ease); }
.link:hover::after { transform: scaleX(1); }
.link::after { background: var(--hair); }

/* Rise: lines of text lift into place once, when they enter the view. */
/* Gather (聚): content settles 8px into place, one after another, 60ms apart. */
.rise { opacity: 0; transform: translateY(8px); transition: opacity .6s var(--ease), transform .6s var(--ease); transition-delay: calc(min(var(--i, 0), 6) * 60ms); }
.rise.in { opacity: 1; transform: none; }

/* ---------- header ---------- */
.head { position: fixed; inset: 0 0 auto; z-index: 40; display: flex; align-items: center; justify-content: space-between; height: 76px; padding: 0 var(--gutter); color: var(--fiber); transition: background .6s var(--ease), box-shadow .6s; }
.head.scrolled { background: rgba(10, 11, 12, .72); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); box-shadow: 0 var(--hw) 0 var(--hair); }
.brand { display: flex; align-items: center; gap: 12px; }
.brand .mark { width: 28px; height: 28px; }
.brand .word { height: 15px; width: auto; }
.head-right { display: flex; align-items: center; gap: clamp(22px, 3.2vw, 44px); }
.nav { display: flex; gap: clamp(20px, 2.8vw, 38px); font: 500 var(--fs-small)/1 var(--sans); letter-spacing: .14em; }
.nav a { color: var(--fiber-2); transition: color .3s; }
.nav a:hover, .nav a[aria-current] { color: var(--fiber); }
/* The current page is marked by an ember knot under its name, not an underline. */
.nav a[aria-current]::after { content: ""; position: absolute; left: 50%; bottom: -12px; width: 5px; height: 5px; margin-left: -2.5px; border-radius: 50%; background: var(--ember); box-shadow: 0 0 0 3px rgba(242, 160, 94, .16); transform: none; }
.menu-btn { display: none; width: 44px; height: 44px; align-items: center; justify-content: center; }
.menu-btn i, .menu-btn i::before { display: block; width: 20px; height: 1.5px; background: currentColor; position: relative; }
.menu-btn i::before { content: ""; position: absolute; top: 6px; }
@media (max-width: 860px) {
  .nav { display: none; }
  .menu-btn { display: inline-flex; }
  .head .btn-line { padding: 7px 13px; font-size: var(--fs-micro); }
  .head-right { gap: 8px; }
}


@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rise { opacity: 1; transform: none; transition: none; }
}

/* Status pill: the honest state of a thing, always in plain words. */
.status { display: inline-flex; gap: 8px; align-items: center; padding: 8px 14px; border-radius: 999px; box-shadow: inset 0 0 0 var(--hw) var(--hair); font: 500 var(--fs-micro)/1.2 var(--sans); letter-spacing: .08em; color: var(--fiber-2); }
.status i { flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }

/* ---------- one screen, one idea ----------
   Every section fills exactly one screen and centres its content, so the next one never peeks in early.
   Gentle snapping brings a section to rest at its start; long reading pages opt out. */
html { scroll-snap-type: y proximity; }
html.reading { scroll-snap-type: none; }
.screen { min-height: 100svh; display: flex; flex-direction: column; justify-content: center; padding: 96px var(--gutter) 56px; scroll-snap-align: start; }
.screen > .inner { width: 100%; max-width: var(--maxw); margin: 0 auto; }
.snap { scroll-snap-align: start; }

/* Page hero shared by inner pages */
.page-hero .display { margin-top: 20px; }
.page-hero .lede { margin-top: 28px; }

/* Join: the one thing we ask, at the end of every page */
.join { text-align: center; align-items: center; }
.join .big { font: 900 var(--fs-display)/1.16 var(--serif); text-wrap: balance; }
.join .en { font: 500 var(--fs-note)/1 var(--latin); letter-spacing: .34em; text-transform: uppercase; color: var(--grey-d); margin-top: 34px; }
.join .join-sub { max-width: 32em; margin: 30px auto 0; color: var(--grey-d); text-wrap: balance; }
.join .btn { margin-top: 40px; }
.join .who b { font-weight: 600; color: var(--fg); }
.join .who { display: flex; gap: 10px 28px; justify-content: center; flex-wrap: wrap; margin-top: 36px; font-size: var(--fs-small); color: var(--grey-d); }

/* Footer */
.foot { position: relative; z-index: 1; padding: 56px var(--gutter) 40px; border-top: var(--hw) solid var(--hair); scroll-snap-align: end; }
/* Site map as one fibre: a knot per page, the current page in ember. */
.foot .foot-map { max-width: var(--maxw); margin: 0 auto 48px; position: relative; display: flex; justify-content: space-between; gap: 0; }
.foot-map::before { content: ""; position: absolute; left: 3px; right: 3px; top: 3px; height: var(--hw); background: var(--hair); }
.foot-map a { position: relative; padding-top: 22px; font: 500 11.5px/1 var(--mono); letter-spacing: .12em; color: var(--fiber-2); transition: color .3s; }
.foot-map a::before { content: ""; position: absolute; left: 0; top: 0; width: 7px; height: 7px; border-radius: 50%; background: var(--void); box-shadow: inset 0 0 0 var(--hw) var(--fiber-2); transition: background .3s, box-shadow .3s; }
.foot-map a:last-child { text-align: right; } .foot-map a:last-child::before { left: auto; right: 0; }
.foot-map a:hover { color: var(--fiber); } .foot-map a:hover::before { background: var(--fiber); }
.foot-map a[aria-current] { color: var(--fiber); } .foot-map a[aria-current]::before { background: var(--ember); box-shadow: 0 0 0 4px rgba(242, 160, 94, .16); }
@media (max-width: 760px) { .foot .foot-map { flex-direction: column; gap: 18px; padding-left: 0; } .foot-map::before { left: 3px; right: auto; top: 3px; bottom: 3px; width: var(--hw); height: auto; } .foot-map a { padding: 0 0 0 22px; } .foot-map a:last-child { text-align: left; } .foot-map a:last-child::before { left: 0; right: auto; } }
.foot-inner { max-width: var(--maxw); margin: 0 auto; display: grid; grid-template-columns: 1.4fr repeat(2, minmax(0, 1fr)); gap: 32px; }
.foot .brand .mark { width: 30px; height: 30px; }
.foot .brand .word { height: 16px; }
.foot p { margin-top: 16px; color: var(--grey-d); font-size: var(--fs-small); }
.foot nav { display: grid; gap: 10px; align-content: start; font-size: var(--fs-small); }
.foot nav b { font: 500 var(--fs-micro)/1.4 var(--latin); letter-spacing: .24em; text-transform: uppercase; color: var(--grey-d); margin-bottom: 4px; }
.foot-base { max-width: var(--maxw); margin: 40px auto 0; display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: var(--fs-note); color: var(--grey-d); }
@media (max-width: 760px) { .foot-inner { grid-template-columns: 1fr 1fr; } .foot-inner > div:first-child { grid-column: 1 / -1; } }

/* Mobile menu */
.menu { position: fixed; inset: 0; z-index: 90; background: var(--void); display: flex; flex-direction: column; padding: 96px var(--gutter) 40px; opacity: 0; visibility: hidden; transition: opacity .28s cubic-bezier(.4, 0, .2, 1), visibility 0s linear .28s; }
.menu.open { opacity: 1; visibility: visible; transition: opacity .48s var(--ease); }
/* Items sit on one vertical fibre, a knot before each; they gather in from the right when the menu opens. */
.menu nav { position: relative; display: grid; gap: 6px; padding-left: 28px; }
.menu nav::before { content: ""; position: absolute; left: 3px; top: 18px; bottom: 18px; width: var(--hw); background: var(--hair); }
.menu nav a { position: relative; font: 900 clamp(36px, 10vw, 48px)/1.45 var(--serif); color: var(--fiber-2); opacity: 0; transform: translateX(16px); transition: opacity .48s var(--ease), transform .48s var(--ease), color .3s; transition-delay: calc(var(--i, 0) * 60ms); }
.menu nav a::before { content: ""; position: absolute; left: -28px; top: 50%; width: 7px; height: 7px; margin-top: -3.5px; border-radius: 50%; background: var(--void); box-shadow: inset 0 0 0 var(--hw) var(--fiber-2); }
.menu.open nav a { opacity: 1; transform: none; }
.menu nav a[aria-current] { color: var(--fiber); }
.menu nav a[aria-current]::before { background: var(--ember); box-shadow: 0 0 0 4px rgba(242, 160, 94, .16); }
.menu .btn { align-self: flex-start; margin-top: auto; }
.menu-close { position: absolute; top: 16px; right: var(--gutter); width: 44px; height: 44px; font-size: 26px; }
html.menu-open { overflow: hidden; }

/* Everything above the field. */
main, .join { position: relative; z-index: 1; }
#field { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; display: block; }
.lede, .label, .note { color: var(--fiber-2); }
.foot p, .foot nav b, .foot-base, .join .en, .join .join-sub, .join .who { color: var(--fiber-2); }

/* ---------- page to page ----------
   Same-site navigations cross-fade instead of flashing white: the header stays put, the old page lifts away,
   the new one settles in, and the clicked nav word becomes the new page's label. */
@view-transition { navigation: auto; }
.head { view-transition-name: site-head; }
.page-label { view-transition-name: page-label; }
/* Scatter (散) out in 280ms, then the new page gathers (聚). The canvas is the same colour on every page, so
   nothing flashes between them. */
/* While the two pages swap, nothing of either is painted for a moment; the transition layer carries the canvas
   colour itself, so that moment is the same dark, not the browser's grey. */
::view-transition { background: #0A0B0C; }
::view-transition-old(root) { animation: vt-out .28s cubic-bezier(.4, 0, .2, 1) both; }
::view-transition-new(root) { animation: vt-in .6s var(--ease) .28s both; }
::view-transition-group(page-label) { animation-duration: .7s; animation-timing-function: var(--ease); }
::view-transition-group(site-head) { animation-duration: .45s; }
@keyframes vt-out { to { opacity: 0; transform: translateY(-8px); } }
@keyframes vt-in { from { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }

/* ---------- material ----------
   A fine grain over everything below the header, so the dark canvas has a surface and soft light never bands. */
body::before { content: ""; position: fixed; inset: 0; z-index: 35; pointer-events: none; background: var(--grain) 0 0 / 180px; opacity: .12; }
/* The pointer is a light: a soft warm pool that follows it (fine pointers only). */
.lamp { position: fixed; inset: 0; z-index: 36; pointer-events: none; background: radial-gradient(240px circle at var(--lx, -400px) var(--ly, -400px), rgba(255, 227, 196, .06), transparent 70%); }
@media (hover: none), (prefers-reduced-motion: reduce) { .lamp { display: none; } }

/* ---------- finishing ---------- */
::selection { background: rgba(242, 160, 94, .3); color: var(--fiber); }
.join-act { display: flex; gap: 14px 22px; align-items: center; justify-content: center; flex-wrap: wrap; margin-top: 40px; }
.join .join-act .btn { margin-top: 0; }
.copy { font: 500 var(--fs-small)/1 var(--sans); letter-spacing: .06em; color: var(--fg2); text-decoration: underline; text-underline-offset: 4px; text-decoration-thickness: var(--hw); }
.copy:hover { color: var(--fg); }
.foot .copy { text-align: left; text-decoration: none; font-size: 14px; letter-spacing: 0; color: inherit; }
.toast { position: fixed; left: 50%; bottom: 28px; z-index: 95; translate: -50% 8px; display: inline-flex; gap: 10px; align-items: center; padding: 12px 18px; border-radius: 999px; background: var(--void-2); box-shadow: inset 0 0 0 var(--hw) var(--hair); color: var(--fiber); font: 400 12.5px/1.2 var(--mono); letter-spacing: .02em; opacity: 0; pointer-events: none; transition: opacity .28s cubic-bezier(.4, 0, .2, 1), translate .48s var(--ease); white-space: nowrap; }
.toast::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--ember); }
.toast.on { opacity: 1; translate: -50% 0; }

/* ---------- Clew language: notation, evidence, thread index, trace ----------
   See docs/restructure/2026-10-23-clew-design-language.md. Pages open with a section mark and a noun title,
   facts carry an evidence grade, and one vertical thread indexes the page. */
.label { font: 500 11.5px/1.4 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--fiber-3); }
.label .sec { color: var(--fg); margin-right: 10px; }
.meta-row { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 14px; font: 400 11.5px/1.5 var(--mono); letter-spacing: .06em; color: var(--fg2); }
.meta-row b { font-weight: 500; color: var(--fg); margin-right: 6px; }
.abstract { margin-top: 18px; max-width: 40em; font-size: var(--fs-lede); line-height: 1.85; color: var(--fg2); text-wrap: pretty; }

/* Evidence grades: established ●, supported ◐, hypothesis ○, engineering analogy ◌ */
.ev { display: inline-grid; place-items: center; width: 1.05em; height: 1.05em; margin: 0 .25em; vertical-align: -.08em; font: 400 .82em/1 var(--mono); font-style: normal; color: var(--fg); cursor: help; border-radius: 50%; outline-offset: 2px; }
.ev::before { content: "●"; }
.ev[data-ev="sup"]::before { content: "◐"; }
.ev[data-ev="hyp"]::before { content: "○"; }
.ev[data-ev="ana"]::before { content: "◌"; }
.ev-tip { position: fixed; z-index: 96; max-width: 300px; padding: 12px 14px; border-radius: 10px; background: var(--void-2); color: var(--fiber); font: 400 12.5px/1.6 var(--sans); box-shadow: 0 0 0 var(--hw) var(--hair); opacity: 0; translate: 0 6px; pointer-events: none; transition: opacity .25s var(--ease), translate .3s var(--ease); }
.ev-tip.on { opacity: 1; translate: 0 0; }
.ev-tip b { display: block; margin-bottom: 4px; font: 500 11px/1.3 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ember); }
.ev-filter { display: inline-flex; flex-wrap: wrap; gap: 6px; font: 500 11.5px/1 var(--mono); letter-spacing: .08em; }
.ev-filter button { display: inline-flex; gap: 8px; align-items: center; padding: 8px 12px; border-radius: 999px; color: var(--fg); box-shadow: inset 0 0 0 var(--hw) var(--line); transition: opacity .3s, box-shadow .3s; }
.ev-filter button[aria-pressed="false"] { opacity: .4; }
.ev-filter button .ev { margin: 0; cursor: inherit; }
[data-claim] { transition: opacity .5s var(--ease), filter .5s var(--ease); }
html.hide-est [data-claim="est"], html.hide-sup [data-claim="sup"], html.hide-hyp [data-claim="hyp"], html.hide-ana [data-claim="ana"] { opacity: .16; filter: blur(.4px); }

/* Thread index: one vertical fibre on the right, a knot per section, the current knot in ember. */
.thread-index { position: fixed; right: 22px; top: 50%; z-index: 38; translate: 0 -50%; display: grid; gap: 18px; padding: 10px 0; }
.thread-index::before { content: ""; position: absolute; left: 50%; top: 0; bottom: 0; width: var(--hw); background: currentColor; opacity: .25; }
.thread-index a { position: relative; width: 11px; height: 11px; display: block; }
.thread-index a::before { content: ""; position: absolute; inset: 3px; border-radius: 50%; background: currentColor; opacity: .45; transition: inset .4s var(--ease), opacity .4s, background .4s; }
.thread-index a[aria-current]::before { inset: 0; opacity: 1; background: var(--ember); box-shadow: 0 0 0 4px rgba(242,160,94,.16); }
.thread-index a span { position: absolute; right: 22px; top: 50%; translate: 6px -50%; white-space: nowrap; padding: 6px 9px; border-radius: 6px; background: var(--void-2); font: 500 11px/1 var(--mono); letter-spacing: .1em; opacity: 0; pointer-events: none; transition: opacity .3s, translate .4s var(--ease); }
.thread-index a:hover span, .thread-index a:focus-visible span { opacity: .85; translate: 0 -50%; }
.thread-index { color: var(--fg); }
@media (max-width: 900px) { .thread-index { display: none; } }

/* Trace: on hover a point of light runs along a link's underline. */
.link { background: linear-gradient(90deg, transparent, var(--ember), var(--fiber), transparent) -60% 100% / 40% 1px no-repeat; }
.link:hover { animation: trace .42s var(--ease) forwards; }
@keyframes trace { to { background-position: 160% 100%; } }
@media (prefers-reduced-motion: reduce) { .link:hover { animation: none; } }

/* ---------- fibre table (spec §8.7) ----------
   No frame, no stripes: rows are parted by hairlines. Under the pointer a row's fibre lights from left to right,
   the row lifts one step of the canvas, and its text comes up to full fibre. */
.ftable { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.ftable thead th { padding: 0 16px 12px 0; white-space: nowrap; text-align: left; font: 500 11px/1.4 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--fiber-3); border-bottom: var(--hw) solid var(--hair); }
.ftable tbody tr { background: linear-gradient(90deg, var(--ember), var(--fiber) 35%, transparent 75%) 0 100% / 0 var(--hw) no-repeat, linear-gradient(var(--hair), var(--hair)) 0 100% / 100% var(--hw) no-repeat; transition: background-size .42s var(--ease), background-color .16s; outline-offset: -1px; }
.ftable tbody tr:hover, .ftable tbody tr:focus-visible { background-color: var(--void-1); background-size: 100% var(--hw), 100% var(--hw); }
.ftable td, .ftable tbody th { padding: 20px 16px 20px 0; vertical-align: baseline; text-align: left; color: var(--fiber-2); transition: color .3s; }
.ftable tbody th { font: 900 var(--fs-h3)/1.4 var(--serif); color: var(--fiber); white-space: nowrap; }
.ftable tbody tr:hover td, .ftable tbody tr:focus-visible td { color: var(--fiber); }
.ftable .k { position: relative; padding-left: 20px; font: 400 11.5px/1.9 var(--mono); letter-spacing: .1em; color: var(--fiber-3); white-space: nowrap; }
.ftable .k::before { content: ""; position: absolute; left: 0; top: 50%; width: 7px; height: 7px; margin-top: -3.5px; border-radius: 50%; box-shadow: inset 0 0 0 var(--hw) var(--fiber-2); transition: background .3s, box-shadow .3s; }
.ftable tbody tr:hover .k::before, .ftable tbody tr:focus-visible .k::before { background: var(--fiber); }
/* Tables with five or more rows: the others step back while one is read. */
.ftable.dense tbody:hover tr:not(:hover) { opacity: .55; transition: opacity .3s .12s; }
@media (max-width: 760px) {
  .ftable thead { display: none; }
  .ftable tbody tr { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 14px; padding: 16px 0; }
  .ftable td, .ftable tbody th { padding: 0; }
  .ftable tbody th { white-space: normal; }
  .ftable td:last-child { grid-column: 1 / -1; }
}

/* ---------- clauses (spec §8.7, the clause variant) ----------
   Numbered clauses, closed to one line each; opening one unfolds its text and where it can be seen. */
.clauses { list-style: none; padding: 0; margin-top: clamp(32px, 6vh, 56px); border-top: var(--hw) solid var(--hair); }
.clauses li { border-bottom: var(--hw) solid var(--hair); background: linear-gradient(90deg, var(--ember), var(--fiber) 35%, transparent 75%) 0 100% / 0 var(--hw) no-repeat; transition: background-size .42s var(--ease); }
.clauses li:hover, .clauses li:focus-within { background-size: 100% var(--hw); }
.clauses button { width: 100%; display: grid; grid-template-columns: 84px minmax(0, 1fr) 24px; gap: 24px; align-items: baseline; padding: clamp(14px, 2.4vh, 22px) 0; text-align: left; }
.clauses .num { position: relative; padding-left: 20px; font: 400 11.5px/1.6 var(--mono); letter-spacing: .08em; color: var(--fiber-3); white-space: nowrap; }
.clauses .num::before { content: ""; position: absolute; left: 0; top: 50%; width: 7px; height: 7px; margin-top: -3.5px; border-radius: 50%; box-shadow: inset 0 0 0 var(--hw) var(--fiber-2); transition: background .3s, box-shadow .3s; }
.clauses [aria-expanded="true"] .num::before { background: var(--ember); box-shadow: 0 0 0 4px rgba(242, 160, 94, .16); }
.clauses b { font: 900 var(--fs-h3)/1.4 var(--serif); color: var(--fiber-2); transition: color .3s; }
.clauses button:hover b, .clauses [aria-expanded="true"] b { color: var(--fiber); }
.clauses .pm { position: relative; width: 11px; height: 11px; align-self: center; }
.clauses .pm::before, .clauses .pm::after { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: var(--hw); background: var(--fiber-2); transition: transform .36s var(--ease); }
.clauses .pm::after { transform: rotate(90deg); }
.clauses [aria-expanded="true"] .pm::after { transform: rotate(0); }
.clause-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .36s var(--ease); }
.clause-body > div { overflow: hidden; padding-left: 108px; }
.clauses [aria-expanded="true"] + .clause-body { grid-template-rows: 1fr; }
.clause-body p { color: var(--fiber-2); padding-bottom: 14px; max-width: 34em; }
.clause-body .where { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: var(--fs-small); padding-bottom: 22px; }
.clause-body .where span { font: 400 11px/1.9 var(--mono); letter-spacing: .12em; color: var(--fiber-3); }
.clause-body .where a { color: var(--fiber); }
@media (max-width: 760px) { .clauses button { grid-template-columns: minmax(0, 1fr) 24px; gap: 6px 16px; } .clauses .num { grid-column: 1 / -1; } .clause-body > div { padding-left: 0; } }
@media (prefers-reduced-motion: reduce) { .clause-body, .clauses li, .ftable tbody tr { transition: none; } }

/* ---------- chips: filters for tables and plates ---------- */
.chips { display: flex; flex-wrap: wrap; gap: 6px; font: 500 11.5px/1 var(--mono); letter-spacing: .08em; }
.chips button { display: inline-flex; gap: 8px; align-items: center; padding: 8px 13px; border-radius: 999px; color: var(--fiber-2); box-shadow: inset 0 0 0 var(--hw) var(--hair); transition: color .3s, box-shadow .3s; }
.chips button::before { content: ""; width: 5px; height: 5px; border-radius: 50%; box-shadow: inset 0 0 0 var(--hw) var(--fiber-3); }
.chips button:hover { color: var(--fiber); }
.chips button[aria-pressed="true"] { color: var(--fiber); box-shadow: inset 0 0 0 var(--hw) rgba(236, 228, 214, .45); }
.chips button[aria-pressed="true"]::before { background: var(--ember); box-shadow: none; }
.chips-count { min-height: 1.6em; margin-top: 10px; font: 400 11.5px/1.6 var(--mono); color: var(--fiber-3); }
.chips-count button { margin-left: 12px; color: var(--fiber); }

/* fibre table: sortable headers, folded rows, rows that unfold */
.ftable th[data-sort] button { display: inline-flex; gap: 6px; align-items: center; font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; }
.ftable th[data-sort] button::after { content: "↕"; opacity: .45; }
.ftable th[aria-sort="ascending"] button::after { content: "↑"; opacity: 1; color: var(--ember); }
.ftable th[aria-sort="descending"] button::after { content: "↓"; opacity: 1; color: var(--ember); }
.ftable th[data-sort] button:hover { color: var(--fiber); }
.ftable tr.folded { display: none; }
.ftable tbody tr[aria-expanded] { cursor: pointer; }
.ftable tbody tr[aria-expanded="true"] .k::before { background: var(--ember); box-shadow: 0 0 0 4px rgba(242, 160, 94, .16); }
.ftable tr.detail { background: none; }
.ftable tr.detail td { padding: 0 0 22px 20px; color: var(--fiber-2); animation: gather-in .36s var(--ease); }
.ftable .more-mark { font: 400 11px/1 var(--mono); color: var(--fiber-3); margin-left: 8px; }
@keyframes gather-in { from { opacity: 0; transform: translateY(-6px); } }
/* Key–value variant: the key is a mono label, and pointing at a row shows where its value comes from. */
.ftable.kv tbody th { width: 9em; font: 500 11px/1.9 var(--mono); letter-spacing: .12em; color: var(--fiber-3); white-space: nowrap; }
.ftable.kv td { color: var(--fiber); }

/* ---------- specimen plates ---------- */
.plates[data-plates] > li { cursor: pointer; outline-offset: -1px; transition: background-color .16s; }
.plates[data-plates] > li:hover, .plates[data-plates] > li:focus-visible { background-color: var(--void-1); }
.plates[data-plates] > li.folded { display: none; }
.plates[data-plates] > li.open { grid-column: 1 / -1; background-color: var(--void-1); padding-left: 22px !important; border-left: 0 !important; }
.plates .more { display: none; }
.plates li.open .more { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px 28px; margin-top: 18px; padding-top: 16px; border-top: var(--hw) solid var(--hair); animation: gather-in .36s var(--ease); }
.plates .more div { font-size: var(--fs-note); line-height: 1.7; color: var(--fiber); }
.plates .more dt { font: 400 10.5px/1.6 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--fiber-3); }
.plates .more dd { margin: 2px 0 0; }

/* ---------- fibre timeline (vertical, lit by scroll) ---------- */
.ftl { position: relative; list-style: none; padding: 0 0 0 30px; --p: 0; }
.ftl::before, .ftl::after { content: ""; position: absolute; left: 3px; top: 6px; bottom: 6px; width: var(--hw); background: var(--hair); }
.ftl::after { background: linear-gradient(var(--fiber), var(--ember)); transform-origin: top; transform: scaleY(var(--p)); width: 1px; }
.ftl > li { position: relative; }
.ftl > li::before { content: ""; position: absolute; left: -30px; top: .72em; width: 7px; height: 7px; border-radius: 50%; background: var(--void); box-shadow: inset 0 0 0 var(--hw) var(--fiber-2); transition: background .4s, box-shadow .4s; z-index: 1; }
.ftl > li.lit::before { background: var(--fiber); }
.ftl > li:last-child.lit::before { background: var(--ember); box-shadow: 0 0 0 4px rgba(242, 160, 94, .16); }

/* numbers that gather out of particles */
.gather-num.waiting { color: transparent !important; }
/* A row's knot can sit on its name cell; .m is a quiet mono cell without one. */
.ftable .m { font: 400 11.5px/1.9 var(--mono); letter-spacing: .06em; color: var(--fiber-3); white-space: nowrap; }
.ftable .k-row { position: relative; padding-left: 20px; }
.ftable .k-row::before { content: ""; position: absolute; left: 0; top: 50%; width: 7px; height: 7px; margin-top: -3.5px; border-radius: 50%; box-shadow: inset 0 0 0 var(--hw) var(--fiber-2); transition: background .3s, box-shadow .3s; }
.ftable tbody tr:hover .k-row::before, .ftable tbody tr:focus-visible .k-row::before { background: var(--fiber); }
.ftable tbody tr[aria-expanded="true"] .k-row::before { background: var(--ember); box-shadow: 0 0 0 4px rgba(242, 160, 94, .16); }
.ftable.dense tbody th { font-size: var(--fs-small); }
.ftable.dense td, .ftable.dense tbody th { padding-top: 13px; padding-bottom: 13px; }
@media (max-width: 760px) { .ftable .m { white-space: normal; } }

/* ---------- viewer: a list and one item in focus ----------
   The focused item takes the large left field; the list on the right stays short and scannable. */
.viewer { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(32px, 5vw, 96px); align-items: start; }
.v-panel { min-height: 100%; }
.v-panel.in > * { animation: gather-in .6s var(--ease) both; }
.v-panel.in > *:nth-child(2) { animation-delay: 60ms; } .v-panel.in > *:nth-child(3) { animation-delay: 120ms; } .v-panel.in > *:nth-child(n+4) { animation-delay: 180ms; }
.v-list { list-style: none; padding: 0; border-top: var(--hw) solid var(--hair); }
.v-item { position: relative; width: 100%; display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; gap: 4px 12px; align-items: baseline; padding: 14px 4px 14px 0; text-align: left; border-bottom: var(--hw) solid var(--hair); background: linear-gradient(90deg, var(--ember), var(--fiber) 35%, transparent 75%) 0 100% / 0 var(--hw) no-repeat; transition: background-size .42s var(--ease), background-color .16s; }
.v-item::before { content: ""; width: 7px; height: 7px; border-radius: 50%; box-shadow: inset 0 0 0 var(--hw) var(--fiber-2); align-self: center; transition: background .3s, box-shadow .3s; }
.v-item b { font: 900 var(--fs-small)/1.5 var(--serif); color: var(--fiber-2); transition: color .3s; }
.v-item small { font: 400 11px/1.4 var(--mono); letter-spacing: .06em; color: var(--fiber-3); white-space: nowrap; }
.v-item:hover, .v-item:focus-visible { background-size: 100% var(--hw); }
.v-item:hover b { color: var(--fiber); }
.v-item[aria-selected="true"] { background-size: 100% var(--hw); background-color: var(--void-1); }
.v-item[aria-selected="true"] b { color: var(--fiber); }
.v-item[aria-selected="true"]::before { background: var(--ember); box-shadow: 0 0 0 4px rgba(242, 160, 94, .16); }
@media (max-width: 900px) { .viewer { grid-template-columns: 1fr; } .v-list { order: -1; } }

/* ---------- contact sheet ("写信给世同") ---------- */
.contact { margin: auto; width: min(560px, calc(100vw - 32px)); max-height: calc(100svh - 32px); padding: 0; border: 0; border-radius: 14px; background: var(--void-2); color: var(--fiber); box-shadow: 0 0 0 var(--hw) var(--hair), 0 30px 80px -20px rgba(0, 0, 0, .7); }
.contact::backdrop { background: rgba(10, 11, 12, .72); backdrop-filter: blur(6px); }
.contact[open] { animation: gather-in .48s var(--ease); }
.c-inner { position: relative; padding: clamp(28px, 4vw, 44px); }
.c-close { position: absolute; top: 14px; right: 14px; width: 44px; height: 44px; font-size: 24px; color: var(--fiber-2); }
.c-close:hover { color: var(--fiber); }
.contact h2 { margin-top: 14px; font: 900 var(--fs-h2)/1.3 var(--serif); }
.c-mail { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: baseline; margin-top: 22px; padding-bottom: 18px; border-bottom: var(--hw) solid var(--hair); }
.c-mail span { font: 400 clamp(15px, 1.6vw, 18px)/1.4 var(--mono); letter-spacing: .02em; word-break: break-all; }
.c-hint { margin-top: 18px; font-size: var(--fs-small); color: var(--fiber-2); }
.c-letter { margin-top: 14px; padding: 16px 18px; border-radius: 8px; background: var(--void); font: 400 12.5px/1.8 var(--mono); color: var(--fiber-2); white-space: pre-wrap; }
.c-letter i { font-style: normal; color: var(--fiber-3); }
.c-act { display: flex; flex-wrap: wrap; gap: 14px 24px; align-items: center; margin-top: 24px; }
html:has(.contact[open]) { overflow: hidden; }
