/* Antilles Software Company: the shared system.

   One thread, many rooms. Every page (and every homepage section) lives in a "world":
   a set of tokens for ground, ink, lines, accent and display type. The components below
   read only those tokens, so the same nav, button, label, form and footer take on the
   room they stand in. Page compositions live in their own sheets.

   Order: reset, worlds, type, controls, nav, layout, picture utilities, contact, motion. */

/* Moving between pages: the old page fades into the new. Only the nav has a transition name;
   a figure given one is lifted out of its page for the transition, away from its layers. */
@view-transition { navigation: auto; }
::view-transition-group(*) { animation-duration: .75s; animation-timing-function: cubic-bezier(.2, .7, .1, 1); }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .5s; }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }

:root {
  --serif: "Spectral", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --bodoni: "Bodoni Moda", "Bodoni 72", Didot, Georgia, serif;
  --cormorant: "Cormorant Garamond", "Cormorant", Garamond, Georgia, serif;
  --fell: "IM Fell English", "IM Fell DW Pica", Georgia, serif;
  --fell-sc: "IM Fell English SC", "IM Fell English", Georgia, serif;
  --condensed: "Sofia Sans Extra Condensed", "Antonio", "Arial Narrow", sans-serif;
  --wide: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --newsreader: "Newsreader", Georgia, serif;

  --gutter: clamp(20px, 5.6vw, 112px);
  --wrap: 1480px;
  --nav-h: 72px;
  --ease: cubic-bezier(.2, .7, .1, 1);

  --grain-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .6 -.14'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  --grain-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .1 0 0 0 0 .08 0 0 0 0 .05 0 0 0 .55 -.2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  /* A breath of white noise, about one level deep. Laid into a wide, faint gradient on a dark
     ground, it keeps the gradient from showing as steps. */
  --dither: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .03 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- Worlds ---------- */

.w-night {
  --ground: #071321; --ground-2: #0c1f34; --ink: #ece6d7; --text: rgba(236, 230, 215, .78); --mute: rgba(236, 230, 215, .64);
  --line: rgba(176, 212, 236, .2); --line-2: rgba(190, 224, 246, .46); --line-3: rgba(208, 233, 250, .86);
  --accent: #c9a44e; --accent-hi: #e9cf8a; --label: #8bbfe2; --on-accent: #06101b;
  --display: var(--bodoni); --dw: 400; --ds: normal; --dls: -.018em; --dtt: none; --dlh: 1; --dscale: 1;
  --grain: none;
}
.w-paper {
  --ground: #efe9dc; --ground-2: #e4dccb; --ink: #14120f; --text: rgba(20, 18, 15, .8); --mute: rgba(20, 18, 15, .66);
  --line: rgba(20, 18, 15, .16); --line-2: rgba(20, 18, 15, .42); --line-3: rgba(20, 18, 15, .88);
  --accent: #c2321f; --accent-hi: #c2321f; --label: #14120f; --on-accent: #efe9dc;
  --display: var(--cormorant); --dw: 500; --ds: italic; --dls: -.012em; --dtt: none; --dlh: 1; --dscale: 1.16;
  --grain: var(--grain-dark);
}
.w-ink {
  --ground: #14120f; --ground-2: #1e1b17; --ink: #efe9dc; --text: rgba(239, 233, 220, .78); --mute: rgba(239, 233, 220, .64);
  --line: rgba(239, 233, 220, .16); --line-2: rgba(239, 233, 220, .4); --line-3: rgba(239, 233, 220, .88);
  --accent: #d8402a; --accent-hi: #ee5a43; --label: #efe9dc; --on-accent: #14120f;
  --display: var(--cormorant); --dw: 500; --ds: italic; --dls: -.012em; --dtt: none; --dlh: 1; --dscale: 1.16;
  --grain: none;
}
.w-sea {
  --ground: #03100f; --ground-2: #06211f; --ink: #f3f0e4; --text: rgba(228, 240, 233, .8); --mute: rgba(228, 240, 233, .66);
  --line: rgba(150, 232, 214, .18); --line-2: rgba(160, 238, 222, .42); --line-3: rgba(196, 248, 236, .88);
  --accent: #f2b441; --accent-hi: #ffd67a; --label: #74e3cf; --on-accent: #03100f;
  --display: var(--bodoni); --dw: 800; --ds: normal; --dls: -.02em; --dtt: none; --dlh: .98; --dscale: 1;
  --grain: none;
}
.w-chalk {
  --ground: #0c0c1d; --ground-2: #14143a; --ink: #f5f5ff; --text: rgba(232, 232, 252, .76); --mute: rgba(232, 232, 252, .64);
  --line: rgba(255, 255, 255, .15); --line-2: rgba(255, 255, 255, .4); --line-3: rgba(255, 255, 255, .9);
  --accent: #2424f5; --accent-hi: #7d86ff; --label: #9aa3ff; --on-accent: #ffffff;
  --display: var(--condensed); --dw: 300; --ds: normal; --dls: -.005em; --dtt: none; --dlh: .92; --dscale: 1.32;
  --grain: none;
}
.w-stone {
  --ground: #c8bdae; --ground-2: #d5ccc0; --ink: #26201a; --text: rgba(38, 32, 26, .82); --mute: rgba(38, 32, 26, .68);
  --line: rgba(38, 32, 26, .18); --line-2: rgba(38, 32, 26, .4); --line-3: rgba(38, 32, 26, .88);
  --accent: #9a7620; --accent-hi: #7c5d12; --label: #4b3f31; --on-accent: #f4eee4;
  --display: var(--cormorant); --dw: 400; --ds: italic; --dls: -.01em; --dtt: none; --dlh: 1; --dscale: 1.12;
  --grain: var(--grain-dark);
}
.w-oxblood {
  --ground: #3a0a11; --ground-2: #26050a; --ink: #ecd8a6; --text: rgba(240, 224, 190, .82); --mute: rgba(240, 224, 190, .66);
  --line: rgba(236, 216, 166, .2); --line-2: rgba(236, 216, 166, .46); --line-3: rgba(236, 216, 166, .9);
  --accent: #d4ad55; --accent-hi: #f0d28a; --label: #d4ad55; --on-accent: #26050a;
  --display: var(--cormorant); --dw: 500; --ds: normal; --dls: .07em; --dtt: uppercase; --dlh: 1.04; --dscale: .84; --head: var(--cormorant); --head-ls: .07em; --head-tt: uppercase;
  --grain: none;
}
.w-view {
  --ground: #15110b; --ground-2: #201a11; --ink: #efe3c8; --text: rgba(239, 227, 200, .8); --mute: rgba(239, 227, 200, .66);
  --line: rgba(239, 227, 200, .18); --line-2: rgba(239, 227, 200, .42); --line-3: rgba(239, 227, 200, .88);
  --accent: #d9a441; --accent-hi: #f1c56a; --label: #d9a441; --on-accent: #15110b;
  --display: var(--fell); --dw: 400; --ds: italic; --dls: -.005em; --dtt: none; --dlh: 1.02; --dscale: 1.06; --num: var(--serif);
  --grain: none;
}
.w-noir {
  --ground: #0a0908; --ground-2: #141210; --ink: #f2ecdf; --text: rgba(242, 236, 223, .84); --mute: rgba(242, 236, 223, .66);
  --line: rgba(242, 236, 223, .12); --line-2: rgba(242, 236, 223, .3); --line-3: rgba(242, 236, 223, .82);
  --accent: #c8a868; --accent-hi: #e3c98f; --label: #c8a868; --on-accent: #0a0908;
  --display: var(--bodoni); --dw: 400; --ds: italic; --dls: -.02em; --dtt: none; --dlh: 1; --dscale: 1.04;
  --grain: none;
}
.w-vault {
  --ground: #03061f; --ground-2: #0a1038; --ink: #f5eedc; --text: rgba(245, 238, 220, .84); --mute: rgba(245, 238, 220, .66);
  --line: rgba(226, 192, 116, .16); --line-2: rgba(226, 192, 116, .4); --line-3: rgba(236, 208, 140, .86);
  --accent: #dcb866; --accent-hi: #f0d79a; --label: #f0d79a; --on-accent: #03061f;
  --display: var(--cormorant); --dw: 500; --ds: normal; --dls: -.012em; --dtt: none; --dlh: 1; --dscale: 1.2;
  --grain: none;
}
.w-mosaic {
  --ground: #e7d8c5; --ground-2: #dccbb5; --ink: #1c2350; --text: rgba(28, 35, 80, .86); --mute: rgba(28, 35, 80, .7);
  --line: rgba(28, 35, 80, .16); --line-2: rgba(28, 35, 80, .4); --line-3: rgba(28, 35, 80, .88);
  --accent: #1d7c74; --accent-hi: #156860; --label: #1c2350; --on-accent: #f4eee0;
  --display: var(--cormorant); --dw: 500; --ds: italic; --dls: -.012em; --dtt: none; --dlh: 1; --dscale: 1.16;
  --grain: none;
}
/* The original site's first screen: parchment, warm black, brass. */
.w-parchment {
  --ground: #faf8f3; --ground-2: #f4f0e8; --ink: #2c2416; --text: #5c4f3a; --mute: #8b7355;
  --line: rgba(44, 36, 22, .13); --line-2: rgba(44, 36, 22, .38); --line-3: #120a00;
  --accent: #b8963e; --accent-hi: #775a19; --label: #b8963e; --on-accent: #120a00;
  --display: var(--newsreader); --dw: 400; --ds: italic; --dls: -.01em; --dtt: none; --dlh: 1.06; --dscale: 1;
  --grain: none;
}
.w { background-color: var(--ground); background-image: var(--grain); color: var(--text); }

/* ---------- Reset and base ---------- */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: #05080c; scroll-behavior: smooth; scroll-padding-top: var(--nav-h); }
body {
  margin: 0;
  font: 400 1.0625rem/1.62 var(--serif);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility;
  overflow-x: clip;
}
/* Film grain over the whole page. No blend mode, so scrolling stays cheap. It stops short of the
   top and bottom edges and fades out toward them: iOS Safari colours its status bar and its
   toolbar from whatever pinned layer touches those edges, and that has to be the nav. */
body::after {
  content: ""; position: fixed; inset: 16px 0; z-index: 90; pointer-events: none; background: var(--grain-light); opacity: .06;
  -webkit-mask-image: linear-gradient(transparent, #000 64px, #000 calc(100% - 64px), transparent);
  mask-image: linear-gradient(transparent, #000 64px, #000 calc(100% - 64px), transparent);
}

img, svg, canvas { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
p { margin: 0 0 1.05em; max-width: 60ch; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }
::selection { background: var(--accent); color: var(--on-accent); }
:focus-visible { outline: 1px solid var(--accent-hi); outline-offset: 4px; }
[hidden] { display: none !important; }

.skip { position: fixed; left: 12px; top: 12px; z-index: 200; padding: 10px 14px; background: #ece6d7; color: #06101b; font: 500 .75rem var(--mono); letter-spacing: .1em; text-decoration: none; }
/* Until it has focus the link is clipped to nothing where it stands. It is not parked above the
   top edge: iOS Safari draws the page behind its status bar, and a link parked there shows. */
.skip:not(:focus) { width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ---------- Type ---------- */

h1, h2, h3, h4 { margin: 0; font-weight: 400; color: var(--ink); text-wrap: balance; }
.t-hero, .t-h2, .t-h3 {
  font-family: var(--display); font-weight: var(--dw); font-style: var(--ds); font-optical-sizing: auto;
  letter-spacing: var(--dls); text-transform: var(--dtt); line-height: var(--dlh);
}
.t-hero { font-size: calc(clamp(2.75rem, 4.3vw + .5rem, 5.75rem) * var(--dscale)); }
.t-h2 { font-size: calc(clamp(2.1rem, 2.75vw + .75rem, 3.9rem) * var(--dscale)); }
.t-h3 { font-size: calc(clamp(1.32rem, .5vw + 1.15rem, 1.62rem) * var(--dscale)); line-height: 1.14; }
.lede { font-size: clamp(1.12rem, .42vw + 1rem, 1.32rem); line-height: 1.52; }

.label { display: block; max-width: none; font: 500 .75rem/1.3 var(--mono); letter-spacing: .18em; text-transform: uppercase; color: var(--label); }
.label--rule { display: flex; align-items: center; gap: 14px; }
.label--rule::before { content: ""; width: 34px; height: 1px; background: var(--accent); flex: none; }

/* ---------- Controls: a bordered plate with an inner hairline and a sweep fill ---------- */

.btn {
  position: relative; display: inline-flex; align-items: center; gap: 1em;
  min-height: 52px; padding: 0 26px;
  border: 1px solid var(--line-3); background: none; color: var(--ink); cursor: pointer;
  font: 500 .6875rem/1 var(--mono); letter-spacing: .22em; text-transform: uppercase; text-decoration: none; white-space: nowrap;
  isolation: isolate; overflow: hidden;
  transition: color .5s var(--ease), border-color .5s var(--ease);
}
.btn::before { content: ""; position: absolute; inset: 3px; border: 1px solid currentColor; opacity: .26; pointer-events: none; }
.btn::after { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--ink); transform: scaleX(0); transform-origin: left; transition: transform .55s var(--ease); }
.btn:hover, .btn:focus-visible { color: var(--ground); }
.btn:hover::after, .btn:focus-visible::after { transform: scaleX(1); }
.btn i { font-style: normal; transition: transform .5s var(--ease); }
.btn:hover i { transform: translateX(5px); }
.btn b { font-weight: inherit; }
.btn--solid { background: var(--ink); border-color: var(--ink); color: var(--ground); }
.btn--solid::after { background: var(--accent); }
.btn--solid:hover, .btn--solid:focus-visible { color: var(--on-accent); }
.btn--accent { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.btn--accent::after { background: var(--ink); }
.btn--accent:hover, .btn--accent:focus-visible { color: var(--ground); }
.btn--small { min-height: 40px; padding: 0 18px; }

.link {
  display: inline-flex; align-items: center; gap: .9em; padding-bottom: 7px; border-bottom: 1px solid var(--accent);
  font: 500 .6875rem/1 var(--mono); letter-spacing: .2em; text-transform: uppercase; text-decoration: none; color: var(--ink);
  transition: color .4s, gap .4s var(--ease);
}
.link:hover { color: var(--accent-hi); gap: 1.4em; }
.link i { font-style: normal; }
.inline { color: var(--ink); text-decoration-color: var(--accent); text-underline-offset: 4px; }

/* ---------- Navigation ----------
   Fixed. It carries the world of whatever section is under it (core.js keeps that in step),
   so it changes room as the page scrolls. */

.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 60; view-transition-name: nav;
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  height: var(--nav-h); padding: 0 var(--gutter);
  color: var(--ink);
  border-bottom: 1px solid transparent;
  transition: background-color .5s, border-color .5s, color .5s;
}
/* The frosted plate is a layer behind the nav, never the nav itself. A backdrop-filter on the nav
   makes it the containing block of the phone menu (position: fixed), which then measures itself
   against a 72px bar and collapses to nothing. */
.nav::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0;
  background-color: color-mix(in srgb, var(--ground) 84%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.3); backdrop-filter: blur(14px) saturate(1.3);
  transition: opacity .5s, background-color .5s;
}
.nav.is-scrolled { border-bottom-color: var(--line); }
.nav.is-scrolled::after { opacity: 1; }
.nav__brand { display: flex; align-items: center; gap: 14px; text-decoration: none; color: inherit; }
.nav__brand svg { width: 36px; height: 36px; flex: none; }
.nav__brand span { font: 500 .6875rem/1 var(--mono); letter-spacing: .24em; text-transform: uppercase; }
.nav__links { display: flex; align-items: center; gap: clamp(18px, 2.4vw, 40px); }
.nav__links a:not(.btn) {
  position: relative; padding: 10px 0;
  font: 500 .6875rem/1 var(--mono); letter-spacing: .2em; text-transform: uppercase; text-decoration: none;
  color: var(--text); transition: color .3s;
}
.nav__links a:not(.btn)::after { content: ""; position: absolute; left: 0; right: 0; bottom: 2px; height: 1px; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform .45s var(--ease); }
.nav__links a:not(.btn):hover, .nav__links a[aria-current="page"] { color: var(--ink); }
.nav__links a:not(.btn):hover::after, .nav__links a[aria-current="page"]::after { transform: scaleX(1); }
.nav__toggle { display: none; }

@media (max-width: 900px) {
  /* On a phone the bar is one plain colour once it has a ground, with no plate and no blur.
     iOS Safari paints the strip behind its status bar in the plain background colour of the bar
     pinned to the top; a blurred or see-through bar gets no strip, and the page shows above it. */
  .nav.is-scrolled, .nav[data-open="true"] { background-color: var(--ground); }
  .nav::after { content: none; }
  .nav__brand span { display: none; }
  .nav__toggle {
    display: inline-flex; align-items: center; gap: 12px; height: 40px; padding: 0 2px;
    border: 0; background: none; color: inherit; cursor: pointer;
    font: 500 .6875rem/1 var(--mono); letter-spacing: .2em; text-transform: uppercase;
  }
  .nav__toggle::after { content: ""; width: 22px; height: 7px; border-block: 1px solid currentColor; transition: height .3s; }
  .nav[data-open="true"] .nav__toggle::after { height: 1px; border-bottom: 0; }
  .nav__links {
    position: fixed; inset: var(--nav-h) 0 0 0;
    flex-direction: column; align-items: flex-start; justify-content: flex-start; gap: 0;
    padding: 18px var(--gutter) 40px; background: var(--ground); overflow-y: auto;
    visibility: hidden; opacity: 0; transition: opacity .35s, visibility .35s;
  }
  .nav[data-open="true"] .nav__links { visibility: visible; opacity: 1; }
  .nav__links a:not(.btn) { width: 100%; padding: 22px 0; border-bottom: 1px solid var(--line); font: 400 2rem/1 var(--bodoni); letter-spacing: -.01em; text-transform: none; color: var(--ink); }
  .nav__links a:not(.btn)::after { display: none; }
  .nav__links .btn { margin-top: 30px; }
}

/* ---------- Layout ---------- */

.wrap { width: min(100% - 2 * var(--gutter), var(--wrap)); margin-inline: auto; }
.sec { position: relative; padding-block: clamp(84px, 10.5vw, 184px); }
.sec__mark {
  position: absolute; top: clamp(84px, 10.5vw, 184px); left: calc(var(--gutter) / 2 - 7px);
  display: flex; align-items: center; gap: 14px; writing-mode: vertical-rl; white-space: nowrap;
  font: 500 .6875rem/1 var(--mono); letter-spacing: .24em; text-transform: uppercase; color: var(--label);
}
.sec__mark::after { content: ""; width: 1px; height: 84px; background: linear-gradient(var(--line-2), transparent); }
@media (max-width: 1180px) { .sec__mark { display: none; } }

/* ---------- Picture utilities ---------- */

/* Tone: maps any image between two colours, and returns it to its own colour when .is-true
   or when a linked plate is hovered. --duo-lo and --duo-hi can be set per use. */
.tone { --duo-lo: #05172a; --duo-hi: #a9d3ee; position: relative; overflow: hidden; isolation: isolate; background: var(--duo-hi); transition: background-color .9s var(--ease); }
.tone > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: var(--op, 50% 50%); filter: grayscale(1) contrast(1.16) brightness(1.04); mix-blend-mode: multiply; transition: filter .9s var(--ease), transform 1.6s var(--ease); }
.tone::before { content: ""; position: absolute; inset: 0; z-index: 1; background: var(--duo-lo); mix-blend-mode: lighten; transition: opacity .9s var(--ease); }
:is(a, .is-live):hover > .tone, :is(a, .is-live):hover .plate__frame > .tone, a:focus-visible .tone, .tone.is-true { background-color: #fff; }
:is(a, .is-live):hover .tone > img, a:focus-visible .tone > img, .tone.is-true > img { filter: none; }
:is(a, .is-live):hover .tone::before, a:focus-visible .tone::before, .tone.is-true::before { opacity: 0; }

/* Cut: a figure shot on black, masked to its outline (tools/cutout.sh makes the mask). */
.cut { -webkit-mask: var(--mask) center / 100% 100% no-repeat; mask: var(--mask) center / 100% 100% no-repeat; }
.cut > img { width: 100%; height: auto; }

/* Ink is black line art and chalk is white line art. Both files carry their own transparency
   (tools/art.py makes them), so they need no blend mode and look the same wherever they stand,
   move or fade. The classes only name the medium. */

/* Frame: a thin outline with a second hairline inside, as on a mounted plate. */
.frame { position: relative; outline: 1px solid var(--line-3); }
.frame::after { content: ""; position: absolute; inset: 5px; border: 1px solid var(--line); pointer-events: none; z-index: 3; }

/* Light: a canvas of moving light (light.js). It is dark until its first frame is drawn and
   then comes up slowly, so a room never changes light at a stroke. --lit is how bright it stands. */
.light { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; mix-blend-mode: screen; opacity: 0; transition: opacity 2.4s var(--ease); }
.light.is-lit { opacity: var(--lit, 1); }

/* ---------- Figures ----------
   Charts drawn by tools/draw.py from real numbers. They read the world's tokens, and each
   draws itself once, when the [data-reveal] block that holds it comes into view. */

.pf { display: block; width: 100%; height: auto; margin-bottom: clamp(22px, 2.2vw, 36px); overflow: visible; fill: none; stroke: var(--ink); stroke-width: 1; }
.pf :is(rect, path, circle) { vector-effect: non-scaling-stroke; }
.pf text { stroke: none; fill: var(--ink); }
.pf .n { font: italic 500 100px/1 var(--cormorant); letter-spacing: -.04em; fill: var(--ink); }
.pf .c { font: italic 400 14.5px/1 var(--serif); fill: var(--text); }
.pf .m { font: 500 12px/1 var(--mono); letter-spacing: .06em; fill: var(--mute); }
.pf .soft { opacity: .34; }
.pf .soft-t { fill: var(--mute); }
.pf .hot { stroke: var(--accent-hi); }
.pf .hotf { fill: var(--accent-hi); stroke: none; }
.pf .hot-t { fill: var(--accent-hi); }
.pf .lead { stroke-dasharray: 2 3; }
.pf .bar rect:last-child { stroke: var(--line-2); }
.pf .bar--hot rect:last-child, .pf .unit--hot rect:last-child { stroke: var(--accent-hi); }
.pf rect.unit { stroke: var(--line-2); }

/* Each figure draws itself once, when it comes into view. */
.pf .bar { transform-box: fill-box; transform-origin: 0 50%; transition: transform 1s var(--ease) calc(var(--i) * 55ms + .25s); }
.pf .unit--hot { transition: opacity .5s linear calc(var(--i) * 14ms + .25s); }
.pf .dot { transform-box: fill-box; transform-origin: center; transition: transform .6s var(--ease) calc(var(--i) * 160ms + .9s); }
html:not(.no-js) [data-reveal]:not(.is-in) .pf .bar { transform: scaleX(0); }
html:not(.no-js) [data-reveal]:not(.is-in) .pf .unit--hot { opacity: 0; }
html:not(.no-js) [data-reveal]:not(.is-in) .pf .dot { transform: scale(0); }
.pf .curve { stroke-width: 1.6; transition: opacity 1s linear .3s; }
.pf .area { opacity: .5; transition: opacity 1s linear .9s; }
html:not(.no-js) [data-reveal]:not(.is-in) .pf .curve { opacity: 0; }
html:not(.no-js) [data-reveal]:not(.is-in) .pf .area { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .pf :is(.bar, .unit--hot, .dot, .curve, .area) { transition: none; } }

/* ---------- Contact and forms ----------
   The details are the same on every page. Each page lays them out in its own material:
   centred under a nimbus (home), beside the form (split), on a label card, on a film slate. */

.contact { overflow: clip; padding-bottom: 0; }
.contact .wrap { position: relative; }
.contact .label { margin-bottom: 24px; color: var(--accent-hi); }
.contact .lede { margin-top: 22px; max-width: 30em; }
.contact__mail {
  display: inline-block; padding-bottom: 6px; border-bottom: 1px solid var(--accent);
  font: 400 clamp(1.4rem, 1.5vw + .9rem, 2.3rem)/1.15 var(--serif); letter-spacing: 0; color: var(--ink); text-decoration: none; overflow-wrap: anywhere;
  transition: color .3s;
}
.contact__mail:hover { color: var(--accent-hi); }
.contact__tel { display: block; width: fit-content; margin-top: 18px; font: 500 1.0625rem/1 var(--mono); letter-spacing: .14em; color: var(--ink); text-decoration: none; }
.contact__tel:hover { color: var(--accent-hi); }
.contact__msg { display: flex; flex-wrap: wrap; gap: 10px 26px; width: fit-content; margin-top: 18px; font: 500 .75rem/1 var(--mono); letter-spacing: .18em; text-transform: uppercase; }
.contact__msg a { padding-bottom: 6px; border-bottom: 1px solid var(--line-2); color: var(--accent-hi); text-decoration: none; transition: border-color .3s; }
.contact__msg a:hover { border-bottom-color: var(--accent-hi); }
.contact__place { margin-top: 26px; font: 500 .6875rem/1 var(--mono); letter-spacing: .26em; text-transform: uppercase; color: var(--mute); }
.contact__reach { margin-top: clamp(28px, 3vw, 44px); }

.contact--center { text-align: center; }
.contact--center .wrap { max-width: 1040px; }
.contact--center :is(p, h2) { margin-inline: auto; }
.contact--center h2 { max-width: 14em; }
.contact--center :is(.contact__tel, .contact__msg) { margin-inline: auto; }

.contact--split .wrap { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(30px, 5vw, 100px); align-items: start; }
.contact--split .inquiry-form { margin-top: 0; }
@media (max-width: 900px) { .contact--split .wrap { grid-template-columns: 1fr; } }

/* A label card: the details set on a card, as on an object label or a wall label. */
.contact--card .wrap { display: grid; justify-items: center; }
.card-label { position: relative; width: min(100%, 720px); padding: clamp(28px, 4vw, 60px); background-color: var(--ground); background-image: var(--grain); color: var(--text); box-shadow: 0 30px 70px rgba(0, 0, 0, .35); }
.card-label::before { content: ""; position: absolute; inset: 7px; border: 1px solid var(--line-2); pointer-events: none; }
.card-label .label { color: var(--label); }
.card-label__rows { margin: clamp(26px, 3vw, 40px) 0 0; border-top: 1px solid var(--line-3); }
.card-label__rows div { display: grid; grid-template-columns: 6rem minmax(0, 1fr); gap: 16px; align-items: baseline; padding: 18px 0; border-bottom: 1px solid var(--line); }
.card-label__rows dt { font: 500 .6875rem/1 var(--mono); letter-spacing: .2em; text-transform: uppercase; color: var(--mute); }
.card-label__rows dd { margin: 0; }
.card-label__rows .contact__mail { border: 0; padding: 0; font-size: clamp(1.25rem, 1vw + .9rem, 1.7rem); }
.card-label__rows :is(.contact__tel, .contact__msg) { margin: 0; }
@media (max-width: 520px) {
  .card-label__rows div { grid-template-columns: 1fr; gap: 8px; }
  .card-label__rows .contact__mail { font-size: 1.2rem; overflow-wrap: normal; }
}

.inquiry-form { position: relative; margin-top: clamp(48px, 5vw, 80px); padding: clamp(24px, 3.4vw, 50px); text-align: left; border: 1px solid var(--line-2); background: color-mix(in srgb, var(--ground-2) 60%, transparent); }
.inquiry-form::after { content: ""; position: absolute; inset: 6px; border: 1px solid var(--line); pointer-events: none; }
.field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px 34px; }
.field { display: flex; flex-direction: column; gap: 9px; min-width: 0; }
.field.wide { grid-column: 1 / -1; }
.field > span { font: 500 .6875rem/1.4 var(--mono); letter-spacing: .2em; text-transform: uppercase; color: var(--label); }
.field > span i { font-style: normal; letter-spacing: .1em; opacity: .7; margin-left: 6px; }
.field input, .field select, .field textarea { width: 100%; min-width: 0; border: 0; border-bottom: 1px solid var(--line-2); border-radius: 0; background: transparent; color: var(--ink); padding: 8px 0 11px; font: 400 1.2rem/1.35 var(--serif); transition: border-color .2s; }
.field textarea { border: 1px solid var(--line-2); padding: 13px 14px; min-height: 132px; resize: vertical; font-size: 1.08rem; line-height: 1.55; }
.field select { appearance: none; cursor: pointer; padding-right: 24px; background: linear-gradient(45deg, transparent 50%, currentColor 50%) right 6px center / 6px 6px no-repeat, linear-gradient(-45deg, transparent 50%, currentColor 50%) right 0 center / 6px 6px no-repeat; }
.field select option { color: #15120c; background: #efe8d6; }
.field select:has(option[value=""]:checked) { color: var(--mute); }
.field input::placeholder, .field textarea::placeholder { color: var(--mute); }
.field input:focus, .field select:focus, .field textarea:focus { outline: 0; border-color: var(--accent-hi); }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-foot { display: flex; align-items: center; gap: 26px; flex-wrap: wrap; margin-top: 36px; }
.form-status { flex: 1 1 220px; margin: 0; font-size: .95rem; }
.inquiry-form[data-state="error"] .form-status { color: #e9a07c; }
.form-sent { position: absolute; inset: 0; z-index: 4; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 18px; padding: clamp(24px, 3.4vw, 50px); background: var(--ground-2); }
.form-sent h3 { font: 400 clamp(1.8rem, 2.4vw, 2.6rem)/1.1 var(--bodoni); }
.form-sent button { border: 0; border-bottom: 1px solid var(--accent); background: none; padding: 0 0 6px; color: var(--ink); cursor: pointer; font: 500 .6875rem/1 var(--mono); letter-spacing: .2em; text-transform: uppercase; }
@media (max-width: 640px) { .field-grid { grid-template-columns: 1fr; } }

.foot {
  position: relative; display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 16px 30px;
  margin-top: clamp(70px, 8vw, 130px); background-color: var(--ground); color: var(--mute); padding: 26px var(--gutter) 30px; border-top: 1px solid var(--line);
  font: 500 .6875rem/1.4 var(--mono); letter-spacing: .2em; text-transform: uppercase; text-align: left;
}
:not(.contact) > .foot { margin-top: 0; }
.foot nav { display: flex; flex-wrap: wrap; gap: 10px 26px; }
@media (max-width: 480px) { .foot > span { letter-spacing: .08em; white-space: nowrap; } }
.foot a { text-decoration: none; transition: color .3s; }
.foot a:hover { color: var(--accent-hi); }

/* ---------- Motion ---------- */

[data-reveal] { opacity: 0; transform: translateY(22px); transition: opacity 1.1s var(--ease), transform 1.2s var(--ease); transition-delay: calc(var(--i, 0) * 90ms); }
[data-reveal].is-in { opacity: 1; transform: none; }
.no-js [data-reveal] { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  .btn::after, .tone, .tone > img, .tone::before { transition: none; }
}
