/* irchiinnuss design: the hand-coded website studio */

/* Helvetica on machines that have it, TeX Gyre Heros (GUST licence) everywhere else */
@font-face {
  font-family: "Heros";
  src: local("Helvetica"), local("Helvetica Neue"),
       url("../assets/fonts/texgyreheros-regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Share Tech Mono";
  src: url("../assets/fonts/share-tech-mono.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Handjet";
  src: url("../assets/fonts/handjet.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
/* the studio's line: LT Terminal Mono (the user's copy, used on the user's say-so) */
@font-face {
  font-family: "LT Terminal Mono";
  src: url("../assets/fonts/lt-terminalmono.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* the printed thesis: TeX Gyre Heros Cn Bold (GUST licence, same family as Heros) */
@font-face {
  font-family: "Heros Cn";
  src: url("../assets/fonts/texgyreheroscn-bold.woff") format("woff");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
/* the quote: Bebas Neue (SIL OFL 1.1, The Bebas Neue Project Authors): tall, tight caps */
@font-face {
  font-family: "Bebas Neue";
  src: url("../assets/fonts/bebas-neue.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- tokens ---------- */

:root {
  --ink: #fff;
  --paper: #000;
  --fg: var(--ink);
  --bg: var(--paper);
  /* 56% keeps small grey text at 4.5:1 on white as well as on black */
  --mute: color-mix(in srgb, var(--fg) 56%, transparent);
  --line: color-mix(in srgb, var(--fg) 22%, transparent);
  /* the one colour: electric blue, only ever a solid block with white on it */
  --accent: #2020ff;
  --accent-ink: #fff;
  /* links in the terminal: the accent lifted for black (the page's own links are ink) */
  --link: #8ea2ff;
  --visited: #8ea2ff;

  --f-sans: "Heros", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --f-term: "Share Tech Mono", ui-monospace, Consolas, Menlo, monospace;
  --f-pix: "Handjet", "Share Tech Mono", ui-monospace, monospace;
  /* the labels: uppercase mono that grows with the window, never under 13px, ~16 wide */
  --ui-size: clamp(13px, calc(.36vw + 8.6px), 17px);

  /* the grid: Material 3 window classes, 4 / 8 / 12 columns, margins and gutters 16 then 24 */
  --cols: 4;
  --g: 16px;
  --head-max: clamp(56px, min(26vh, 20vw), 260px);
  /* the bar along the top: the one thing that stays put while you scroll */
  --bar-h: 40px;

  /* Material 3 motion (Easing and duration). Emphasized is a path; browsers with linear() get it below */
  --md-ease-emphasized: cubic-bezier(.2, 0, 0, 1);
  --md-ease-emphasized-decelerate: cubic-bezier(.05, .7, .1, 1);
  --md-ease-emphasized-accelerate: cubic-bezier(.3, 0, .8, .15);
  --md-ease-standard: cubic-bezier(.2, 0, 0, 1);
  --md-short2: 100ms;
  --md-short3: 150ms;
  --md-short4: 200ms;
  --md-medium2: 300ms;
  --md-medium4: 400ms;
  --md-long2: 500ms;
  --md-long4: 600ms;
  --md-xlong2: 800ms;
  /* state layers */
  --md-hover: .08;
  --md-focus: .1;
  --md-press: .1;
  color-scheme: dark;
}
@media (min-width: 600px) { :root { --g: 24px; --cols: 8; } }
@media (min-width: 840px) { :root { --cols: 12; } }
@supports (transition-timing-function: linear(0, 1)) {
  :root {
    --md-ease-emphasized: linear(0, 0.005 2.5%, 0.0206 5%, 0.0453 7.25%, 0.078 9.25%, 0.1174 11%, 0.1622 12.5%, 0.2104 13.75%, 0.2592 14.75%, 0.3045 15.5%, 0.3406 16%, 0.3836 16.5%, 0.4566 17.25%, 0.5198 18%, 0.5711 18.75%, 0.6125 19.5%, 0.6562 20.5%, 0.6985 21.75%, 0.7376 23.25%, 0.7772 25.25%, 0.8144 27.75%, 0.8504 31%, 0.8847 35.25%, 0.9161 40.75%, 0.9446 48%, 0.9685 57.5%, 0.9871 70.25%, 0.998 87.25%, 1);
  }
}
html.invert { --ink: #000; --paper: #fff; color-scheme: light; }

/* a section that inverts the page: white panels between the black ones */
.flip {
  --fg: var(--paper);
  --bg: var(--ink);
  --mute: color-mix(in srgb, var(--fg) 56%, transparent);
  --line: color-mix(in srgb, var(--fg) 22%, transparent);
}

/* ---------- base ---------- */

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

html {
  background: var(--paper);
  color: var(--ink);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scrollbar-gutter: stable;
  scroll-padding-top: calc(var(--bar-h) + 16px);
}
body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font: 400 16px/1.4 var(--f-sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}
/* with a mouse the page's scrollbar is drawn (.page-scrollbar, below): the native one goes, and
   with it the lane it took out of the page (the gutter stays for the rare classic bar elsewhere) */
@media (hover: hover) and (pointer: fine) {
  html.js { scrollbar-gutter: auto; scrollbar-width: none; }
  html.js::-webkit-scrollbar { display: none; }
}
/* Lenis, the smooth scroll (js/vendor/lenis): the page keeps its own height, and a box that
   scrolls by itself (the console, the terminal) keeps its scroll to itself */
html.lenis, html.lenis body { height: auto; }
.lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
.lenis [data-lenis-prevent] { overscroll-behavior: contain; }
img, svg, canvas { display: block; max-width: 100%; }
a { color: inherit; }
p, h1, h2, h3, ol, ul, dl, dd, figure { margin: 0; }
ol, ul { list-style: none; padding: 0; }
button { font: inherit; color: inherit; }
section:focus { outline: none; }
::selection { background: var(--accent); color: var(--accent-ink); }
/* Material 3 focus ring: 3px, 2px outside, grows to 8px and settles over 600ms */
:focus-visible {
  outline: 3px solid var(--fg);
  outline-offset: 2px;
  animation: md-focus var(--md-long4) var(--md-ease-emphasized);
}
@keyframes md-focus { 25% { outline-width: 8px; } }

/* one link look: ink, a faint underline that comes up to full ink and 2px
   on hover (no second colour, no purple once visited) */
.foot__row a {
  color: var(--fg);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .2em;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
  transition: text-decoration-color var(--md-short3) var(--md-ease-standard), text-decoration-thickness var(--md-short3) var(--md-ease-standard);
}
.foot__row a:hover { text-decoration-color: currentColor; text-decoration-thickness: 2px; }
.term__out a { color: var(--link); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .18em; }

/* the sprite's defs (the pen's shading). The icons are the pack's: assets/icons draws them on the
   mark's 9 x 9 modules, css/ii-icons.css sizes them by --ii-m (the module, 1 to 4 px: 9 to 36 px
   icons), icons.html shows them all */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ---------- the two voices ---------- */

/* labels, numbers, tables: uppercase mono, never smaller than M3's label roles */
.t {
  font-family: var(--f-term);
  font-size: var(--ui-size);
  line-height: 1.35;
  letter-spacing: .1px;
  text-transform: uppercase;
}
/* condensed text for longer answers */
.px {
  font-family: var(--f-pix);
  font-variation-settings: "wght" 430, "ELSH" 2;
  font-size: clamp(19px, 1.25vw, 24px);
  line-height: 1.33;
  letter-spacing: .015em;
}
/* the big statements: Helvetica, all caps, tight, lines that rise out of a slot */
.caps {
  margin: 0;
  padding: 0 var(--g);
  font: 400 clamp(52px, 9.4vw, 300px)/.84 var(--f-sans);
  letter-spacing: -.045em;
  text-transform: uppercase;
}
/* each line rises out of its own slot; the slot leaves room for the caps' tops and the comma's tail */
.caps__line { display: block; overflow: hidden; padding: .12em 0 .1em; margin: -.12em 0 -.1em; }
.caps__line > span { display: inline-block; }
.js .caps[data-reveal] { opacity: 1; transform: none; }
.js .caps[data-reveal] .caps__line > span { transform: translateY(120%); transition: transform var(--md-xlong2) var(--md-ease-emphasized-decelerate); }
.js .caps[data-reveal] .caps__line:nth-child(2) > span { transition-delay: 90ms; }
.js .caps[data-reveal] .caps__line:nth-child(3) > span { transition-delay: 180ms; }
.js .caps[data-reveal].is-in .caps__line > span { transform: none; }
/* statements that type themselves up as they arrive, a letter at a time, once */
.ww { display: inline-block; white-space: nowrap; }
.ch { display: inline-block; }
/* each word is a slot (a clip, so the baseline stays put); its letters rise out of it */
.js [data-rise] .ww { clip-path: inset(-.3em -.12em -.22em -.12em); }
.js [data-rise] .ch { opacity: 0; transform: translateY(112%); transition: opacity var(--md-medium2) linear, transform var(--md-long2) var(--md-ease-emphasized-decelerate); transition-delay: calc(var(--ci, 0) * 22ms); }
.js [data-rise].is-in .ch { opacity: 1; transform: none; }
/* pictures inside the words: the work, in grey until you point at it */
.inl {
  display: inline-block;
  width: 1.46em;
  height: .73em;
  margin: 0 .04em 0 .08em;
  object-fit: cover;
  object-position: 50% var(--at, 30%);
  vertical-align: baseline;
  filter: grayscale(1) contrast(1.08);
  transition: filter var(--md-medium2) var(--md-ease-standard);
}
.inl + .inl { margin-left: .1em; }
.inl:hover { filter: none; }

/* square-bracket buttons: a block of blue when you point at one */
.bk {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  padding: 0 6px;
  margin: 0 -6px;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--md-short3) var(--md-ease-standard), color var(--md-short3) var(--md-ease-standard);
}
.bk:hover { background: var(--accent); color: var(--accent-ink); }

kbd {
  display: inline-grid;
  place-items: center;
  min-width: 1.5em;
  height: 1.35em;
  padding: 0 .3em;
  background: var(--fg);
  color: var(--bg);
  font: inherit;
}
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.skip {
  position: fixed;
  left: 8px;
  top: 8px;
  z-index: 200;
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  padding: 0 16px;
  background: var(--accent);
  color: var(--accent-ink);
  font: 14px/20px var(--f-term);
  text-transform: uppercase;
  transform: translateY(-200%);
}
.skip:focus { transform: none; }
.only-touch { display: none; }
@media (hover: none), (pointer: coarse) {
  .only-hover { display: none; }
  .only-touch { display: block; }
}
/* open for work: the blue dot, steady */
.led {
  display: inline-block;
  width: .6em;
  height: .6em;
  margin-left: .3em;
  background: var(--accent);
  vertical-align: .02em;
}
@keyframes blink { 50% { opacity: 0; } }

/* ---------- the grid, drawn ---------- */

/* hairlines on the column edges, over everything but the HUD, in a grey that
   reads on black and on white alike. G turns it off. */
.gridlines {
  position: fixed;
  inset: 0;
  z-index: 3;
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  column-gap: var(--g);
  padding: 0 var(--g);
  pointer-events: none;
  transition: opacity var(--md-medium2) var(--md-ease-standard);
}
.gridlines i { border-inline: 1px solid rgb(128 128 128 / .17); transition: background-color var(--md-short4) var(--md-ease-standard); }
/* the column under the pointer, faintly filled in */
.gridlines i.is-hot { background: rgb(128 128 128 / .07); }
@media (max-width: 839.98px) { .gridlines i:nth-child(n + 9) { display: none; } }
@media (max-width: 599.98px) { .gridlines i:nth-child(n + 5) { display: none; } }
html.grid-off .gridlines { opacity: 0; }

/* ---------- intro ---------- */

.intro-canvas {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: progress;
}
html:is(.intro, .route-intro) { overflow: hidden; }
html.intro .intro-canvas { display: block; }
html.intro .head,
html.intro main,
html.intro .cases,
html.intro .foot { visibility: hidden; }
html.intro.intro-reveal main { visibility: visible; }
/* The frame is visible during the intro. The navigation types in when it ends. */
html.intro .gridlines, html.intro .bar { z-index: 101; }
html:is(.intro, .route-intro, .route-wait) .bar :is(a, button) { visibility: hidden; }
html:is(.intro, .route-intro, .route-wait) .bar a[aria-current]::after { content: none; }

/* ---------- shared navigation ---------- */
/* (the bar's unlit words, 11px: 48% of the ink is 4.9:1 on the black bar, and 56% is 4.9:1 on the
   white one. At 36% they were 3.1:1, under the 4.5 that small text needs: the audit's one
   accessibility failure on every page of the site) */
:root { --bar-mute: color-mix(in srgb, var(--ink) 48%, transparent); }
html.invert { --bar-mute: color-mix(in srgb, var(--ink) 56%, transparent); }
.bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 60;
  display: flex;
  align-items: stretch;
  height: var(--bar-h);
  background: var(--paper);
  color: var(--ink);
  border-bottom: 1px solid var(--log-line);
  font: 400 12px/1 var(--f-term);
  letter-spacing: .02em;
  text-transform: none;
  white-space: nowrap;
}
.bar a, .bar button { color: inherit; text-decoration: none; }
.bar :focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
.bar__page, .bar__list a { position: relative; display: flex; flex: none; align-items: center; padding: 0 14px; }
.bar .bar__page { color: var(--bar-mute); }
.bar__secs { display: flex; min-width: 0; margin-left: auto; overflow-x: auto; scrollbar-width: none; color: var(--bar-mute); }
.bar__secs::-webkit-scrollbar { display: none; }
.bar__list { display: flex; margin: 0; }
.bar__list a { height: 100%; transition: color .5s cubic-bezier(.19, 1, .22, 1); }
.bar a:is([aria-current], :hover) { color: var(--ink); }
.bar a[aria-current]::after { content: ""; position: absolute; left: 50%; bottom: 5px; width: 4px; height: 4px; translate: -50% 0; background: var(--accent); }
@media (max-width: 599.98px) { .bar__page, .bar__list a { padding: 0 8px; } }
@media (max-width: 380px) {
  .bar { font-size: 11px; }
  .bar__page, .bar__list a, .bar .bar__mo { padding-inline: 6px; }
}
/* typing in: a block for a cursor, a wrong letter just ahead of it */
.bar__typing { position: relative; display: inline-block; }
.bar__type-space { opacity: 0; }
.bar__type-ink { position: absolute; top: 0; left: 0; white-space: nowrap; }
.bar__type-ink:not(:empty)::after {
  content: "";
  display: inline-block;
  width: .6em;
  height: .9em;
  margin-left: .08em;
  vertical-align: -.12em;
  background: currentColor;
  opacity: .5;
}
/* Motion, the pause for the loops: lit while they run */
.bar__mo { flex: none; padding: 0 clamp(8px, 2vw, 14px); background: none; border: 0; color: var(--bar-mute); font: inherit; letter-spacing: inherit; cursor: pointer; transition: color .5s cubic-bezier(.19, 1, .22, 1); }
.bar__mo[aria-pressed="true"], .bar__mo:hover { color: var(--ink); }
/* the console's tab: as wide as the console, its name lit and underlined while it is open */
.bar__log { position: relative; display: none; flex: none; align-items: stretch; justify-content: space-between; width: var(--log-panel); padding: 0; background: none; border: 0; border-left: 1px solid var(--log-line); color: var(--bar-mute); font: inherit; letter-spacing: inherit; cursor: pointer; }
@media (min-width: 1600px) { .bar__log { display: flex; } }
.bar__log-t { position: relative; display: flex; align-items: center; padding: 0 12px; transition: color .5s cubic-bezier(.19, 1, .22, 1); }
.bar__log-t::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--accent); opacity: 0; }
.bar__log:hover .bar__log-t, html.log-open .bar__log-t { color: var(--ink); }
html.log-open .bar__log-t::after { opacity: 1; }
/* two icons from the pack, one over the other, a module a pixel: the panel (an arrow stopping one
   module short of the edge it comes out of) while the console is shut, the cross once it is open.
   The one going fades at once; the one coming waits for the panel to move first (.3s on the way
   in, .4s on the way out), on the panel's own curve */
.bar__log-ic { position: relative; flex: none; width: 40px; }
.bar__ic { --ii-m: 1; position: absolute; left: 50%; top: 50%; translate: -50% -50%; transition: opacity .5s cubic-bezier(.23, 1, .32, 1) .4s; }
.bar__ic--x { opacity: 0; transition-delay: 0s; }
html.log-open .bar__ic--arrow { opacity: 0; transition-delay: 0s; }
html.log-open .bar__ic--x { opacity: 1; transition-delay: .3s; }

/* ---------- header: the mark, drawn with its own name, at the top of the page
   under the bar. It is not pinned: it scrolls away with the page ---------- */

.head {
  position: absolute;
  top: var(--bar-h);
  left: 0;
  right: 0;
  z-index: 40;
  height: var(--head-max);
  overflow: hidden;
  background: var(--paper);
  color: var(--ink);
  contain: layout paint;
}
html.case-open .head { display: none; }
.head__mark { position: absolute; inset: 0; display: block; color: inherit; }
.head__mark canvas { position: absolute; left: 0; top: 0; width: 100%; height: var(--head-max); }
.head__fallback {
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 var(--g);
  font: 400 calc(var(--head-max) * .62)/1 var(--f-sans);
  letter-spacing: -.04em;
}
.js .head__fallback { display: none; }

/* ---------- console.log: a file of code down the right of a wide screen, a
   side panel: under the bar, its tab at the bar's right end; line
   numbers in a narrow dim column, the code typed in as you reach each part of
   the page. It slides in and out over the page, which stays where it is (the
   user's call; in fast and settling, ~500ms; out on an in-out curve,
   ~450ms). Shut unless it was opened before ---------- */

:root { --log-panel: 0px; --log-str: #8ea2ff; --log-line: color-mix(in srgb, var(--ink) 16%, transparent); }
html.invert { --log-str: var(--accent); }
@media (min-width: 1600px) {
  :root { --log-panel: clamp(240px, 12.4vw, 300px); }
}
.log {
  position: fixed;
  top: var(--bar-h);
  right: 0;
  bottom: 0;
  z-index: 55;
  display: none;
  flex-direction: column;
  width: var(--log-panel);
  background: var(--paper);
  color: color-mix(in srgb, var(--ink) 80%, transparent);
  border-left: 1px solid var(--log-line);
  font: 400 11px/1.5 var(--f-term);
  letter-spacing: 0;
  text-transform: none;
  transform: translateX(100%);
  visibility: hidden;
  transition: transform .45s cubic-bezier(.65, 0, .35, 1), visibility 0s .45s;
}
@media (min-width: 1600px) { .log { display: flex; } }
html.log-open .log { transform: none; visibility: visible; transition: transform .5s cubic-bezier(.23, 1, .32, 1), visibility 0s; }
html.intro .log { visibility: hidden; }
/* soft edges, 24px: the top one once the file has scrolled, the bottom one always */
.log::before, .log::after { content: ""; position: absolute; left: 0; right: 0; z-index: 2; height: 24px; pointer-events: none; }
.log::before { top: 0; background: linear-gradient(var(--paper), transparent); opacity: 0; transition: opacity .3s ease-out; }
.log.is-scrolled::before { opacity: 1; }
.log::after { bottom: 0; background: linear-gradient(transparent, var(--paper)); }
/* the file fades in once the panel is nearly in, and out at once */
.log__body {
  flex: 1;
  display: grid;
  grid-template-columns: 4.5ch minmax(0, 1fr);
  align-content: start;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  opacity: 0;
  transition: opacity .1s ease-in;
}
html.log-open .log__body { opacity: 1; transition: opacity .5s cubic-bezier(.23, 1, .32, 1) .3s; }
.log__body::-webkit-scrollbar { display: none; }
.log__n { margin: 0; padding: 6px 0 20px; border-right: 1px solid var(--log-line); color: color-mix(in srgb, var(--ink) 24%, transparent); text-align: center; user-select: none; }
.log__n li { animation: log-in .2s ease-out both; }
@keyframes log-in { from { opacity: 0; } }
.log__code { min-width: 0; padding: 6px 12px 20px; white-space: pre; overflow: hidden; }
.log__ln { min-height: 1.5em; }
.log__art { color: color-mix(in srgb, var(--ink) 40%, transparent); }
.log__art b { color: var(--ink); font-weight: 400; }
.log__art i { color: var(--accent); font-style: normal; }
.log__c { color: color-mix(in srgb, var(--ink) 40%, transparent); }
.log__s { color: var(--log-str); }
.log__k, .log__f { color: var(--ink); }
.log__d { color: color-mix(in srgb, var(--ink) 92%, transparent); }
/* the cursor: the blue block, there while it types */
.log__cur { display: inline-block; width: .6em; height: 1.1em; margin-left: 1px; background: var(--accent); vertical-align: -.22em; }
/* the terminal opens beside the console, not under it */
html.log-open .term { right: calc(var(--log-panel) + var(--g)); }

/* ---------- the page's scrollbar, VoiceTagGods' own (a thin
   floating bar): a 5px rounded thumb and no track, drawn over the page by the
   script from under the bar to the window's foot, so the page keeps the whole
   window: a native bar takes a lane out of the layout, and the lane showed the
   page colour down the side of everything full-bleed (the blue footer). While
   the console is open it rides the console's edge, on the panel's own curves.
   Mouse and trackpad only: touch screens keep their own bar ---------- */
.page-scrollbar {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 58;
  width: 5px;
  height: 0;
  border-radius: 5px;
  background: color-mix(in srgb, var(--ink) 26%, transparent);
  opacity: 0;
  pointer-events: none;
  touch-action: none;
  will-change: transform;
  transition: opacity .2s linear, background-color .2s linear, right .45s cubic-bezier(.65, 0, .35, 1);
}
.page-scrollbar.is-on { opacity: 1; pointer-events: auto; }
/* (5px is hard to catch with a mouse: it catches 16, mostly on its inner side, and looks the same) */
.page-scrollbar::before { content: ""; position: absolute; top: 0; bottom: 0; left: -9px; right: -2px; }
.page-scrollbar:hover, .page-scrollbar.is-dragging { background: color-mix(in srgb, var(--ink) 42%, transparent); }
html.log-open .page-scrollbar { right: var(--log-panel); transition: opacity .2s linear, background-color .2s linear, right .5s cubic-bezier(.23, 1, .32, 1); }
html.intro .page-scrollbar { opacity: 0; pointer-events: none; }
@media (hover: none), (pointer: coarse), print { .page-scrollbar { display: none; } }

/* ---------- layout ---------- */

main { display: block; overflow-x: clip; }
section { position: relative; background: var(--bg); color: var(--fg); }

/* chapters breathe the same amount (no heading rows over them any more: the user, 2026-11-09,
   "remove CHAPTER 01 | ABOUT" and "(02) RECENT WORK OPEN ONE") */
.work { padding: clamp(48px, 10vh, 120px) 0 clamp(56px, 12vh, 140px); }

/* the brand's full stop: a square in the one blue, like the dot after the mark */
.bdot { display: inline-block; width: .17em; height: .17em; margin-left: .05em; background: var(--accent); vertical-align: baseline; }
.nw { white-space: nowrap; }

/* ---------- (00) the opening: the studio, the thesis over it, and the door, one pinned move ---------- */

/* the track: one screen of stage and 3.65 of scroll (the curtains and the card, the card
   becoming the About, a short hold, then the quote's panel rising over it: the quote's last
   screen of pull-up is this track's last screen); the stage holds the line, the thesis and the
   card. .open__at marks where the About is whole (2.55 of the 3.65). It was 4.4: a measured
   scroll found 5 wheel notches with nothing changing while the About held, 2 more on the door */
.open { position: relative; height: 465vh; height: 465svh; }
.open__at { position: absolute; left: 0; top: calc((100% - 100svh) * .7); width: 1px; height: 1px; pointer-events: none; }
.open__stage { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; background: var(--bg); color: var(--fg); }
/* Held: a stage the script keeps on the screen where its scene is, while that is not where the
   page's scroll would have it (main.js, initScrub: the opening and the quote play in their order
   off one clock, however fast the page is scrolled). The same box either way: fixed to the top it
   is where the sticky one is while it is stuck, so taking it and giving it back moves nothing */
.open__stage.is-held, .mem__stage.is-held { position: fixed; left: 0; right: 0; top: 0; }
/* the studio, in LT Terminal Mono caps (the reference's "/ freelance developer" lines),
   placed as the user's mockup has it, as shares of the screen: the first half a quarter
   in from the left just under halfway down, the second set flush right to ~72% of the
   width further down, both across the thesis (a phone puts them in the corners) */
.lead {
  position: absolute;
  inset: 0;
  margin: 0;
  font: 400 clamp(20px, 2vw, 40px)/1.08 "LT Terminal Mono", var(--f-term);
  letter-spacing: 0;
  text-transform: uppercase;
}
.lead__l { position: absolute; display: block; max-width: calc(50% - var(--g)); will-change: transform; }
.lead__l--a { left: 25.9%; top: 45.7%; }
.lead__l--b { right: 27.8%; top: 71.6%; text-align: right; }
.lead__row { display: block; }
/* writing in, the way the bar's labels do: a wrong letter ahead, a dim block after it, and the
   rest of the row still clear. The block hangs off the wrong letter, out of the flow, so it takes
   no room and adds no place a wrapped row could break */
.lead__wr { position: relative; }
.lead__row.is-typing .lead__wr::after { content: ""; position: absolute; left: 100%; top: 50%; width: .6em; height: .9em; translate: 0 -50%; background: currentColor; opacity: .5; }
.lead__off { color: transparent; }
/* The thesis holds its position with a still layer of ASCII characters. */
.ht { position: absolute; inset: 0; z-index: 1; display: grid; align-content: center; padding-top: calc(var(--bar-h) + var(--head-max)); pointer-events: none; }
.about__big {
  /* four lines, well inside the screen under the header */
  font: 700 min(10vw, calc((100svh - var(--bar-h) - var(--head-max)) * .21))/.8 "Heros Cn", var(--f-sans);
  font-stretch: condensed;
  letter-spacing: -.005em;
  text-align: center;
}
.ht .about__big { color: var(--mute); }
.ht.is-drawn .about__big { color: transparent; }
.ht__cv { position: absolute; left: 0; top: 0; z-index: 1; width: 100%; height: 100%; pointer-events: none; }

/* the card: the page in miniature. It rises into the gap between the curtains
   at a fifth of its size, then grows until it is the page (set by the scroll) */
.door { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.door__panel {
  /* the card's own colours (the About on it reads these): the door is the ink, the About a light
     studio grey a step over the services' tiles (--m, from the script, takes it from one to the other) */
  --studio: color-mix(in srgb, var(--ink) 96%, var(--paper));
  --fg: var(--paper);
  --bg: color-mix(in srgb, var(--ink), var(--studio) calc(var(--m, 0) * 100%));
  --mute: color-mix(in srgb, var(--fg) 56%, transparent);
  --line: color-mix(in srgb, var(--fg) 22%, transparent);
  position: absolute;
  inset: 0;
  background: var(--bg);
  color: var(--fg);
  transform-origin: 50% 50%;
  transform: translate3d(0, 72vh, 0) scale(.22);
  visibility: hidden;
  will-change: transform;
}
/* the mark on the door, as an object: the header's and the footer's 3D renderer, live, on a canvas
   over its picture (the picture is all there is without the script) */
.door__media {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(72vw, calc((100svh - var(--bar-h)) * 1.6), 1500px);
  aspect-ratio: 16 / 9;
  translate: -50% -50%;
}
.door__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* the floor's last shadow fades out before the frame's edge */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
}
/* the render's white studio melts into the white card, and the words behind
   it show through. The box blends, not the video: the box's translate makes
   it a stacking context, so a blend on the video would only reach the box */
html:not(.invert) .door__media { mix-blend-mode: multiply; }
/* in the light the card is dark: the render turned negative (the blue kept) and screened on,
   so its studio drops away and the blocks come out light */
html.invert .door__media { mix-blend-mode: screen; }
html.invert .door__media video { filter: invert(1) hue-rotate(180deg); }
/* the 3D model's canvas covers the whole card (its cubes fly to the tiles), under the About */
.door__mark { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.door__media.is-live img { visibility: hidden; }
/* ---------- with the 3D model the tiles load as an app's do (the user: the cube becomes a
   loading skeleton from which the video and the letters load and start). The script drives it
   from the scroll: --h hands each piece over from the 3D model, which has turned it into flat 2D
   pixels on its way in (the user: "as it's transitioning from 3d it should become 2d"), to the
   tile, whose cells are the same pixels in the same place, in one frame; --a brings the tile's
   surface up under them; --sf closes their gaps and fills in the empty ones (a bar); --sk opens the
   bar into the skeleton's block where the loop goes, paling from the cubes' grey to the skeleton's;
   --sb brings the name's and number's bars. .is-skel runs M3's light over the skeleton while it
   waits; .is-loaded (the piece home and its loop with a frame) brings the loop and the name up out
   of it and lets the skeleton go. Geometry (--pl/--pt/--pw/--ph the piece, --fx/--fy/--fw/--fh the
   loop's box, --tx0/--ty0/--sx0/--sy0 the one in the other, --bl/--bt/--bh/--tw/--nw/--nh/--nt the
   bars) from the script, measured with the tile at its size ---------- */
.idea__skel, .idea__bg { display: none; }
/* (at its own size the whole way: its piece's cells must sit exactly on the cubes; its surface is
   the growing card below) */
.idea.is-morph .idea__card { opacity: var(--h, 0); scale: var(--ok, 1); translate: calc(var(--x, 0px) - 50% + var(--ox, 0px)) calc(var(--y, 0px) - 50% + var(--oy, 0px)); background: transparent; will-change: translate, scale; }
/* the tile's surface grows out of its piece: a card hugging the piece at first (--gx0/--gy0 of the
   tile), the whole tile at --g 1, its corners 12px all the way (the radii undo the scale) */
.idea.is-morph .idea__bg {
  --gsx: calc(var(--gx0, 1) + (1 - var(--gx0, 1)) * var(--g, 1));
  --gsy: calc(var(--gy0, 1) + (1 - var(--gy0, 1)) * var(--g, 1));
  display: block;
  position: absolute;
  inset: 0;
  z-index: -1;
  background: #ebebeb;
  opacity: var(--a, 1);
  scale: var(--gsx) var(--gsy);
  border-radius: calc(12px / var(--gsx)) / calc(12px / var(--gsy));
}
.idea.is-morph .idea__skel {
  --bone: #dcdcdc;
  display: block;
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  transition: opacity var(--md-medium2) var(--md-ease-standard) var(--md-short3);
}
/* the cells' grey, on the card: the door's 3D pieces go flat in it on their way in (the script reads
   it off the canvas), so the cells that take over from them are the same pixels. Light grey when
   the colours are flipped, as the cubes are */
.door__panel { --cube: #303030; }
html.invert .door__panel { --cube: #c9c9c9; }
.idea.is-morph .idea__card.is-loaded .idea__skel { opacity: 0; }
/* the loop and the name wait under it, and settle in out of it: the loop from a touch larger, the
   name from a few px lower, a beat after */
.idea.is-morph .idea__card .idea__media { opacity: 0; scale: 1.03; transition: opacity var(--md-short4) var(--md-ease-standard), scale var(--md-short4) var(--md-ease-standard); }
.idea.is-morph .idea__card .idea__lab { opacity: 0; translate: 0 6px; transition: opacity var(--md-short4) var(--md-ease-standard), translate var(--md-short4) var(--md-ease-standard); }
.idea.is-morph .idea__card.is-loaded .idea__media { opacity: 1; scale: 1; transition: opacity var(--md-long2) var(--md-ease-emphasized-decelerate), scale var(--md-long4) var(--md-ease-emphasized-decelerate); }
.idea.is-morph .idea__card.is-loaded .idea__lab { opacity: 1; translate: 0 0; transition: opacity var(--md-medium2) var(--md-ease-emphasized-decelerate) var(--md-short3), translate var(--md-long2) var(--md-ease-emphasized-decelerate) var(--md-short3); }
/* the piece's cells (a canvas the script draws: its cubes, flat, closing up, the empty ones filling
   in), right where the piece's cubes are; they go as the block takes over from them */
.idea__cells { position: absolute; left: var(--pl); top: var(--pt); width: var(--pw); height: var(--ph); opacity: calc(1 - clamp(0, (var(--sk, 0) - .015) * 60, 1)); }
/* the skeleton: M3's placeholders, a step under the tile's grey, rounded; the light that runs over
   them is one band across the whole tile (each piece of it placed by its own left, --bx) */
.idea__sk {
  position: absolute;
  display: block;
  background-color: var(--bone);
  background-image: linear-gradient(100deg, rgb(255 255 255 / 0) 0, rgb(255 255 255 / .62) 50%, rgb(255 255 255 / 0) 100%);
  background-repeat: no-repeat;
  background-size: calc(var(--w, 300px) * .5) 100%;
  background-position: calc(var(--shine, -9999px) - var(--bx, 0px)) 0;
}
/* the loop's block: the bar the cells made, opening into the loop's box and paling as it goes */
.idea__sk--m {
  --bx: var(--fx);
  left: var(--fx);
  top: var(--fy);
  width: var(--fw);
  height: var(--fh);
  border-radius: 8px;
  background-color: color-mix(in srgb, var(--cube) calc((1 - var(--sk, 0)) * 100%), var(--bone));
  translate: calc(var(--tx0, 0px) * (1 - var(--sk, 0))) calc(var(--ty0, 0px) * (1 - var(--sk, 0)));
  scale: calc(var(--sx0, 1) + (1 - var(--sx0, 1)) * var(--sk, 0)) calc(var(--sy0, 1) + (1 - var(--sy0, 1)) * var(--sk, 0));
  opacity: clamp(0, calc((var(--sf, 0) - .97) * 40), 1);
}
/* the Branding tile's loop fills it: its block is the part under the name, out to the tile's edge */
.idea__card--branding .idea__sk--m { border-radius: 8px 8px 0 0; }
.idea__sk--w { --bx: var(--bl); left: var(--bl); top: var(--bt); width: var(--tw); height: var(--bh); border-radius: 999px; opacity: var(--sb, 0); }
.idea__sk--n { --bx: calc(var(--w, 300px) - var(--bl) - var(--nw)); right: var(--bl); top: var(--nt); width: var(--nw); height: var(--nh); border-radius: 999px; opacity: var(--sb, 0); }
/* the description's, under the name's: as long as its words, as thin as its line */
.idea__sk--d { --bx: var(--bl); left: var(--bl); top: var(--dt); width: var(--dw); height: var(--dh); border-radius: 999px; opacity: var(--sb, 0); }
@property --shine { syntax: '<length>'; inherits: true; initial-value: -9999px; }
/* (an even pass, then a breath: the standard curve shot across and crawled at the far edge) */
@keyframes idea-shine {
  0% { --shine: calc(var(--w, 300px) * -.6); animation-timing-function: cubic-bezier(.4, 0, .6, 1); }
  75%, 100% { --shine: calc(var(--w, 300px) * 1.3); }
}
.idea.is-morph .idea__card.is-skel .idea__skel { animation: idea-shine 1.6s infinite; }
html.still .idea__skel { animation: none !important; }
/* ---------- (01) about, on the door's card: From idea to launch, laid out
   in our words and our things: the words and the
   two buttons on the left, the three services' tiles on the right; on a
   narrow window the words, the tiles, then the buttons. The card that grew
   into the page turns studio grey and the door's mark goes. The script drives
   it from the opening's scroll: --m on the card, --a / --t on each tile (there,
   its name), --v on the words and the buttons. Left at 1 they are the
   finished About ---------- */

.door .idea {
  position: absolute;
  inset: calc(var(--bar-h) + clamp(52px, 9vh, 76px)) 0 clamp(24px, 5vh, 56px);
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  grid-template-rows: 1fr auto auto 1fr;
  column-gap: var(--g);
  row-gap: clamp(20px, 3.4vh, 36px);
  margin: 0;
  padding: 0 var(--g);
  /* see-through: the door's mark is under it while it goes (sections are opaque elsewhere) */
  background: none;
  pointer-events: none;
}
.door .idea.is-on { pointer-events: auto; }
.idea__side { grid-column: 1 / 6; grid-row: 2; display: grid; justify-items: start; gap: clamp(14px, 2.4vh, 24px); }
/* the two ways in side by side, each as wide as its words, a size down from the footer's (the
   user, 2026-11-09: smaller, next to each other instead of one under the other; the note under
   them went). The words sit in the room right of the tile */
.idea__cta { grid-column: 1 / 6; grid-row: 3; display: flex; align-items: start; gap: 10px; }
.idea__cta .barbtn { --h: clamp(48px, 2.75vw, 54px); --bb-pl: calc(var(--h) + 14px); --bb-pr: 20px; flex: none; font-size: clamp(15px, .92vw, 18px); }
.idea__side > *, .idea__cta { opacity: var(--v, 1); translate: 0 calc((1 - var(--v, 1)) * 28px); }
.idea__h { font: 400 clamp(44px, min(5.2vw, 12.5vh), 140px)/.92 var(--f-sans); letter-spacing: -.045em; }
.idea__p { max-width: 23em; font: 400 clamp(17px, 1.25vw, 26px)/1.28 var(--f-sans); letter-spacing: -.01em; color: var(--mute); }
/* the tiles' box: the rest of the width and the whole height; the script lays the tiles out in
   it (--w / --mh / --x / --y on each) and, on a narrow window, gives it its height */
.idea__stage { grid-column: 6 / -1; grid-row: 1 / -1; position: relative; min-height: 0; }
.idea__team { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; }
/* a service: an M3 filled card (12dp corners, no elevation) on the loops' own grey, a step under
   the studio grey; its name top left (title large), its number top
   right, its loop under them, square (in the wide tile the square sits in the middle, on the same
   grey). Not a link, so no state layers. It comes in as M3 brings in a container: fade, small scale */
.idea__card {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--w, 300px);
  translate: calc(var(--x, 0px) - 50%) calc(var(--y, 0px) - 50%);
  scale: calc(.94 + .06 * var(--a, 1));
  opacity: var(--a, 1);
  overflow: hidden;
  border-radius: 12px;
  background: #ebebeb;
  color: #161616;
  container-type: inline-size;
}
/* a tile under 160 wide: a smaller name and no number, so the name never runs out of the tile */
@container (max-width: 159.98px) {
  .idea__lab { font-size: 14px; }
  .idea__n { display: none; }
  .idea__d { font-size: 12px; line-height: 16px; }
}
.idea__lab { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; column-gap: 12px; height: 64px; margin: 0; padding: 16px 16px 0; font: 400 20px/28px var(--f-sans); letter-spacing: -.01em; white-space: nowrap; opacity: var(--t, 1); }
/* what it is, under its name: M3's supporting text (body medium) in the number's grey, on a line
   of its own. It took over from the loops' own top-left labels (the user, 2026-11-09) */
.idea__d { flex-basis: 100%; font: 400 14px/20px var(--f-sans); letter-spacing: .01em; color: #666; }
/* (the description's grey: #6b6b6b was 4.47:1 on the tile, a hair under the 4.5 small text needs) */
.idea__n { font: 400 13px/1 var(--f-term); letter-spacing: .04em; color: #666; }
.idea__w { font-weight: inherit; color: inherit; }
.idea__media { position: relative; height: var(--mh, 260px); }
.idea__media > img, .idea__media > video { position: absolute; top: 0; left: 50%; width: auto; height: 100%; aspect-ratio: 1; translate: -50% 0; object-fit: cover; }
/* The Branding heading overlays its art so the strap and lanyard can meet the card edge. */
.idea__card--branding { padding-bottom: var(--mh, 260px); }
.idea__card--branding .idea__lab { position: relative; z-index: 1; }
.idea__card--branding .idea__media { position: absolute; inset: 0; height: auto; }
.idea__card--branding .idea__media > video { inset: 0; width: 100%; translate: none; }
@container (max-width: 119.98px) {
  .idea__card--branding .idea__lab { padding-top: 6px; font-size: 13px; line-height: 18px; }
}
/* while the script measures: every tile where it ends up */
.idea.is-measuring .idea__card { --a: 1 !important; --t: 1 !important; --ox: 0px !important; --oy: 0px !important; --ok: 1 !important; }
/* the colours flipped: the tiles flip with the page (the user, 2026-11-09: "flip the color / invert
   don't work on 3 video cards"). Their grey goes to its negative, #141414, their words light, and
   the loops (posters too) are shown negative with their hues kept, as the door's photo is: their own
   #ebebeb grounds land on the tile's #141414 exactly. The skeleton's block a step up from the tile */
html.invert .idea__card { background: #141414; color: #ebebeb; }
html.invert .idea.is-morph .idea__bg { background: #141414; }
html.invert .idea__n { color: #949494; }
html.invert .idea__d { color: #999; }
html.invert .idea.is-morph .idea__skel { --bone: #262626; }
html.invert .idea__sk { background-image: linear-gradient(100deg, rgb(255 255 255 / 0) 0, rgb(255 255 255 / .1) 50%, rgb(255 255 255 / 0) 100%); }
html.invert .idea__media video, html.invert .idea__hold { filter: invert(1) hue-rotate(180deg); }

/* ---------- the bar buttons (About's two, More work, the footer's two), the work page's
   toggles and the cases' Visit site are ONE block, css/ii-buttons.css (.blk): square, flat at
   rest; pointed at, the face leans toward the pointer and opens a stack of two lines behind it,
   blue and grey (the user's reference, in our shape and colours; 2026-11-09). Here
   only where each one sits and how big it is ---------- */

/* ---------- services: under From idea to launch, on its grey (a row,
   three lines): a column each with its name, its line, a picture
   that moves and a bar button to its own page. The row holds its last screen
   (sticky, --svc-top from the script) while the quote's black panel rises
   over it, as the About used to ---------- */
.svc {
  --bg: color-mix(in srgb, var(--ink) 91%, var(--paper));
  --fg: var(--paper);
  --mute: color-mix(in srgb, var(--fg) 56%, transparent);
  --line: color-mix(in srgb, var(--fg) 14%, transparent);
  padding-top: clamp(32px, 6vh, 80px);
}
.svc::after { content: ""; display: block; height: 100vh; height: 100svh; }
.svc__in { position: sticky; top: var(--svc-top, 0px); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(40px, 6vh, 64px) clamp(16px, 2.4vw, 48px); padding: 0 var(--g) clamp(40px, 7vh, 88px); }
.svc__col { display: grid; align-content: start; gap: clamp(12px, 1.4vw, 20px); }
.svc__h { font: 400 clamp(38px, 3.3vw, 68px)/1 var(--f-sans); letter-spacing: -.05em; }
.svc__p { max-width: 20em; min-height: 2.6em; font: 400 clamp(17px, 1.15vw, 23px)/1.24 var(--f-sans); letter-spacing: -.01em; color: var(--mute); }
.svc__col .barbtn { width: 100%; }

/* ---------- the pictures: drawn, not rendered. Each is a 400px stage scaled to
   its card (--k from the script) and run by the script on one 8s loop: the
   pen draws the mark and dots it blue, then the name and the palette come in
   (Branding); code types itself and the page under it builds as it goes
   (Development); a booking screen is used, a day, a time, booked (UI/UX). What
   is set here is each one's finished frame: with less motion that is all ---------- */
.viz { position: relative; aspect-ratio: 1; overflow: hidden; border-radius: 10px; background: color-mix(in srgb, var(--fg) 6%, var(--bg)); }
.viz__stage { position: absolute; left: 50%; top: 50%; width: 400px; height: 400px; margin: -200px 0 0 -200px; scale: var(--k, 1); }
/* Branding: an artboard, the pen, the mark it draws (outlined, then filled, the second dot blue) */
.vb { display: block; width: 400px; height: 400px; overflow: visible; }
.vb__board { fill: #fff; stroke: rgb(0 0 0 / .07); }
.vb__guides { opacity: 0; }
.vb__ring { fill: none; stroke: #c4c4c4; stroke-width: 1; stroke-dasharray: 3 5; transform-box: fill-box; transform-origin: center; }
.vb__gx, .vb__gy { stroke: #dedede; stroke-width: 1; }
.vb__f { fill: #000; }
.vb__f4 { fill: var(--accent); transform-box: fill-box; transform-origin: center; }
.vb__o { fill: none; stroke: #000; stroke-width: 2; stroke-dasharray: 272; stroke-dashoffset: 0; }
.vb__o3, .vb__o4 { stroke-dasharray: 144; }
.vb__o4 { stroke: var(--accent); }
.vb__name { fill: #000; font: 400 26px var(--f-sans); letter-spacing: -.03em; }
.vb__chip { transform-box: fill-box; transform-origin: center; }
.vb__chip1 { fill: #000; }
.vb__chip2 { fill: #fff; stroke: #cfcfcf; }
.vb__chip3 { fill: var(--accent); }
.vb__pen { transform: translate(470px, 330px); }
.vb__shade { stroke: #000; stroke-opacity: .26; stroke-width: 14; stroke-linecap: round; }
/* Development: the editor, and the page it is writing, under it */
.vd__ed { position: absolute; left: 20px; top: 20px; width: 360px; height: 198px; overflow: hidden; border-radius: 10px; background: #0e0e0e; color: #cfcfcf; font: 400 12px/20px var(--f-term); box-shadow: 0 18px 36px -22px rgb(0 0 0 / .6); }
.vd__top { display: flex; align-items: center; gap: 5px; height: 28px; padding: 0 12px; border-bottom: 1px solid #222; color: #7a7a7a; font-size: 10px; letter-spacing: .02em; }
.vd__top i { width: 7px; height: 7px; background: #3a3a3a; }
.vd__top span { margin-left: 8px; }
.vd__code { margin: 0; padding: 8px 0 0; list-style: none; counter-reset: vd; }
.vd__code li { display: flex; align-items: center; height: 20px; padding: 0 12px; white-space: pre; counter-increment: vd; }
.vd__code li::before { content: counter(vd, decimal-leading-zero); flex: none; width: 28px; color: #4a4a4a; }
.vd__l { display: inline-block; flex: none; width: calc(var(--n) * 1ch); overflow: hidden; }
.vd__cur { flex: none; width: 7px; height: 14px; background: var(--accent); opacity: 0; }
.vd__k, .vd__f { color: #fff; }
.vd__a { color: #9a9a9a; }
.vd__s { color: #8ea2ff; }
.vd__status { position: absolute; right: 12px; bottom: 8px; display: grid; color: #7a7a7a; font-size: 10px; }
.vd__st { grid-area: 1 / 1; display: flex; align-items: center; justify-self: end; gap: 6px; }
.vd__st i { width: 6px; height: 6px; background: #555; }
.vd__st--a { opacity: 0; }
.vd__st--b i { background: var(--accent); }
.vd__web { position: absolute; left: 20px; top: 230px; width: 360px; height: 150px; overflow: hidden; border-radius: 10px; background: #fff; color: #000; box-shadow: 0 1px 0 rgb(0 0 0 / .05), 0 18px 36px -24px rgb(0 0 0 / .45); }
.vd__url { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 10px; border-bottom: 1px solid #eee; color: #8a8a8a; font: 400 9px/1 var(--f-term); }
.vd__url i { width: 6px; height: 6px; background: #ccc; }
.vd__nav { position: absolute; left: 12px; right: 12px; top: 32px; display: flex; align-items: center; gap: 8px; height: 10px; }
.vd__nav b { width: 9px; height: 9px; margin-right: auto; background: var(--accent); }
.vd__nav i { width: 24px; height: 3px; background: #c8c8c8; }
.vd__h { position: absolute; left: 12px; top: 52px; font: 400 20px/1 var(--f-sans); letter-spacing: -.035em; }
.vd__btn { position: absolute; left: 12px; top: 80px; display: grid; place-items: center; height: 20px; padding: 0 14px; border: 1px solid var(--accent); border-radius: 4px; background: var(--accent); color: #fff; font: 400 9px/1 var(--f-sans); }
.vd__cards { position: absolute; left: 12px; right: 12px; top: 108px; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; height: 32px; }
.vd__cards > span { display: flex; align-items: flex-end; gap: 4px; padding: 5px 8px; border-radius: 4px; background: #f1f1f1; }
.vd__cards i { flex: 1; height: var(--h); background: #000; transform-origin: 50% 100%; }
.vd__cards span:nth-child(2) i:nth-child(3) { background: var(--accent); }
/* UI/UX: a phone with a booking screen, and the cursor using it */
.vu__phone { position: absolute; left: 104px; top: 12px; width: 192px; height: 376px; padding: 7px; border-radius: 32px; background: #0b0b0b; box-shadow: 0 26px 50px -26px rgb(0 0 0 / .6); }
.vu__scr { position: relative; height: 100%; overflow: hidden; padding: 28px 14px 14px; border-radius: 26px; background: #fff; color: #111; }
.vu__scr::before { content: ""; position: absolute; left: 50%; top: 9px; width: 48px; height: 11px; margin-left: -24px; border-radius: 6px; background: #0b0b0b; }
.vu__h { font: 400 17px/1 var(--f-sans); letter-spacing: -.035em; }
.vu__sub { margin-top: 5px; color: #8a8a8a; font: 400 8px/1 var(--f-term); letter-spacing: .04em; text-transform: uppercase; }
.vu__mo { display: flex; justify-content: space-between; margin-top: 14px; color: #222; font: 400 9px/1 var(--f-term); letter-spacing: .04em; text-transform: uppercase; }
.vu__cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 3px; margin-top: 8px; }
.vu__cal b, .vu__cal span { display: grid; place-items: center; height: 19px; border-radius: 4px; font: 400 8px/1 var(--f-term); }
.vu__cal b { color: #9a9a9a; }
.vu__cal span { color: #333; }
.vu__cal .is-off { color: #c4c4c4; }
.vu__cal .vu__day { background: var(--accent); color: #fff; }
.vu__slots { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 12px; }
.vu__slots span { display: grid; place-items: center; height: 24px; border: 1px solid #dcdcdc; border-radius: 12px; color: #222; font: 400 9px/1 var(--f-term); }
.vu__slots .vu__slot { border-color: var(--accent); background: var(--accent); color: #fff; }
.vu__go { position: absolute; left: 14px; right: 14px; bottom: 14px; display: grid; place-items: center; height: 34px; border-radius: 7px; background: #000; color: #fff; font: 400 11px/1 var(--f-sans); }
.vu__go-t, .vu__dots { grid-area: 1 / 1; }
.vu__dots { display: flex; gap: 4px; opacity: 0; }
.vu__dots i { width: 4px; height: 4px; background: #fff; }
.vu__ok { position: absolute; inset: 0; display: grid; place-content: center; justify-items: center; gap: 9px; background: #fff; opacity: 0; }
.vu__check { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 10px; background: var(--accent); }
.vu__check svg { width: 22px; height: auto; fill: #fff; shape-rendering: crispEdges; }
.vu__ok b { font: 400 16px/1 var(--f-sans); letter-spacing: -.03em; }
.vu__ok > span:last-child { color: #8a8a8a; font: 400 8px/1 var(--f-term); letter-spacing: .04em; text-transform: uppercase; }
.vu__cur { position: absolute; left: 0; top: 0; width: 18px; height: auto; fill: #000; shape-rendering: crispEdges; transform: translate(205px, 352px); filter: drop-shadow(1px 0 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 1px 0 #fff) drop-shadow(0 -1px 0 #fff); }

/* words start as grey blocks and turn into words as you read down the page */
[data-fill] .wd {
  color: transparent;
  background: color-mix(in srgb, var(--fg) 16%, transparent);
  transition: color var(--md-medium2) var(--md-ease-standard), background-color var(--md-medium2) var(--md-ease-standard);
}
[data-fill] .wd.lit { color: var(--fg); background: transparent; }
/* the other read-along: grey words come up to full ink */
/* (a word not yet reached still has to be readable: someone may read ahead of the scroll, and
   on a tall screen the last words never get there. At 26% they were 1.9:1. 56% is 4.9:1 on white
   and 6.5:1 on black, what text under 24px needs; from 1280px the line is 24px and over, where
   3:1 is the rule, and 44% is 3.2:1 on white, 4.4:1 on black) */
[data-fill="ink"] .wd { color: color-mix(in srgb, var(--fg) 56%, transparent); background: none; }
@media (min-width: 1280px) { [data-fill="ink"] .wd { color: color-mix(in srgb, var(--fg) 44%, transparent); } }
[data-fill="ink"] .wd.lit { color: var(--fg); }


/* (the pointer is the browser's own: the crosshair and its x / y readout went, the user,
   2026-11-09: "remove this custom cursor we have - just use vanilla one") */

/* ---------- (02) work: a list of names on hairlines (the user, 2026-11-09: "recent
   work should be kinda like this, so without arrow etc"). It sits on our grid: the rules from the
   second column to the eleventh, the names from the third, what
   each was from the ninth, in 19px; rows 214 high at 1966, names at 5.25vw.
   With a mouse the project's picture follows the pointer and the blue View circle rides on
   it; a click opens the case in place ---------- */

/* "Recent work" over the list: 11.4px capitals spaced .05em at half ink, set over the
   names (grid col 3), 48px above the list at 1966 */
.wl__h {
  margin: 0 0 clamp(24px, 2.4vw, 56px);
  padding-left: calc(2 * (100% - 13 * var(--g)) / 12 + 3 * var(--g));
  font: 400 clamp(10px, .58vw, 13px)/1.1 var(--f-sans);
  letter-spacing: .05em;
  text-transform: uppercase;
  opacity: .5;
}
/* (half ink is 5.3:1 on black but 3.9:1 on white: with the colours flipped it takes a little more) */
html.invert .wl__h { opacity: .58; }
.wl { margin: 0 calc((100% - 13 * var(--g)) / 12 + 2 * var(--g)); border-top: 1px solid var(--line); }
.wl__row { border-bottom: 1px solid var(--line); }
.wl__link {
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  column-gap: var(--g);
  align-items: center;
  padding: clamp(24px, 2.3vw, 60px) 0;
  color: var(--fg);
  text-decoration: none;
}
.wl__name {
  grid-column: 2 / 8;
  font: 400 clamp(44px, 5.25vw, 140px)/1.2 var(--f-sans);
  letter-spacing: -.045em;
  white-space: nowrap;
  transition: transform .3s cubic-bezier(.7, 0, .3, 1);
}
.wl__type { grid-column: 8 / 11; font: 400 clamp(15px, .97vw, 20px)/1.3 var(--f-sans); transition: transform .3s cubic-bezier(.7, 0, .3, 1); }
/* The hover (2026-11-09; the user's reference, matched one to one).
   The row under the pointer fades to a third, its name steps back a quarter of its own size
   (-.25em, 26px at 1966) and its kind on by 15px (.8em of 19px), in .3s. With a mouse that is the
   row you point at; on a phone or a narrow window, the one the card stands over as the list
   scrolls under it (.is-hot, the script) */
.wl__link { transition: opacity .3s cubic-bezier(.7, 0, .3, 1); }
.wl__link.is-hot { opacity: .33; }
.wl__link.is-hot .wl__name { transform: translateX(-.25em); }
.wl__link.is-hot .wl__type { transform: translateX(15px); }
@media (hover: hover) and (pointer: fine) and (min-width: 840px) {
  .wl__link:hover { opacity: .33; }
  .wl__link:hover .wl__name { transform: translateX(-.25em); }
  .wl__link:hover .wl__type { transform: translateX(15px); }
}
/* the card and the circle, centred on the pointer (the script sets translate: the circle keeps up,
   about .05 s behind, the card trails, about .1 s). The card opens as a window from its middle with
   the pictures in it at their full size, .4 s, quick then
   settling, and closes the same way; the circle grows with it */
.wl__peek, .wl__view {
  position: fixed;
  left: 0;
  top: 0;
  pointer-events: none;
  transform: translate(-50%, -50%);
}
/* a square card, 475 at 1966: each project its picture, inset to 85%, on its own colour */
.wl__peek {
  z-index: 30;
  width: clamp(280px, 24.2vw, 520px);
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--line);
  clip-path: inset(50%);
  transition: clip-path .4s cubic-bezier(.34, 1, .64, 1);
}
/* every project in one column; it slides to the one under the pointer (.6 s, slow at both ends) */
.wl__strip { height: 100%; transform: translateY(calc(var(--i, 0) * -100%)); transition: transform .6s cubic-bezier(.65, 0, .35, 1); }
.wl__slide { display: grid; place-items: center; height: 100%; background: var(--slide, var(--line)); }
.wl__slide img { display: block; width: 85%; height: auto; aspect-ratio: 16 / 10; object-fit: cover; object-position: 50% 0; }
/* View is the mark's blue square, SOLID, with View in white on it (the user, 2026-11-09: first "use
   our '.' logo shape and inside 'view'", then "smaller and without hole in the middle": it was the
   hollow dot, 108 at 1966, the word in its hole). 77 at 1966, the word a fifth of the side */
.wl__view {
  --dot: clamp(64px, 3.9vw, 84px);
  z-index: 31;
  display: grid;
  place-items: center;
  width: var(--dot);
  aspect-ratio: 1;
  background: var(--accent);
  color: var(--accent-ink);
  font: 500 calc(var(--dot) * .2)/1 var(--f-sans);
  letter-spacing: -.01em;
  transform-origin: 0 0;
  scale: 0;
  transition: scale .4s cubic-bezier(.34, 1, .64, 1);
}
.work.is-peek .wl__peek, .wk.is-peek .wl__peek { clip-path: inset(0); }
/* (the work page's too: the card over its rows, the dot alone over its pictures) */
.work.is-peek .wl__view, .wk.is-peek .wl__view, .wk.is-view .wl__view { scale: 1; }
/* On touch, the preview stays at the center while the list scrolls under it. */
@media (hover: none), (pointer: coarse), (max-width: 839.98px) {
  .wl__peek { width: clamp(168px, 46vw, 300px); }
  .wl__view { --dot: 64px; }
}
@media (prefers-reduced-motion: reduce) { .wl__peek, .wl__view, .wl__strip, .wl__link, .wl__name, .wl__type { transition: none !important; } }

@media (max-width: 599.98px) {
  .pop .ii-ic { --ii-m: 5; }
  .pop--l .ii-ic { --ii-m: 7; }
  .pop--s .ii-ic { --ii-m: 3; }
  .pop--blue, .pop--cream { width: 72px; }
  .pop--blue .ii-ic, .pop--cream .ii-ic { --ii-m: 4; }
  .pop--code { width: 84px; }
}

/* ---------- More work (a bar button, centred under the list). The work page's filters and
   views are toggle blocks (.blk.pill, css/ii-buttons.css): grey, the one that is on filled with
   the ink ---------- */

.more { display: flex; justify-content: center; margin-top: clamp(48px, 9vh, 104px); }
.more .barbtn { width: clamp(300px, 20.6vw, 405px); }

/* ---------- project indexes ---------- */

.case.wk { padding-bottom: clamp(96px, 18vh, 220px); }
.wk__head, .case__head { padding-inline: calc((100% + var(--g)) / 12); }
.case .wk__h { max-width: 11.5em; font: 400 clamp(44px, 6.1vw, 132px)/1.06 var(--f-sans); letter-spacing: -.045em; }
.wk__title { display: flex; align-items: flex-start; }
.wk__title .wk__total { margin-top: .65em; font-size: clamp(17px, 2.4vw, 44px); }
.wk__tools { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; margin-top: clamp(32px, 7vh, 72px); }
.wk__filters, .wk__views { display: flex; flex-wrap: wrap; gap: 10px; }
.wk__list { margin-top: clamp(56px, 12vh, 140px); }
.wk__list[hidden], .wk__grid[hidden], .wk__row[hidden], .wk__card[hidden], .wk__filters [hidden] { display: none; }
.wk__heads, .wk__link { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); column-gap: var(--g); }
.wk__heads { padding-bottom: clamp(14px, 2.6vh, 28px); color: var(--mute); }
.wk__heads > :nth-child(1), .wk__name { grid-column: 2 / 6; }
.wk__heads > :nth-child(2), .wk__c:nth-child(2) { grid-column: 6 / 8; }
.wk__heads > :nth-child(3), .wk__c:nth-child(3) { grid-column: 8 / 11; }
.wk__heads > :nth-child(4), .wk__c:nth-child(4) { grid-column: 11 / 13; }
.wk__rows { border-bottom: 1px solid var(--line); }
.wk__row { border-top: 1px solid var(--line); }
.wk__link { align-items: center; padding: clamp(26px, 5.4vh, 40px) 0; color: var(--fg); text-decoration: none; }
.wk__name { font: 400 clamp(28px, 2.3vw, 52px)/1 var(--f-sans); letter-spacing: -.03em; transition: transform .3s cubic-bezier(.7, 0, .3, 1); }
.wk__c { font: 400 clamp(15px, .97vw, 19px)/1.3 var(--f-sans); }
.wk__link:focus-visible { outline-offset: -2px; }
/* the row under the card fades to a third and its name steps back a quarter of its size, as on the
   home page (a phone or a narrow window: .is-hot) */
.wk__link { transition: opacity .3s cubic-bezier(.7, 0, .3, 1); }
.wk__link.is-hot { opacity: .33; }
.wk__link.is-hot .wk__name { transform: translateX(-.25em); }
@media (hover: hover) and (pointer: fine) and (min-width: 840px) {
  .wk__link:hover { opacity: .33; }
  .wk__link:hover .wk__name { transform: translateX(-.25em); }
}
.wk__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(48px, 9vh, 112px) var(--g); margin-top: clamp(56px, 12vh, 140px); }
.wk__tile { display: grid; color: var(--fg); text-decoration: none; }
/* the site on the studio grey, as the case pages show it */
.wk__pic { display: grid; place-items: center; aspect-ratio: 1 / .9; overflow: hidden; background: var(--panel); }
.wk__pic img { display: block; width: 76%; height: auto; box-shadow: 0 30px 60px -34px rgb(0 0 0 / .45); transition: scale var(--md-long2) var(--md-ease-emphasized); }
.wk__cname { margin-top: clamp(18px, 3vh, 28px); font: 400 clamp(28px, 2.3vw, 52px)/1 var(--f-sans); letter-spacing: -.03em; }
.wk__cmeta { display: flex; justify-content: space-between; margin-top: clamp(14px, 2.4vh, 22px); padding-top: 14px; border-top: 1px solid var(--line); color: var(--mute); }
@media (hover: hover) and (pointer: fine) { .wk__tile:hover .wk__pic img { scale: 1.035; } }
/* each row or picture comes up in turn: when the page opens, a filter changes or the view does */
@keyframes wk-in { from { opacity: 0; transform: translateY(28px); } }
.is-anim > .wk__row, .is-anim > .wk__card { animation: wk-in var(--md-long2) var(--md-ease-emphasized-decelerate) calc(var(--n, 0) * 70ms + 60ms) both; }
@media (max-width: 839.98px) {
  .wk__head, .case__head { padding: 0; }
  .wk__heads { display: none; }
  .wk__link { grid-template-columns: minmax(0, 1fr) auto; row-gap: 10px; }
  .wk__name { grid-column: 1 / -1; }
  .wk__c:nth-child(2) { grid-column: 1; grid-row: 3; color: var(--mute); }
  .wk__c:nth-child(3) { grid-column: 1; grid-row: 2; color: var(--mute); }
  .wk__c:nth-child(4) { grid-column: 2; grid-row: 2; }
  .wk__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- the cases: a page per project. Opening one swaps the home page
   out for it behind the curtain (the window scrolls the case); closing swaps
   the home page back in, where it was ---------- */

.cases[hidden], .case[hidden] { display: none; }
html.case-open #top { display: none; }
html.case-open .cases[hidden] + .foot { visibility: hidden; }
.cases {
  display: flow-root;
  --panel: color-mix(in srgb, var(--fg) 7%, var(--bg));
  min-height: 100vh;
  padding-top: var(--bar-h);
  background: var(--bg);
  color: var(--fg);
}
.case { padding: clamp(64px, 12vh, 144px) var(--g) 0; }
.case__h { margin: 0; font: 400 clamp(48px, min(9.5vw, 20vh), 250px)/.95 var(--f-sans); letter-spacing: -.05em; }
.case__h:focus { outline: none; }
/* four facts on the grid, three columns each, a hairline over each */
.case__meta { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--g); margin-top: clamp(28px, 6vh, 64px); }
.case__meta > div { display: grid; align-content: start; gap: 10px; padding-top: 12px; border-top: 1px solid var(--line); }
.case__meta dt { color: var(--mute); }
/* the privacy policy (#/privacy), a page in the cases' type: each part's name at the left, its
   words in the right half under the lead, a hairline over each part */
.pv > .case__lead { max-width: 34ch; margin: clamp(48px, 10vh, 120px) 0 0 calc(50% + var(--g) / 2); font: 400 clamp(20px, 1.9vw, 44px)/1.25 var(--f-sans); letter-spacing: -.02em; }
@media (max-width: 839.98px) { .pv > .case__lead { margin-left: 0; } }
.pv__body { margin: clamp(56px, 10vh, 120px) 0 clamp(72px, 14vh, 160px); }
.pv__sec { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--g); padding: 14px 0 clamp(40px, 7vh, 72px); border-top: 1px solid var(--line); }
.pv__k { margin: 0; color: var(--mute); font-weight: 400; }
.pv__t { max-width: 62ch; font: 400 17px/1.55 var(--f-sans); letter-spacing: -.005em; }
/* (h3: the policy's title is the page's h1, its parts h2, these under them) */
.pv__t h3 { margin: 26px 0 6px; font: 400 20px/1.3 var(--f-sans); letter-spacing: -.01em; }
.pv__t h3:first-child { margin-top: 0; }
.pv__t p { margin: 0 0 14px; }
.pv__t ul { margin: 0 0 14px; padding-left: 1.1em; }
.pv__t li { margin: 4px 0; }
.pv__t code { font: 400 .86em/1 var(--f-term); letter-spacing: .02em; }
.pv__t a { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.pv__t a:hover { text-decoration-thickness: 2px; }
.pv__facts { display: grid; grid-template-columns: minmax(104px, 11ch) minmax(0, 1fr); gap: 10px 20px; margin: 0 0 20px; }
.pv__facts dt { padding-top: 3px; color: var(--mute); font: 400 12px/1.4 var(--f-term); letter-spacing: .04em; text-transform: uppercase; }
.pv__facts dd { margin: 0; }
/* a detail still to come: the one blue, so none can be missed */
.pv mark { padding: 0 .3em; border-radius: 3px; background: var(--accent); color: var(--accent-ink); font: 400 .82em/1.6 var(--f-term); letter-spacing: .02em; -webkit-box-decoration-break: clone; box-decoration-break: clone; }
@media (max-width: 839.98px) { .pv__sec { grid-template-columns: minmax(0, 1fr); gap: 18px; } }
@media (max-width: 599.98px) {
  .pv__facts { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .pv__facts dd { margin-bottom: 12px; }
}
/* ---------- case studies ---------- */
.case--study {
  --case-content: min(68vw, 1300px);
  --case-wide: min(84vw, 1660px);
  --case-stage: color-mix(in srgb, var(--case-tone) 17%, #eeedeb);
  padding-top: clamp(122px, 22vh, 240px);
}
html:not(.intro):has(.case--study:not([hidden])) .gridlines { opacity: .35; }
.case--study .case__head { width: var(--case-content); margin-inline: auto; padding: 0; }
.case--study .case__h { font-size: clamp(52px, 7.1vw, 156px); line-height: 1; }
.case--study .case__meta {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(22px, 4.5vw, 80px);
  margin: clamp(54px, 10.5vh, 136px) 0 0;
}
.case--study .case__meta > div { min-width: 0; gap: 0; padding: 0; border: 0; }
.case--study .case__meta dt { padding-bottom: clamp(14px, 2.8vh, 32px); font-size: 11px; }
.case--study .case__meta dd {
  margin: 0;
  padding-top: clamp(14px, 2.8vh, 32px);
  border-top: 1px solid var(--line);
  font: 400 clamp(15px, 1.25vw, 22px)/1.32 var(--f-sans);
}
.case__place { display: flex; flex-wrap: wrap; align-items: baseline; gap: .25em .5em; }
.case__place [aria-hidden] { color: var(--mute); }

.case__hero {
  position: relative;
  width: var(--case-wide);
  margin: clamp(90px, 14vh, 170px) auto clamp(54px, 9vw, 152px);
}
.case__cover { position: relative; overflow: hidden; background: var(--case-tone); }
.case__cover img { display: block; width: 100%; height: auto; }
.case__visit {
  position: absolute;
  top: 0;
  right: 7.2%;
  z-index: 3;
  width: clamp(98px, 11.8vw, 176px);
  aspect-ratio: 1;
  translate: 0 -50%;
}
.case__visit > .blk__face { flex-direction: row; gap: 9px; }
.case__cover--vtg { aspect-ratio: 7 / 3; background: #806c76; }
.case__cover--vtg .vtg-cover__portrait { height: 100%; object-fit: cover; object-position: center; }
.case__cover--vtg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(270deg, rgb(26 13 24 / .55), transparent 65%);
  pointer-events: none;
}
.vtg-cover__mark {
  position: absolute;
  z-index: 1;
  top: 50%;
  right: 7%;
  translate: 0 -50%;
  display: grid;
  justify-items: center;
  gap: 8px;
  color: #fff;
  text-align: center;
}
.vtg-cover__mark img { width: min(17vw, 260px); height: auto; }
.vtg-cover__mark span { font: 400 clamp(15px, 2vw, 30px)/1 var(--f-sans); letter-spacing: -.04em; }

.case__showcase { margin-inline: calc(var(--g) * -1); color: #292a2d; }
.case__stage {
  display: grid;
  justify-items: center;
  gap: clamp(46px, 8vw, 136px);
  padding: clamp(46px, 8.5vw, 150px) var(--g);
  background: var(--case-stage);
}
.case__scene { width: min(100%, 1300px); margin: 0; }
.case__caption { margin-top: clamp(14px, 2.5vw, 32px); color: #48484c; text-align: center; font-size: 11px; }
.case__laptop { width: min(84vw, 1240px); margin-inline: auto; }
.case__lid {
  position: relative;
  width: 88%;
  margin-inline: auto;
  padding: clamp(6px, 1.42vw, 20px) clamp(5px, .88vw, 13px) clamp(5px, 1vw, 14px);
  border: 1px solid #767982;
  border-radius: clamp(7px, 1.18vw, 17px) clamp(7px, 1.18vw, 17px) 2px 2px;
  background: linear-gradient(115deg, #26282c, #101113 44%, #151619);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .11), 0 23px 60px -24px rgb(0 0 0 / .62);
}
.case__lid::before {
  content: "";
  position: absolute;
  top: clamp(2px, .48vw, 7px);
  left: 50%;
  width: clamp(3px, .46vw, 7px);
  aspect-ratio: 1;
  translate: -50% 0;
  border-radius: 50%;
  background: radial-gradient(circle at 37% 34%, #687291 3%, #1d263a 26%, #08080a 66%);
  box-shadow: 0 0 0 1px #303238;
}
.case__screen { overflow: hidden; aspect-ratio: 16 / 10; border-radius: clamp(2px, .5vw, 7px); background: #111; }
.case__screen :is(img, video), .case__film video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.case__base {
  position: relative;
  height: clamp(7px, 1.05vw, 16px);
  margin-top: -1px;
  border-radius: 1px 1px 44% 44% / 1px 1px 65% 65%;
  background:
    linear-gradient(90deg, rgb(0 0 0 / .45), transparent 7% 92%, rgb(0 0 0 / .42)),
    linear-gradient(#d0d1d5 2%, #92949e 28%, #575862 64%, #34353b 100%);
  box-shadow: 0 15px 20px -8px rgb(21 20 23 / .58);
}
.case__base::before {
  content: "";
  position: absolute;
  inset: 0 43% 58%;
  border-radius: 0 0 9px 9px;
  background: linear-gradient(#41434b, #898b95);
}
.case__detail {
  display: block;
  width: min(78vw, 1120px);
  height: auto;
  margin-inline: auto;
  box-shadow: 0 24px 52px -25px rgb(16 16 21 / .48);
}
.case__film {
  margin: 0;
  overflow: hidden;
  aspect-ratio: 16 / 9;
  max-height: 92svh;
  background: #111114;
}
.case__film video { object-fit: contain; }
.case__film--screen { aspect-ratio: 16 / 10; }
.case__phones {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(21vw, 292px);
  justify-content: center;
  align-items: start;
  gap: clamp(16px, 4.5vw, 72px);
  width: 100%;
  padding: 12px 4px 18px;
}
.case__phone { min-width: 0; margin: 0; }
.case__phone:nth-child(2) { margin-top: clamp(22px, 4vw, 60px); }
.case__glass {
  position: relative;
  padding: clamp(9px, 1.38vw, 19px) clamp(3px, .43vw, 7px) clamp(8px, 1.2vw, 16px);
  border: 1px solid #898c95;
  border-radius: clamp(22px, 3vw, 44px);
  background: #111216;
  box-shadow: inset 0 0 0 2px #373942, 0 20px 44px -16px rgb(17 18 22 / .64);
}
.case__glass::before {
  content: "";
  position: absolute;
  top: clamp(4px, .49vw, 7px);
  left: 50%;
  width: 24%;
  height: clamp(4px, .64vw, 9px);
  translate: -50% 0;
  border-radius: 20px;
  background: radial-gradient(circle at 84% 50%, #293449 0 7%, #07070a 9%);
  box-shadow: 0 0 0 1px rgb(255 255 255 / .08);
}
.case__glass::after {
  content: "";
  position: absolute;
  bottom: clamp(4px, .52vw, 8px);
  left: 50%;
  width: 30%;
  height: 2px;
  translate: -50% 0;
  border-radius: 2px;
  background: #bfc0c5;
}
.case__glass img { display: block; width: 100%; height: auto; border-radius: clamp(12px, 1.8vw, 25px); }

.case__end {
  --fg: #f5f5f6;
  --bg: #101114;
  --mute: #babac2;
  display: grid;
  justify-items: center;
  gap: clamp(26px, 5vw, 72px);
  margin-inline: calc(var(--g) * -1);
  padding: clamp(66px, 12vh, 150px) var(--g) clamp(40px, 6vh, 90px);
  background: var(--bg);
  color: var(--fg);
}
.case__next {
  position: relative;
  display: grid;
  justify-items: center;
  gap: clamp(14px, 2.8vh, 32px);
  width: var(--case-content);
  padding-bottom: clamp(142px, 18vw, 272px);
  overflow: hidden;
  border-bottom: 1px solid #45454d;
  color: inherit;
  text-align: center;
  text-decoration: none;
}
.case__next-k { display: inline-flex; align-items: center; gap: 9px; color: var(--mute); }
.case__next-k .ii-ic { --ii-m: 1; }
.case__next-n { font: 400 clamp(38px, 7vw, 116px)/1 var(--f-sans); letter-spacing: -.05em; }
.case__next-art {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: min(35vw, 450px);
  padding: clamp(10px, 1.7vw, 26px);
  translate: -50% 32%;
  background: var(--next-tone);
}
.case__next-art img { display: block; width: 100%; height: auto; }
.case__next:focus-visible { outline: 2px solid #fff; outline-offset: 8px; }
.case__end .barbtn { width: min(100%, 300px); }

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  html:not(.still) .case__next-art, html:not(.still) .case__next-n {
    transition: translate .45s var(--md-ease-emphasized), opacity .45s var(--md-ease-emphasized);
  }
  html:not(.still) .case__next:hover .case__next-art { translate: -50% 12%; }
  html:not(.still) .case__next:hover .case__next-n { opacity: .64; }
}
@media (max-width: 839.98px) {
  .case--study { --case-content: 100%; --case-wide: 100%; padding-top: clamp(78px, 13vh, 126px); }
  .case__laptop, .case__detail { width: min(100%, 740px); }
  .case__visit { right: 12px; }
}
@media (max-width: 599.98px) {
  .case--study .case__h { font-size: clamp(38px, 11.8vw, 68px); line-height: .96; }
  .case--study .case__meta { grid-template-columns: 1fr; gap: 0; margin-top: 34px; }
  .case--study .case__meta > div {
    grid-template-columns: minmax(106px, .8fr) minmax(0, 1.2fr);
    align-items: baseline;
    gap: 10px;
    padding: 12px 0;
    border-top: 1px solid var(--line);
  }
  .case--study .case__meta dt, .case--study .case__meta dd { padding: 0; border: 0; }
  .case__hero { margin-block: 66px 44px; }
  .case__visit > .blk__face { flex-direction: column; gap: 5px; }
  .case__cover--vtg { aspect-ratio: 4 / 5; }
  .case__cover--vtg .vtg-cover__portrait { object-position: 48% center; }
  .case__cover--vtg::after { background: linear-gradient(0deg, rgb(26 13 24 / .66), transparent 58%); }
  .vtg-cover__mark { right: 0; left: 0; top: auto; bottom: 9%; translate: none; }
  .vtg-cover__mark img { width: 25%; }
  .case__phones { grid-auto-columns: min(69vw, 284px); gap: 18px; }
  .case__phones:has(> .case__phone:nth-child(2)) {
    justify-content: start;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
  }
  .case__phone { scroll-snap-align: start; }
  .case__phone:nth-child(2) { margin-top: 0; }
  .case__glass { padding: 16px 5px 13px; border-radius: 34px; }
  .case__glass::before { top: 6px; height: 7px; }
  .case__glass img { border-radius: 22px; }
  .case__next-art { width: min(63vw, 310px); }
}

.case__h .ww { clip-path: inset(-.3em -.12em -.22em -.12em); }
.js .case__h .ch { transform: translateY(112%); transition: transform var(--md-long2) var(--md-ease-emphasized-decelerate) calc(var(--ci, 0) * 26ms + 60ms); }
.case.is-in .case__h .ch { transform: none; }
html.route-intro .case__h .ch { transition: none; }

/* ---------- a service's page (#/branding, #/development, #/ui-ux-design):
   only what is true here. The name and its line,
   its picture large, then what it covers, how it goes and the work that shows
   it, each with its label in the first three columns; the two ways in, and on
   to the next service ---------- */
.sv__head { display: grid; gap: clamp(14px, 2vh, 24px); }
.sv__lede { max-width: 24em; font: 400 clamp(20px, 1.7vw, 34px)/1.22 var(--f-sans); letter-spacing: -.02em; color: var(--mute); }
.sv__hero { margin: clamp(40px, 8vh, 96px) 0 clamp(56px, 10vh, 120px); }
.sv__hero .viz { width: min(100%, 860px, 78vh); margin: 0 auto; border-radius: 14px; }
.sv__sec { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); gap: 24px var(--g); padding: clamp(48px, 9vh, 112px) 0; border-top: 1px solid var(--line); }
.sv__k { grid-column: 1 / 4; color: var(--mute); }
.sv__list, .sv__steps, .sv__work { grid-column: 4 / -1; margin: 0; padding: 0; list-style: none; }
.sv__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--g); }
.sv__list li { padding: clamp(12px, 1.6vh, 18px) 0; border-bottom: 1px solid var(--line); font: 400 clamp(22px, 2.1vw, 42px)/1.1 var(--f-sans); letter-spacing: -.035em; }
.sv__steps { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(28px, 5vh, 56px) var(--g); }
.sv__steps li { display: grid; align-content: start; gap: 10px; }
.sv__steps .t { color: var(--mute); }
.sv__steps b { font: 400 clamp(24px, 2vw, 40px)/1.05 var(--f-sans); letter-spacing: -.035em; }
.sv__steps p { max-width: 24em; color: var(--mute); font: 400 clamp(16px, 1.05vw, 20px)/1.35 var(--f-sans); }
.sv__work { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(20px, 3vh, 36px) var(--g); }
.sv__work a { display: grid; gap: 8px; color: inherit; text-decoration: none; }
.sv__work img { width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: cover; object-position: 50% 0; filter: grayscale(1); transition: filter var(--md-medium2) var(--md-ease-standard); }
.sv__work a:hover img, .sv__work a:focus-visible img { filter: none; }
.sv__work span:not(.t) { font: 400 clamp(20px, 1.5vw, 30px)/1.1 var(--f-sans); letter-spacing: -.03em; }
.sv__work .t { color: var(--mute); }
.sv__cta { display: grid; justify-items: start; gap: clamp(28px, 5vh, 48px); padding: clamp(64px, 12vh, 140px) 0; border-top: 1px solid var(--line); }
/* (the tight leading lets a g or a y hang out of the line, so the line keeps a little foot for them) */
.sv__big { max-width: 11em; padding-bottom: .1em; font: 400 clamp(46px, 6.2vw, 130px)/.94 var(--f-sans); letter-spacing: -.055em; }
.sv__btns { display: grid; gap: 12px; width: clamp(300px, 20.6vw, 405px); }
.sv__next { display: grid; gap: 12px; padding: clamp(48px, 10vh, 120px) 0 clamp(64px, 12vh, 140px); border-top: 1px solid var(--line); color: inherit; text-decoration: none; }
.sv__next .t { color: var(--mute); }
.sv__next-n { font: 400 clamp(56px, min(10vw, 20vh), 300px)/.9 var(--f-sans); letter-spacing: -.05em; transition: transform var(--md-medium4) var(--md-ease-emphasized); }
.sv__next:hover .sv__next-n, .sv__next:focus-visible .sv__next-n { transform: translateX(12px); }
/* a picture arrives as characters, then big pixels, then itself (the script
   lays the canvas over the picture) */

/* ---------- the curtain between pages: the mark's dot, a hollow blue square, comes up where you
   clicked and swells over the screen, its hole closes, the name comes up on the blue, and the hole
   opens again onto the new page (the script draws it on the canvas) ---------- */

.wipe { position: fixed; inset: 0; z-index: 90; visibility: hidden; pointer-events: none; }
.wipe.is-on, html.route-intro .wipe { visibility: visible; pointer-events: auto; }
html.route-intro .wipe:not(.is-on) {
  --wipe-hole: clamp(48px, 12vmin, 110px);
  background: var(--paper);
}
html.route-intro .wipe:not(.is-on)::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  box-sizing: content-box;
  width: var(--wipe-hole);
  height: var(--wipe-hole);
  border: var(--wipe-hole) solid var(--accent);
}
.wipe__cv { display: block; width: 100%; height: 100%; }
/* through the dot (view transitions): the two pages are pictures the script scales into and out of
   the dot's hole; the dot's canvas is its own picture over them, drawn live */
::view-transition-group(root), ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
/* (they slide past each other in the hole: the new over the old, not added to it) */
::view-transition-old(root), ::view-transition-new(root) { mix-blend-mode: normal; }
html.route-intro::view-transition-old(root) { opacity: 0; }
.wipe.is-vt { view-transition-name: ii-dot; }
::view-transition-group(ii-dot), ::view-transition-new(ii-dot) { animation: none; }
.wipe__t {
  position: absolute;
  left: 50%;
  top: 50%;
  overflow: hidden;
  padding: .12em .04em;
  color: var(--accent-ink);
  font: 400 clamp(34px, 4.2vw, 80px)/1 var(--f-sans);
  letter-spacing: -.035em;
  white-space: nowrap;
  translate: -50% -50%;
}
.wipe__t > span { display: block; transform: translateY(115%); }
/* (before the name, the dot again: hollow, its hole a third of its side) */
.wipe__t i { display: inline-block; width: .3em; height: .3em; margin-right: .32em; box-shadow: inset 0 0 0 .1em currentColor; vertical-align: .06em; }
.wipe.has-t .wipe__t > span { transform: none; transition: transform var(--md-long2) var(--md-ease-emphasized-decelerate); }
.wipe.is-out .wipe__t { opacity: 0; transition: opacity var(--md-short3) linear; }

/* ---------- the quote, the opening of the work. Its
   black stage is pulled up a whole screen, so it rises over the About while
   the About still holds on its card, on a slanted top edge that tilts further
   as it rises (--sl from the
   script). Then it pins and holds the quote while the script plays it: the
   dots gather and shrink, the lines wipe solid, the marks drop in and the
   line under it comes up. Then it goes up with the page and the list
   follows ---------- */

/* the work opens on the quote: no top padding, and its own block formatting
   context, so the quote's pull-up overlaps the opening instead of moving the section */
.work { display: flow-root; padding-top: 0; }
.mem { position: relative; z-index: 2; margin-top: -100vh; margin-top: -100svh; clip-path: polygon(0 var(--sl, 0px), 100% 0, 100% 100%, 0 100%); }
/* the slant, while the stage comes up over the About: with motion the stage's black is a sheet
   under it (initMem adds it), sheared from its top right corner by a transform the GPU moves.
   The clip-path above, redrawn every frame over the pinned stage, flickered and dashed the cut.
   It lies in the stage and goes where the stage goes; half as tall again, because it runs on up
   past the stage's top while the slant closes (the stage cuts off what hangs out) */
.mem__sheet { position: absolute; left: 0; top: 0; width: 100%; height: 150%; background: var(--paper); transform-origin: 100% 0; will-change: transform; }
/* clicks go where the eye goes: through the see-through part above the slant to the About (its
   buttons stayed dead there), while the sheet, sheared as it is drawn, takes the ones on the black
   (so they never reach the About hidden under it). The quote has nothing to press */
.mem.has-sheet { clip-path: none; pointer-events: none; }
.mem.has-sheet .mem__sheet { pointer-events: auto; }
.mem.has-sheet .mem__stage { background: transparent; }
/* 1 screen of stage + 1.72 screens of quote + .2 of hold (it was .45: 2.4 wheel notches of nothing) */
.mem__track { position: relative; height: 292vh; height: 292svh; }
.mem__stage { position: sticky; top: 0; display: grid; place-items: center; height: 100vh; height: 100svh; overflow: hidden; background: var(--paper); color: var(--ink); }
/* the dots, over the whole stage (the script fades them once every line is solid) */
.mem__cv { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
/* the block, in its own unit: 9.5 × min(1vw, 1.8vh) for the letters, 3.33 of it between the
   quote and the line under it */
.mem__box { --vu: min(1vw, 1.8vh); position: relative; text-align: center; }
.mem__q {
  font: 400 clamp(36px, calc(var(--vu) * 9.5), 220px)/.92 "Bebas Neue", var(--f-sans);
  letter-spacing: -.005em;
  text-transform: uppercase;
  white-space: nowrap;
  /* the solid letters zoom with the dots, about the same middle (--z from the script) */
  transform: scale(var(--z, 1));
  font-synthesis: none;
}
/* each line uncovered behind the band of swelling dots that fills it, on an edge that leans like
   the band (--ft0..2 / --fb0..2 from the script: the edge's x at the top of the line and at its foot) */
.mem__l { --ft: 130%; --fb: 130%; display: block; width: max-content; margin-inline: auto; clip-path: polygon(0 -15%, var(--ft) -15%, var(--fb) 115%, 0 115%); }
.mem__l:nth-child(1) { --ft: var(--ft0, 130%); --fb: var(--fb0, 130%); }
.mem__l:nth-child(2) { --ft: var(--ft1, 130%); --fb: var(--fb1, 130%); }
.mem__l:nth-child(3) { --ft: var(--ft2, 130%); --fb: var(--fb2, 130%); }
/* the full stop is our hollow dot (the favicon's, the ii's: its hole a third of the side), its
   middle opening while the dots fill it (--hole 0 → 1 from the script: the hole is 1/3 of the side
   × it; open without it) */
.mem__q .bdot { width: .15em; height: .15em; background: none; box-shadow: inset 0 0 0 calc(.075em - var(--hole, 1) * .025em) var(--accent); }
.mem__sub {
  position: absolute;
  top: 100%;
  left: 50%;
  width: max-content;
  max-width: min(30em, 86vw);
  margin-top: calc(var(--vu) * 3.33);
  translate: -50% calc(var(--fall, 0) * 100vh);
  color: var(--ink);
  opacity: var(--sub, .85);
}
@media (max-width: 599.98px) {
  /* a phone keeps the three lines, a size up for its width */
  .mem__box { --vu: min(1.26vw, 1.8vh); }
}

/* ---------- (03) the footer:one screen of the blue (a room, corners and
   buttons; our mark and our words). Everything sits on the screen as a
   share of it: the code near the top, the mark across the middle at its
   own proportions, the two ways in under it, the pill on the left and the
   round shortcuts on the right at half height, the small print in the
   bottom corners. The ink is our black: the buttons, the pill, the
   round shortcuts. The room is drawn by the script; it flies forward
   for ever and slides against the mouse ---------- */

.foot {
  --fg: #fff;
  --bg: var(--accent);
  --mute: rgb(255 255 255 / .74);
  --line: rgb(255 255 255 / .32);
  position: relative;
  height: 100vh;
  height: 100svh;
  min-height: 540px;
  overflow: hidden;
  overflow: clip;
  isolation: isolate;
  background: var(--bg);
  color: var(--fg);
  /* "contact" lands on the end of the page, the footer whole, not a bar's height short of it */
  scroll-margin-top: calc(-1 * (var(--bar-h) + 16px));
}
.foot .bdot { background: #fff; }
/* the work into the footer, a footer parallax (the user's reference, 2026-11-09: "lets do
   it basic like this"; before it the arc, then our dot, then the dot in 3D: "too much"). The footer
   lies under the work, and the work lifts off it on a straight edge. Everything in the footer rides
   one layer that starts a quarter of its height up and settles as the page ends (it comes up at
   three quarters of the scroll's speed), and a black shade over all of it lifts from half to
   nothing on the way, so the footer comes up out of the work's shadow. Measured on the clip: the
   footer's ground goes from 131 to its own 236 evenly as it comes in, which is black at .5 to 0,
   linear (a quarter of its height and black at .5, scrubbed from the footer's top at
   the screen's foot to its top at the screen's top). Scroll timelines run both on the compositor;
   browsers without them get the same sums from the script (initUnder). With less motion: the
   footer simply follows the work, no shade */
.foot__in { position: absolute; inset: 0; }
.foot::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background: #000;
  opacity: var(--shade, 0);
  pointer-events: none;
}
@keyframes foot-under { from { transform: translate3d(0, -25%, 0); } }
@keyframes foot-shade { from { opacity: .5; } to { opacity: 0; } }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* (inset 0: the timeline would otherwise take the bar's scroll-padding off the screen, and finish 44px early) */
    .foot { view-timeline: --foot block; view-timeline-inset: 0; }
    .foot__in { animation: foot-under linear both; animation-timeline: --foot; animation-range: entry 0% entry 100%; }
    .foot::after { animation: foot-shade linear both; animation-timeline: --foot; animation-range: entry 0% entry 100%; }
  }
}
@media (prefers-reduced-motion: reduce) { .foot::after { display: none; } }
.foot__room { position: absolute; left: 0; top: 0; z-index: -1; width: 100%; height: 100%; pointer-events: none; }
/* our code, typing itself out (the script; it shows whole without it) */
.foot__code { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.foot__snip { position: absolute; margin: 0; color: rgb(255 255 255 / .5); font: 400 11px/1.4 var(--f-term); white-space: pre; }
.foot__snip--a { left: 8.7%; top: calc(var(--bar-h) + 3.5%); }
.foot__snip--b { left: 33%; top: calc(var(--bar-h) + 14%); }
.foot__snip--c { left: 80%; top: calc(var(--bar-h) + 4.5%); }
.foot__cur { display: inline-block; width: .62em; height: 1.05em; margin-left: 1px; vertical-align: -.18em; background: rgb(255 255 255 / .7); }
.foot__snip.is-done .foot__cur { display: none; }
/* the middle: the mark across it at its own proportions, the two ways in under it */
.foot__stage { position: absolute; inset: 0; pointer-events: none; }
/* (the mark holds still: nothing to point at or grab) */
.foot__band { position: absolute; left: 0; right: 0; top: 47%; height: clamp(70px, 10vw, 320px); translate: 0 -50%; }
.foot__mark { display: block; width: 100%; height: 100%; }
/* the two ways in: bar buttons side by side, both Book a call's grey as the light page shows it,
   dark: white words on #1b1b1b, a #363636 tile, on the dark page and the light one alike (the user,
   2026-11-09: "match colors of button we use above on 'from idea to launch'", "make email the same
   color as terminal", then, of the light page's footer, "i want this to be the default one"). The
   About's own sums with its light-page ink (#fff) and studio grey (#0a0a0a). On the blue the blue
   line behind them would vanish, so it is black here, the grey a neutral one */
.foot .blk { --blk-back: #000; --blk-mid: #b4b4b4; }
.foot .barbtn { --fg: #fff; --bg: #0a0a0a; }
.foot__btns { position: absolute; left: 50%; top: 68%; display: flex; gap: 12px; translate: -50% 0; pointer-events: auto; white-space: nowrap; }
.foot__btns .barbtn { width: clamp(300px, 20.6vw, 405px); }
/* (the ISO/IEC 27002 capsule up the left side went: the user, 2026-11-09, "remove foot__badge") */
/* the small print in a bar along the foot (the user's reference, 2026-11-09) in
   ours: the top bar's black, its 11px mono and its muted-to-lit colour, the buttons' 7px corners,
   our pixel icons. The year and the name at the left, what you can do in the middle (the bar's own
   middle, whatever the sides measure), the studio's city at the right */
.foot__bar { position: absolute; left: var(--g); right: var(--g); bottom: var(--g); z-index: 1; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; column-gap: 24px; height: 36px; padding: 0 14px; border-radius: 7px; background: #000; color: rgb(255 255 255 / .62); font: 400 11px/1 var(--f-term); letter-spacing: .02em; text-transform: none; white-space: nowrap; }
.foot__copy { justify-self: start; margin: 0; }
.foot__act { display: inline-flex; align-items: center; height: 36px; color: inherit; text-decoration: none; transition: color .5s cubic-bezier(.19, 1, .22, 1); }
.foot__act:hover, .foot__act:focus-visible, .foot__act[aria-current] { color: #fff; }
.foot__act[aria-current] { text-decoration: underline; text-underline-offset: .25em; }
.foot__rights { justify-self: end; margin: 0; }

/* Case studies continue from their Next Case panel into the contact and legal links. */
.cases:has(> .case--study:not([hidden])) + .foot {
  --bg: #101114;
  height: auto;
  min-height: 0;
  scroll-margin-top: var(--bar-h);
}
.cases:has(> .case--study:not([hidden])) + .foot :is(.foot__room, .foot__code, .foot__band),
.cases:has(> .case--study:not([hidden])) + .foot::after { display: none; }
.cases:has(> .case--study:not([hidden])) + .foot .foot__in {
  position: relative;
  inset: auto;
  display: grid;
  gap: 24px;
  padding: 0 var(--g) calc(var(--g) + env(safe-area-inset-bottom, 0px));
  animation: none;
  transform: none !important;
}
.cases:has(> .case--study:not([hidden])) + .foot :is(.foot__stage, .foot__btns, .foot__bar) {
  position: static;
  margin: 0;
  padding: 0;
  translate: none;
}
.cases:has(> .case--study:not([hidden])) + .foot .foot__btns {
  display: flex;
  flex-flow: row wrap;
  justify-content: center;
  gap: 8px;
}
.cases:has(> .case--study:not([hidden])) + .foot .foot__btns .barbtn {
  --h: 42px;
  flex: 0 1 290px;
  width: min(100%, 290px);
  max-width: 100%;
}
.cases:has(> .case--study:not([hidden])) + .foot .foot__bar { padding-inline: 14px; }

/* ---------- terminal ---------- */

.term {
  --link: #8ea2ff;
  --visited: #c9a3ff;
  position: fixed;
  right: var(--g);
  bottom: 14px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  width: min(560px, calc(100vw - 2 * var(--g)));
  height: min(400px, calc(100vh - var(--bar-h) - 40px));
  background: #000;
  color: #fff;
  border: 1px solid #fff;
  box-shadow: 8px 8px 0 var(--accent);
  opacity: 0;
  transform: translateY(16px);
  /* exit: 200ms, emphasized accelerate */
  transition: opacity var(--md-short4) var(--md-ease-emphasized-accelerate), transform var(--md-short4) var(--md-ease-emphasized-accelerate);
}
/* enter: 500ms, emphasized decelerate (a dialog-sized surface) */
.term.is-on {
  opacity: 1;
  transform: none;
  transition: opacity var(--md-short4) linear, transform var(--md-long2) var(--md-ease-emphasized-decelerate);
}
.term[hidden] { display: none; }
.term__bar { display: flex; justify-content: space-between; align-items: center; min-height: 48px; padding: 0 0 0 16px; background: #fff; color: #000; }
.term__x { display: grid; place-items: center; width: 48px; height: 48px; padding: 0; background: none; border: 0; color: inherit; font: inherit; cursor: pointer; }
.term__x:hover { color: var(--accent-ink); background: var(--accent); }
.term__out {
  flex: 1;
  overflow-y: auto;
  padding: 12px 16px 4px;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: .25px;
  text-transform: none;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  scrollbar-width: thin;
  scrollbar-color: #555 #000;
}
.term__line.is-cmd { color: var(--link); }
.term__line.is-dim { color: #8a8a8a; }
.term__line.is-err { color: #ff6b5b; }
.term__in { display: flex; gap: 8px; align-items: center; min-height: 48px; padding: 4px 16px 8px; text-transform: none; }
.term__ps { flex: none; color: var(--link); }
.term__in input {
  flex: 1;
  min-width: 0;
  padding: 0;
  background: none;
  border: 0;
  outline: 0;
  color: #fff;
  caret-color: var(--link);
  font: 400 14px/20px var(--f-term);
}

/* entering the screen: emphasized decelerate; a large area, so the long end (500ms) */
.js [data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity var(--md-long2) linear, transform var(--md-long2) var(--md-ease-emphasized-decelerate); transition-delay: calc(var(--i, 0) * 70ms); }
.js [data-reveal].is-in { opacity: 1; transform: none; }

/* ---------- Material 3 state layers: hover 8%, focus 10%, pressed 10% ---------- */

.bk, .term__x { position: relative; }
:is(.bk, .term__x)::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: currentColor;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--md-short3) var(--md-ease-standard);
}
:is(.bk, .term__x):hover::after { opacity: var(--md-hover); }
:is(.bk, .term__x):focus-visible::after { opacity: var(--md-focus); }
:is(.bk, .term__x):active::after { opacity: var(--md-press); }

/* ---------- smaller windows ---------- */

/* compact and medium (below 840): eight columns, then four */
@media (max-width: 839.98px) {
  .caps { font-size: clamp(44px, 13.2vw, 120px); }
  /* the About on the card stacks on a phone: the words, the tiles (two over
     one wide one; the script gives their box its height), then the buttons */
  .door .idea { inset: calc(var(--bar-h) + 48px) 0 16px; grid-template-columns: minmax(0, 1fr); grid-template-rows: none; align-content: center; row-gap: clamp(14px, 2.4vh, 24px); }
  .idea__side, .idea__stage, .idea__cta { grid-column: 1 / -1; grid-row: auto; }
  .idea__stage { height: var(--stage-h, 70vw); }
  .idea__side { gap: 12px; }
  .idea__h { font-size: clamp(38px, 11vw, 64px); }
  /* (two halves of the width on a phone, so the pair still fits side by side at 320) */
  .idea__cta .barbtn { --bb-pl: calc(var(--h) + 6px); --bb-pr: 10px; flex: 1 1 0; min-width: 0; max-width: 260px; }
  .idea__lab { height: 50px; padding: 12px 12px 0; font-size: 16px; line-height: 22px; }
  .idea__n { font-size: 12px; }
  .idea__d { font-size: 12px; line-height: 16px; }
  /* the door's mark across nearly the whole card */
  .door__media { width: min(96vw, calc((100svh - var(--bar-h)) * 1.6)); }
  /* the list across the whole width, each name over what it was, the label over the names */
  .wl { margin: 0 var(--g); }
  .wl__h { padding-left: var(--g); font-size: 11px; }
  .wl__link { grid-template-columns: minmax(0, 1fr); row-gap: 8px; padding: clamp(18px, 3.4vh, 32px) 0; }
  .wl__name, .wl__type { grid-column: 1 / -1; }
  .wl__name { font-size: clamp(40px, 11vw, 80px); line-height: 1.05; white-space: normal; }
  .case__meta { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 20px; }
  /* the footer: the middle snippet goes */
  .foot__snip--b { display: none; }
  /* and it is one column. The snippets at the top, the bar at the foot, and between them the mark
     (the whole width, stretched as the header is) over the two ways in, held in the middle of what
     is left however tall the screen is (the user: "on mobile it should stretch better so it can
     stay in the middle") */
  .foot__in { display: flex; flex-direction: column; }
  .foot__stage { position: relative; inset: auto; flex: 1; display: flex; flex-direction: column; justify-content: center; gap: clamp(20px, 3.4vh, 40px); padding-top: calc(var(--bar-h) + 72px); }
  .foot__band { position: relative; top: auto; flex: none; height: clamp(64px, 24vw, 200px); translate: none; }
  /* (side by side while both fit their words, 290 each at least, else one over the other: squeezed,
     the address ran under its tile) */
  .foot__btns { position: relative; left: auto; top: auto; flex-wrap: wrap; justify-content: center; margin: 0 var(--g); translate: none; }
  .foot__btns .barbtn { flex: 1 1 290px; width: auto; max-width: 405px; }
  .foot__bar { position: relative; left: auto; right: auto; bottom: auto; margin: 0 var(--g) calc(var(--g) + env(safe-area-inset-bottom, 0px)); }
  .term {
    left: 0;
    right: 0;
    bottom: env(safe-area-inset-bottom, 0px);
    width: auto;
    height: min(62vh, 460px);
    border-width: 1px 0 0;
    box-shadow: none;
  }
  .term__in input, .term__out { font-size: 16px; line-height: 24px; }
  /* the services one under another; a service's page in one column */
  .svc__in { grid-template-columns: minmax(0, 1fr); }
  .sv__k, .sv__list, .sv__steps, .sv__work { grid-column: 1 / -1; }
}
@media (max-width: 599.98px) {
  .sv__list, .sv__steps, .sv__work { grid-template-columns: minmax(0, 1fr); }
  /* the thesis a size down; the studio's halves go to the corners under the header */
  .about__big { font-size: 13vw; }
  .lead { inset: calc(var(--bar-h) + var(--head-max)) 0 0; }
  .lead__l--a { left: var(--g); top: clamp(14px, 3.4vh, 40px); }
  .lead__l--b { right: var(--g); top: auto; bottom: clamp(18px, 4.6vh, 52px); }
  /* a phone: the mark where it was, in the middle of what is left, and the two ways in across the
     width under it, the address over the terminal (the user, 2026-11-09: "logo / button / button",
     the mark not moved; it had stood between them). Rows of 1fr either side of it hold it there, and
     the room the bar's second line took stays under the buttons, so it does not move down either */
  .foot__stage { display: grid; grid-template-rows: 1fr auto 1fr; justify-content: normal; padding-bottom: 40px; }
  .foot__band { grid-row: 2; }
  .foot__btns { grid-row: 3; align-self: start; flex-direction: column; flex-wrap: nowrap; gap: 12px; }
  .foot__btns .barbtn { flex: none; width: auto; max-width: none; }
  /* (at 320 the address's words wanted 290 of the 288 there are: a size down) */
  @media (max-width: 340px) { .foot__btns .barbtn { font-size: 15px; } }
  /* the bar's three on one line, the privacy policy in its middle (the user, 2026-11-09: "- - -",
     not the policy over the other two): the type a size down as the width needs it (11px at 423
     and up, 9 at 346 and under), 40px to a tap */
  .foot__bar { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); column-gap: 12px; height: 40px; padding: 0 12px; font-size: clamp(9px, 2.6vw, 11px); }
  .foot__act { height: 40px; }
  /* (under 360 the three want a little more of the width) */
  @media (max-width: 359.98px) { .foot__bar { margin-left: 8px; margin-right: 8px; column-gap: 8px; padding: 0 8px; } }
  .foot__snip--c { display: none; }
  .foot__snip--a { left: var(--g); }
}
/* a phone on its side: the footer is the screen's height (its 540 minimum left the mark's top above
   the screen at the page's end), so the snippets go, the mark keeps under a third of it, and the
   buttons and the bar go back to one line each (stacked, they were taller than the screen) */
@media (max-width: 839.98px) and (max-height: 520px) {
  .foot { min-height: 0; }
  .foot__code { display: none; }
  .foot__stage { gap: 14px; padding-top: calc(var(--bar-h) + 10px); }
  .foot__band { height: min(24vw, 30vh); }
  /* (a column again, not a phone's rows: the mark over the two, side by side) */
  .foot__stage { display: flex; justify-content: center; padding-bottom: 0; }
  .foot__btns { flex-direction: row; flex-wrap: nowrap; align-self: stretch; }
  .foot__btns .barbtn { --h: 44px; flex: 0 1 auto; width: auto; margin: 0; }
  .foot__bar { height: 36px; padding: 0 14px; }
  .foot__act { height: 36px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  /* nothing pins and nothing scrubs: every scroll piece shows its finished state */
  .open { height: auto; }
  /* the opening: the studio's line under the thesis, then the card already open under it */
  .open__stage { position: relative; height: auto; overflow: visible; }
  .ht { position: relative; min-height: 100vh; min-height: 100svh; }
  .lead { bottom: auto; height: 100vh; height: 100svh; }
  /* the card is the About already: its own height, the door's mark gone */
  .door { position: relative; height: auto; }
  .door__panel { position: relative; min-height: 100vh; min-height: 100svh; transform: none; visibility: visible; }
  .door__media { display: none; }
  .door .idea { position: relative; inset: auto; min-height: 100svh; padding-top: calc(var(--bar-h) + 76px); padding-bottom: 48px; pointer-events: auto; }
  /* the quote: still and solid, in its own screen at the top of the work */
  .mem { margin-top: 0; clip-path: none; }
  .mem__track { height: auto; }
  .mem__stage { position: relative; height: auto; min-height: 100vh; min-height: 100svh; }
  .mem__cv { display: none; }
  .mem__q { transform: none; }
  .mem__l { clip-path: none; }
  .mem__sub { translate: -50% 0; opacity: .85; }
}
