/* Version E, the portal: the live site's quiet frame, with the work in the middle 40% of the screen. The page takes
   the colour of the project on show; what each piece is sits to its left, where it's from to its right. Drag, swipe,
   scroll sideways or use the arrow keys to move along; Ask me anything floats at the bottom. Everything is a token. */

/* ---------- the scale of the page: 16px up to 1440, growing to 20px at 2560, capped at 22px ---------- */
html { font-size: clamp(100%, calc(100% + (100vw - 1440px) / 280), 137.5%); -webkit-text-size-adjust: 100%; }

:root {
  /* Warm Ink: hue 75, lightness only */
  --ink: #1b1a18; --grey: #6f6e6b; --secondary: #535250; --paper: #fafaf9; --surface: #ffffff; --tint: #f1f0ee;
  --hairline: #e4e2de; --sheet: #efede9; --outline: rgba(27, 26, 24, .08);
  --shadow: 0 1px 2px rgba(28,25,20,.05), 0 6px 16px -6px rgba(28,25,20,.14);
  --shadow-lift: 0 2px 4px rgba(28,25,20,.05), 0 6px 14px rgba(28,25,20,.06), 0 18px 36px rgba(28,25,20,.06);
  /* objects, not boxes: a tight contact shadow, and a softer one when lifted (V2) */
  --contact: 0 1px 2px rgba(28,25,20,.06), 0 14px 28px -14px rgba(28,25,20,.22);
  --contact-lift: 0 2px 4px rgba(28,25,20,.06), 0 24px 44px -18px rgba(28,25,20,.3);
  --tile-ring: 0 0 0 1px rgba(28,25,20,.07), 0 8px 16px -8px rgba(28,25,20,.35);
  --sticker-shadow: drop-shadow(0 1px 1px rgba(28,25,20,.16)) drop-shadow(0 4px 6px rgba(28,25,20,.14));
  /* the grease pencil, kept for the one place it belongs: the selects on the contact sheet */
  --pencil: oklch(56% 0.2 29);
  --pencil-w: 2.3px;

  /* One typeface for every word (Owen's pick, 12 Oct 2026): small labels and numbers included. The live pieces keep
     their own products' fonts. */
  --sans: "Schibsted Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: var(--sans);

  /* The baseline unit is the body leading: 24px at 360, 28 at 1440 (35 at 2560 through the root size) */
  --bl: clamp(1.5rem, 1.417rem + 0.3704vw, 1.75rem);
  --bl-q: calc(var(--bl) / 4);
  --bl-h: calc(var(--bl) / 2);
  --line-1: var(--bl); --line-2: calc(var(--bl) * 2); --line-3: calc(var(--bl) * 3); --line-4: calc(var(--bl) * 4);
  --line-6: calc(var(--bl) * 6); --line-8: calc(var(--bl) * 8);

  /* One scale */
  --step-n1: clamp(0.8333rem, 0.8299rem + 0.0154vw, 0.8438rem);  /* 13.3 to 13.5: meta, numbers */
  --step-cap: clamp(0.875rem, 0.8542rem + 0.0926vw, 0.9375rem);   /* 14 to 15: captions */
  --step-0: clamp(1rem, 0.9583rem + 0.1852vw, 1.125rem);          /* 16 to 18: body */
  --step-1: clamp(1.2rem, 1.1rem + 0.4444vw, 1.5rem);             /* 19 to 24: leads */
  --step-2: clamp(1.5rem, 1.25rem + 1.111vw, 2.25rem);            /* 24 to 36: section heads */
  --step-3: clamp(1.9rem, 1.45rem + 2vw, 3.25rem);                /* 30 to 52: product names */
  --step-hero: clamp(2.25rem, 1.5rem + 3.333vw, 4.5rem);          /* 36 to 72: the claim */

  /* The grid: 4, 8, 12 columns; gutter one line; margins from one formula */
  --margin: max(1.25rem, min(9.524vw - 1.071rem, 8.333vw));
  --cols: 4;
  --gutter: var(--bl-h);
  --measure: 30em;

  /* Shape */
  --radius-plate: 12px;
  --radius-tile: 0.8rem;
  --radius-pill: 999px;

  /* Motion */
  --ease-out: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-ui: cubic-bezier(0.4, 0, 0.2, 1);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --spring: cubic-bezier(.34, 1.56, .64, 1);   /* arrivals and hover only, never on press */
  --dur-hover: 150ms; --dur-open: 250ms; --dur-close: 150ms; --dur-sheet: 500ms; --dur-enter: 800ms;
  --stagger: 90ms; --stagger-word: 45ms; --press: 0.97; --rise: 8px; --blur: 8px;
  --lift: 3px; --dur-lift: 450ms; --ease-lift: var(--ease-expo);
  --draw: 900ms;

  /* The names the shared pieces, the larger view and the chat already use, mapped onto this system */
  --space-3xs: var(--bl-q); --space-2xs: calc(var(--bl) / 3); --space-xs: var(--bl-h); --space-s: calc(var(--bl) * .75);
  --space-m: var(--bl); --space-l: calc(var(--bl) * 1.5); --space-xl: var(--line-2); --space-2xl: var(--line-4); --space-3xl: var(--line-6);
  --text-xs: var(--step-n1); --text-s: var(--step-n1); --text-m: var(--step-0); --text-l: var(--step-0); --text-xl: var(--step-1); --text-2xl: var(--step-hero);
  --leading: 1.55; --radius-s: 6px; --radius-m: 10px; --radius-card: 12px; --radius-panel: 16px; --gap: var(--gutter);
}
@media (width >= 600px)  { :root { --cols: 8; --gutter: var(--bl); } }
@media (width >= 1024px) { :root { --cols: 12; } }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --ink: #e7e6e3; --grey: #9a9893; --secondary: #b3b1ac; --paper: #131211; --surface: #1d1c1a; --tint: #24231f;
    --hairline: #2f2e2b; --sheet: #1a1917; --outline: rgba(255, 255, 255, .08);
    --shadow: 0 0 0 1px rgba(255,255,255,.08); --shadow-lift: 0 0 0 1px rgba(255,255,255,.14);
    --contact: 0 0 0 1px rgba(255,255,255,.06), 0 16px 30px -14px rgba(0,0,0,.6);
    --contact-lift: 0 0 0 1px rgba(255,255,255,.08), 0 26px 46px -18px rgba(0,0,0,.7);
    --tile-ring: 0 0 0 1px rgba(255,255,255,.1), 0 8px 16px -8px rgba(0,0,0,.6);
    --pencil: oklch(68% 0.18 31);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --ink: #e7e6e3; --grey: #9a9893; --secondary: #b3b1ac; --paper: #131211; --surface: #1d1c1a; --tint: #24231f;
  --hairline: #2f2e2b; --sheet: #1a1917; --outline: rgba(255, 255, 255, .08);
  --shadow: 0 0 0 1px rgba(255,255,255,.08); --shadow-lift: 0 0 0 1px rgba(255,255,255,.14);
  --contact: 0 0 0 1px rgba(255,255,255,.06), 0 16px 30px -14px rgba(0,0,0,.6);
  --contact-lift: 0 0 0 1px rgba(255,255,255,.08), 0 26px 46px -18px rgba(0,0,0,.7);
  --tile-ring: 0 0 0 1px rgba(255,255,255,.1), 0 8px 16px -8px rgba(0,0,0,.6);
  --pencil: oklch(68% 0.18 31);
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; background: var(--paper); color: var(--ink); font: 400 var(--step-0) / var(--bl) var(--sans);
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow-x: clip; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
p, h1, h2, h3, ol, ul, figure, blockquote { margin: 0; }
ol, ul { padding: 0; list-style: none; }
img, video { display: block; max-width: 100%; }
:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; border-radius: 4px; }
::selection { background: color-mix(in srgb, var(--ink) 14%, transparent); }
.g { color: var(--grey); }
.mono { font-family: var(--mono); font-size: var(--step-n1); line-height: round(nearest, 1.45em, var(--bl-q)); letter-spacing: 0; }
/* even-width figures only where numbers line up and change: the counters */
.count, .m-count { font-variant-numeric: tabular-nums; }
script { display: none !important; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.skip { position: absolute; left: var(--margin); top: -4rem; z-index: 50; padding: var(--bl-q) var(--bl-h); background: var(--ink); color: var(--paper); border-radius: 6px; font-size: var(--step-n1); }
.skip:focus { top: var(--bl-h); }


/* ---------- E's frame: four quiet corners, and the work in the middle 40% of the screen ---------- */
:root {
  --frame-x: clamp(1.25rem, 0.5rem + 4.2vw, 5rem);        /* side gutter: 20px on a phone to 80px */
  --frame-y: clamp(1rem, 0.7rem + 1.4vw, 2.25rem);          /* top and bottom: 16 to 36px */
  /* The grid: 10 columns from 960px, 8 from 600px, 4 on a phone. The frame is the margin; gutters grow from 16 to 24px.
     Every edge sits on a column line: the corners on the outer edges, the words in columns 1-2 and 9-10, the work in
     3-8, the chat over the middle four. Shift+G draws it. */
  --g-cols: 10;
  --g-gap: clamp(1rem, 0.6rem + 1.1vw, 1.5rem);
  --g-col: calc((100vw - 2 * var(--frame-x) - (var(--g-cols) - 1) * var(--g-gap)) / var(--g-cols));
  --ui-w: calc(6 * var(--g-col) + 5 * var(--g-gap));        /* the work: six columns */
  --pad: clamp(1.5rem, 1rem + 1.5vw, 3rem);                 /* room around a piece for its own shadow */
  --slide-ms: 560;                                          /* one step, in ms (Shift+D) */
  --hover: color-mix(in oklab, var(--ink) 7%, transparent);
  --canvas: var(--paper);
  --grey: #5f5e5a;   /* a step darker than the system's grey, so small grey words keep 4.5:1 on the tinted canvases (dark mode keeps its own) */
}
@media (width < 960px) { :root { --g-cols: 8; } }
@media (width < 600px) { :root { --g-cols: 4; --ui-w: calc(100vw - 2 * var(--frame-x)); } }

/* The canvas takes its colour from the piece on show: a tint of that piece's own accent or image, never a brand
   colour that would clash with it. Light and dark. */
:root[data-tint="blue"] { --canvas: oklch(0.935 0.024 262); }   /* Stravue's pricing piece: its blue button and badge */
:root[data-tint="moss"] { --canvas: oklch(0.932 0.032 118); }   /* Stravue's moss coin */
:root[data-tint="apricot"] { --canvas: oklch(0.936 0.036 50); }   /* Stravue's orange, on its homepage */
:root[data-tint="mint"] { --canvas: oklch(0.944 0.03 170); }   /* the mint Copytone marks customers' words in */
:root[data-tint="paper"] { --canvas: oklch(0.93 0.009 85); }   /* the paper of Copytone's film */
:root[data-tint="oat"] { --canvas: oklch(0.94 0.02 82); }   /* CivAccount's warm paper and amber ring */
:root[data-tint="periwinkle"] { --canvas: oklch(0.932 0.028 280); }   /* the indigo of ProblemShared's screener */
:root[data-tint="peach"] { --canvas: oklch(0.94 0.034 65); }   /* ProblemShared's homepage hero */
:root[data-tint="sand"] { --canvas: oklch(0.935 0.02 70); }   /* wulfsage's afternoon sand */
:root[data-tint="sheet"] { --canvas: oklch(0.925 0.008 70); }   /* a lab's contact sheet */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"])[data-tint="blue"] { --canvas: oklch(0.245 0.038 262); }
  :root:not([data-theme="light"])[data-tint="moss"] { --canvas: oklch(0.25 0.034 120); }
  :root:not([data-theme="light"])[data-tint="apricot"] { --canvas: oklch(0.255 0.04 45); }
  :root:not([data-theme="light"])[data-tint="mint"] { --canvas: oklch(0.25 0.03 170); }
  :root:not([data-theme="light"])[data-tint="paper"] { --canvas: oklch(0.235 0.008 85); }
  :root:not([data-theme="light"])[data-tint="oat"] { --canvas: oklch(0.24 0.018 80); }
  :root:not([data-theme="light"])[data-tint="periwinkle"] { --canvas: oklch(0.25 0.04 280); }
  :root:not([data-theme="light"])[data-tint="peach"] { --canvas: oklch(0.255 0.034 55); }
  :root:not([data-theme="light"])[data-tint="sand"] { --canvas: oklch(0.24 0.02 65); }
  :root:not([data-theme="light"])[data-tint="sheet"] { --canvas: oklch(0.225 0.006 70); }
}
:root[data-theme="dark"][data-tint="blue"] { --canvas: oklch(0.245 0.038 262); }
:root[data-theme="dark"][data-tint="moss"] { --canvas: oklch(0.25 0.034 120); }
:root[data-theme="dark"][data-tint="apricot"] { --canvas: oklch(0.255 0.04 45); }
:root[data-theme="dark"][data-tint="mint"] { --canvas: oklch(0.25 0.03 170); }
:root[data-theme="dark"][data-tint="paper"] { --canvas: oklch(0.235 0.008 85); }
:root[data-theme="dark"][data-tint="oat"] { --canvas: oklch(0.24 0.018 80); }
:root[data-theme="dark"][data-tint="periwinkle"] { --canvas: oklch(0.25 0.04 280); }
:root[data-theme="dark"][data-tint="peach"] { --canvas: oklch(0.255 0.034 55); }
:root[data-theme="dark"][data-tint="sand"] { --canvas: oklch(0.24 0.02 65); }
:root[data-theme="dark"][data-tint="sheet"] { --canvas: oklch(0.225 0.006 70); }
html, body { background: var(--canvas); transition: background-color 800ms var(--ease-drawer); }

.app { min-height: 100dvh; overflow-x: clip; display: grid; grid-template-columns: repeat(var(--g-cols), minmax(0, 1fr)); grid-template-rows: auto minmax(0, 1fr) auto;
  column-gap: var(--g-gap); padding: var(--frame-y) var(--frame-x) calc(var(--frame-y) + env(safe-area-inset-bottom, 0px)); }
.corner { display: flex; align-items: center; gap: var(--bl-h); min-width: 0; }
.tl { grid-column: 1 / span 4; grid-row: 1; }
/* the theme icon's own edge, not its round hover plate, sits on the right edge, in line with Copy and the project's name */
.tr { grid-column: span 4 / -1; grid-row: 1; justify-self: end; margin-inline-end: calc((var(--bl) * 1.5 - 1rem) / -2); }
#theme-toggle { width: calc(var(--bl) * 1.5); min-width: 0; padding-inline: 0; }
/* the status's last line and the email share a baseline */
.bl { grid-column: 1 / span 2; grid-row: 3; align-self: last baseline; }
.br { grid-column: span 4 / -1; grid-row: 3; justify-self: end; align-self: last baseline; }
/* one screen, nothing to scroll, wherever there's room for it */
@media (width >= 960px) and (height >= 600px) {
  .app { height: 100dvh; overflow: clip; }
  :root.has-ask body { padding-bottom: 0; }   /* the chat pads the page for its pill; this page is one screen, so it mustn't */
}

/* the corners */
.who { display: inline-flex; align-items: center; gap: var(--bl-h); font-weight: 500; white-space: nowrap; }
.who .g { font-weight: 400; }
.mono-mark { width: calc(var(--bl) * 0.95); height: calc(var(--bl) * 0.95); flex: none; display: block; color: var(--ink); }
.tr { gap: var(--bl-q); }
.tool { height: calc(var(--bl) * 1.5); min-width: calc(var(--bl) * 1.5); padding-inline: var(--bl-h); border-radius: var(--radius-pill); display: inline-flex; align-items: center; justify-content: center;
  color: var(--grey); font-size: var(--step-n1); white-space: nowrap; transition: color var(--dur-hover) var(--ease-ui), background-color var(--dur-hover) var(--ease-ui), transform var(--dur-hover) var(--ease-ui); }
.tool:hover { color: var(--ink); background: var(--hover); }
.tool:active { transform: scale(var(--press)); }
.tool svg { width: 1rem; height: 1rem; display: block; transition: transform var(--dur-sheet) var(--ease-drawer); }
:root[data-theme="dark"] #theme-toggle svg { transform: rotate(180deg); }
.status { color: var(--grey); text-wrap: balance; }
.status .dot { display: inline-block; width: 0.42em; height: 0.42em; border-radius: 50%; background: var(--ink); margin-right: 0.6em; transform: translateY(-0.12em); }
.br { gap: var(--bl-h); color: var(--grey); font-size: var(--step-n1); }
.br .address { color: var(--ink); user-select: all; }
/* the page's one call to action: copy the address */
.copy-btn { position: relative; overflow: hidden; height: 2.25rem; min-width: 4.4rem; padding-inline: 1rem; border-radius: var(--radius-pill); background: var(--ink); color: var(--paper); font-size: var(--step-n1); font-weight: 500; transition: transform var(--dur-hover) var(--ease-ui); }
.copy-btn:active { transform: scale(var(--press)); }
.copy-btn span { display: block; transition: opacity var(--dur-hover) var(--ease-ui), filter var(--dur-hover) var(--ease-ui), transform var(--dur-hover) var(--ease-ui); }
.copy-btn .done { position: absolute; inset: 0; display: grid; place-items: center; opacity: 0; filter: blur(4px); transform: translateY(6px); }
.copy-btn.copied .idle { opacity: 0; filter: blur(4px); transform: translateY(-6px); }
.copy-btn.copied .done { opacity: 1; filter: blur(0); transform: translateY(0); }

/* ---------- the middle: what it is on the left, the work in the middle 40%, where it's from on the right ---------- */
/* The middle is the page's own grid (subgrid). The words sit on one shared line: the label's first line and the project's
   name start together, and that pair is centred on the work. */
.center { grid-column: 1 / -1; grid-row: 2; min-height: 0; display: grid; grid-template-columns: subgrid; grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr);
  cursor: grab; touch-action: pan-y; }
.label, .where { position: relative; z-index: 2; pointer-events: none; grid-template-columns: minmax(0, 1fr); }
.label .open, .where .open { max-width: calc(100% + 1.2rem); pointer-events: auto; display: grid; gap: 0.3rem; text-align: inherit; padding: 0.5rem 0.6rem; margin: -0.5rem -0.6rem; border-radius: 10px; cursor: pointer; transition: background-color var(--dur-hover) var(--ease-ui); }
.where .open { justify-items: end; gap: 0.3rem; }
@media (hover: hover) { .label .open:hover, .where .open:hover { background: var(--hover); } }
.label .open:active, .where .open:active { transform: scale(0.985); }
.label { grid-column: 1 / 3; grid-row: 2; align-self: start; justify-self: start; max-width: 100%; display: grid; gap: 0.3rem; cursor: auto; }
.label .name { font-size: var(--step-cap); font-weight: 500; line-height: 1.45; text-wrap: balance; }
.label .detail { font-size: var(--step-cap); line-height: 1.5; color: color-mix(in oklab, var(--grey) 80%, var(--ink)); text-wrap: pretty; }
.where { grid-column: 9 / -1; grid-row: 2; align-self: start; justify-self: end; text-align: right; display: grid; gap: 0.3rem; color: var(--grey); cursor: auto; font-size: var(--step-cap); line-height: 1.45; }
.where .proj { color: var(--ink); font-weight: 500; }
.stage { grid-column: 3 / 9; grid-row: 1 / -1; position: relative; align-self: stretch; min-height: 0; outline: none; }

/* each piece is a slide, shaped for its own composition, the width of the stage, centred in it */
.slide { position: absolute; left: 50%; top: 50%; width: calc(100% + 2 * var(--pad)); height: min(100%, calc(var(--ui-w) / var(--r, 1.25) + 2 * var(--pad)));
  transform: translate(-50%, -50%); }
.slide:not(.on) { pointer-events: none; }
.slide .btile { margin: 0; height: 100%; }
.slide .ptile-stage { height: 100%; aspect-ratio: auto; background: transparent; border-radius: 0; cursor: auto; }
.slide .ptile-safe { inset: var(--pad); transition: none; }
.slide .btile:hover .ptile-safe { transform: none; }
.slide .bt-open { display: none; }
.slide .center-obj { position: absolute; inset: var(--pad); display: grid; place-items: center; container-type: size; }
/* Two pieces are a slice of their product's page rather than a card of their own. They sit on that page, CivAccount's
   warm white and wulfsage's afternoon sand, with a margin all round, so they read as the product on any canvas. */
.slide.surf .ptile-safe { background: var(--surface); border-radius: 14px; box-shadow: 0 0 0 1px rgba(28,25,20,.06), 0 1px 2px rgba(28,25,20,.06), 0 14px 28px -14px rgba(28,25,20,.22); }
.slide.surf .pt-fit > .pt { width: calc(100% - 2.5rem) !important; height: calc(100% - 2.5rem) !important; }
.slide.surf .pt-wulfsage-nav { display: grid; place-items: center; }

/* The whole of each side is a button, out to the screen's edge: the left goes back, the right goes on. Its arrow sits
   centred in the margin, clear of the words, and shows when a pointer is near; the words over it pass clicks through.
   On touch, swipe; the sides stay for screen readers. */
.side { grid-row: 1 / -1; align-self: stretch; justify-self: stretch; position: relative; z-index: 1; cursor: pointer; }
.side-prev { grid-column: 1 / 3; margin-left: calc(-1 * var(--frame-x)); }
.side-next { grid-column: 9 / -1; margin-right: calc(-1 * var(--frame-x)); }
.chev { position: absolute; top: var(--chev-y, 50%); width: 2.75rem; height: 2.75rem; margin-top: -1.375rem; border-radius: 50%; display: grid; place-items: center;
  color: var(--ink); opacity: 0; transition: opacity 220ms var(--ease-ui), background-color var(--dur-hover) var(--ease-ui), transform var(--dur-hover) var(--ease-ui); }
.side-prev .chev { left: calc(var(--frame-x) / 2 - 1.375rem); }
.side-next .chev { right: calc(var(--frame-x) / 2 - 1.375rem); }
.chev svg { width: 1.05rem; height: 1.05rem; transition: transform var(--dur-hover) var(--ease-ui); }
@media (hover: hover) and (pointer: fine) {
  .center:hover .chev { opacity: .45; }
  .side:hover .chev { opacity: 1; background: var(--hover); }
  .side-prev:hover .chev svg { transform: translateX(-2px); }
  .side-next:hover .chev svg { transform: translateX(2px); }
}
.side:active .chev { transform: scale(var(--press)); }
.side:focus-visible { outline: none; }
.side:focus-visible .chev { opacity: 1; box-shadow: 0 0 0 3px var(--ink); }
@media not ((hover: hover) and (pointer: fine)) { .side:not(:focus-visible) .chev { opacity: 0; } }
:root.dragging, :root.dragging * { cursor: grabbing !important; user-select: none !important; -webkit-user-select: none !important; }
:root.dragging .chev { opacity: 0 !important; }
:root.dragging .side { cursor: grabbing !important; }

/* the brand itself, a product's own site, a film or a print, as objects on the canvas */
.browser { width: min(100%, calc((100cqh - 1.9rem) * 1.6)); border-radius: 10px; background: #fff; box-shadow: var(--contact); overflow: hidden; }
.browser .bar { height: 1.9rem; display: flex; align-items: center; gap: 0.35rem; padding: 0 0.75rem; background: #f7f6f3; border-bottom: 1px solid #e9e7e3; }
.browser .bar i { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: #dcd9d3; }
.browser .bar .url { margin-inline: auto; padding-right: 1.4rem; font: 400 0.72rem/1 var(--mono); color: #8a8780; }
.browser video { width: 100%; aspect-ratio: 16 / 10; height: auto; object-fit: cover; object-position: top; background: #fff; display: block; }
/* a product's real homepage, captured whole: it glides on its own, pauses under the pointer, and scrolls by hand */
.browser.site .viewport { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: #fff; touch-action: none; outline: none; }
.browser.site .viewport img { width: 100%; height: auto; display: block; transform: translate3d(0, 0, 0); will-change: transform; backface-visibility: hidden; user-select: none; -webkit-user-drag: none; }
.browser.site .viewport:focus-visible { box-shadow: inset 0 0 0 3px #1b1a18; }
.print-card { max-width: 100%; max-height: 100%; width: auto; height: auto; border-radius: 8px; box-shadow: var(--contact); }
.film-card { position: relative; width: min(100%, calc(100cqh * 16 / 9)); aspect-ratio: 16 / 9; border-radius: 10px; overflow: hidden; box-shadow: var(--contact); background: #f3f1ec; }
.film-card video { width: 100%; height: 100%; object-fit: cover; display: block; }
.coin { display: grid; justify-items: center; gap: 7cqh; }
.coin .big { width: 50cqh; height: auto; filter: drop-shadow(0 10px 16px rgba(28,25,20,.18)); transition: transform 700ms var(--spring); }
.coin .row { display: flex; gap: 3cqh; }
.coin .row img { width: 12cqh; height: auto; transition: transform 420ms var(--spring); }
@media (hover: hover) { .slide.on .coin .big:hover { transform: rotate(-8deg) scale(1.03); } .coin .row img:hover { transform: translateY(-4px) rotate(-10deg); } }
/* the contact sheet, in miniature */
.sheet-mini { width: 100%; display: grid; gap: 5cqh; }
.sheet-mini .strip { display: flex; gap: 2.2cqw; align-items: flex-end; }
.frame { position: relative; flex: var(--arn) 1 0%; min-width: 0; margin: 0; }
.frame button { display: block; width: 100%; padding: 0; border-radius: 3px; cursor: zoom-in; }
.frame img { width: 100%; height: auto; aspect-ratio: var(--ar); object-fit: cover; border-radius: 2px; box-shadow: var(--contact); background: var(--tint);
  transition: transform var(--dur-lift) var(--ease-lift), box-shadow var(--dur-lift) var(--ease-lift); }
@media (hover: hover) and (pointer: fine) { .frame button:hover img { transform: translateY(calc(-1 * var(--lift))); box-shadow: var(--contact-lift); } }
.frame .edge { display: block; margin-bottom: 0.3em; color: var(--grey); font-family: var(--mono); font-size: clamp(0.6rem, 2.2cqh, 0.8rem); line-height: 1.2; }
.proof-mark { position: absolute; z-index: 3; overflow: visible; pointer-events: none; transition: opacity 200ms var(--ease-ui); }
.proof-mark path { fill: none; stroke: var(--pencil); stroke-width: var(--pencil-w); stroke-linecap: round; stroke-linejoin: round; }
/* a film's pause control */
.vctl { position: absolute; right: 0.6rem; top: 0.6rem; z-index: 4; width: 2.1rem; height: 2.1rem; border-radius: 50%; display: grid; place-items: center;
  background: rgba(255, 255, 255, .9); color: #1b1a18; box-shadow: 0 1px 2px rgba(28,25,20,.1), 0 8px 18px -10px rgba(28,25,20,.4); opacity: 0; transition: opacity var(--dur-hover) var(--ease-ui); }
.vctl svg { width: 0.8rem; height: 0.8rem; }
.vctl .i-play { display: none; } .vctl.paused .i-play { display: block; } .vctl.paused .i-pause { display: none; }
.slide.on:hover .vctl, .vctl:focus-visible { opacity: 1; }
@media (hover: none) { .vctl { opacity: 1; } }

/* ---------- smaller screens: the words go under the work, and the page scrolls ---------- */
/* 960 to 1200: the work takes more still, and only the piece's name stays beside it (the full line is still read out) */
@media (width >= 960px) and (width < 1200px) {
  .label .detail { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
}
/* 600 to 960, 8 columns: the work takes the middle six, the words go under it on the same lines, and the page scrolls */
@media (width < 960px) {
  .app { grid-template-rows: auto auto auto auto; row-gap: var(--bl-h); align-content: start; }   /* rows keep their own height; the header stays on the frame line */
  .center { grid-template-rows: auto auto; row-gap: var(--bl-h); padding-block: var(--line-1) var(--bl-h); }
  .stage { grid-column: 2 / 8; grid-row: 1; height: min(calc(var(--ui-w) / 1.12 + 2 * var(--pad)), calc(100dvh - 17rem)); min-height: 18rem; }
  .label { grid-column: 2 / 6; grid-row: 2; }
  .where { grid-column: 6 / 8; grid-row: 2; }
  .side { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .bl { grid-column: 1 / span 4; grid-row: 3; padding-top: var(--bl); }
  .br { grid-column: span 4 / -1; grid-row: 3; padding-top: var(--bl); padding-bottom: 5.5rem; }
}
/* a phone, 4 columns: the project and count head the work, the label follows it, everything full width */
@media (width < 600px) {
  :root { --pad: 1.25rem; }
  .tl, .tr { grid-column: 1 / -1; }
  .center { grid-template-rows: auto auto auto; row-gap: var(--bl-h); }
  .where { grid-column: 1 / -1; grid-row: 1; justify-self: stretch; }
  .where .open { display: flex; justify-content: space-between; align-items: baseline; max-width: none; }
  .stage { grid-column: 1 / -1; grid-row: 2; }
  .label { grid-column: 1 / -1; grid-row: 3; }
  /* on a phone every piece gets a squarer box, so the wide ones switch to their own compact layouts */
  .slide { height: min(100%, calc(var(--ui-w) / 1.12 + 2 * var(--pad))); }
  .bl { grid-column: 1 / -1; padding-top: var(--bl); }
  .br { grid-column: 1 / -1; grid-row: 4; justify-self: start; padding-top: 0; flex-wrap: wrap; }
  .who .g { display: none; }
}

/* the chat on the grid: its pill shares Copy's centre line; its panel spans the middle four columns, or the work's six
   where four would be too narrow to read */
html .ask { bottom: calc(var(--frame-y) - 0.375rem + env(safe-area-inset-bottom, 0px)); width: calc(4 * var(--g-col) + 3 * var(--g-gap)); }
@media (width < 1360px) { html .ask { width: var(--ui-w); } }

/* Shift+G: the grid, drawn over the page */
:root.show-grid body::after { content: ""; position: fixed; inset: 0; z-index: 99; pointer-events: none; padding: 0 var(--frame-x);
  background: repeating-linear-gradient(to right, rgb(255 40 80 / .09) 0 var(--g-col), transparent var(--g-col) calc(var(--g-col) + var(--g-gap))) content-box,
    linear-gradient(rgb(255 40 80 / .5), rgb(255 40 80 / .5)) 50% 50% / 100% 1px no-repeat,
    linear-gradient(rgb(255 40 80 / .5), rgb(255 40 80 / .5)) 0 var(--frame-y) / 100% 1px no-repeat,
    linear-gradient(rgb(255 40 80 / .5), rgb(255 40 80 / .5)) 0 calc(100% - var(--frame-y)) / 100% 1px no-repeat; }

/* ---------- one stage: Work, About and How I work are scenes in the middle, one in focus at a time ----------
   They share the middle's grid (subgrid), so the words beside each sit on the same lines as the work's. Moving between
   them is a step in depth (e.js): forward, the scene in front drifts past and blurs away while the next rises from behind
   into focus; back, the reverse. The corners never move. */
.scene { grid-column: 1 / -1; grid-row: 1 / -1; min-height: 0; display: grid; grid-template-columns: subgrid; grid-template-rows: subgrid; transform-origin: 50% 46%; }
.scene[hidden] { display: none; }
.scene.is-leaving { pointer-events: none; }
:root:not([data-scene="work"]) .center { cursor: auto; }

/* the switch, top right: a marker slides to what is in the middle */
.seg { position: relative; display: inline-flex; align-items: center; gap: 2px; padding: 3px; border-radius: 999px; background: color-mix(in oklab, var(--ink) 5%, transparent); }
.seg-b { position: relative; z-index: 1; height: calc(var(--bl) * 1.5 - 6px); padding-inline: calc(var(--bl-h) + 2px); border-radius: 999px; color: var(--grey); white-space: nowrap; transition: color var(--dur-hover) var(--ease-ui); }
.seg-b:hover, .seg-b[aria-current="true"] { color: var(--ink); }
.seg-b:focus-visible { outline: 1.5px solid color-mix(in oklab, var(--ink) 35%, transparent); outline-offset: -2px; }
.seg-mark { position: absolute; z-index: 0; top: 3px; bottom: 3px; left: 0; width: 0; border-radius: 999px; background: var(--seg-mark, var(--paper));
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--ink) 7%, transparent), 0 1px 2px color-mix(in oklab, var(--ink) 10%, transparent), 0 3px 8px -3px color-mix(in oklab, var(--ink) 14%, transparent);
  transition: transform 300ms cubic-bezier(.34, 1.25, .64, 1), width 300ms cubic-bezier(.34, 1.25, .64, 1); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --seg-mark: color-mix(in oklab, var(--ink) 15%, var(--canvas)); } }
:root[data-theme="dark"] { --seg-mark: color-mix(in oklab, var(--ink) 15%, var(--canvas)); }

/* About: the story in the work's six columns, scrolling inside the stage, its edges fading into the canvas */
.ab-side { grid-column: 1 / 3; grid-row: 2; align-self: start; display: grid; gap: 0.3rem; }
.ab-body { grid-column: 3 / 9; grid-row: 1 / -1; align-self: center; max-height: 100%; overflow: auto; overscroll-behavior: contain; scrollbar-width: none;
  display: grid; gap: var(--bl); align-content: start; padding-block: var(--line-1) var(--line-2);
  mask-image: linear-gradient(transparent, #000 var(--line-1), #000 calc(100% - var(--line-2)), transparent); }
.ab-body::-webkit-scrollbar { display: none; }
.ab-body h2 { font-weight: 500; text-wrap: pretty; max-width: 30em; }
.ab-body h2 .g, .ab-body .big .g { font-weight: 500; }
.ab-body p { text-wrap: pretty; max-width: 36em; }
.ab-body .big { font-weight: 500; }
.ab-body .rail { display: grid; }
.ab-body .r-row { display: grid; grid-template-columns: 7rem minmax(0, 1fr); gap: var(--bl-h); padding-block: 0.75rem; border-top: 1px solid var(--hairline); }
.ab-body .r-row:last-child { border-bottom: 1px solid var(--hairline); }
.ab-body .r-row .y { color: var(--grey); }
.ab-body .r-row b { font-weight: 500; }
.ab-body .r-row .g { display: block; }
.ab-body .go { justify-self: start; display: inline-flex; align-items: center; gap: 0.4em; height: 2.6rem; padding: 0 1.1rem; border-radius: var(--radius-pill); background: var(--ink); color: var(--paper); transition: transform var(--dur-hover) var(--ease-ui); }
.ab-body .go:active { transform: scale(var(--press)); }

/* How I work: three steps through the stage, each a wulfsage drawing on a deep panel of the canvas's own hue */
.scene-method .open.static { cursor: default; }
.scene-method .open.static:hover { background: none; }
.mt-stage { grid-column: 3 / 9; grid-row: 1 / -1; position: relative; min-height: 0; display: grid; place-items: center; }
.mt-step { grid-area: 1 / 1; width: 100%; margin: 0; }
.mt-step[hidden] { display: none; }
.mt-illo { aspect-ratio: 16 / 9; width: 100%; max-height: 100%; border-radius: 18px; overflow: hidden; background: var(--illo-bg, #1c1b19); color: var(--illo-ink, #d4d0ca);
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--illo-ink, #fff) 6%, transparent) inset, 0 1px 2px rgb(0 0 0 / .12), 0 24px 48px -24px rgb(0 0 0 / .45); }
.mt-illo svg { display: block; width: 100%; height: 100%; }
@supports (color: oklch(from red l c h)) {
  html:root { --illo-bg: oklch(from var(--canvas) 0.2 calc(c * 1.2) h); --illo-ink: oklch(from var(--canvas) 0.88 calc(c * 0.5) h); }
}
@media (width < 960px) {
  .ab-side { grid-column: 2 / 8; grid-row: 1; }
  .ab-body { grid-column: 2 / 8; grid-row: 2; max-height: none; overflow: visible; mask-image: none; padding-top: 0; }
  .mt-stage { grid-column: 2 / 8; grid-row: 1; }
}
@media (width < 600px) {
  .ab-side, .ab-body, .mt-stage { grid-column: 1 / -1; }
  .scene-method .where { grid-row: 1; } .scene-method .mt-stage { grid-row: 2; } .scene-method .label { grid-row: 3; }
  .seg-b { padding-inline: var(--bl-h); }
}

/* ---------- the popup: the piece larger and still live, on its tint, with the project's context under it ---------- */
/* the popup is sized by the screen, never by what's in it, so it holds still from piece to piece */
.more { --m-foot: clamp(13rem, 10.5rem + 5dvh, 15rem); border: 0; padding: 0; --m-span: var(--g-cols); width: calc(var(--m-span) * var(--g-col) + (var(--m-span) - 1) * var(--g-gap)); height: min(64rem, calc(100dvh - 2 * var(--frame-y) - 7rem));
  max-width: none; max-height: none; margin: auto; translate: 0 -1.75rem;   /* centred in the room above the Ask pill */ border-radius: 18px; background: var(--paper); color: var(--ink); box-shadow: var(--shadow-lift); overflow: hidden; }
.more[open] { display: grid; grid-template-rows: minmax(0, 1fr) var(--m-foot); }
.more::backdrop { background: rgba(10, 9, 8, .55); }
.m-stage { position: relative; min-height: 0; background: var(--canvas); transition: background-color 500ms var(--ease-drawer); }
.m-stage .slide { position: absolute !important; inset: 0 !important; width: auto !important; height: auto !important; left: 0 !important; top: 0 !important; transform: none !important; opacity: 1 !important; --pad: clamp(1.5rem, 1rem + 2vw, 3.5rem); }
.m-foot { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--bl) calc(var(--bl) * 1.5); align-items: start; padding: var(--bl) clamp(1.25rem, 0.8rem + 1.5vw, 2rem) calc(var(--bl) * 1.1); overflow: auto; overscroll-behavior: contain; }
.m-words { display: contents; }
.m-foot { grid-template-areas: "meta nav" "title title" "about about"; row-gap: 0.45rem; align-items: center; }
.m-meta { grid-area: meta; } .m-nav { grid-area: nav; }
.m-title { grid-area: title; max-width: 46em; margin-top: 0.2rem; } .m-about { grid-area: about; max-width: 50em; }
.m-meta { color: var(--grey); display: flex; flex-wrap: wrap; gap: 0 0.55em; }
.m-meta b { color: var(--ink); font-weight: 500; }
.m-meta > *:not(:empty) + *:not(:empty)::before { content: "·"; margin-right: 0.55em; }
.m-title { font-size: var(--step-0); line-height: 1.45; font-weight: 500; letter-spacing: -0.01em; text-wrap: pretty; }
.m-title .g { font-weight: 400; }
.m-about { color: var(--grey); font-size: var(--step-cap); line-height: 1.5; text-wrap: pretty; }
.m-about b { color: var(--ink); font-weight: 500; }
.m-nav { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; justify-content: flex-end; }
.m-nav .mono { color: var(--grey); margin-right: 0.4rem; }
.m-nav button, .m-nav a { height: 2.5rem; min-width: 2.5rem; padding-inline: 0.85rem; border-radius: var(--radius-pill); background: var(--tint); color: var(--ink); font-size: var(--step-n1); display: inline-grid; place-items: center; transition: background-color var(--dur-hover) var(--ease-ui), transform var(--dur-hover) var(--ease-ui); }
.m-nav button:hover, .m-nav a:hover { background: var(--hairline); }
.m-nav button:active, .m-nav a:active { transform: scale(var(--press)); }
.m-nav svg { width: 0.95rem; height: 0.95rem; }
.m-nav a[hidden] { display: none; }
@media (width >= 1700px) { .more { --m-span: 8; } }
@media (width < 700px) { .more { --m-foot: 20.5rem; } .m-foot { grid-template-columns: 1fr; grid-template-areas: "nav" "meta" "title" "about"; } .m-nav { justify-content: flex-start; } }

/* ---------- the larger view of a frame ---------- */
.lb { border: 0; padding: 0; background: transparent; max-width: none; max-height: none; width: 100vw; height: 100dvh; overflow: hidden; }
.lb::backdrop { background: rgba(14, 13, 12, .9); }
.lb-in { position: absolute; inset: 0; display: grid; grid-template-rows: 1fr auto; padding: var(--bl) var(--frame-x); gap: var(--bl-h); }
.lb img { place-self: center; max-width: 100%; max-height: calc(100dvh - var(--bl) * 5); width: auto; height: auto; border-radius: 2px; box-shadow: 0 30px 80px -30px rgba(0,0,0,.7); }
.lb-bar { display: flex; justify-content: space-between; align-items: center; color: rgba(255,255,255,.72); }
.lb-bar .mono { color: rgba(255,255,255,.6); }
.lb-bar nav { display: flex; gap: var(--bl-q); }
.lb-bar button { height: calc(var(--bl) * 1.6); min-width: calc(var(--bl) * 1.6); padding-inline: var(--bl-h); border-radius: var(--radius-pill); background: rgba(255,255,255,.1); color: #fff; font-size: var(--step-n1); }

/* ---------- motion: one arrival, then motion only answers the hand ---------- */
.mono-mark circle, .mono-mark line { stroke-dasharray: 1; stroke-dashoffset: 0; }
html.play .mono-mark circle { animation: drawmark 900ms var(--ease-out) 200ms both; }
html.play .mono-mark line { animation: drawmark 420ms var(--ease-out) both; }
html.play .mono-mark line:nth-of-type(1) { animation-delay: 950ms; }
html.play .mono-mark line:nth-of-type(2) { animation-delay: 1150ms; }
html.play .mono-mark line:nth-of-type(3) { animation-delay: 1330ms; }
@keyframes drawmark { from { stroke-dashoffset: 1; } }
@keyframes rise { from { opacity: 0; transform: translateY(var(--rise)); filter: blur(var(--blur)); } }
html.play .enter { animation: rise var(--dur-enter) var(--ease-out) both; animation-delay: calc(var(--i, 0) * var(--stagger)); }
/* switching theme: every colour on the page eases across together, as on the original site */
:root.theming *:not(.pt *), :root.theming *:not(.pt *)::before, :root.theming *:not(.pt *)::after {
  transition: background-color 0.8s ease, color 0.8s ease, border-color 0.8s ease, fill 0.8s ease, stroke 0.8s ease, box-shadow 0.8s ease !important; }
:root.theming, :root.theming body { transition: background-color 0.8s ease, color 0.8s ease !important; }
@media (prefers-reduced-motion: reduce) {
  html.play .enter, html.play .mono-mark circle, html.play .mono-mark line { animation: none; }
  html, body { transition: none; }
  *, *::before, *::after { transition: none !important; }
}

/* ---------- the chat: one dark island ----------
   The pill and its panel share one fill in both themes and merge like goo: a blurred, thresholded layer of plain shapes
   behind them (after Jakub Antalik's Gooey, libraries.dev/gooey), with the words and controls crisp on top. e.js draws it. */
html .ask[data-island] { --island: var(--isl, #1c1b19); --ink: #edebe7; --paper: var(--island); --surface: transparent; --tint: rgb(255 255 255 / .085);
  --grey: #aaa79f; --outline: transparent; --hairline: rgb(255 255 255 / .09); --hover: rgb(255 255 255 / .08); color: var(--ink); }
/* in dark mode the island is raised a step above the canvas, so the whole shape still reads */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --isl: #353430; } }
:root[data-theme="dark"] { --isl: #353430; }
/* on the island, e.js fades the words in once the shape has formed, so the panel's own entrance is off */
html .ask[data-island] .ask-panel.enter { opacity: 1; transform: none; filter: none; }
html .ask[data-island] .ask-panel { transition: none; }
html .ask[data-island] .ask-panel { background: transparent; box-shadow: none; position: relative; z-index: 1; }
html .ask[data-island] .ask-pill, html .ask[data-island] .metal-fx-root.of-lift[data-variant] { background: transparent; color: var(--ink); box-shadow: none; position: relative; z-index: 1; }
html .ask[data-island] .ask-pill .g { color: color-mix(in srgb, var(--ink) 58%, var(--island)); }
html .ask[data-island] .ask-form input::placeholder { color: var(--grey); }
/* the island's shapes, rim and glow (drawn by e.js): the rim and glow show while the chat is open, and hand back to the
   pill's own metal ring as it closes */
.goo { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: visible; z-index: 0; pointer-events: none; }
.goo .fill { fill: var(--island); transition: fill 800ms var(--ease-drawer); }
.goo .rim, .goo .glow { opacity: 0; transition: opacity 140ms var(--ease-ui); }
.ask.is-settled .goo .rim { opacity: 1; transition: opacity 420ms var(--ease-ui); }
.ask.is-settled .goo .glow { opacity: .4; transition: opacity 420ms var(--ease-ui); }
/* the rim is the canvas's own hue: a quiet line a step lighter than the island, and one soft highlight that travels round */
html .ask[data-island] { --rim-lo: rgb(255 255 255 / .12); --rim-mid: rgb(255 255 255 / .35); --rim-hi: rgb(255 255 255 / .85); }
@supports (color: oklch(from red l c h)) {
  html .ask[data-island] { --rim-lo: oklch(from var(--island) calc(l + 0.1) calc(c * 1.1) h); --rim-mid: oklch(from var(--island) calc(l + 0.3) c h); --rim-hi: oklch(from var(--canvas) 0.97 calc(c * 0.6) h); }
}
html .ask[data-island] .ask-send { background: var(--ink); color: var(--island); box-shadow: 0 1px 2px rgb(0 0 0 / .2), inset 0 1px 0 rgb(255 255 255 / .5); }
.ask[data-island] .metal-fx-root.of-lift > :not(.metal-fx-content) { transition: opacity 260ms var(--ease-ui) 420ms; }
.ask[data-island].is-open .metal-fx-root.of-lift > :not(.metal-fx-content) { opacity: 0 !important; transition: opacity 160ms var(--ease-ui); }
.ask[data-island] .metal-fx-inner { background: transparent !important; }

/* ---------- one tonal family per piece ----------
   Every colour on the page comes from the canvas, which comes from the piece on show: the same hue at different
   lightness. Text and greys carry a trace of it; the chat island is the canvas raised a step (dark) or deepened (light),
   and its chips, input and hairlines are lighter layers of the island. Contrast: grey text 5:1 or more on every canvas. */
@supports (color: oklch(from red l c h)) {
  html:root {
    --ink: oklch(from var(--canvas) 0.2 calc(c * 0.6) h);
    --grey: oklch(from var(--canvas) 0.47 calc(c * 0.9) h);
    --secondary: oklch(from var(--canvas) 0.36 calc(c * 0.8) h);
    --paper: oklch(from var(--canvas) 0.985 calc(c * 0.2) h);
    --isl: oklch(from var(--canvas) 0.25 calc(c * 1.4) h);
    --island-ink: oklch(from var(--canvas) 0.95 calc(c * 0.35) h);
    --island-grey: oklch(from var(--canvas) 0.76 calc(c * 0.8) h);
  }
  @media (prefers-color-scheme: dark) {
    html:root:not([data-theme="light"]) {
      --ink: oklch(from var(--canvas) 0.94 calc(c * 0.4) h);
      --grey: oklch(from var(--canvas) 0.74 calc(c * 0.7) h);
      --secondary: oklch(from var(--canvas) 0.82 calc(c * 0.6) h);
      --paper: oklch(from var(--canvas) 0.2 c h);
      --isl: oklch(from var(--canvas) calc(l + 0.065) calc(c * 1.2) h);
      --island-ink: oklch(from var(--canvas) 0.95 calc(c * 0.35) h);
      --island-grey: oklch(from var(--canvas) 0.76 calc(c * 0.7) h);
    }
  }
  html:root[data-theme="dark"] {
    --ink: oklch(from var(--canvas) 0.94 calc(c * 0.4) h);
    --grey: oklch(from var(--canvas) 0.74 calc(c * 0.7) h);
    --secondary: oklch(from var(--canvas) 0.82 calc(c * 0.6) h);
    --paper: oklch(from var(--canvas) 0.2 c h);
    --isl: oklch(from var(--canvas) calc(l + 0.065) calc(c * 1.2) h);
    --island-ink: oklch(from var(--canvas) 0.95 calc(c * 0.35) h);
    --island-grey: oklch(from var(--canvas) 0.76 calc(c * 0.7) h);
  }
  html .ask[data-island], html:root[data-theme="dark"] .ask[data-island] {
    --ink: var(--island-ink); --grey: var(--island-grey); --paper: var(--island);
    --tint: oklch(from var(--island) calc(l + 0.06) c h); --hairline: oklch(from var(--island) calc(l + 0.08) c h);
    --hover: oklch(from var(--island) calc(l + 0.09) c h);
  }
  @media (prefers-color-scheme: dark) { html:root:not([data-theme="light"]) .ask[data-island] { --ink: var(--island-ink); --grey: var(--island-grey); --paper: var(--island); } }
}

/* ---------- read more, in the stage ----------
   The piece keeps its six columns and glides to columns 1-6; its story takes 7-10. The words and arrows beside the
   work step back while the story is out. */
.story { grid-column: 7 / -1; grid-row: 1 / -1; align-self: center; display: grid; gap: var(--bl-h); max-height: 100%; overflow: auto; scrollbar-width: none; padding-left: var(--g-gap); }
.story[hidden] { display: none; }
.scene-work.is-story .stage { grid-column: 1 / 7; }
.scene-work .label, .scene-work .where, .scene-work .side { transition: opacity 220ms var(--ease-ui), filter 220ms var(--ease-ui); }
.scene-work.is-story .label, .scene-work.is-story .where, .scene-work.is-story .side { opacity: 0; filter: blur(4px); pointer-events: none; }
.st-meta { display: flex; flex-wrap: wrap; gap: 0 0.75em; color: var(--grey); }
.st-meta b { color: var(--ink); font-weight: 500; }
.st-title { font-weight: 500; text-wrap: balance; }
.st-title .g { font-weight: 400; }
.st-about { color: var(--secondary); text-wrap: pretty; max-width: 34em; }
.st-about b { color: var(--ink); font-weight: 500; }
.st-nav { display: flex; align-items: center; flex-wrap: wrap; gap: 0.35rem; margin-top: var(--bl-h); }
.st-nav .st-count { margin-right: 0.4rem; color: var(--grey); font-variant-numeric: tabular-nums; }
.st-nav button, .st-nav a { height: 2.25rem; min-width: 2.25rem; padding-inline: 0.8rem; border-radius: 999px; display: inline-grid; place-items: center; color: var(--ink);
  background: color-mix(in oklab, var(--ink) 6%, transparent); transition: background-color var(--dur-hover) var(--ease-ui), transform var(--dur-hover) var(--ease-ui); }
.st-nav button[data-st="-1"], .st-nav button[data-st="1"] { padding-inline: 0; }
.st-nav button svg { width: 1rem; height: 1rem; }
.st-nav button:hover, .st-nav a:hover { background: color-mix(in oklab, var(--ink) 11%, transparent); }
.st-nav button:active, .st-nav a:active { transform: scale(var(--press)); }
.st-nav .st-close { background: var(--ink); color: var(--paper); margin-left: auto; }
.st-nav .st-close:hover { background: var(--ink); }
@media (width < 960px) {
  .story { grid-column: 2 / 8; grid-row: 2; padding-left: 0; max-height: none; }
  .scene-work.is-story .stage { grid-column: 2 / 8; }
  .scene-work.is-story .label, .scene-work.is-story .where { display: none; }
}
@media (width < 600px) {
  .story { grid-column: 1 / -1; grid-row: 3; }
  .scene-work.is-story .stage { grid-column: 1 / -1; }
}

/* ---------- the chat's conversation height, and glass ----------
   A conversation takes one capped height, so new messages scroll inside it rather than pushing the island up; the work
   stays in view above. The island and the nav are a touch of frosted glass: slightly see-through, the page blurred behind,
   a fine highlight on the top edge. Text keeps its contrast: the fill is 76% opaque and the page behind is blurred and dimmed. */
html .ask[data-island] .ask-panel { max-height: min(56dvh, 32rem); }   /* sized by its content up to here, every change eased (ask.html); past it, the conversation scrolls */
html .ask[data-island] .ask-log { scroll-behavior: smooth; }
.goo .fill { fill-opacity: .76; }
html .ask[data-island] .ask-panel, html .ask[data-island] .ask-pill { -webkit-backdrop-filter: blur(28px) saturate(1.7) brightness(.82); backdrop-filter: blur(28px) saturate(1.7) brightness(.82); }
html .ask[data-island] .ask-panel { border-radius: 16px; box-shadow: inset 0 1px 0 rgb(255 255 255 / .1); background: linear-gradient(180deg, rgb(255 255 255 / .07), rgb(255 255 255 / 0) 38%); }
html .ask[data-island] .ask-pill { box-shadow: inset 0 1px 0 rgb(255 255 255 / .12); background: linear-gradient(180deg, rgb(255 255 255 / .08), rgb(255 255 255 / 0) 60%); }
.seg { background: color-mix(in oklab, var(--paper) 45%, transparent); -webkit-backdrop-filter: blur(14px) saturate(1.4); backdrop-filter: blur(14px) saturate(1.4);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--ink) 6%, transparent), inset 0 1px 0 rgb(255 255 255 / .35); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .seg { background: color-mix(in oklab, var(--ink) 6%, transparent); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--ink) 8%, transparent), inset 0 1px 0 rgb(255 255 255 / .06); } }
:root[data-theme="dark"] .seg { background: color-mix(in oklab, var(--ink) 6%, transparent); box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--ink) 8%, transparent), inset 0 1px 0 rgb(255 255 255 / .06); }

/* ---------- the arrows live in the grid ----------
   Each side column has one job: the left says what the piece is; the right says where it sits and holds the controls,
   a pair of buttons under the count, flush to the right edge of column 10. Nothing sits in the margins. The empty sides
   still move along when clicked (no arrow drawn there). */
.side .chev { display: none; }
.where { justify-items: end; }
.steps { pointer-events: auto; display: flex; gap: 6px; margin-top: calc(var(--bl-h) + 2px); }
.steps button { width: 2rem; height: 2rem; border-radius: 999px; display: grid; place-items: center; color: var(--ink); background: color-mix(in oklab, var(--ink) 6%, transparent);
  transition: background-color var(--dur-hover) var(--ease-ui), transform var(--dur-hover) var(--ease-ui); }
.steps button svg { width: 0.95rem; height: 0.95rem; transition: transform var(--dur-hover) var(--ease-ui); }
@media (hover: hover) { .steps button:hover { background: color-mix(in oklab, var(--ink) 11%, transparent); } .steps [data-step="-1"]:hover svg, .steps [data-mstep="-1"]:hover svg { transform: translateX(-1.5px); } .steps [data-step="1"]:hover svg, .steps [data-mstep="1"]:hover svg { transform: translateX(1.5px); } }
.steps button:active { transform: scale(var(--press)); }
.steps button:focus-visible, .st-nav button:focus-visible, .st-nav a:focus-visible { outline: 1.5px solid color-mix(in oklab, var(--ink) 45%, transparent); outline-offset: 2px; }
@media (width < 600px) {
  .scene .where { display: flex; align-items: center; gap: var(--bl-h); }
  .scene .where .open { flex: 1; }
  .steps { margin-top: 0; }
}
/* while the chat is open the pill is part of one shape: its own glass edge and blur hand over to the island, so no line
   crosses the neck */
html .ask[data-island] .ask-pill { transition: box-shadow 200ms var(--ease-ui), background 200ms var(--ease-ui), backdrop-filter 200ms var(--ease-ui); }
html .ask[data-island].is-open .ask-pill { box-shadow: none; background: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
/* the quiet links to the plain pages, at the foot of About */
.ab-body .legal a { color: inherit; text-decoration: none; transition: color var(--dur-hover) var(--ease-ui); }
.ab-body .legal a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* ---------- the chat is real glass ----------
   No colour of its own: it blurs and gently dims (dark) or brightens (light) whatever is behind it, so the page shows
   through, distorted, as through frosted glass. Text sits on it in the page's own ink. The rim is a neutral hairline with
   a soft white highlight that travels round. Overrides the tinted island above. */
html .ask[data-island] { --glass: rgb(255 255 255 / .68); --glass-blur: blur(10px) saturate(1.9) brightness(1.08); --glass-glow: 0; --glass-shadow: .1;
  --ink: #1b1a18; --grey: #5f5e5a; --paper: #fbfaf8; --tint: rgb(0 0 0 / .05); --hairline: rgb(0 0 0 / .08); --hover: rgb(0 0 0 / .08);
  --rim-lo: rgb(0 0 0 / .08); --rim-mid: rgb(0 0 0 / .08); --rim-hi: rgb(0 0 0 / .08); color: var(--ink); }
@media (prefers-color-scheme: dark) { html:root:not([data-theme="light"]) .ask[data-island] { --glass: rgb(30 30 32 / .44); --glass-blur: blur(10px) saturate(1.8) brightness(.55); --glass-glow: .35; --glass-shadow: .22;
  --ink: #f7f6f3; --grey: #dcdad4; --paper: #161616; --tint: rgb(255 255 255 / .08); --hairline: rgb(255 255 255 / .1); --hover: rgb(255 255 255 / .1);
  --rim-lo: rgb(255 255 255 / .12); --rim-mid: rgb(255 255 255 / .35); --rim-hi: rgb(255 255 255 / .9); } }
html:root[data-theme="dark"] .ask[data-island] { --glass: rgb(30 30 32 / .44); --glass-blur: blur(10px) saturate(1.8) brightness(.55); --glass-glow: .35; --glass-shadow: .22;
  --ink: #f7f6f3; --grey: #dcdad4; --paper: #161616; --tint: rgb(255 255 255 / .08); --hairline: rgb(255 255 255 / .1); --hover: rgb(255 255 255 / .1);
  --rim-lo: rgb(255 255 255 / .12); --rim-mid: rgb(255 255 255 / .35); --rim-hi: rgb(255 255 255 / .9); }
.goo .fill { fill: var(--glass); fill-opacity: 1; }
html .ask[data-island] .ask-panel, html .ask[data-island] .ask-pill { -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); }
html .ask[data-island] .ask-panel { background: linear-gradient(180deg, rgb(255 255 255 / .08), rgb(255 255 255 / 0) 40%); box-shadow: inset 0 1px 0 rgb(255 255 255 / .14); }
html .ask[data-island] .ask-pill .g { color: var(--grey); }
html .ask[data-island] .ask-send { background: var(--ink); color: var(--paper); box-shadow: 0 1px 2px rgb(0 0 0 / .2); }
.ask.is-settled .goo .glow { opacity: .35; }

/* How I work: two plain sentences under each drawing, on how the step works with the team */
/* the drawing keeps its 16:9 and shrinks as a whole on short screens; the sentences sit right under it, on its left edge */
.mt-stage { container-type: size; }
.mt-step { display: grid; gap: var(--bl-h); align-content: center; width: min(100%, calc((100cqh - 6.5rem) * 16 / 9)); justify-self: center; }
.mt-more { color: var(--secondary); max-width: 36em; text-wrap: pretty; margin: 0; }
@media (width < 960px) { .mt-stage { container-type: normal; } .mt-step { width: 100%; } }

/* Apple-style glass edge: a fine bright hairline all round and a soft gloss across the top, over the blurred page */
html .ask[data-island] .ask-panel { box-shadow: inset 0 0 0 1px rgb(255 255 255 / .1), inset 0 1px 0 rgb(255 255 255 / .18); background: linear-gradient(180deg, rgb(255 255 255 / .1), rgb(255 255 255 / .02) 35%, rgb(255 255 255 / 0)); }
html .ask[data-island]:not(.is-open) .ask-pill { box-shadow: inset 0 0 0 1px rgb(255 255 255 / .12), inset 0 1px 0 rgb(255 255 255 / .2); }
/* legibility over bright work behind the glass, in dark mode: a soft shadow that only shows where the glass is light */
@media (prefers-color-scheme: dark) { html:root:not([data-theme="light"]) .ask[data-island] .ask-panel, html:root:not([data-theme="light"]) .ask[data-island] .ask-pill { text-shadow: 0 0 14px rgb(0 0 0 / .28), 0 1px 2px rgb(0 0 0 / .18); } }
html:root[data-theme="dark"] .ask[data-island] .ask-panel, html:root[data-theme="dark"] .ask[data-island] .ask-pill { text-shadow: 0 0 14px rgb(0 0 0 / .28), 0 1px 2px rgb(0 0 0 / .18); }
html .ask[data-island] .ask-form input { text-shadow: none; }
/* light glass is quiet: a faint even hairline, no glow, a light shadow; dark keeps its travelling highlight and glow */
.ask.is-settled .goo .glow { opacity: var(--glass-glow, .35); }
.goo feDropShadow { flood-opacity: var(--glass-shadow, .22); }
html .ask[data-island]:not(.is-open) .ask-pill { background: none; }

/* one focus: while the chat is open, the work steps back (softened, dimmed, a touch further away), so the glass sits
   over a calm page; minimising the chat or clicking anywhere brings it straight back */
.center { transition: filter 420ms cubic-bezier(.2, .9, .25, 1), opacity 420ms cubic-bezier(.2, .9, .25, 1), transform 420ms cubic-bezier(.2, .9, .25, 1); }
:root.chat-open .center { filter: blur(5px) saturate(.9); opacity: .6; transform: scale(.985); }
@media (prefers-reduced-motion: reduce) { :root.chat-open .center { filter: none; transform: none; opacity: .6; } }

/* ---------- the glass, as one sheet ----------
   A blur layer cut to the island's exact outline (panel, neck and pill) frosts the page behind; the glass tint sits over
   it at true transparency; the shadow is drawn only outside the shape. Nothing on the panel or pill draws an edge of its
   own, so no line ever crosses the neck. */
.goo-frost { position: absolute; inset: 0; z-index: 0; pointer-events: none; -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); }
/* the island's shadow: a canvas the script draws only outside the shape (so it never shows through the glass) */
.goo-shadow { position: absolute; left: 0; top: 0; z-index: 0; pointer-events: none; }
html .ask[data-island] .ask-panel, html .ask[data-island] .ask-pill, html .ask[data-island]:not(.is-open) .ask-pill, html .ask[data-island].is-open .ask-pill { -webkit-backdrop-filter: none; backdrop-filter: none; }
html .ask[data-island] .ask-panel { box-shadow: inset 0 1px 0 rgb(255 255 255 / .16); }
html .ask[data-island]:not(.is-open) .ask-pill { box-shadow: inset 0 1px 0 rgb(255 255 255 / .18); }
/* the frost's tint is set so the words keep 4.5:1 over the worst piece behind (measured, 12 Oct 2026) */
html .ask[data-island] { --glass-color: #fff; --glass-alpha: .57; }
@media (prefers-color-scheme: dark) { html:root:not([data-theme="light"]) .ask[data-island] { --glass-color: rgb(30 30 32); --glass-alpha: .5; } }
html:root[data-theme="dark"] .ask[data-island] { --glass-color: rgb(30 30 32); --glass-alpha: .5; }
.goo .fill { fill: var(--glass-color); opacity: var(--glass-alpha); }
.goo .shadow { fill: #000; }
.goo .isl-flood { flood-opacity: var(--glass-shadow, .2); }

/* chat: Focus steps the work back; Float and Compact leave it fully usable */
:root:not([data-chat="focus"]).chat-open .center { filter: none; opacity: 1; transform: none; }
:root[data-chat="compact"] .ask[data-island] .ask-panel { max-height: min(34dvh, 19rem); }
:root.ask-dragging, :root.ask-dragging * { cursor: grabbing !important; user-select: none !important; }

/* How I work's sentences */
:root[data-caption="small"] .mt-step { gap: var(--bl); }
:root[data-caption="small"] .mt-more { font-size: var(--t-small) !important; line-height: 1.5 !important; color: var(--grey); max-width: 30em; }
:root[data-caption="card"] .mt-step { gap: 0; }
:root[data-caption="card"] .mt-step > * { grid-area: 1 / 1; }
:root[data-caption="card"] .mt-more { align-self: end; justify-self: center; text-align: center; max-width: 30em; padding: 0 6% 5.5%; color: var(--illo-ink, #d4d0ca); opacity: .8; z-index: 1; font-size: var(--t-label) !important; text-wrap: balance; }
:root[data-caption="side"] .mt-more { display: none; }
.scene-method .mt-line-more { display: none; }
:root[data-caption="side"] .scene-method .mt-line-more { display: block; margin-top: 0.4rem; }

/* ---------- Float: the chat is a headshot that can be put anywhere ----------
   The chat layer covers the screen without catching a single click; the face (48px, with the metallic ring while the
   chat is put away) and the panel are placed by e.js, the panel always opening on the side with room. */
.ask > .goo, .ask > .goo-frost, .ask > .goo-shadow { pointer-events: none !important; }
.goo-frost { inset: auto; }
.ask-dock { display: none; }
:root[data-chat="float"] .ask[data-island] { left: 0; top: 0; right: 0; bottom: 0; width: auto; height: auto; transform: none; display: block; }
:root[data-chat="float"] .ask[data-island] .ask-pill { display: none; }
:root[data-chat="float"] .ask[data-island] .ask-panel { position: absolute; z-index: 1; }
:root.ask-dragging .ask-dock { cursor: grabbing; }
.ask-bubble:focus-visible { outline: 1.5px solid color-mix(in oklab, var(--ink) 45%, transparent); outline-offset: 3px; }
.ask-dock .metal-fx-root { background: transparent !important; }
/* the ring belongs to the face on its own; while the chat is open the island's rim takes over */
/* held, the face comes up off the page: a deeper shadow */
:root.ask-dragging .goo .isl-flood { flood-opacity: calc(var(--glass-shadow, .2) * 1.7); }
/* the face shows at once; its ring fades in whenever the metal has started */
.ask-dock .metal-fx-root { opacity: 1 !important; visibility: visible !important; }

/* ---------- the face ----------
   On landing it is the pill, "Ask me anything"; once used it closes into the face (48px), which wears the metallic ring
   while the chat is put away. e.js places it and drives its width and lift, so nothing here transitions them. */
:root[data-chat="float"] .ask-dock { display: block; position: absolute; left: 0; top: 0; height: 48px; z-index: 2; pointer-events: auto; touch-action: none; }
.ask-bubble { height: 48px; width: 100%; display: flex; align-items: center; gap: 6px; padding: 0 18px 0 0; border-radius: 999px; overflow: hidden; white-space: nowrap; background: transparent; color: var(--ink); cursor: pointer; }
.ask-dock.is-face .ask-bubble { padding-right: 0; }
.ask-face { position: relative; flex: none; width: 48px; height: 48px; border-radius: 50%; display: grid; place-items: center; }
.ask-face img { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; object-position: 50% 28%; display: block; pointer-events: none; -webkit-user-drag: none; user-select: none; }
.ask-face-label { transition: opacity 200ms var(--ease-ui) 90ms, transform 260ms var(--ease-ui) 60ms; }
.ask-dock.is-face .ask-face-label { transition: opacity 120ms var(--ease-ui), transform 200ms var(--ease-ui); }
.ask-face-label .g { color: var(--grey); }
.ask-dock.is-face .ask-face-label { opacity: 0; transform: translateX(-10px); }
.ask-bubble:focus-visible { outline: 1.5px solid color-mix(in oklab, var(--ink) 45%, transparent); outline-offset: 3px; }
:root.ask-dragging, :root.ask-dragging * { cursor: grabbing !important; }
/* the ring is only for the face on its own, put away */
.ask.is-face:not(.is-open) .goo .rim, .ask.is-face:not(.is-open) .goo .glow { opacity: 0 !important; }
/* the labelled pill keeps the glass's top light; the face and the open chat draw no edges of their own */
/* no lines inside the chat: no rule above the question, no highlight along the panel's edge */
html .ask[data-island] .ask-form { border-top: 0; }
html .ask[data-island] .ask-panel { box-shadow: none; }
@media (prefers-color-scheme: dark) { html:root:not([data-theme="light"]) .ask[data-island] .ask-bubble { text-shadow: 0 0 14px rgb(0 0 0 / .28), 0 1px 2px rgb(0 0 0 / .18); } }
html:root[data-theme="dark"] .ask[data-island] .ask-bubble { text-shadow: 0 0 14px rgb(0 0 0 / .28), 0 1px 2px rgb(0 0 0 / .18); }

/* ---------- weight ----------
   Every moving thing is a physical object with one spring model (weight/RESEARCH.md): taps settle without wobble, only
   a throw earns overshoot, small things are quick and big ones carry more mass, exits run about 0.7x of their entrance,
   and shadows follow height. Tuned to the speeds chosen by hand (perceived arrival, 90%: tiny ~80ms, small ~120ms,
   medium ~200ms, large ~230ms). Each token is a duration and a spring baked into linear(). e.js reads the same tokens. */
:root {
  --tiny-enter: 250ms linear(0, 0.1478 6.67%, 0.409 13.33%, 0.6423 20%, 0.8083 26.67%, 0.9107 33.33%, 0.9666 40%, 0.9933 46.67%, 1.0038 53.33%, 1.0063 60%, 1);
  --tiny-exit: 183ms linear(0, 0.2403 9.09%, 0.5577 18.18%, 0.7698 27.27%, 0.8874 36.36%, 0.9471 45.45%, 0.9758 54.55%, 0.9892 63.64%, 0.9952 72.73%, 1);
  --small-enter: 267ms linear(0, 0.0734 6.25%, 0.2271 12.5%, 0.3976 18.75%, 0.5535 25%, 0.6826 31.25%, 0.7826 37.5%, 0.8565 43.75%, 0.9088 50%, 0.9444 56.25%, 0.9679 62.5%, 0.9918 75%, 0.9997 87.5%, 1);
  --small-exit: 267ms linear(0, 0.1296 6.25%, 0.3542 12.5%, 0.5577 18.75%, 0.7113 25%, 0.8176 31.25%, 0.8874 37.5%, 0.9317 43.75%, 0.9591 50%, 0.9758 56.25%, 0.9858 62.5%, 0.9952 75%, 1);
  --medium-enter: 467ms linear(0, 0.0432 3.57%, 0.1402 7.14%, 0.3764 14.29%, 0.4867 17.86%, 0.584 21.43%, 0.667 25%, 0.7361 28.57%, 0.7925 32.14%, 0.838 35.71%, 0.8743 39.29%, 0.9029 42.86%, 0.9428 50%, 0.9748 60.71%, 0.9918 75%, 1);
  --medium-exit: 350ms linear(0, 0.0805 4.76%, 0.2403 9.52%, 0.409 14.29%, 0.5577 19.05%, 0.6777 23.81%, 0.7698 28.57%, 0.838 33.33%, 0.8874 38.1%, 0.9225 42.86%, 0.9471 47.62%, 0.9758 57.14%, 0.9928 71.43%, 1);
  --large-enter: 550ms linear(0, 0.0317 3.03%, 0.1061 6.06%, 0.2008 9.09%, 0.4005 15.15%, 0.4922 18.18%, 0.5744 21.21%, 0.6466 24.24%, 0.7086 27.27%, 0.7613 30.3%, 0.8055 33.33%, 0.8422 36.36%, 0.8726 39.39%, 0.8975 42.42%, 0.9342 48.48%, 0.9582 54.55%, 0.9737 60.61%, 0.992 75.76%, 1);
  --large-exit: 400ms linear(0, 0.0599 4.17%, 0.1867 8.33%, 0.3305 12.5%, 0.4669 16.67%, 0.5854 20.83%, 0.6832 25%, 0.7613 29.17%, 0.8221 33.33%, 0.8686 37.5%, 0.9037 41.67%, 0.9298 45.83%, 0.9492 50%, 0.9737 58.33%, 0.9866 66.67%, 0.9932 75%, 1);
}
/* the switch's marker is a small object: it glides and settles, no wobble from a tap */
.seg-mark { transition: transform var(--small-enter), width var(--small-enter); }
/* every control is a tiny object: pressed, it sinks quickly; let go, it springs back on its own weight; hovered (fine
   pointers), it lifts a pixel */
.steps button, .st-nav button, .st-nav a, .seg-b, .copy-btn, .ab-body .go, .ask-send, .ask-close, .ask-start, .ask-chip, .tool, .label .open, .where .open {
  transition: transform var(--tiny-enter), background-color 150ms var(--ease-ui), color 150ms var(--ease-ui), box-shadow 150ms var(--ease-ui); }
.steps button:active, .st-nav button:active, .st-nav a:active, .seg-b:active, .copy-btn:active, .ab-body .go:active, .ask-send:active, .ask-close:active, .ask-start:active, .ask-chip:active, .tool:active {
  transform: scale(.97); transition: transform 90ms cubic-bezier(.2, .8, .3, 1), background-color 150ms, color 150ms; }
.label .open:active, .where .open:active { transform: scale(.985); transition: transform 90ms cubic-bezier(.2, .8, .3, 1); }
@media (hover: hover) and (pointer: fine) { .steps button:hover:not(:active), .st-nav button:hover:not(:active), .st-nav a:hover:not(:active) { transform: translateY(-1px); } }
@media (prefers-reduced-motion: reduce) { .steps button, .st-nav button, .st-nav a, .seg-b, .copy-btn, .ask-send, .ask-close, .tool { transition: background-color 150ms, color 150ms; } .seg-mark { transition: none; } }

/* ---------- liquid metal ----------
   One ring on the pill (it closes with it into the face) and one riding the open panel, the same metal-fx finish on
   both, each fading out where the face meets the chat. With the metal running, the island's thin rim stands down. */
/* (the library wraps each ring in an invisible span, so these reach in rather than relying on direct children) */
.ask .metal-fx-root.of-face { display: block !important; width: 100% !important; height: 100% !important; min-width: 0 !important; border-radius: 999px; }
.ask .metal-fx-root.of-face .metal-fx-content { display: block !important; width: 100% !important; height: 100% !important; min-width: 0 !important; }
.ask-dock .ask-bubble { min-width: 0; }
.ask .metal-fx-root.of-ring { position: absolute !important; display: block !important; z-index: 1; background: transparent !important; }
.ask .metal-fx-root.of-ring, .ask .metal-fx-root.of-ring * { pointer-events: none !important; }
.metal-fx-root.of-ring .metal-fx-content, .ask-ring { display: block !important; width: 100% !important; height: 100% !important; border-radius: 16px; }
.metal-fx-root.of-ring:not(.is-shown) { opacity: 0 !important; transition: opacity 90ms var(--ease-ui) !important; }
.metal-fx-root.of-ring.is-shown { opacity: 1 !important; visibility: visible !important; transition: opacity 160ms var(--ease-ui) !important; }
.ask.has-metal .goo .rim, .ask.has-metal .goo .glow { display: none; }

/* ---------- phones: the work scrolls vertically ----------
   Each piece in its own box, the same squarer box the track used on a phone, settling in the middle of the screen; its
   caption under it (where it sits, what it is); the story opens in place. The single words beside the work, the arrows
   and the side story stand down. The site captures let a finger scroll the page. */
:root.work-list { scroll-snap-type: y proximity; }
.work-list .scene-work .label, .work-list .scene-work .where, .work-list .scene-work .side, .work-list .story { display: none !important; }
.work-list .scene-work .stage { grid-column: 1 / -1; grid-row: 1 / -1; height: auto !important; min-height: 0 !important; display: flex; flex-direction: column; overflow: visible; }
.work-list .slide { position: relative !important; left: auto !important; top: auto !important; transform: none !important; opacity: 1 !important; flex: none;
  width: calc(100% + 2 * var(--pad)); margin-inline: calc(-1 * var(--pad)); height: calc(var(--ui-w) / 1.12 + 2 * var(--pad)); scroll-snap-align: center; scroll-margin-bottom: 4rem; }
.work-list .browser.site .viewport { touch-action: pan-y; }
.m-cap { display: grid; gap: 0.6rem; padding: 0.25rem 0 calc(var(--bl) * 3); }
.m-cap-open { display: grid; gap: 0.3rem; padding: 0; text-align: left; color: var(--ink); background: none; cursor: pointer; }
.m-cap-where { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; color: var(--grey); }
.m-cap-where b { color: var(--ink); font-weight: 500; }
.m-cap-name { font-weight: 500; }
.m-cap-detail { color: var(--grey); text-wrap: pretty; }
.m-cap-story { display: grid; gap: 0.6rem; color: var(--secondary); text-wrap: pretty; }
.m-cap-story b { color: var(--ink); font-weight: 500; }
.m-cap-visit { justify-self: start; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.m-cap-story[hidden] { display: none; }
/* phones: the switch gets its own row under the header, full width, so the name keeps its room */
@media (width < 600px) {
  .app { grid-template-rows: auto auto auto auto auto; }
  .tr { display: contents; }
  .tl { grid-column: 1 / -1; grid-row: 1; }
  #theme-toggle { grid-column: 1 / -1; grid-row: 1; justify-self: end; align-self: center; margin-inline-end: calc((var(--bl) * 1.5 - 1rem) / -2); }
  .seg { grid-column: 1 / -1; grid-row: 2; display: flex; justify-self: stretch; margin-top: var(--bl-h); }
  .seg-b { flex: 1; }
  .center { grid-row: 3; }
  .bl { grid-row: 4; }
  .br { grid-row: 5; }
  .who .g { display: inline; }
}

/* ---------- phones, refined (audit, 12 Oct 2026) ----------
   A site or a film takes the height it needs, so it never floats in an empty box and the gaps down the list stay even;
   a film's pause sits in its own corner. How I work reads in order: the step, then its detail. The timeline stacks, so
   its words get the full width. The footer sits on a hairline and clears the floating chat. */
.work-list .slide:has(> .center-obj > .browser), .work-list .slide:has(> .center-obj > .film-card) { height: auto; }
.work-list .slide:has(> .center-obj > .browser) > .center-obj, .work-list .slide:has(> .center-obj > .film-card) > .center-obj { position: relative; inset: auto; padding: var(--pad); container-type: inline-size; }
.work-list .slide:has(> .center-obj > .film-card) > .vctl { top: calc(var(--pad) + 0.6rem); right: calc(var(--pad) + 0.6rem); }
@media (width < 600px) {
  .mt-more { display: none; }
  .scene-method .mt-line-more { display: block; margin-top: 0.4rem; color: var(--grey); }
  .ab-body .r-row { grid-template-columns: minmax(0, 1fr); gap: 0.2rem; padding-block: 0.9rem; }
  .bl { margin-top: calc(var(--bl) * 2); padding-top: var(--bl); border-top: 1px solid var(--hairline); }
  .status { text-wrap: pretty; }
  .br { padding-bottom: calc(6.5rem + env(safe-area-inset-bottom, 0px)); }
}
/* the trimmed boxes overlap their neighbours' margins: only what shows takes a touch, and the captions stay on top */
.work-list .slide { pointer-events: none; }
.work-list .slide .pt, .work-list .slide .center-obj > *, .work-list .slide .vctl, .work-list .slide.surf .ptile-safe { pointer-events: auto; }
.work-list .m-cap { position: relative; z-index: 1; }

/* ---------- Liquid Glass on the open chat (see the island in e.js) ----------
   The lens bends the page at the rim and keeps the words readable (Chromium); the frost stands in while the shape moves,
   and everywhere else. The closed pill keeps its metal ring, a button like Copy; open, it is all glass. */
.goo-lens, .goo-band, .goo-spec { position: absolute; left: 0; top: 0; z-index: 0; pointer-events: none; }
.goo-lens { opacity: 0; visibility: hidden; transition: opacity 120ms var(--ease-ui), visibility 0s linear 120ms;
  -webkit-backdrop-filter: blur(1px) url(#isl-lens) saturate(1.2); backdrop-filter: blur(1px) url(#isl-lens) saturate(1.2); }
.ask.is-lens .goo-lens { opacity: 1; visibility: visible; transition: opacity 280ms var(--ease-ui), visibility 0s; }
/* the lens fades in over the frost as it settles; when the shape moves again the frost is back at once and the lens fades fast */
.ask.is-lens .goo-frost, .ask.is-lens .goo .fill { opacity: 0; transition: opacity 280ms var(--ease-ui); }
.goo-band { opacity: 0; transition: opacity 320ms var(--ease-ui); -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-backdrop-filter: saturate(1.6) brightness(1.08) contrast(1.04); backdrop-filter: saturate(1.6) brightness(1.08) contrast(1.04); }
.ask .metal-fx-root.of-face canvas { transition: opacity 200ms var(--ease-ui) !important; }
.ask.is-open .metal-fx-root.of-face canvas { opacity: 0 !important; }
@media (prefers-color-scheme: dark) { html:root:not([data-theme="light"]) .goo-lens { -webkit-backdrop-filter: blur(1px) url(#isl-lens) saturate(1.3); backdrop-filter: blur(1px) url(#isl-lens) saturate(1.3); }
  html:root:not([data-theme="light"]) .goo-band { -webkit-backdrop-filter: saturate(1.6) brightness(1.15) contrast(1.04); backdrop-filter: saturate(1.6) brightness(1.15) contrast(1.04); } }
html:root[data-theme="dark"] .goo-lens { -webkit-backdrop-filter: blur(1px) url(#isl-lens) saturate(1.3); backdrop-filter: blur(1px) url(#isl-lens) saturate(1.3); }
html:root[data-theme="dark"] .goo-band { -webkit-backdrop-filter: saturate(1.6) brightness(1.15) contrast(1.04); backdrop-filter: saturate(1.6) brightness(1.15) contrast(1.04); }
/* Words on glass: the quieter text is darker (light) or lighter (dark) than elsewhere, so it keeps 4.5:1 over the glass. */
html .ask[data-island] .ask-panel { --grey: #33312d; --secondary: #33312d; }
@media (prefers-color-scheme: dark) { html:root:not([data-theme="light"]) .ask[data-island] .ask-panel { --grey: #ece9e3; --secondary: #ece9e3; } }
html:root[data-theme="dark"] .ask[data-island] .ask-panel { --grey: #ece9e3; --secondary: #ece9e3; }
/* Reduced transparency and increased contrast: a near-solid frost; increased contrast adds an edge; forced colours, a border. */
@media (prefers-reduced-transparency: reduce) { html .ask[data-island] { --glass-alpha: .9 !important; } }
@media (prefers-contrast: more) { html .ask[data-island] { --glass-alpha: .97 !important; } .ask[data-island] .ask-panel { box-shadow: 0 0 0 1.5px var(--ink) !important; } }
@media (forced-colors: active) { .goo-lens, .goo-band, .goo-spec, .goo-shadow { display: none; } .ask[data-island] .ask-panel { border: 1px solid CanvasText; } }
