/* OSG SITE KIT — components.css
   규칙과 부품 목록은 COMPONENTS.md.
   새 화면을 만들 때 여기 없는 스타일을 새로 쓰지 않는다. 필요하면 부품을 여기에 먼저 추가한다. */

/* ── 0. tokens ───────────────────────────────────────────── */
:root {
  --ink: #000;
  --paper: #fff;
  --veil: rgba(255, 255, 255, .92);
  --line: 1px solid var(--ink);   /* the only border: 1px, ink */
  --pad: 20px;                    /* the only spacing unit; 16px on phones */
  --fs: 17px;                     /* THE text size: titles, nav, tables, facts, tags, popups, fixed corners — hierarchy comes from position and lines, never from size */
  --lh: 24px;
  --fs-mark: 44px;                /* the only other size: the nav wordmark (phones 40px) */
  --w: 400;                       /* Regular — every glyph, until the reader picks another weight */
  --corner-h: 48px;               /* fixed clock / Contact height = the footer's last row */
  --logo-w: 290px;                /* the logo cell: wide enough for the three logos side by side at one height */
  --nav-h: 73px;                  /* the bar: 72 + line; phones 110px (+49 with their sub row) */
  --bar-h: 49px;                  /* a bar's height (12 + 24 + 12 + 1) */
}

/* ── 1. base ─────────────────────────────────────────────── */
* { box-sizing: border-box; border-radius: 0; }
html { -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: "OSG Capsules", sans-serif;
  font-weight: var(--w);
  font-stretch: 75%;              /* Condensed */
  font-size: var(--fs);
  line-height: var(--lh);
  word-break: keep-all;
}
/* the content region is one viewport high (under the nav): the footer always starts below the fold */
.content { min-height: calc(100svh - var(--nav-h)); padding-bottom: var(--corner-h); }   /* room above the floating clock and Contact: the footer never creeps into the first screen */
html[data-weight="thin"] body { --w: 100; }
html[data-weight="light"] body { --w: 300; }
html[data-weight="bold"] body { --w: 700; }   /* Regular (400) is the default; the reader steps Thin → Light → Regular → Bold */
:root[data-theme="dark"] { --ink: #fff; --paper: #000; --veil: rgba(0, 0, 0, .92); color-scheme: dark; }   /* black and white swap; pictures keep their colour */
:root[data-theme="dark"] .logo { filter: invert(1); }   /* only the vector logo swaps; every picture keeps its own ground, the portrait its white */
h1, h2, h3, p, ul, ol, dl, dd, figure { margin: 0; padding: 0; font-size: inherit; font-weight: inherit; }
th, b, strong, button, input { font: inherit; }          /* no browser bold anywhere */
button { padding: 0; border: 0; background: none; color: inherit; cursor: pointer; text-align: left; }
a { color: inherit; }
@media (hover: hover) { a:hover { background: var(--ink); color: var(--paper); } }   /* small text links invert on pointer devices only: a tap must not leave a stuck black patch */
:focus { outline: none; }
:focus-visible { outline: 1px solid var(--ink); outline-offset: 2px; }
img, video { display: block; width: 100%; height: auto; }
.t { text-decoration: none; }                            /* link without underline */
.t:hover { background: none; color: inherit; text-decoration: underline; }   /* plain browser underline, nothing styled */
[hidden] { display: none !important; }

/* ── 2. nav — wordmark cell ↔ logos 1·2·3 by cursor x · pages · About alone at the far right ── */
.nav { display: flex; align-items: stretch; border-bottom: var(--line); }
.nav__logo { position: relative; display: flex; align-items: center; width: var(--logo-w); padding: 0 var(--pad); min-height: 72px; border-right: var(--line); cursor: crosshair; user-select: none; text-decoration: none; }
.nav__logo:hover { background: none; color: inherit; }
.nav__links { display: flex; align-items: center; gap: calc(var(--pad) * 1.5); padding: 0 var(--pad); }
.nav__about { display: flex; align-items: center; margin-left: auto; padding: 0 var(--pad); }
.nav [aria-current="page"] { text-decoration: underline; }   /* current page = the browser's own underline */
.nav__wm { font-size: var(--fs-mark); line-height: var(--fs-mark); white-space: nowrap; }
.nav__logo.is-live .nav__wm { visibility: hidden; }
.nav__wm.is-return { animation: osg-rows .55s steps(7, end) both; }   /* the wordmark's capsule rows stack in from the top, row by row */
/* exactly one capsule row per step: the caps are 7 capsule rows high (OSG Capsules caps 534–6942 of 8188 units, 7 rows of 915.5), so the clip opens
   from the top of row 1 (--wm-top) to the bottom of row 7 (--wm-bot) in 7 equal steps. behaviors.js measures both from the wordmark's real baseline
   (the browser rounds the font's ascent/descent to whole pixels, so em values alone drift by a fraction of a row); the em values are the fallback */
@keyframes osg-rows { from { clip-path: inset(0 0 calc(100% - var(--wm-top, .0824em)) 0); } to { clip-path: inset(0 0 calc(100% - var(--wm-bot, .8657em)) 0); } }
@media (prefers-reduced-motion: reduce) { .nav__wm.is-return { animation: none; } }
/* the logo cell: wordmark at rest; on hover the cell goes empty and only the zone under the pointer shows its logo.
   Zones sit side by side, each exactly as wide as its logo (wide · pixel OSG · toy OSG). Entering a zone draws that logo once:
   the outline is traced stroke by stroke, then the fill comes in — a different fill for each (wipe-glitch · low-res steps · jelly). */
.nav__zones { display: none; position: absolute; inset: 0 var(--pad); align-items: stretch; }
.nav__logo.is-live .nav__zones { display: flex; }
.zone { display: flex; align-items: center; flex: none; }
.zone--mark { width: calc(34px * 1085 / 259); }
.zone--blocks { width: calc(34px * 350 / 240); }
.zone--ofstgrnd { width: calc(34px * 640 / 630); }
.nav__zones .logo { height: 34px; width: auto; max-height: none; visibility: hidden; overflow: visible; }
.zone { overflow: visible; }
.zone.is-on .logo { visibility: visible; }
/* the two built logos pop up where they stand — flat, cut-out, no flying.
   wide OSG = a plastic-kit runner: the pill frame clacks in, then the parts O · S · G sit loose inside it and are pressed in one by one, each followed by its two gates (the little stems that hold a part to the frame).
   pixel OSG = stop-motion stamps on a syncopated beat. */
.zone .piece { opacity: 0; }
.zone--mark.is-on .piece--ring, .zone--mark.is-on .piece.ring { animation: osg-ring .3s steps(1, end) both; }
.zone--mark.is-on .piece.part { animation: osg-seat .62s cubic-bezier(.3, 1.5, .5, 1) both; animation-delay: var(--d, 0s); }
.zone--mark.is-on .piece.gate { animation: osg-gate .18s steps(3, end) both; animation-delay: var(--d, 0s); }
.zone--mark.is-on .piece.gate--bot { animation-delay: calc(var(--d, 0s) + .05s); }
.zone--blocks.is-on .piece { animation: osg-stamp .5s steps(1, end) both; animation-delay: var(--d, 0s); }
.zone--blocks.is-on .boil { animation: osg-boil .125s steps(1, end) infinite alternate; animation-delay: .9s; }
@keyframes osg-ring { 0% { opacity: 0; transform: scale(.9); } 40% { opacity: 1; transform: scale(1.04); } 100% { opacity: 1; transform: none; } }
@keyframes osg-seat {   /* loose and small inside its slot, then pressed in with a bounce — it never leaves its own slot, so S and G never reach their neighbours */
  0% { opacity: 0; transform: translate(0, calc(var(--oy) * 1px)) rotate(calc(var(--r) * 1deg)) scale(.7); }
  30% { opacity: 1; transform: translate(0, calc(var(--oy) * .9px)) rotate(calc(var(--r) * .9deg)) scale(.72); }
  62% { opacity: 1; transform: translate(0, 3px) rotate(0deg) scale(1.07); }
  82% { transform: translate(0, -1px) scale(.985); }
  100% { opacity: 1; transform: none; }
}
@keyframes osg-gate { 0% { opacity: 0; transform: scaleY(0); } 60% { opacity: 1; transform: scaleY(1.25); } 100% { opacity: 1; transform: none; } }
@keyframes osg-stamp {
  0% { opacity: 0; transform: scale(0); }
  20% { opacity: 1; transform: scale(1.5, .45); }
  45% { transform: scale(.78, 1.35); }
  70% { transform: scale(1.12, .9); }
  100% { opacity: 1; transform: none; }
}
@keyframes osg-boil { 0% { transform: translate(0, 0) rotate(0deg); } 100% { transform: translate(5px, -4px) rotate(1.2deg); } }
/* the toy OSG (kept as it was): per-piece trace, fill, jelly. Drawn in #000 like the other two logos, so the dark-mode invert() turns it white */
.zone--ofstgrnd.is-on .logo path { fill: #000; stroke: #000; stroke-width: 1.4px; vector-effect: non-scaling-stroke; stroke-dasharray: 1 1; stroke-dashoffset: 1; fill-opacity: 0; transform-box: fill-box; transform-origin: 50% 100%;
  animation: osg-trace .6s cubic-bezier(.4, 0, .2, 1) both, osg-fill .2s ease-out both, osg-jelly .6s cubic-bezier(.3, 1.6, .5, 1) both;
  animation-delay: calc(var(--i, 0) * 80ms), calc(var(--i, 0) * 80ms + .5s), calc(var(--i, 0) * 80ms + .5s); }
/* the traced outline is only a drawing aid: it is gone again once the fill is in, so the gaps between the glyphs are exactly the logo's own */
@keyframes osg-trace { 0% { stroke-dashoffset: 1; stroke-opacity: 1; } 70% { stroke-dashoffset: 0; stroke-opacity: 1; } 100% { stroke-dashoffset: 0; stroke-opacity: 0; } }
@keyframes osg-fill { from { fill-opacity: 0; } to { fill-opacity: 1; } }
@keyframes osg-jelly { 0% { transform: scale(.55, .3); } 55% { transform: scale(1.12, 1.2); } 100% { transform: none; } }
@media (prefers-reduced-motion: reduce) { .zone.is-on .logo, .zone.is-on .logo * { animation: none !important; stroke-dashoffset: 0; fill-opacity: 1; transform: none; } }

/* ── 2b. sub-items: row 2 of the bar (the logo cell spans both rows), starting under their parent; phones: a row under the bar ── */
.nav__links { align-items: stretch; }
.nav__item { position: relative; display: flex; align-items: center; gap: 6px; }
.nav__item > a, .nav__links > a { display: flex; align-items: center; align-self: stretch; }
.nav__crumb { display: inline-flex; gap: 6px; margin-right: 0; }
/* the drop hangs from the bar line, its text lined up with the parent's text. Safe area: an invisible trapezoid joins the parent (narrow, top) to the drop (wide, bottom),
   and the drop lingers 300ms after the pointer leaves, so a diagonal move never loses it */
.nav__drop { visibility: hidden; opacity: 0; position: absolute; left: -14px; top: 100%; margin-top: -1px; z-index: 120; display: flex; flex-direction: column; gap: 8px; min-width: calc(100% + 28px); padding: 12px 14px 14px; border: var(--line); background: var(--paper); white-space: nowrap; transition: visibility 0s linear .3s, opacity 0s linear .3s; }
.nav__drop::before { content: ""; position: absolute; left: -1px; right: -1px; bottom: 100%; height: 72px; clip-path: polygon(14px 0, 64px 0, 100% 100%, 0 100%); }
.nav__item:hover .nav__drop, .nav__item:focus-within .nav__drop { visibility: visible; opacity: 1; transition-delay: 0s; }
.nav__row2 { display: none; }
.nav__links a, .nav__row2 a, .float-nav a { text-decoration: none; }
.nav__drop [aria-current="page"], .nav__crumb [aria-current="page"], .nav__row2 [aria-current="page"], .float-nav [aria-current="page"], [data-cat-link][aria-current="true"] { text-decoration: underline; }
.nav__drop a:hover, .nav__row2 a:hover, .float-nav a:hover { text-decoration: underline; }
.nav__links { white-space: nowrap; }
.nav { flex-wrap: wrap; }

/* ── 2c. floating nav — once the full bar has scrolled away the same pages float at the top, transparent, like the corners below ── */
.float-nav { position: fixed; top: 0; left: 0; right: 0; z-index: 100; height: var(--corner-h); display: flex; align-items: center; gap: calc(var(--pad) * 1.5); padding: 0 var(--pad); line-height: 32px; color: #fff; mix-blend-mode: difference; white-space: nowrap; opacity: 0; pointer-events: none; }
.nav-away .float-nav { opacity: 1; pointer-events: auto; }
.float-nav a { color: inherit; }
.float-nav a:hover { background: none; color: inherit; }
.float-nav__about { margin-left: auto; }

/* ── 3. meta strip — one line under the nav (About only) ── */
.meta { display: flex; justify-content: space-between; gap: var(--pad); padding: 8px var(--pad); border-bottom: var(--line); }

/* ── 4. bar — a title across the whole width ────────────── */
.bar { padding: 12px var(--pad); border-bottom: var(--line); background: var(--paper); }
.bar--sticky { position: sticky; top: var(--corner-h); z-index: 3; }   /* opt-in only; nothing uses it now — bars scroll away like any row */
.bar--group { display: flex; justify-content: space-between; gap: var(--pad); align-items: baseline; }
.bar--group > span:last-child { white-space: nowrap; }

/* ── 5. text atoms ───────────────────────────────────────── */
.facts { display: grid; grid-template-columns: 6em 1fr; }
.tags { overflow-wrap: anywhere; }                                     /* [Tag] [Tag] */
.stack > * + * { margin-top: 22px; }
.price { font-variant-numeric: tabular-nums; }

/* ── 6. work index — a tree of names on the left; a click shows only that category's covers on the right ── */
.tree, .tree ul { list-style: none; margin: 0; padding: 0; }
.tree ul { padding-left: calc(var(--pad) * 1.2); }
.tree li > span { font-variant-numeric: tabular-nums; }
.body--index .aside { margin: calc(var(--pad) * 2) calc(var(--pad) * -1) 0; padding: var(--pad) var(--pad) 0; border-top: var(--line); }
.tree a { text-decoration: none; }
[data-view-link][aria-current="true"] { text-decoration: underline; }   /* the release shown right now */
.tree a:hover, .tree a[aria-current="true"] { text-decoration: underline; }   /* the browser's own underline marks hover and the chosen one only */

/* ── 7. table — plain rows, link underlines on hover ───── */
.index { width: 100%; border-collapse: collapse; flex: none; font-variant-numeric: tabular-nums; }
.index th, .index td { border-bottom: var(--line); border-right: var(--line); padding: 6px var(--pad); text-align: left; vertical-align: top; }
.index th:last-child, .index td:last-child { border-right: 0; }
.index td:first-child, .index thead th:first-child { width: 50%; }
.index a { text-decoration: none; }
.index a:hover { background: none; color: inherit; text-decoration: underline; }
.index td:last-child { white-space: nowrap; }

/* ── 8. body — info column 1 : files column 2 ──────────── */
.body { display: grid; grid-template-columns: 1fr 1fr; border-bottom: var(--line); }   /* half and half: an image fills its cell and still fits the screen */
.body > * { min-width: 0; }
.info { border-right: var(--line); padding: var(--pad); }
.info > div { position: sticky; top: calc(var(--corner-h) + var(--pad)); }
.info > div > * + * { margin-top: 22px; }
.info--back > div { display: flex; flex-direction: column; min-height: calc(100svh - var(--nav-h) - var(--bar-h) - var(--corner-h) - var(--pad)); }   /* unscrolled, the panel starts under the bars; its last line must still clear the clock */   /* the panel is one screen tall, so its last line sits at the bottom left, above the clock */
.info > div > .info__back { margin-top: auto; padding-top: 22px; }   /* beats the stack's own 22px gap: it sits at the bottom */
.body__back { display: none; }
.files figure + figure, .files .ph + .ph { border-top: var(--line); }
/* one image per viewport (desktop): each cell is exactly one screen below the sticky bar; the image fills it, never cropped */
@media (min-width: 761px) {
  .files--one .shot { height: calc(100svh - var(--bar-h)); display: grid; place-items: center; scroll-snap-align: start; scroll-margin-top: var(--bar-h); }
  .files--one .shot + .shot { border-top: var(--line); }
  .files--one .shot > * { width: 100%; height: 100%; aspect-ratio: auto; object-fit: contain; }
}

/* gallery: flush tiles, two across, one line between, click → lightbox */
.gallery { overflow: hidden; }
.gallery__grid { display: grid; grid-template-columns: repeat(2, 1fr); margin: 0 -1px -1px 0; }
.tile { display: block; width: 100%; aspect-ratio: 4 / 3; border-right: var(--line); border-bottom: var(--line); background: var(--paper); overflow: hidden; cursor: zoom-in; position: relative; }
.tile img, .tile video { width: 100%; height: 100%; object-fit: cover; }
.tile--static { cursor: default; }
.tile--yt { cursor: pointer; background: #000; }
.gallery--stack .tile--yt img { object-fit: cover; }
.tile__play { position: absolute; right: 0; bottom: 0; padding: 18px var(--pad) 8px 34px; color: #fff; line-height: 1; text-decoration: none; isolation: isolate; }   /* the word is white; the shade behind it is the pseudo-element below */
.tile__play::before { content: ""; position: absolute; z-index: -1; top: -24px; left: -56px; right: -16px; bottom: -16px; background: rgba(0, 0, 0, .18); border-top-left-radius: 110px; filter: blur(22px); pointer-events: none; }   /* a very faint corner shade, its top left very round, blurred until it has no edge */
.tile--yt iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.tile__cap { padding: 8px var(--pad); border-bottom: var(--line); }   /* which typeface / style a specimen shows */
.tile:has(+ .tile__cap) { border-bottom: 0; }
/* store covers: 4 : 5 portrait, six across on desktop, two on phones */
.gallery--portrait .gallery__grid { grid-template-columns: repeat(6, 1fr); }
.gallery--portrait .wtile__img { aspect-ratio: 4 / 5; }
.gallery--portrait .wtile__cap { flex-direction: column; justify-content: flex-start; gap: 0; }
.gallery--portrait .wtile__cap > :last-child { text-align: left; }
/* work tile: a cover that links to its own page; a caption line (title · note) is the only text */
.wtile { display: flex; flex-direction: column; border-right: var(--line); border-bottom: var(--line); text-decoration: none; min-width: 0; }
.wtile:hover { background: none; color: inherit; }
.wtile:hover .wtile__cap > :first-child { text-decoration: underline; }
.wtile__img { display: block; flex: none; min-height: 0; aspect-ratio: 4 / 3; overflow: hidden; background: #000; }   /* the picture keeps its ratio; when a neighbour's caption wraps to two lines the caption cell takes the extra height, not the picture */
.wtile__img img, .wtile__img video { width: 100%; height: 100%; object-fit: cover; }
.wtile__cap { display: flex; flex: 1 0 auto; align-items: flex-start; justify-content: space-between; gap: var(--pad); padding: 12px var(--pad); border-top: var(--line); }
.wtile__cap > :last-child { text-align: right; }
.wtile--fit .wtile__img img { object-fit: contain; }   /* specimens keep their whole picture (the style name is inside it) */
.wtile--wide { grid-column: 1 / -1; }
.wtile--wide .wtile__img { aspect-ratio: 21 / 9; }
.wtile--wide .wtile__img img, .wtile--wide .wtile__img video { object-fit: contain; }   /* the whole thumbnail on its black ground */
/* the work index fills the screen: the tiles stretch, nothing is left empty above the footer */
@media (min-width: 761px) {
  .body--index { min-height: calc(100svh - 72px - 49px); }
  .body--index .files { display: flex; }
  .body--index .view { flex: 1; display: flex; min-width: 0; }
  .body--index .view .gallery { flex: 1; display: flex; }
  .body--index .view .gallery__grid { flex: 1; grid-auto-rows: 1fr; }
  .body--index .wtile__img { min-height: 220px; }
}

/* stack: modules one under another at their own ratio (the Behance order) */
.gallery--stack .gallery__grid { grid-template-columns: 1fr; }
.gallery--stack .tile { aspect-ratio: auto; background: #000; }
.gallery--stack .tile img, .gallery--stack .tile video { object-fit: contain; }

/* type tester — big stage, two sliders on the variable font (they give a little at the named styles), your own text */
.tester { border-bottom: var(--line); }
.tester__stage { background: #000; color: #fff; padding: var(--pad); height: clamp(200px, 34vh, 380px); display: flex; align-items: center; overflow: hidden; }   /* the test window never changes size: the type adapts to it */
.tester__text { width: 100%; outline: none; font-size: var(--fz, clamp(36px, 8vw, 128px)); line-height: 1.15; font-weight: var(--tw, 100); font-stretch: var(--ts, 75%); font-style: var(--ti, normal); white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-all; overflow: visible; caret-color: var(--paper); }   /* a line that runs past the window wraps and the whole block stays centred top to bottom (user 2026-10-19; it was pinned to the first line before) */
.tester__samples { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--pad); padding: 8px var(--pad); line-height: 22px; border-bottom: var(--line); }   /* the four lines sit in the four corners: OFFSETGROUND │ 0123456789 over Many Things Make One │ 내가 하고 싶은 걸 하는 시대 */
.tester__samples button:nth-child(even) { justify-self: end; text-align: right; }
.tester__samples button { line-height: 22px; }
.tester__samples button:hover { text-decoration: underline; }
.tester__ctl { padding: 12px var(--pad) 8px; border-bottom: var(--line); }
.tester__row { display: grid; grid-template-columns: 7em 1fr 3em; align-items: center; gap: var(--pad); }   /* the same 7em label column as every other control column on the site */
.tester__ctl--sw { padding-top: 14px; padding-bottom: 14px; }   /* the switch and the style line are rows of the same grid as the sliders: label │ control │ value */
.tester__ctl--last { border-bottom: 0; }
.tester__row .tg { justify-self: start; }
.tester__row output { text-align: right; font-variant-numeric: tabular-nums; }
.tester__ticks { position: relative; height: var(--lh); margin: 4px calc(3em + var(--pad)) 0 calc(7em + var(--pad)); }   /* the names sit under the handle's centre at each style; the first and last are flush with the ends */
.tester__ticks { margin-right: calc(3em + var(--pad) + var(--hw, 9px)); }
.tester__ticks button { position: absolute; top: 0; padding: 4px 6px; margin: -4px 0; transform: translateX(-50%); white-space: nowrap; }   /* each name is a button: it takes the slider there */
.tester__ticks .is-at, .tester__ticks button:hover { text-decoration: underline; }
.tester__ticks .tk { display: block; font-size: 24px; line-height: 26px; }   /* weight and width are shown, not named: the letter A in each style */
.tester__ticks .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.tester__ticks--w, .tester__ticks--s { height: 26px; }
/* slider: a hairline track and a G3 capsule handle; the cursor fuses into the handle while it is grabbed (see the lens) */
.sl { position: relative; display: block; height: 40px; margin-inline: var(--hw, 9px); cursor: none; touch-action: none; user-select: none; outline: none; }   /* inset by half a handle: at the ends the handle's edge is the column's edge, like the switch below */
.sl__track { position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--ink); }
.sl__handle { position: absolute; top: 50%; left: 0; width: 18px; height: 31px; margin: -15.5px 0 0 -9px; }
.sl__handle::before { content: ""; position: absolute; inset: -9px -14px; }   /* a bigger target than the picture */
.sl__handle svg { display: block; fill: var(--ink); overflow: visible; }
.sl--h .sl__handle { width: 37.5px; height: 24px; margin: -12px 0 0 -18.75px; }
.sl--h .sl__handle::before { inset: -10px -10px; }   /* a finger needs a bigger target */
.sl--h .sl__handle svg { transition: transform var(--spring-t) var(--spring); }
.sl--h.is-grab .sl__handle svg { transform: scale(1.22); }   /* under the finger it swells, quickly and softly */
.sl:focus-visible .sl__handle svg { outline: 1px solid var(--ink); outline-offset: 4px; }
.tester__text { transition: none; }   /* the text follows the handle at once */

/* placeholder — an empty frame with its two diagonals */
.ph { position: relative; width: 100%; aspect-ratio: var(--ar, 4 / 5); background: var(--paper); }
.ph svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.ph svg line { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; }
.ph span { position: absolute; left: var(--pad); top: calc(var(--pad) * .7); background: var(--paper); padding-right: 8px; }

/* split — ruled columns, ratios from --cols */
.split { display: grid; grid-template-columns: var(--cols, 1fr 1fr 1fr); border-bottom: var(--line); }
.split > * { min-width: 0; border-right: var(--line); align-self: stretch; }
.split > :last-child { border-right: 0; }
.split > figure { overflow: hidden; width: 100%; aspect-ratio: auto !important; }   /* a picture in a split keeps its own shape at the top of its cell; a taller row leaves the cell below it empty, never a crop*/
.split > figure img { width: 100%; height: auto; }
/* About's third cell: the easter egg (desktop only) — a plain black-and-white Snake that fills its cell */
.split > .about-game { align-self: stretch; display: grid; grid-template-rows: 1fr auto; min-height: 0; }
.game__field { position: relative; min-height: 0; }
.game canvas { position: absolute; inset: 0; width: 100%; height: 100%; background: var(--paper); cursor: pointer; }
.game__read { display: flex; justify-content: space-between; padding: 12px var(--pad); border-top: var(--line); font-variant-numeric: tabular-nums; }

/* ── 9. specimen — the harness live wordmark, on ink ───── */
.spec { --wm-extra: 0px; background: #000; color: #fff; border-bottom: var(--line); overflow-x: clip; }
.spec__read { display: flex; justify-content: space-between; padding: 8px var(--pad); border-bottom: 1px solid var(--paper); }
.spec__word { position: relative; padding: calc(var(--pad) * 2) 0 calc(var(--pad) * 2 + var(--wm-extra)); margin-inline: var(--pad); cursor: crosshair; user-select: none; font-weight: 300; line-height: 1; }
.spec__line { display: block; }
.spec__line [data-fit] { display: inline-block; white-space: nowrap; }

/* ── 10. footer — three ruled cells (OFFSETGROUND + contact · pages · legal), then a plain © row.
   No thick line, no divider row: the fixed clock and Contact simply float over the last row. ── */
.foot__grid { display: grid; grid-template-columns: repeat(3, 1fr); border-top: var(--line); margin-top: -1px; }   /* -1px: the content's last line and this one are the same line */
.foot__grid > div { display: flex; flex-direction: column; padding: var(--pad); border-right: var(--line); min-width: 0; }
.foot__grid > div:last-child { border-right: 0; }
.foot a { text-decoration: none; }
.foot a:hover { background: none; color: inherit; text-decoration: underline; }
.foot__k { margin-bottom: 8px; }
.foot [aria-current="page"] { text-decoration: underline; }   /* where you are: the browser's own underline, same as the bars */
/* the consent box is only an overlay: it never changes the footer's size */
.foot__kid { padding-left: var(--pad); }
.foot__base { display: flex; justify-content: center; align-items: center; height: var(--corner-h); border-top: var(--line); text-align: center; }
.foot__c { display: none; }

/* ── 11. fixed corners ───────────────────────────────────── */
.corner { position: fixed; bottom: 0; z-index: 100; height: var(--corner-h); padding: 8px var(--pad); line-height: 32px; font-size: var(--fs); color: #fff; mix-blend-mode: difference; white-space: nowrap; font-variant-numeric: tabular-nums; }
.corner--bl { left: 0; }
.corner--br { right: 0; }
.corner a { display: inline-block; padding-inline: 4px; color: inherit; text-decoration: none; }
.corner a:hover { background: #fff; color: #000; }

/* ── 12. popup, lightbox, cookie ─────────────────────────── */
/* one system: a transparent dialog; [Close] stands apart above the box, at its right end; the box is the content */
.pop { width: min(720px, calc(100vw - 2 * var(--pad))); padding: 0; border: 0; background: none; color: var(--ink); font: inherit; overflow: visible; }
.pop[open] { display: flex; flex-direction: column; max-height: calc(100svh - 24px); }   /* dialog is centred: the [Close] row above the box rides with it */
.pop::backdrop { background: var(--veil); }
.pop .close { align-self: flex-end; margin: 0 12px 12px 0; }
.pop--media .close { margin-right: 0; }   /* over a picture or a film the [Close] sits flush with the right edge of the picture */
.pop__body { overflow-y: auto; padding: var(--pad); border: var(--line); background: var(--paper); }   /* like a .txt document in one box */
.pop__body section + section, .pop__body h2 + section { margin-top: 24px; }
.pop__body h3 { margin-bottom: 0; }
.pop--media { width: min(1200px, calc(100vw - 2 * var(--pad))); }
.pop--media .pop__body { padding: 0; border: 0; display: flex; flex-direction: column; align-items: center; background: #000; overflow: hidden; }
.pop--media img { width: auto; max-width: 100%; max-height: calc(100svh - 96px); }
.pop--media video { width: auto; max-width: 100%; max-height: calc(100svh - 150px); }
/* video player: our own. It lies over the bottom of the picture and shows only while the pointer is over the video.
   time · [Pause] · [Sound] (hover → 10 volume steps); a 1px line is the progress. White with difference blend: readable on any picture. */
.pop--media .pop__body { position: relative; }
.player { position: absolute; left: 0; right: 0; bottom: 0; color: #fff; mix-blend-mode: difference; opacity: 0; transition: none; }
.pop--media .pop__body:hover .player, .player:focus-within { opacity: 1; }
@media (hover: none) { .player { opacity: 1; } }
.player__line { height: 9px; cursor: pointer; position: relative; }
.player__line::before { content: ""; position: absolute; left: 0; right: 0; top: 4px; height: 1px; background: #fff; opacity: .4; }
.player__fill { position: absolute; left: 0; top: 4px; height: 1px; background: #fff; width: 0; }
.player__bar { display: flex; align-items: baseline; gap: calc(var(--pad) * 1.5); padding: 4px var(--pad) 12px; font-variant-numeric: tabular-nums; }
.player__bar button { color: #fff; }
.player__bar button:hover { background: none; color: #fff; text-decoration: underline; }
.player__sound { display: inline-flex; align-items: center; gap: 12px; }   /* the ten steps are centred on the word, not hung from its baseline */
.player__vol { display: none; align-items: flex-end; gap: 4px; height: 17px; touch-action: none; padding: 8px 0; margin: -8px 0; box-sizing: content-box; cursor: pointer; }   /* touch-action: a drag on the bar is the bar's, not the page's; the padding makes the touch target taller than the ticks */
.player__sound:hover .player__vol, .player__sound:focus-within .player__vol { display: inline-flex; }
@media (hover: none) { .player__vol { display: inline-flex; } }   /* touch has no hover: the steps are simply there while the controls are */
.player__vol button { display: block; width: 6px; height: 100%; padding: 0; background: none; border: 0; position: relative; cursor: pointer; }
.player__vol button::after { content: ""; position: absolute; left: 2px; bottom: 0; width: 1px; height: 100%; background: #fff; opacity: .35; }
.player__vol button.is-on::after { opacity: 1; width: 2px; left: 2px; }
.player__vol button:hover { background: none; }
/* close: plain text [Close] */
.close:hover, .close:focus-visible { text-decoration: underline; outline: none; }
.cookie { position: fixed; right: 0; bottom: var(--corner-h); z-index: 200; width: min(360px, 100vw); padding: var(--pad); border: var(--line); border-right: 0; background: var(--paper); }
.cookie p + p { margin-top: 12px; }
.cookie button:hover { background: var(--ink); color: var(--paper); }

/* ── 13. phones ─────────────────────────────────────────── */
@media (max-width: 760px) {
  .wtile__cap { flex-direction: column; justify-content: flex-start; gap: 0; }   /* stacked lines stay together at the top when the cell is taller */
  .wtile__cap > :last-child { text-align: left; }
  :root { --pad: 16px; --fs-mark: 40px; --nav-h: 110px; }
  body:has(.nav--sub) { --nav-h: 159px; }
  .nav__drop, .nav__crumb { display: none !important; }
  .nav__row2 { flex: 1 0 100%; display: flex; gap: calc(var(--pad) * 1.5); padding: 12px var(--pad); border-top: var(--line); flex-wrap: wrap; }
  /* the work index fills the screen on phones too: tree on top, tiles stretch below it */
  .body--index { min-height: calc(100svh - var(--nav-h) - 49px); grid-template-rows: auto 1fr; }
  .body--index .files, .body--index .view, .body--index .view .gallery { display: flex; flex-direction: column; }
  .body--index .view, .body--index .view .gallery { flex: 1; }
  .body--index .view .gallery__grid { flex: 1; grid-template-columns: 1fr; grid-auto-rows: 1fr; }   /* one column: full-width covers, never narrow tall crops */
  .body--index .wtile__img { min-height: 150px; }
  .nav { flex-wrap: wrap; }
  .nav__logo { flex: 1 0 100%; width: auto; border-right: 0; border-bottom: var(--line); min-height: 64px; }
  .split > .about-game { display: none; }   /* no game on phones */
  .split > :has(+ .about-game) { border-bottom: 0; }   /* the cell before the hidden game is now the last: the split's own bottom line is the only line */
  html, body { overflow-x: clip; }   /* nothing on the page is meant to scroll sideways */
  .bar--group { flex-direction: column; gap: 0; }   /* a long tag list wraps under the title instead of pushing the page wider */
  .bar--group > span:last-child { white-space: normal; }
  .bar--echo > span:first-child { display: none; }   /* the phone's sub row already names this page; the title row keeps only its tags */
  .gallery--portrait .gallery__grid { grid-template-columns: repeat(2, 1fr); }
  .nav__links { flex: 1; gap: var(--pad); min-height: 44px; padding-right: 0; }
  .nav__about { min-height: 44px; }
  .index .opt { display: none; }
  .index td:first-child, .index thead th:first-child { width: auto; }
  .index th:first-child, .index td:first-child { border-right: 0; }
  .body, .split { grid-template-columns: 1fr; }
  .split > * { border-right: 0; border-bottom: var(--line); }
  .split > :last-child { border-bottom: 0; }
  .info { border-right: 0; border-bottom: var(--line); }
  .info--back > div { min-height: 0; }
  .info__back { display: none; }
  .body__back { display: block; padding: var(--pad); border-top: var(--line); }   /* on a phone the way back closes the post, after the media */
  .info > div { position: static; }
  .foot__grid { grid-template-columns: 1fr 1fr; }
  .foot__grid > div { border-bottom: var(--line); }
  .foot__grid > div:nth-child(2) { border-right: 0; }
  .foot__grid > :last-child { grid-column: 1 / -1; border-right: 0; border-bottom: 0; }
  .foot__base { border-top: 0; font-size: 0; }   /* phones: the row is only room for the floating clock and Contact; © lives in the Legal cell */
  .foot__c { display: block; }
}

/* cursor: the system cursor is replaced by the dot / capsule everywhere (it lives in the top layer, so it also shows over the privacy policy and the lightbox), except on text fields */
.lens { position: fixed; inset: 0; width: 100vw; height: 100vh; margin: 0; padding: 0; border: 0; background: transparent; overflow: visible; pointer-events: none; z-index: 2147483647; mix-blend-mode: difference; }
html.has-lens, html.has-lens * { cursor: none !important; }
html.has-lens input, html.has-lens textarea, html.has-lens [contenteditable] { cursor: text !important; }
html.lens-fallback .lens { display: none; }
html.lens-fallback.has-lens, html.lens-fallback.has-lens * { cursor: auto !important; }

/* About: the logos play in turn, endlessly, bottom right of the credit cell — small and tidy; one logo is shown at a time, all anchored to the corner */
.about-credit { position: relative; }
.about-credit .stack { padding-bottom: calc(24px + var(--pad)); }   /* room for the looping logo in the corner */
.about-loop { position: absolute; right: var(--pad); bottom: var(--pad); width: calc(24px * 1085 / 259); height: 24px; pointer-events: none; }
.about-loop .zone { position: absolute; right: 0; bottom: 0; height: 24px; padding: 0; }
.about-loop .zone--mark { width: calc(24px * 1085 / 259); }
.about-loop .zone--blocks { width: calc(24px * 350 / 240); }
.about-loop .zone--ofstgrnd { width: calc(24px * 640 / 630); }
.about-loop .logo { height: 24px; width: auto; max-height: none; visibility: hidden; overflow: visible; }
.about-loop .zone.is-on .logo { visibility: visible; }

.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }   /* the page's own h1, for readers and indexes; the visible title row is the h2 */

/* switch (the Italic toggle): a hairline G3 capsule track and a G3 capsule knob.
   pointer: 62 × 24 track, 27 × 16 knob; touch: 63 × 28 track, 37.5 × 24 knob — the proportions of an iOS 26 switch.
   Off: outline + black knob. On: black track + white knob. The knob only ever moves by transform (translateX + scale): no layout, no repaint of the page,
   which is what keeps it smooth on a phone. Held, it is bigger and rides the rail only. */
.tg { display: inline-flex; align-items: center; cursor: none; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.tg__track { position: relative; display: inline-block; width: 62px; height: 24px; }
.tg__bg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.tg__bg path { fill: var(--paper); stroke: var(--ink); stroke-width: 1; transition: fill .22s ease; }
.tg__knob { position: absolute; top: 4px; left: 4px; width: 27px; height: 16px; transform: translate3d(var(--kx, 0px), 0, 0) scale(var(--ks, 1)); transition: transform var(--spring-t) var(--spring); will-change: transform; --run: 27px; --big: 1; }   /* pointer: the knob keeps its size, it is only dragged */
.tg__knob svg { display: block; overflow: visible; fill: var(--ink); transition: fill .22s ease; }
.tg[aria-checked="true"] .tg__bg path { fill: var(--ink); }
.tg[aria-checked="true"] .tg__knob { --kx: var(--run); }
.tg[aria-checked="true"] .tg__knob svg { fill: var(--paper); }
.tg:active .tg__knob, .tg.is-drag .tg__knob, .tg.is-moving .tg__knob { --ks: var(--big); }   /* held (or travelling): bigger */
.tg.is-drag .tg__knob { transition: none; }   /* the knob is the hand's while it is held */
.tg--touch { cursor: auto; }
.tg--touch .tg__track { width: 63px; height: 28px; }
.tg--touch .tg__knob { top: 2px; left: 2px; width: 37.5px; height: 24px; --run: 21.5px; --big: 1.45; transition: transform .34s cubic-bezier(.25, 1.1, .4, 1); }   /* quick, soft spring with a small overshoot */
.tg--touch .tg__bg path, .tg--touch .tg__knob svg { transition-duration: .24s; transition-timing-function: cubic-bezier(.3, 0, .2, 1); }
.tg--touch[aria-checked="true"].is-drag .tg__knob path, .tg--touch[aria-checked="true"].is-moving .tg__knob path { stroke: var(--ink); stroke-width: 1.2; }   /* on and held: the pale knob grows past the dark track, so it gets a rim; off, the dark knob already shows on the page (a pale rim only cut notches out of the track outline) */
.tg:focus-visible { outline: 1px solid var(--ink); outline-offset: 4px; }

/* ── the bracket rule ──
   The words in the bars (top bar, floating bar, the footer's page list) are taken as pressable: no marks there; "you are here" is the underline, as always.
   Everywhere else a pressable thing is written in [ ]. An underline then means one thing: it leaves the site (a link out, mail).
   The one you are on is not pressable, so it has no brackets (the release switch). */
a { text-decoration: none; }   /* the browser's own underline on every link is switched off: an underline now carries one meaning */
a[href^="mailto:"], a[href^="http"] { text-decoration: underline; }
.j:not([data-view-link])::before { content: "["; }
.j:not([data-view-link])::after { content: "]"; }   /* the release switch (data-view-link) is a bar of its own: plain words, the shown one underlined */
.tile__play { text-decoration: none; }
/* bottom left = status: the clock, then [Display], which opens the reader's two controls to its right; bottom right = ways out.
   On phones the same line: while open the clock and the links step aside (kept in place, hidden) so the controls fit. */
.corner--bl { display: flex; align-items: center; gap: 14px; }   /* the status words sit close, like one phrase */
.corner__tools { display: flex; gap: 14px; }
.corner__tools[hidden] { display: none !important; }
.corner__display, .corner__tools button { color: inherit; padding: 0; }
.corner__tools button:hover span { text-decoration: underline; }
.foot__ctl { display: none; padding: 0; }
.foot__tools[hidden] { display: none !important; }
.foot__ctl:hover span { text-decoration: underline; }
@media (max-width: 760px) {
  .foot__ctl, .foot__tools { display: none !important; }   /* the footer copy is for nobody: the floating one below serves phones too */
  .corner__display { order: -1; }   /* phones: [Display] stands first on the line and never moves; opened, the two controls take the clock's place */
  body.display-open [data-clock] { display: none !important; }
  body.display-open .corner--br { visibility: hidden; }
}

/* ── album player: head = art (a third of the width, square) │ deck (now · time · progress · controls); the tracklist under both ── */
.album__head { display: grid; grid-template-columns: minmax(200px, 34%) 1fr; border-bottom: var(--line); }
.album__art { position: relative; aspect-ratio: 1 / 1; background: #000; overflow: hidden; padding: 0; border-right: var(--line); cursor: pointer; }
.album__art img { width: 100%; height: 100%; object-fit: cover; }
.album__deck { display: flex; flex-direction: column; justify-content: flex-end; gap: 4px; padding: var(--pad); min-width: 0; font-variant-numeric: tabular-nums; }
.album__now { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.album__line { height: 9px; cursor: pointer; position: relative; margin: 6px 0; }
.album__line::before { content: ""; position: absolute; left: 0; right: 0; top: 4px; height: 1px; background: var(--ink); opacity: .4; }
.album__fill { position: absolute; left: 0; top: 4px; height: 1px; background: var(--ink); width: 0; }
.album__ctl { display: flex; gap: var(--pad); }
.album__ctl button { color: inherit; }
.album__sound { display: inline-flex; align-items: center; gap: 12px; }   /* [Sound] mutes; the ten steps open beside it, like the video player's */
.album__vol { display: none; align-items: flex-end; gap: 4px; height: 17px; touch-action: none; padding: 8px 0; margin: -8px 0; box-sizing: content-box; cursor: pointer; }
.album__sound:hover .album__vol, .album__sound:focus-within .album__vol, .album__sound.is-open .album__vol { display: inline-flex; }
@media (hover: none) { .album__vol { display: inline-flex; } }
.album__vol button { display: block; width: 6px; height: 100%; padding: 0; position: relative; }
.album__vol button::after { content: ""; position: absolute; left: 2px; bottom: 0; width: 1px; height: 100%; background: var(--ink); opacity: .35; }
.album__vol button.is-on::after { opacity: 1; width: 2px; }
.album__list { list-style: none; margin: 0; padding: 12px 0 var(--pad); }
.album__list button { display: grid; grid-template-columns: 3em 1fr auto; width: 100%; padding: 6px var(--pad); text-align: left; font-variant-numeric: tabular-nums; }
.album__list button:hover span:nth-child(2), .album__list button.is-at span:nth-child(2) { text-decoration: underline; }   /* a list of pressables: no marks; the playing one is underlined, like any "you are here" */
.album__list button span:last-child { text-align: right; }
@media (max-width: 760px) { .album__head { grid-template-columns: 200px 1fr; } .album__ctl { gap: 14px; flex-wrap: wrap; } }

/* ── 14. lacemaker — switch rows in the panel, the cloth on ink in the files column ── */
.choices dd { display: flex; flex-wrap: wrap; gap: 0 14px; }
.choices button[aria-pressed="true"] { text-decoration: underline; }   /* the chosen word: the browser's own underline, as in every switch list */
@media (hover: hover) { .choices button:hover { text-decoration: underline; } }
.lace { position: sticky; top: var(--corner-h); background: #000; display: flex; justify-content: center; align-items: center; height: max(360px, calc(100svh - var(--nav-h) - var(--bar-h) - var(--corner-h))); overflow: hidden; }   /* ink, like the tester window; the whole 4:5 cloth fits the screen */
.lace[data-ground="white"], .lace[data-ground="clear"] { background: #fff; }
.lace canvas { display: block; width: auto; height: auto; max-width: 100%; max-height: 100%; object-fit: cover; image-rendering: auto; }   /* 4:5 covers its whole cell; the other shapes are sized to fit, so nothing is cropped */
.lace.is-mosaic canvas { image-rendering: pixelated; }
.lace.is-actual { overflow: auto; justify-content: flex-start; align-items: flex-start; }
.lace.is-actual canvas { max-width: none; max-height: none; }
@media (max-width: 760px) { .body--lace .files { order: -1; position: sticky; top: 0; z-index: 5; } .lace { position: static; height: auto; aspect-ratio: 1 / 1; } }   /* phones: the cloth first and held at the top (a square, full width: 1:1 fills it, 4:5 and 9:16 sit inside with bars at the sides), so every change is seen while the controls scroll under it */
/* UI controls: the control column is ruled like the tester — one cell per function, lines between, no gaps */
.info--rows { padding: 0; }
.info--rows > div > * + * { margin-top: 0; }
.info--rows .info__back { padding-left: var(--pad); padding-right: var(--pad); padding-bottom: var(--pad); }   /* the link up to the collection keeps the same inset as every cell */
.ui-row { display: grid; grid-template-columns: 5.2em max-content minmax(0, 1fr); align-items: center; column-gap: var(--pad); min-height: 56px; padding: 10px var(--pad); border-bottom: var(--line); }
.ui-row__c { display: flex; align-items: center; gap: var(--gap-ui, 12px); min-width: 0; }
.ui-row output { text-align: left; min-width: 4.5em; margin-left: calc(var(--gap-ui, 12px) - var(--pad)); }   /* the value's name sits one --gap-ui after its control (same gap as between the capsules), not a column away */   /* the value reads right after its control, not at the far edge of the row */
.ui-row--sl { align-items: start; padding-top: 6px; padding-bottom: 6px; }
.ui-row--sl .ui-row__k, .ui-row--sl output { line-height: 40px; }
.ui-cell { padding: 14px var(--pad); border-bottom: var(--line); }
/* two short controls share one ruled line when the column is wide enough; narrower, they stack */
.ui-pair { display: grid; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1400px) {
  .ui-pair { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .ui-pair > .ui-row { grid-template-columns: 5.2em minmax(0, 1fr); }
  .ui-pair > .ui-row output { display: none; }
  .ui-pair > .ui-row:first-child { border-right: var(--line); }
}
/* the colour bar, its well, and the PNG / JPG capsules sit the same --gap-ui apart (the row's gap); nothing adds its own margin */
.pill + .pill { margin-left: 0; }
/* slider in a row: never longer than the other controls (about half the column on a PC) */
.ui-sl { position: relative; display: block; width: 17em; max-width: 100%; }
.ui-sl { margin-left: calc(-1 * var(--hw, 9px)); }   /* the track (inset by half a handle) starts on the same line as every bar's outline */
.ui-sl .sl { margin-inline: var(--hw, 9px); }
.ui-sl__ticks { position: relative; display: block; height: var(--lh); margin-inline: var(--hw, 9px); }
.ui-sl__ticks button { position: absolute; top: 0; padding: 0 4px; margin: 0; transform: translateX(-50%); white-space: nowrap; }   /* every name is centred on its handle position, the end ones too */
.ui-sl__ticks .is-at, .ui-sl__ticks button:hover { text-decoration: underline; }
/* segmented bar (iOS 26 floating pill, in ink): G3 outline track; a G3 pill, white with a difference blend, sits over the words — whatever it covers is inverted, glyph by glyph */
/* one motion for every bar: the colour bar's damped spring (a soft rebound: it overshoots a little, then settles) as a CSS curve, so every segmented control moves with the same character */
:root { --spring-t: 0.77s; --spring: linear(0, 0.025, 0.083, 0.165, 0.261, 0.369, 0.472, 0.571, 0.663, 0.751, 0.823, 0.885, 0.937, 0.978, 1.011, 1.035, 1.051, 1.061, 1.066, 1.067, 1.065, 1.061, 1.055, 1.048, 1.041, 1.034, 1.028, 1.021, 1.016, 1.011, 1.007, 1.004, 1.001, 0.999, 0.998, 0.996, 0.996, 0.996, 0.996, 0.996, 1); }
.seg { position: relative; display: inline-flex; flex: none; height: 36px; padding: 4px; transition: padding-left var(--spring-t) var(--spring), padding-right var(--spring-t) var(--spring); visibility: hidden; isolation: isolate; user-select: none; -webkit-user-select: none; touch-action: pan-y; }
.seg.is-ready { visibility: visible; }
.seg__bg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 0; }
.seg__bg path { fill: var(--paper); stroke: var(--ink); stroke-width: 1; }
.seg button { position: relative; z-index: 1; min-width: 50px; padding: 0 16px; margin: 0 1px; transition: transform var(--spring-t) var(--spring); line-height: 28px; text-align: center; white-space: nowrap; }   /* 50 ≥ the narrowest G3 pill at this height (3.35 half-heights): the pill never spills out of its cell, so its inset is 3 px on every side */
.seg__knob { position: absolute; top: 4px; left: 0; z-index: 2; pointer-events: none; mix-blend-mode: difference; transition: transform var(--spring-t) var(--spring), width var(--spring-t) var(--spring); will-change: transform; }
.seg__knob svg { display: block; overflow: visible; fill: #fff; transition: transform var(--spring-t) var(--spring); transform-origin: 50% 50%; }
.seg.is-drag .seg__knob { transition: none; }
.seg__knob svg, .seg__ring svg { transform: scale(calc(var(--sw, 1) * var(--qx, 1)), calc(var(--sh, 1) * var(--qy, 1))); }
.seg--touch.is-drag .seg__knob svg, .seg--touch.is-drag .seg__ring svg { --sw: var(--gx, 1); --sh: var(--gy, 1); }   /* under the finger the pill grows beyond the body, by the same 3 px on every side */
.seg__ring { position: absolute; top: 4px; left: 0; z-index: 3; pointer-events: none; opacity: 0; transition: opacity .15s; }
.seg__ring svg { display: block; overflow: visible; transition: transform var(--spring-t) var(--spring); transform-origin: 50% 50%; }
.seg__ring path { fill: none; stroke: var(--ink); stroke-width: 1; }
.seg--touch.is-drag .seg__ring { opacity: 1; }   /* held: the pill gets an outline, since it can be the colour of the ground behind it */
.seg--fill .seg__ring { display: none; }
.seg--pointer { cursor: none; }
@media (hover: hover) { .seg button[aria-checked="false"]:hover { text-decoration: underline; } }
.seg button:focus-visible { outline: 1px solid var(--ink); outline-offset: -5px; }
/* optical centre: lowercase words read low, so caps and figures alone look high in the same line box — they go 1 px down; a ratio frame centres on the figures */
.seg button.seg__caps, .pill--caps .pill__in { position: relative; top: 1px; }
.seg__icon { display: inline-block; margin-left: 4px; vertical-align: middle; position: relative; top: -1.5px; fill: none; stroke: currentColor; stroke-width: 1px; }   /* not chosen: an outline */
.seg__icon-f { fill: currentColor; stroke: none; }   /* clipped by the pill's outline (see behaviors: a clipPath per icon) */   /* chosen: filled (the pill's difference blend inverts it with the word) */   /* close to its word, optically centred on the x-height */   /* a ratio's frame, after its name */
/* colour bars: the pill is the colour itself (no inversion); the chosen word takes black or white, whichever reads */
.seg--fill .seg__knob { z-index: 2; mix-blend-mode: normal; }
.seg--fill .seg__knob svg { fill: var(--knob, #fff); stroke: var(--ink); stroke-width: 1; overflow: visible; }   /* every colour is outlined, once: one 1 px ink line, no inner line */
.seg--fill .seg__knob path { transition: fill .16s ease-out, fill-opacity .16s ease-out; }   /* see-through ⇄ colour: a quick, soft melt rather than a cut */
.seg--fill button { transition: color .15s; }
/* swatch bar: one bar of colour chips; the chosen chip becomes the pill itself */
.seg button:first-of-type { margin-left: 0; } .seg button:last-of-type { margin-right: 0; }   /* the bar's own padding sets the end distance */
.seg button.seg__sw { min-width: 21px; width: 21px; padding: 0; margin: 0 calc(var(--gap-ui, 12px) / 2); }   /* chip → chip = the row's --gap-ui, as bar → well and PNG → JPG */
.seg button.seg__sw:first-of-type { margin-left: 0; } .seg button.seg__sw:last-of-type { margin-right: 0; }
.seg__chip { position: absolute; left: 50%; top: 50%; margin: -7px 0 0 -11px; overflow: visible; pointer-events: none; }
.seg__chip path { fill: var(--c); stroke: var(--ink); stroke-width: 1; }   /* a G3 capsule, ringed in ink: white shows on a white page, black on a black one */
/* capsule button: a G3 outline around a few words; it grows with what is put in it */
.pill { position: relative; display: inline-flex; align-items: center; height: 40px; padding: 0 18px; flex: none; overflow: visible; transition: width .34s cubic-bezier(.25, 1.1, .4, 1); }
.pill__bg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.pill__bg path { fill: var(--paper); stroke: var(--ink); stroke-width: 1; }
.pill__in { position: relative; display: inline-flex; align-items: center; gap: 10px; white-space: nowrap; }
.pill__in img { width: 26px; height: 26px; object-fit: cover; flex: none; clip-path: path('M26.00 13.00 L25.99 16.55 L25.95 17.93 L25.88 18.97 L25.79 19.83 L25.67 20.57 L25.52 21.23 L25.34 21.82 L25.14 22.35 L24.91 22.83 L24.64 23.26 L24.35 23.66 L24.02 24.02 L23.66 24.35 L23.26 24.64 L22.83 24.91 L22.35 25.14 L21.82 25.34 L21.23 25.52 L20.57 25.67 L19.83 25.79 L18.97 25.88 L17.93 25.95 L16.55 25.99 L13.00 26.00 L9.45 25.99 L8.07 25.95 L7.03 25.88 L6.17 25.79 L5.43 25.67 L4.77 25.52 L4.18 25.34 L3.65 25.14 L3.17 24.91 L2.74 24.64 L2.34 24.35 L1.98 24.02 L1.65 23.66 L1.36 23.26 L1.09 22.83 L0.86 22.35 L0.66 21.82 L0.48 21.23 L0.33 20.57 L0.21 19.83 L0.12 18.97 L0.05 17.93 L0.01 16.55 L0.00 13.00 L0.01 9.45 L0.05 8.07 L0.12 7.03 L0.21 6.17 L0.33 5.43 L0.48 4.77 L0.66 4.18 L0.86 3.65 L1.09 3.17 L1.36 2.74 L1.65 2.34 L1.98 1.98 L2.34 1.65 L2.74 1.36 L3.17 1.09 L3.65 0.86 L4.18 0.66 L4.77 0.48 L5.43 0.33 L6.17 0.21 L7.03 0.12 L8.07 0.05 L9.45 0.01 L13.00 0.00 L16.55 0.01 L17.93 0.05 L18.97 0.12 L19.83 0.21 L20.57 0.33 L21.23 0.48 L21.82 0.66 L22.35 0.86 L22.83 1.09 L23.26 1.36 L23.66 1.65 L24.02 1.98 L24.35 2.34 L24.64 2.74 L24.91 3.17 L25.14 3.65 L25.34 4.18 L25.52 4.77 L25.67 5.43 L25.79 6.17 L25.88 7.03 L25.95 8.07 L25.99 9.45 Z'); }   /* the thumbnail of the uploaded picture: a soft G3-like square (superellipse), never a sharp one */
.pill.is-over .pill__bg path, .pill:not(.pill--well):hover .pill__bg path { fill: var(--ink); }
.pill.is-over, .pill:not(.pill--well):hover { color: var(--paper); }
.pill--well { width: 58px; height: 36px; padding: 0; }   /* the colour well: a G3 capsule with a G3 capsule of colour inside, 3 px all round (as the segmented bar's pill) */
.pill--well .pill__in { position: static; }   /* the swatch is placed against the capsule itself */
.pill__sw { position: absolute; inset: 3px; width: calc(100% - 6px); height: calc(100% - 6px); overflow: visible; pointer-events: none; }
.pill__sw path { stroke: none; }   /* the well is one outline (its own capsule) around the colour; a second line inside it would read as a double line */
.ui-row .tg { justify-self: start; }
/* the tester as its own page: controls left, the window fills the right column */
.body--tester .info { border-right: var(--line); }
.body--tester .tester__ctl, .body--tester .tester__samples { border-bottom: var(--line); }
.tester__stage--tall { height: max(320px, calc(100svh - var(--nav-h) - var(--bar-h) - var(--corner-h))); position: sticky; top: var(--corner-h); }
/* sliders in the tester never run the whole column on a PC */
.tester__row { max-width: 30em; }
/* controls that start on the same line as the bars above: the slider's track (inset by half a handle) starts where a bar's outline does */
.tester__row .sl { margin-left: 0; margin-right: var(--hw, 9px); }
.tester__ticks { margin-left: calc(7em + var(--pad)); }
@media (min-width: 1180px) { .tester__pair { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); border-bottom: var(--line); } .tester__pair > .tester__ctl { border-bottom: 0; } .tester__pair > .tester__ctl:first-child { border-right: var(--line); } .tester__pair .tester__row { grid-template-columns: 7em max-content 1fr; } .tester__pair output { text-align: left; } }   /* the italic angle reads right after its switch */
.tester__ticks { max-width: calc(30em - 10em - 2 * var(--pad) - var(--hw, 9px)); }   /* the names span the track only: the row's label and value columns and the handle insets come off */
@media (max-width: 760px) {
  .ui-row { grid-template-columns: 5.2em minmax(0, 1fr); } .ui-row output { display: none; }
  .ui-row__c { flex-wrap: wrap; row-gap: 8px; }
  .seg button { padding: 0 9px; min-width: 47px; }
  .seg--fill { --gap-ui: 7px; }   /* only the color chips get the tighter spacing; PNG / JPG and the bar → well gap keep the full 12 px */
  .seg button.seg__sw { min-width: 14px; width: 14px; }   /* narrow screens: round chips, never packed tight */
  .ui-sl { width: calc(100% - 2.4em); }   /* room on both sides for the end names, which are centred on their stops */
  .tester__stage--tall { position: static; height: 26svh; }   /* on a phone the result comes first and stays in view while the controls are used */
  .body--tester .files { order: -1; position: sticky; top: var(--corner-h, 0px); z-index: 3; }
}
/* colour popover: opens just right of the colour well; a G3 outline panel (the same capsule family), paper inside */
.ui-row__c { position: relative; }
.cp { position: absolute; left: calc(100% + 10px); top: 50%; z-index: 20; width: 232px; padding: 14px; background: var(--paper); border: var(--line); border-radius: 18px / 18px; display: grid; gap: 12px; transform: translateY(-50%); }
.cp[hidden] { display: none; }
@media (max-width: 760px) {   /* phones: the color panel is a sheet at the bottom of the screen, never beside the well */
  .cp { position: fixed; left: 16px; right: 16px; top: auto; bottom: 16px; width: auto; transform: none; z-index: 60; padding: 16px; gap: 16px; border-radius: 22px / 22px; }
  .cp__sv { height: 176px; }
  .cp__hue { height: 24px; margin: 0 14px; border-radius: 12px; }
  .cp__hex input { height: 40px; border-radius: 20px; }
}
.cp__sv { position: relative; height: 132px; border: var(--line); border-radius: 12px; touch-action: none; cursor: crosshair; background: linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(var(--h, 160), 100%, 50%)); }
.cp__dot { position: absolute; width: 14px; height: 14px; margin: -7px 0 0 -7px; border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1px #000; pointer-events: none; }
.cp__hue { position: relative; height: 18px; margin: 0 9px; border-radius: 9px; touch-action: none; cursor: crosshair; background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00); box-shadow: 0 0 0 1px var(--ink); }
.cp__handle { position: absolute; top: 50%; left: 0; width: 18px; height: 31px; margin: -15.5px 0 0 -9px; pointer-events: none; }
.cp__handle svg { display: block; overflow: visible; fill: var(--ink); stroke: var(--paper); stroke-width: 2; paint-order: stroke; }
.cp__hex { display: flex; align-items: center; gap: 10px; }
.cp__hex input { flex: 1; min-width: 0; height: 30px; padding: 0 10px; border: var(--line); border-radius: 15px; background: var(--paper); color: var(--ink); text-transform: lowercase; }
.cp__hex input:focus-visible { outline: 1px solid var(--ink); outline-offset: 2px; }
@media (max-width: 760px) { .lace, .tester__stage--tall { border-bottom: var(--line); } }   /* on a phone the picture sits above the controls: a rule separates them */
.lace .pill[data-lace-ok] { position: absolute; left: 12px; bottom: 12px; min-width: 64px; justify-content: center; z-index: 4; display: none; }   /* bottom left of the picture: the progress in percent while it works, then "Success!" (a tap dismisses it) */
.lace .pill[data-lace-ok].is-on { display: inline-flex; }
.info__ver { display: flex; justify-content: space-between; align-items: baseline; }
#tools { border-bottom: var(--line); }   /* the two tools close with a rule, as every other block */
@media (max-width: 760px) { #tools .gallery__grid { grid-template-columns: 1fr; } }   /* phones: one above the other, full width */
.ui-row--post .ui-row__c { align-items: flex-start; gap: 22px; }
.ui-row--post .tg { margin-top: calc((40px - 24px) / 2); flex: none; }   /* the switch sits on the slider's line */
.ui-row--post .ui-sl { flex: none; width: 13.5em; }
@media (max-width: 760px) { .ui-row--post .ui-sl { flex: 1 1 auto; width: auto; margin-right: 1.2em; } }
.ui-sl.is-off { opacity: .32; pointer-events: none; }   /* Posterize off: its strength cannot be moved */
