/* Vladimir Ermant — portfolio v5-polish. The page structure follows zkevinbai.com; the visual system is ours:
   warm dark paper (light on request), one teal accent in both themes, Fraunces display type at weight 500 for
   anything large, Inter for everything else, one spacing rhythm, and every control with a rest, hover and focus state. */
:root {
  color-scheme: dark;
  --paper: #14110f; --cream: #1b1714; --cream-2: #241f1b; --white: #201b18;
  --card: rgba(255,255,255,.04); --card-raised: rgba(255,255,255,.055); --card-hover: rgba(255,255,255,.07);
  --ink: #f3eee6; --ink-soft: #d6cec2; --muted: #9a8f82; --line: #2d2723; --line-strong: #3b3430;
  --clay: #2bb3bf; --clay-deep: #6fd0da; --clay-ink: #06222a; --clay-soft: rgba(43,179,191,.12); --gold: #d8b768;
  --shadow-card: 0 18px 50px -28px rgba(0,0,0,.85);
  --shadow-photo: 0 30px 60px -30px rgba(0,0,0,.7);
  --ring: 0 0 0 1px var(--line);
  --ease: cubic-bezier(.2,.8,.2,1);
  --r-md: .875rem; --r-lg: 1.125rem;
  --serif: "Fraunces", Georgia, serif; --sans: "Inter", system-ui, sans-serif;
  /* type: Inter at six sizes (the lead is a step smaller under 768px); Fraunces at weight 500, with card and row
     titles at two sizes */
  --fs-lead: 1.15rem; --fs-essay: 1.125rem; --fs-long: 1.0625rem; --fs-body: 1rem; --fs-small: .875rem; --fs-micro: .75rem;
  --fs-title: 1.5rem; --fs-title-sm: 1.25rem;
  /* two insets: cards (career, education, the side card, the work and closing cards), and the blocks inside a text
     column (asides, stats, diagram columns, callouts, previous/next) */
  --inset-card: 2rem; --inset-block: 1.25rem 1.5rem;
}
@media (max-width: 639px) { :root { --inset-card: 1.5rem; } }
@media (min-width: 768px) { :root { --fs-lead: 1.25rem; } }
/* light: --muted keeps at least 4.5:1 on every surface it sits on (paper, cards, the footer) */
html.light {
  color-scheme: light;
  --paper: #fbf7f0; --cream: #f6f0e6; --cream-2: #eee5d5; --white: #ffffff;
  --card: rgba(255,255,255,.65); --card-raised: #ffffff; --card-hover: #ffffff;
  --ink: #1b1714; --ink-soft: #2f2924; --muted: #766b5e; --line: #e6ddd0; --line-strong: #d8cdbd;
  --clay: #0b7580; --clay-deep: #075f69; --clay-ink: #ffffff; --clay-soft: rgba(11,117,128,.08); --gold: #c69749;
  --shadow-card: 0 18px 50px -30px rgba(27,23,20,.35);
  --shadow-photo: 0 30px 60px -30px rgba(27,23,20,.35);
}
*, *::before, *::after { box-sizing: border-box; border: 0 solid var(--line); }
html { scroll-behavior: smooth; scroll-padding-top: 88px; }
body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--sans); font-size: 100%; line-height: 1.5; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
h1, h2, h3, p { margin: 0; font-size: inherit; font-weight: inherit; }
h1, h2 { text-wrap: balance; }
a { color: inherit; text-decoration: none; }
/* a tap shows the control's own pressed state (:active) instead of the browser's grey flash */
a, button { -webkit-tap-highlight-color: transparent; }
img { max-width: 100%; display: block; }
strong { font-weight: 600; color: var(--ink); }
::selection { background: color-mix(in srgb, var(--clay) 30%, transparent); }
:focus-visible { outline: 2px solid var(--clay); outline-offset: 3px; }
/* a text link's ring has soft corners, like the round rings of the controls beside it; :where() adds no specificity, so
   pills, circles, cards and rows that set their own radius keep it */
:where(a:focus-visible) { border-radius: .375rem; }
.page { max-width: 1080px; margin: 0 auto; padding: 0 1.5rem; width: 100%; }
@media (min-width: 768px) { .page { padding: 0 2rem; } }
.eyebrow { text-transform: uppercase; letter-spacing: .12em; color: var(--clay); font-size: var(--fs-micro); font-weight: 600; }
/* one small-label style for every label, category and field name: muted small capitals. The section eyebrows above
   share its size and tracking; they and the case-study section numbers are the only teal ones. */
.label, .logos .lab, .cat, .side p:first-child, .calm .d-title dt, .calm .status .k, .contact .ways .k, .essay .nav2 .k,
.prose-body .in-short .k, .prose-body .prompt-card figcaption, .arch .col .sub4, .job .label { font: 600 var(--fs-micro)/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.label { margin-bottom: 1rem; }

/* reveal on scroll. Nothing is hidden before the script runs: site.js marks only the blocks that start below the
   screen (.pre) and fades each in (.in) as it arrives. What is on screen at load is drawn at once, and print, reduced
   motion and a missing script show everything. */
@media screen and (prefers-reduced-motion: no-preference) {
  .reveal.pre:not(.in) { opacity: 0; transform: translateY(20px); }
  .reveal.pre.in { animation: rise .7s cubic-bezier(.2,.8,.2,1); }
}
@keyframes rise { from { opacity: 0; transform: translateY(20px); } }
/* reduced motion: nothing slides, lifts or scrolls. Anchor jumps and focus moves are instant, the reveal above never
   runs (everything is simply there), and pointing at a button, pill, arrow link or footer icon changes its colour only.
   The reels (site.js) and the logo row (its rule further down) already stay still. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn:hover, .btn:active, .pill:hover, .pill:hover span, footer .social a:hover, footer .social a:active, .hdr .links a.cta:hover,
  .back:hover span, .back:focus-visible span, .post-row:hover .read span, .post-row:focus-visible .read span,
  .workcard a.more:hover::after, .job .body li.links a:hover span, .reel .arrow:active { transform: none !important; }
}

/* header */
.hdr { position: fixed; top: 0; left: 0; right: 0; z-index: 50; height: 4rem; background: transparent; border-bottom: 1px solid transparent; transition: background-color .2s, border-color .2s, backdrop-filter .2s, -webkit-backdrop-filter .2s; }
/* scrolled, the header is 94% paper over a blur, so text passing under it doesn't show through and the teal links keep
   their contrast over a dark screenshot; the fill, hairline and blur fade in together (and only they do). Without
   JavaScript nothing marks it as scrolled, so it keeps that look throughout and text never runs under it. */
.hdr.scrolled { background: color-mix(in srgb, var(--paper) 94%, transparent); border-bottom-color: var(--line); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
@media (scripting: none) { .hdr { background: color-mix(in srgb, var(--paper) 94%, transparent); border-bottom-color: var(--line); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); } }
/* the skip link is the first stop on every page: out of sight above the page until it has focus */
.skip { position: absolute; top: .75rem; left: 1rem; z-index: 60; padding: .5rem 1rem; border-radius: 9999px; background: var(--ink); color: var(--paper); font-size: .875rem; font-weight: 600; transform: translateY(-4rem); }
.skip:focus { transform: none; }
/* icons (inline SVG, drawn in tools/stamp.mjs) are 1.25em square, so each takes its size from the text it sits in, as
   the icon font did; in a box of fixed size (the toolkit tiles) they never outgrow it */
.icon { display: block; flex-shrink: 0; width: 1.25em; height: 1.25em; max-width: 100%; max-height: 100%; }
.hdr nav { display: flex; height: 100%; align-items: center; justify-content: space-between; }
/* the header's column is the page's 1080px at the default text size and grows with a larger default font, so the menu
   keeps to one row where it fits (with the em breakpoints below, text zoomed to 200% gets two rows up to 1438px) */
.hdr .page { max-width: 67.5rem; }
.hdr .brand { font-family: var(--serif); font-size: 1.35rem; font-weight: 500; letter-spacing: -.01em; color: var(--ink); white-space: nowrap; transition: color .2s; }
.hdr .links { display: flex; align-items: center; gap: .25rem; }
/* one row: the menu reaches 9px into the right gutter, the space between the theme switch's round edge and its glyph
   (9.7px to the moon, 8.8px to the sun's rays), so the glyph ends on the page edge the way the name starts on it */
@media (min-width: 45em) { .hdr .links { gap: .5rem; margin-right: -.5625rem; } }
.hdr .links a { position: relative; padding: .5rem .75rem; font-size: .875rem; font-weight: 500; color: var(--ink-soft); transition: color .2s; }
.hdr .links a.on { color: var(--clay); }
.hdr .links a::after { content: ""; position: absolute; left: .75rem; right: .75rem; bottom: -.125rem; height: 1px; background: currentColor; opacity: 0; transition: opacity .2s; }
.hdr .links a.on::after { opacity: 1; }
.hdr .theme { position: relative; margin-left: .25rem; display: flex; flex-shrink: 0; height: 2.25rem; width: 2.25rem; align-items: center; justify-content: center; border-radius: 9999px; color: var(--ink-soft); background: none; cursor: pointer; padding: 0; font-size: 1rem; transition: color .2s; }
/* the theme switch needs the script, so without JavaScript it is left out rather than shown doing nothing */
@media (scripting: none) { .hdr .theme { display: none; } }
/* pointing turns the name, a menu link or the theme switch teal, only where the pointer can hover, so a tapped link on
   a phone doesn't stay teal */
@media (hover: hover) { .hdr .brand:hover, .hdr .links a:hover, .hdr .theme:hover { color: var(--clay); } }
/* light theme: the current and pointed-at links take the deeper teal, 5:1 or better even where a dark screenshot shows
   through the header (the Contact pill keeps its own colours) */
html.light .hdr .links a.on:not(.cta) { color: var(--clay-deep); }
@media (hover: hover) { html.light .hdr .brand:hover, html.light .hdr .links a:not(.cta):hover, html.light .hdr .theme:hover { color: var(--clay-deep); } }
/* Windows high contrast draws no backgrounds, so the current page's underline takes a system colour */
@media (forced-colors: active) { .hdr .links a::after { forced-color-adjust: none; background: LinkText; } }
/* phones and narrow windows (under 720px at the default text size, where one row stops fitting; the breakpoint is in em,
   so larger text gets this layout sooner): the name and the theme switch share the first row and the menu takes a
   full-width second row, so every target is visible without scrolling. Only a much larger default font wraps the menu
   onto a third row, rather than pushing Contact off the screen. */
@media (max-width: 44.9375em) {
  .hdr { height: auto; }
  .hdr nav { position: relative; flex-wrap: wrap; height: auto; padding-top: .6rem; padding-bottom: .3rem; }
  .hdr .brand { font-size: 1.2rem; }
  .hdr .links { width: 100%; flex-wrap: wrap; justify-content: space-between; gap: 0; }
  .hdr .links a { padding: .45rem .3rem; font-size: .8rem; }
  .hdr .links a::after { left: .3rem; right: .3rem; }
  /* the menu's first word starts on the name's edge, and the switch's glyph ends on the page edge (the page's 1.5rem
     side padding less the glyph's 9px inset, as in the one-row header) */
  .hdr .links a:first-child { padding-left: 0; }
  .hdr .links a:first-child::after { left: 0; }
  .hdr .theme { position: absolute; top: .4rem; right: .9375rem; width: 2.25rem; height: 2rem; margin-left: 0; }
  html { scroll-padding-top: 6.75rem; }
}
/* a larger default font can bring the two-row header to 768px and wider, where the page's side padding is 2rem */
@media (max-width: 44.9375em) and (min-width: 768px) { .hdr .theme { right: 1.4375rem; } }
/* touch screens: the header's targets reach further than they look, without moving anything or taking a neighbour's
   space. In the one-row header each link is 44px tall and the theme switch 44px square; in the two-row header the menu
   reaches down to the header's edge, and the switch up to its top and 44px across. */
@media (pointer: coarse) {
  .hdr .links a::before, .hdr .theme::before { content: ""; position: absolute; left: 0; right: 0; top: calc(50% - 1.375rem); bottom: calc(50% - 1.375rem); }
  .hdr .theme::before { left: calc(50% - 1.375rem); right: calc(50% - 1.375rem); }
}
@media (pointer: coarse) and (max-width: 44.9375em) {
  .hdr .links a::before { top: 0; bottom: -.3rem; }
  /* the first link gave up its left padding to line up with the name; its target keeps that width in the gutter */
  .hdr .links a:first-child::before { left: -.3rem; }
  .hdr .theme::before { top: -.4rem; bottom: 0; }
}
.theme .sun, html.light .theme .moon { display: none; }
html.light .theme .sun { display: block; }

/* hero */
.hero { position: relative; overflow: hidden; padding: 8.5rem 0 3.5rem; }
@media (min-width: 768px) { .hero { padding: 10rem 0 5rem; } }
.hero .glow { pointer-events: none; position: absolute; inset: 0; z-index: -1; background: radial-gradient(55% 45% at 15% 0%, color-mix(in srgb, var(--clay) 9%, transparent), transparent 70%), radial-gradient(45% 40% at 90% 10%, color-mix(in srgb, var(--gold) 9%, transparent), transparent 70%); }
/* on light paper the teal lobe turns the paper grey-green, so the light theme keeps only the warm lobe, fainter */
html.light .hero .glow { background: radial-gradient(45% 40% at 90% 10%, color-mix(in srgb, var(--gold) 6%, transparent), transparent 70%); }
.hero .grid { display: grid; grid-template-columns: minmax(0, 1fr); align-items: center; gap: 2rem; }
@media (min-width: 768px) { .hero .grid { gap: 2.5rem; } }
@media (min-width: 1024px) { .hero .grid { grid-template-columns: minmax(0,1fr) 300px; gap: 4rem; } }
.hero .copy { max-width: 48rem; }
/* the eyebrow's two roles share a line when they fit; on phones each takes its own line and the dot drops out, so a
   role never breaks in the middle ("... · AI" / "Product Developer") */
.hero .eyebrow .role { white-space: nowrap; }
@media (max-width: 31em) { .hero .eyebrow { line-height: 1.75; } .hero .eyebrow .role { display: block; } .hero .eyebrow .sep { display: none; } }
.hero h1 { margin-top: 1rem; font-family: var(--serif); font-size: clamp(2.75rem, 1.9rem + 3.8vw, 4.4rem); font-weight: 500; line-height: 1.02; letter-spacing: -.028em; color: var(--ink); }
@media (max-width: 31em) { .hero h1 { margin-top: .75rem; } }
.hero .lede { margin-top: 1.5rem; font-size: var(--fs-lead); line-height: 1.6; color: var(--ink-soft); text-wrap: pretty; }
.hero .btns { margin-top: 2.25rem; display: flex; flex-wrap: wrap; gap: .75rem; }
/* where the three buttons can't share a row, the primary takes the first and the two links pair up on the second,
   the same at every phone width (instead of one button left alone on the second row) */
@media (max-width: 31em) {
  .hero .btns { row-gap: 0; }
  .hero .btns::after { content: ""; flex-basis: 100%; order: 1; }
  .hero .btns .btn:not(.primary) { order: 2; margin-top: .75rem; }
}
/* buttons and pills are one control: 40px tall (44px on touch screens), one inset and weight, the filled button a
   weight heavier. Pointed at, or pressed on a touch screen, they change colour and nothing moves but a trailing
   arrow, which steps forward 3px. */
.btn { display: inline-flex; align-items: center; gap: .625rem; min-height: 2.5rem; border-radius: 9999px; padding: 0 1.0625rem; font-size: var(--fs-small); font-weight: 500; border: 1px solid var(--line-strong); background: transparent; color: var(--ink-soft); transition: border-color .2s, color .2s, background .2s; }
.btn:active { border-color: var(--clay); color: var(--clay-deep); background: var(--clay-soft); }
.btn.primary { background: var(--clay); color: var(--clay-ink); border-color: var(--clay); font-weight: 600; box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.btn.primary:active { background: color-mix(in srgb, var(--clay) 88%, var(--ink)); border-color: color-mix(in srgb, var(--clay) 88%, var(--ink)); color: var(--clay-ink); }
.btn span { display: inline-block; transition: transform .2s var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .btn:hover { border-color: var(--clay); color: var(--clay-deep); background: var(--clay-soft); }
  .btn.primary:hover { background: color-mix(in srgb, var(--clay) 88%, var(--ink)); border-color: color-mix(in srgb, var(--clay) 88%, var(--ink)); color: var(--clay-ink); }
  .btn:hover span { transform: translateX(3px); }
}
/* the portrait sits on the page grid: above the copy and on its left edge when stacked (the paper-coloured border is
   pulled into the gutter so the photo lines up with the text), on the right edge beside the copy from 1024px */
.portrait { order: -1; justify-self: start; margin-left: -5px; }
@media (min-width: 1024px) { .portrait { order: 0; justify-self: end; margin: 0 -5px 0 0; } }
.portrait img { height: 9.5rem; width: 9.5rem; border-radius: 9999px; border: 5px solid var(--paper); object-fit: cover; object-position: center 15%; box-shadow: var(--ring), var(--shadow-photo); }
@media (min-width: 640px) { .portrait img { height: 11.5rem; width: 11.5rem; } }
@media (min-width: 1024px) { .portrait img { height: 17rem; width: 17rem; } }

/* sections */
section.sec { scroll-margin-top: 6rem; padding: 3.75rem 0; }
@media (min-width: 768px) { section.sec { padding: 5.5rem 0; } }
.sec-head { margin-bottom: 2.75rem; max-width: 720px; }
.sec-head h2 { margin-top: .875rem; font-family: var(--serif); font-size: clamp(1.85rem, 1.15rem + 1.6vw, 2.4rem); font-weight: 500; line-height: 1.12; letter-spacing: -.018em; color: var(--ink); }
.sec-head .sub { margin-top: 1rem; font-size: var(--fs-body); line-height: 1.65; color: var(--muted); max-width: 44em; text-wrap: pretty; }
/* cards hold information, not links, so they stay still when pointed at */
.card { border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--card); box-shadow: inset 0 1px 0 rgba(255,255,255,.03); }
/* printed, a section heading stays on the page with the start of its section */
@media print { .sec-head { break-inside: avoid; break-after: avoid; } }

/* about: one calm profile. Its sections are short, so they follow each other at one even interval (closer than the
   home page's), the side card stays beside the prose while it is read, and the page ends where the other pages do. */
.profile .plain-page { padding-bottom: 0; }
.profile section.sec { padding: 0; margin-top: 5rem; }
@media (min-width: 768px) { .profile section.sec { margin-top: 7rem; } }
.profile section.sec:last-child { padding-bottom: 4rem; }
.about { margin-top: 2.5rem; display: grid; grid-template-columns: minmax(0, 1fr); gap: 3rem; }
.about > * { max-width: 38rem; }
@media (min-width: 768px) { .about { margin-top: 3rem; } }
@media (min-width: 1024px) {
  .about { grid-template-columns: minmax(0,1.6fr) minmax(0,1fr); gap: 4.5rem; }
  .about > * { max-width: none; }
  .about > :last-child { position: sticky; top: 6.5rem; align-self: start; }
}
.about .prose { display: flex; flex-direction: column; gap: 1.5rem; }
.about .prose p { font-size: var(--fs-long); line-height: 1.8; color: var(--ink-soft); text-wrap: pretty; }
/* the profile states things in plain prose: names, titles and tools carry no bold */
.about .prose strong { font-weight: inherit; color: inherit; }
.about .chips-row { display: flex; flex-wrap: wrap; gap: .5rem; padding-top: .5rem; }
.pill { display: inline-flex; align-items: center; gap: .5rem; min-height: 2.5rem; border-radius: 9999px; border: 1px solid var(--line-strong); background: transparent; padding: 0 1.0625rem; font-size: var(--fs-small); font-weight: 500; color: var(--ink-soft); transition: border-color .2s, color .2s, background .2s; }
.pill:active { border-color: var(--clay); color: var(--clay-deep); background: var(--clay-soft); }
.pill span { display: inline-block; transition: transform .2s var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .pill:hover { border-color: var(--clay); color: var(--clay-deep); background: var(--clay-soft); }
  .pill:hover span { transform: translateX(3px); }
}
@media (pointer: coarse) { .btn, .pill { min-height: 2.75rem; } }
.side { border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--card); padding: var(--inset-card); box-shadow: inset 0 1px 0 rgba(255,255,255,.03); align-self: start; }
.side .list { margin-top: .75rem; overflow: hidden; font-family: var(--serif); font-size: 1.125rem; line-height: 1.9; color: var(--ink); }
/* Separators sit before each item; the negative margin clips the one that starts each line, so none dangle. */
.side .list ul { display: flex; flex-wrap: wrap; margin: 0 0 0 -1.25rem; padding: 0; list-style: none; }
.side .list li { white-space: nowrap; }
.side .list li::before { content: "·"; display: inline-block; width: 1.25rem; text-align: center; color: var(--muted); }

/* career */
.job { position: relative; }
@media (min-width: 768px) { .job { padding-left: 6rem; } }
.job .mark { margin-bottom: .75rem; display: flex; height: 3.5rem; width: 3.5rem; align-items: center; justify-content: center; overflow: hidden; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--white); padding: .45rem; box-shadow: 0 1px 2px rgba(0,0,0,.05); font-family: var(--serif); font-weight: 500; color: var(--ink-soft); font-size: 1rem; }
@media (min-width: 768px) { .job .mark { position: absolute; left: 0; top: 0; margin-bottom: 0; } }
.job .mark img { height: 100%; width: 100%; object-fit: contain; border-radius: .4rem; }
.job .card { padding: var(--inset-card); }
.job .head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .25rem 1rem; }
/* on phones the dates sit under the titles on every card, rather than beside the short ones and under the long ones */
@media (max-width: 639px) { .job .head { flex-direction: column; align-items: flex-start; } }
.job h3 { font-family: var(--serif); font-size: var(--fs-title-sm); font-weight: 500; letter-spacing: -.01em; color: var(--ink); }
.job .when { font-size: var(--fs-small); font-weight: 500; color: var(--muted); font-variant-numeric: tabular-nums; }
.job .org { margin-top: .25rem; font-size: var(--fs-small); font-weight: 500; color: var(--ink-soft); }
.job .loc { margin-top: .125rem; font-size: var(--fs-small); color: var(--muted); }
.job .body { margin-top: 1.25rem; display: flex; flex-direction: column; gap: 1rem; }
.chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.chip { border-radius: 9999px; border: 1px solid var(--line); background: var(--cream); padding: .25rem .75rem; font-size: var(--fs-micro); font-weight: 500; color: var(--ink-soft); }

/* education: the career cards' family (same mark size, card surface and inset); the text stays quiet */
.edu { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; }
@media (min-width: 768px) { .edu { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; } }
.ecard { display: flex; align-items: center; gap: 1.25rem; padding: var(--inset-card); }
.ecard .mark { display: flex; height: 3.5rem; width: 3.5rem; flex-shrink: 0; align-items: center; justify-content: center; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--white); font-family: var(--serif); font-size: 1rem; font-weight: 500; color: var(--ink-soft); }
.ecard h3 { font-family: var(--serif); font-size: var(--fs-title-sm); font-weight: 500; line-height: 1.3; letter-spacing: -.01em; color: var(--ink); }
.ecard .field { margin-top: .3rem; font-size: var(--fs-small); font-weight: 500; line-height: 1.45; color: var(--ink-soft); }
.ecard .where { margin-top: .125rem; font-size: var(--fs-small); line-height: 1.45; color: var(--muted); }

/* toolkit (Kevin Bai's, on purpose). The tiles are the cards' small siblings: the same line, surface and inset edge,
   one radius step down. Nothing here is a link, so nothing reacts to the pointer, and every mark is drawn in one quiet
   colour: devicon glyphs, and inline SVG from tools/stamp.mjs. The spoken languages have no mark (emoji flags draw as
   letter pairs on Windows). Every label stays on one line at every width, so every row keeps the same height. */
.kit { display: flex; flex-direction: column; gap: 2.5rem; }
.kit .chip.lg { padding: .375rem .875rem; font-size: var(--fs-small); }
.tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .75rem; }
@media (min-width: 640px) { .tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .tiles { grid-template-columns: repeat(6, minmax(0, 1fr)); } }
.tile { display: flex; align-items: center; gap: .625rem; min-height: 3.25rem; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--card); padding: .75rem .875rem; box-shadow: inset 0 1px 0 rgba(255,255,255,.03); }
.tile .ico { display: flex; height: 1.5rem; width: 1.5rem; flex-shrink: 0; align-items: center; justify-content: center; font-size: 1.375rem; color: var(--ink-soft); }
/* the devicons' brand colours ("colored") give way to the one quiet colour */
.tile .ico > i { color: inherit; }
.tile .n { min-width: 0; font-size: .875rem; font-weight: 500; line-height: 1.3; color: var(--ink-soft); }
.tile .n.b { font-weight: 600; color: var(--ink); display: block; }
/* where the tiles run narrow (phones under 400px, and six across on 1024-1199px screens) the labels step down a size,
   so "Tailwind CSS" and "Swoogo API" keep to one line */
@media (max-width: 399px), (min-width: 1024px) and (max-width: 1199px) { .tile { padding: .75rem; } .tile .n { font-size: .8125rem; } }
@media (max-width: 359px) { .tile { padding: .625rem; gap: .5rem; } .tile .ico { width: 1.25rem; height: 1.25rem; font-size: 1.125rem; } .tile .n { font-size: .78rem; } }

/* contact (Kevin's newsletter card slot) */
/* the space above the card matches the gap between any two sections (section.sec padding); below it, the page ends
   4rem above the footer's own margin, like every other page */
section.cta-sec { padding: 3.75rem 0 4rem; }
@media (min-width: 768px) { section.cta-sec { padding-top: 5.5rem; } }
/* the same surface as the work card (--card, hairline border, top highlight); the extra rule is scoped so the
   header's Contact link, which shares the class name, keeps its own look */
.cta { border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--card); padding: 3.25rem var(--inset-card); text-align: center; }
.cta-sec .cta { box-shadow: inset 0 1px 0 rgba(255,255,255,.03); }
@media (max-width: 639px) { .cta-sec .cta { padding-block: 2.75rem; } }
/* the badge is a quiet mark, drawn like the testimonial initials; the button under the words is the teal thing to press */
.cta .ic { margin: 0 auto; display: flex; height: 3rem; width: 3rem; align-items: center; justify-content: center; border-radius: 9999px; border: 1px solid var(--line); background: var(--cream-2); color: var(--ink-soft); font-size: 1.1rem; }
.cta h2 { margin: 1.5rem auto 0; max-width: 42rem; font-family: var(--serif); font-size: 1.875rem; font-weight: 500; line-height: 1.25; color: var(--ink); }
.cta p { margin: 1rem auto 0; max-width: 36rem; font-size: var(--fs-body); line-height: 1.625; color: var(--muted); }
.cta .btn { margin-top: 1.75rem; }

/* footer */
footer { margin-top: 6rem; border-top: 1px solid var(--line); background: color-mix(in srgb, var(--cream) 50%, transparent); }
footer .ftop { display: flex; flex-direction: column; gap: 2rem; padding-top: 3rem; padding-bottom: 3rem; }
@media (min-width: 768px) { footer .ftop { flex-direction: row; align-items: center; justify-content: space-between; } }
footer .name { font-family: var(--serif); font-size: var(--fs-title-sm); font-weight: 500; color: var(--ink); }
footer .ftag { margin-top: .25rem; font-size: var(--fs-small); color: var(--muted); }
footer .social { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
/* the two icon links behave like the site's pills: a line at rest, a teal line and tint when pointed at or pressed;
   44px on touch screens, like the reel arrows */
footer .social a { display: flex; height: 2.5rem; width: 2.5rem; align-items: center; justify-content: center; border-radius: 9999px; border: 1px solid var(--line-strong); background: transparent; color: var(--ink-soft); transition: border-color .2s var(--ease), color .2s var(--ease), background .2s var(--ease); }
footer .social a:active { border-color: var(--clay); background: var(--clay-soft); color: var(--clay-deep); }
@media (hover: hover) and (pointer: fine) { footer .social a:hover { border-color: var(--clay); background: var(--clay-soft); color: var(--clay-deep); } }
@media (pointer: coarse) { footer .social a { height: 2.75rem; width: 2.75rem; } }
/* The rule is drawn inside the page gutters so it lines up with the text above it. */
footer .legal { display: flex; flex-direction: column; gap: .5rem; background: linear-gradient(var(--line), var(--line)) top / calc(100% - 3rem) 1px no-repeat; padding-top: 1.25rem; padding-bottom: 1.25rem; font-size: var(--fs-micro); color: var(--muted); }
@media (min-width: 640px) { footer .legal { flex-direction: row; align-items: center; justify-content: space-between; } }
@media (min-width: 768px) { footer .legal { background-size: calc(100% - 4rem) 1px; } }
footer .legal .r { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
footer .legal a { transition: color .2s var(--ease); }
footer .legal a:active { color: var(--clay-deep); }
@media (hover: hover) and (pointer: fine) { footer .legal a:hover { color: var(--clay-deep); } }
/* on touch screens each small link gets a 44px tall target; the negative margin keeps the line where it was */
@media (pointer: coarse) { footer .legal a { padding-block: .8125rem; margin-block: -.8125rem; } }

/* back links (case studies and essays): quiet until pointed at; the arrow leads the way back */
.back { display: inline-flex; align-items: center; gap: .375rem; margin-bottom: 2rem; font-size: var(--fs-small); font-weight: 500; color: var(--muted); transition: color .2s var(--ease); }
.back:focus-visible, .back:active { color: var(--clay-deep); }
.back span { display: inline-block; transition: transform .2s var(--ease); }
.back:focus-visible span { transform: translateX(-3px); }
@media (hover: hover) and (pointer: fine) { .back:hover { color: var(--clay-deep); } .back:hover span { transform: translateX(-3px); } }
/* on touch screens the link gets a 44px tall target; the negative margins keep it where it was */
@media (pointer: coarse) { .back { padding-block: .75rem; margin-top: -.75rem; margin-bottom: 1.25rem; } }
@media (prefers-reduced-motion: reduce) { .back, .back span { transition: none; } }

/* ---------- writing (Kevin's /blog, editorial upgrade). The page head shares the title and standfirst rule under
   "contact"; the category is a small label, not a chip. ---------- */
.wr-head { padding: 8.5rem 0 3rem; }
@media (min-width: 768px) { .wr-head { padding-top: 10rem; } }
/* essay page: a 656px column (about 70 characters of 18px text) that starts where every other page does, the pull
   quote in the reading colour, and the callouts and previous/next cards on the card surface */
.essay { max-width: 720px; margin: 0 auto; padding: 8.5rem 1.5rem 4rem; }
@media (min-width: 768px) { .essay { padding: 10rem 2rem 4rem; } }
.essay .back { margin: 0; }
@media (pointer: coarse) { .essay .back { margin-block: -.75rem; } }
.essay header { margin-top: 2rem; border-bottom: 1px solid var(--line); padding-bottom: 2.25rem; }
.essay header .meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: .375rem .75rem; font-size: var(--fs-small); color: var(--muted); }
.essay h1 { margin-top: 1rem; font-family: var(--serif); font-size: clamp(2.2rem, 1.6rem + 2.4vw, 3.1rem); font-weight: 500; line-height: 1.08; letter-spacing: -.025em; color: var(--ink); }
.essay .by { margin-top: 1rem; font-size: var(--fs-small); color: var(--muted); }
.essay .lead { margin-top: 1.5rem; font-family: var(--serif); font-size: 1.35rem; line-height: 1.5; color: var(--ink-soft); font-style: italic; text-wrap: pretty; }
.prose-body { margin-top: 2.75rem; color: var(--ink-soft); font-size: var(--fs-essay); line-height: 1.75; }
.prose-body > * { margin: 0; }
.prose-body p, .prose-body li { text-wrap: pretty; }
.prose-body > * + * { margin-top: 1.4em; }
.prose-body h2 { margin-top: 2.2em; font-family: var(--serif); font-size: var(--fs-title); font-weight: 500; line-height: 1.2; letter-spacing: -.012em; color: var(--ink); text-wrap: balance; }
.prose-body h3 { margin-top: 1.8em; font-family: var(--serif); font-size: var(--fs-title-sm); font-weight: 500; line-height: 1.25; color: var(--ink); }
.prose-body h2 + *, .prose-body h3 + * { margin-top: .75em; }
.prose-body a { color: var(--clay-deep); font-weight: 500; text-decoration-line: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); transition: text-decoration-color .2s var(--ease); }
.prose-body a:active { text-decoration-color: currentColor; }
@media (hover: hover) and (pointer: fine) { .prose-body a:hover { text-decoration-color: currentColor; } }
.prose-body ul { padding-left: 1.2em; list-style: none; }
.prose-body li { margin-top: .6em; padding-left: 1.1em; position: relative; }
.prose-body ul li::before { content: ""; position: absolute; left: 0; top: .72em; width: 6px; height: 6px; border-radius: 50%; background: var(--muted); -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.prose-body ol { padding-left: 1.6em; list-style: decimal; }
.prose-body ol li { padding-left: .2em; }
.prose-body ol li::marker { color: var(--muted); font-weight: 600; }
.prose-body blockquote { margin: 1.6em 0; padding: .15em 0 .15em 1.1em; border-left: 2px solid var(--muted); font-family: var(--serif); font-size: 1.3em; font-style: italic; line-height: 1.45; color: var(--ink); text-wrap: balance; }
.prose-body img { width: 100%; height: auto; display: block; border-radius: var(--r-md); border: 1px solid var(--line); }
.prose-body hr { border: 0; border-top: 1px solid var(--line); margin-top: 2.4em; }
.prose-body code { background: var(--cream); border: 1px solid var(--line); border-radius: .3rem; padding: .1em .35em; font-size: .9em; }
.prose-body .in-short, .prose-body .prompt-card { border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--card); box-shadow: inset 0 1px 0 rgba(255,255,255,.03); }
.prose-body .in-short { padding: var(--inset-block); font-size: var(--fs-body); line-height: 1.65; }
.prose-body .in-short ul { margin: .625rem 0 0; padding-left: 0; }
.prose-body .in-short li { margin-top: .5em; }
.prose-body .in-short li::before { top: .66em; }
.prose-body .prompt-card { padding: var(--inset-block); background: var(--card-raised); }
.prose-body .prompt-card p { margin-top: .625rem; font-size: var(--fs-body); line-height: 1.7; color: var(--ink); }
.essay .end { margin-top: 3rem; border-top: 1px solid var(--line); padding-top: 1.75rem; display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; justify-content: space-between; font-size: var(--fs-small); color: var(--muted); }

/* ---------- writing list: ruled rows. The date shares the meta line's baseline (in its own column from 768px), and
   pointing at a row lights its title and its arrow. ---------- */
/* the list ends 4rem above the footer's own margin, like the other pages (padding, so it can't fold into that margin) */
.posts { display: flex; flex-direction: column; padding-bottom: 4rem; }
.post-row { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: baseline; column-gap: 1rem; border-top: 1px solid var(--line); padding: 2rem 0 2.25rem; color: inherit; }
.post-row > h2, .post-row > h3, .post-row > p, .post-row > .read { grid-column: 1 / -1; }
@media (min-width: 768px) {
  .post-row { grid-template-columns: 10rem minmax(0, 1fr); column-gap: 2rem; padding: 2.25rem 0 2.5rem; }
  .post-row > h2, .post-row > h3, .post-row > p, .post-row > .read { grid-column: 2; }
  .post-row .date { grid-row: 1 / span 4; }
}
.post-row:last-child { border-bottom: 1px solid var(--line); }
.post-row:focus-visible { outline-offset: 6px; border-radius: 2px; }
.post-row .date { font-size: var(--fs-small); color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; transition: color .2s var(--ease); }
.post-row .meta { display: flex; align-items: baseline; gap: .75rem; font-size: var(--fs-small); color: var(--muted); }
.post-row h2 { margin-top: .625rem; font-family: var(--serif); font-size: var(--fs-title); font-weight: 500; line-height: 1.25; letter-spacing: -.012em; color: var(--ink); text-wrap: balance; transition: color .2s var(--ease); }
.post-row p { margin-top: .5rem; max-width: 48em; font-size: var(--fs-body); line-height: 1.625; color: var(--ink-soft); text-wrap: pretty; }
.post-row .read { margin-top: .875rem; justify-self: start; display: inline-flex; align-items: center; gap: .375rem; font-size: var(--fs-small); font-weight: 500; color: var(--ink-soft); transition: color .2s var(--ease); }
.post-row .read span { display: inline-block; transition: transform .2s var(--ease); }
.post-row:focus-visible h2, .post-row:focus-visible .read, .post-row:active h2, .post-row:active .read { color: var(--clay-deep); }
.post-row:focus-visible .date, .post-row:active .date { color: var(--ink-soft); }
.post-row:focus-visible .read span { transform: translateX(3px); }
@media (hover: hover) and (pointer: fine) {
  .post-row:hover h2, .post-row:hover .read { color: var(--clay-deep); }
  .post-row:hover .date { color: var(--ink-soft); }
  .post-row:hover .read span { transform: translateX(3px); }
}
/* essays: reading bar on the header's bottom edge (one row or two), and the previous/next cards */
.hdr .progress { position: absolute; left: 0; bottom: -1px; height: 2px; width: 0; background: var(--clay); transition: width .1s linear; }
.essay .nav2 { margin-top: 2rem; display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; }
@media (min-width: 640px) { .essay .nav2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .essay .nav2 a.next { grid-column: 2; } }
.essay .nav2 a { display: block; border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--card); padding: var(--inset-block); color: inherit; box-shadow: inset 0 1px 0 rgba(255,255,255,.03); transition: border-color .25s var(--ease), background .25s var(--ease); }
.essay .nav2 .k { display: block; transition: color .2s var(--ease); }
.essay .nav2 .t { display: block; margin-top: .5rem; font-family: var(--serif); font-size: var(--fs-title-sm); font-weight: 500; line-height: 1.3; color: var(--ink); text-wrap: balance; transition: color .2s var(--ease); }
.essay .nav2 a:active { border-color: var(--line-strong); background: var(--card-hover); }
.essay .nav2 a:focus-visible .k, .essay .nav2 a:active .k { color: var(--clay); }
.essay .nav2 a:focus-visible .t, .essay .nav2 a:active .t { color: var(--clay-deep); }
@media (hover: hover) and (pointer: fine) {
  .essay .nav2 a:hover { border-color: var(--line-strong); background: var(--card-hover); }
  .essay .nav2 a:hover .k { color: var(--clay); }
  .essay .nav2 a:hover .t { color: var(--clay-deep); }
}
.essay .nav2 a.next { text-align: right; }

/* ---------- case studies: a long-form write-up. Sections take their content's height and the page scrolls
   normally. Each numbered section opens on a hairline rule, its number and heading in a side column that stays
   beside its words and screens (from 900px). The dots on the right are a quiet index of the sections; they show
   from 1200px, where they sit clear of the page, 40px outside its right edge. ---------- */
.deck-nav { position: fixed; top: 50%; right: max(1rem, calc(50vw - 568px)); z-index: 45; display: none; flex-direction: column; transform: translateY(-50%); }
@media (min-width: 1200px) { .deck-nav { display: flex; } }
.deck-nav a { display: grid; place-items: center; width: 1.25rem; height: 1.25rem; border-radius: 50%; }
/* each dot is a control, so even at rest it keeps 3:1 against the paper (--muted: 5.9:1 dark, 4.9:1 light); the one
   being read is teal and larger */
.deck-nav a::before { content: ""; width: .5rem; height: .5rem; border-radius: 50%; background: var(--muted); transition: background .2s var(--ease), transform .25s var(--ease); }
@media (hover: hover) { .deck-nav a:hover::before { background: var(--ink-soft); } }
.deck-nav a.on::before { background: var(--clay); transform: scale(1.4); }
.deck-nav a:focus-visible { outline-offset: 0; }
@media (prefers-reduced-motion: reduce) { .deck-nav a::before { transition: none; } }
/* Windows high contrast draws no backgrounds, so the dots take system colours */
@media (forced-colors: active) { .deck-nav a::before { forced-color-adjust: none; background: CanvasText; } .deck-nav a.on::before { background: Highlight; } }

/* ---------- case studies: calm write-up content ---------- */
/* top of the page: the way back, the title, the summary and the facts, then the lead screen straight after */
.calm .d-title { padding: 8.5rem 0 2.5rem; }
@media (min-width: 768px) { .calm .d-title { padding: 10rem 0 3rem; } }
.calm .d-title .eyebrow { margin-bottom: 1.25rem; }
/* the title is set on the page-title scale (.plain-page h1), and the summary is a lead like every page's */
.calm .d-title h1 { margin-top: 1rem; font-family: var(--serif); font-size: clamp(2.4rem, 1.6rem + 3vw, 3.5rem); font-weight: 500; line-height: 1.05; letter-spacing: -.025em; color: var(--ink); max-width: 12em; }
.calm .d-title .summary { margin-top: 1.5rem; font-size: var(--fs-lead); line-height: 1.6; color: var(--ink-soft); max-width: 36em; text-wrap: pretty; }
/* the facts' rule runs the width of the page, flush with the lead screen below it */
.calm .d-title dl { margin: 2.5rem 0 0; padding-top: 1.5rem; border-top: 1px solid var(--line); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem 2rem; }
@media (max-width: 359px) { .calm .d-title dl { grid-template-columns: minmax(0, 1fr); } }
@media (min-width: 768px) { .calm .d-title dl { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.calm .d-title dt { margin-bottom: .5rem; }
.calm .d-title dd { margin: 0; font-size: var(--fs-small); line-height: 1.5; color: var(--ink); overflow-wrap: anywhere; text-wrap: pretty; }
/* links in the facts and the text: teal with a quiet underline that fills in on hover */
.calm .d-title dd a, .calm .d-text p a { color: var(--clay-deep); font-weight: 500; text-decoration-line: underline; text-decoration-thickness: 1px; text-decoration-color: color-mix(in srgb, var(--clay-deep) 35%, transparent); text-underline-offset: .2em; transition: color .2s var(--ease), text-decoration-color .2s var(--ease); }
.calm .d-title dd a:active, .calm .d-text p a:active { color: var(--clay); text-decoration-color: currentColor; }
@media (hover: hover) and (pointer: fine) { .calm .d-title dd a:hover, .calm .d-text p a:hover { color: var(--clay); text-decoration-color: currentColor; } }

/* sections: the lead screen and each numbered section end on the same space, and each numbered section opens on a
   hairline rule with a little less space under it, so the rule belongs to the section it opens */
.calm .d-image, .calm .d-text { padding-bottom: 3.5rem; }
@media (min-width: 900px) { .calm .d-image, .calm .d-text { padding-bottom: 4.5rem; } }
/* the last section ends 4rem above the footer's own margin, where every other page ends */
.calm .d-text:last-child { padding-bottom: 4rem; }
.calm .d-text .grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem; align-items: start; padding-top: 2.25rem; border-top: 1px solid var(--line); }
@media (min-width: 900px) { .calm .d-text .grid { grid-template-columns: 300px minmax(0, 1fr); gap: 2.75rem 5rem; padding-top: 3rem; } }
.calm .d-text h2 { font-family: var(--serif); font-size: 1.9rem; font-weight: 500; line-height: 1.15; letter-spacing: -.02em; color: var(--ink); }
@media (min-width: 900px) { .calm .d-text h2 { font-size: 2.2rem; position: sticky; top: 6.5rem; } }
/* the section number is the case study's eyebrow: teal, in the sans at the eyebrow's size, tracked only enough that
   "05" reads as one number */
.calm .d-text h2 .k { display: block; margin-bottom: 1rem; font: 600 var(--fs-micro)/1.4 var(--sans); letter-spacing: .04em; color: var(--clay); font-variant-numeric: tabular-nums; }
/* the text column: one measure (the paragraphs' 40em) shared by every block in it, and one rhythm, with a little
   more room around the blocks than between paragraphs */
.calm .d-text h2 + div { max-width: 43.2rem; }
.calm .d-text h2 + div > * { margin: 0; }
.calm .d-text h2 + div > * + * { margin-top: 1.25rem; }
.calm .d-text h2 + div > * + :is(.pair, .aside, .tech, .facts-row, .status, .nextrow), .calm .d-text h2 + div > .facts-row + * { margin-top: 2rem; }
.calm .d-text p { font-size: var(--fs-long); line-height: 1.75; color: var(--ink-soft); text-wrap: pretty; }
.calm .d-text ul { padding: 0; list-style: none; }
.calm .d-text li { position: relative; padding-left: 1.4rem; font-size: var(--fs-long); line-height: 1.7; color: var(--ink-soft); text-wrap: pretty; }
.calm .d-text li + li { margin-top: .7em; }
.calm .d-text li::before { content: ""; position: absolute; left: .25rem; top: .72em; width: 6px; height: 6px; border-radius: 50%; background: var(--muted); }

/* screenshots: one frame for every product screen (hairline, --r-lg corners, --white under the image, the photo
   shadow), shown whole at their natural shape and never cropped. Each opens its full-size original. The lead screen
   runs the width of the page; the screens that illustrate a section sit in its text column, one above the other and
   the full width of the column, so its heading stays beside them. */
.calm figure { margin: 0; }
.calm figure > a { display: block; border-radius: var(--r-lg); cursor: zoom-in; }
.calm figure img { width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--white); box-shadow: var(--shadow-photo); transition: border-color .25s var(--ease); }
.calm figure > a:active img { border-color: color-mix(in srgb, var(--clay) 60%, transparent); }
@media (hover: hover) and (pointer: fine) { .calm figure > a:hover img { border-color: color-mix(in srgb, var(--clay) 60%, transparent); } }
.calm figcaption { margin-top: .875rem; font-size: var(--fs-small); line-height: 1.55; color: var(--muted); max-width: 40em; text-wrap: pretty; }
.calm .pair { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2rem; }
/* the architecture diagram is the one figure that spans both columns, under its section's words */
.calm .d-text .grid > .wide { grid-column: 1 / -1; }
@media (max-width: 899px) { .calm .d-text .grid > .wide { margin-top: .5rem; } }
@media (prefers-reduced-motion: reduce) { .calm figure img { transition: none; } }

/* one family of blocks: a hairline, --r-md corners, the card fill and the same inner spacing */
.calm .aside { position: relative; padding: var(--inset-block); padding-left: 2.125rem; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--card); font-size: var(--fs-body); line-height: 1.65; color: var(--ink-soft); }
.calm .aside::before { content: ""; position: absolute; left: 1.125rem; top: 1.25rem; bottom: 1.25rem; width: 2px; border-radius: 2px; background: var(--muted); }
.calm .tech { padding: var(--inset-block); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--card); }
.calm .tech p { font-size: var(--fs-body); line-height: 1.7; }
.calm .tech .chips { margin-top: 1rem; }
.calm .status { padding-top: 1.5rem; border-top: 1px solid var(--line); }
.calm .status .k { display: block; margin-bottom: .5rem; }
.calm .nextrow { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; }
.calm .nextrow .lab { font-size: var(--fs-small); color: var(--muted); margin-right: .5rem; }

/* ---------- v4: Anton-shaped site, Kevin's visual system ---------- */
.hero .lede.short { max-width: 31em; }
/* availability reads as a status line: a small teal dot, quiet text */
.hero .avail { margin-top: 1.25rem; display: flex; align-items: flex-start; gap: .6rem; font-size: var(--fs-body); line-height: 1.55; color: var(--muted); max-width: 34em; }
.hero .avail::before { content: ""; flex-shrink: 0; width: .5rem; height: .5rem; margin-top: .5em; border-radius: 50%; background: var(--clay); box-shadow: 0 0 0 3px var(--clay-soft); }
/* reel: screens crossfade in one box; the caption and the controls share a strip below the image, so nothing ever
   covers a screen. The strip is as tall as the reel's longest caption on every slide (subgrid), so it never moves,
   and the caption wraps instead of running under the controls. The arrows are drawn like the site's pills: a line at
   rest, a teal line and tint when pointed at. */
.reel { position: relative; border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--white); overflow: hidden; }
.reel .track { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto; }
.reel .track > figure { grid-area: 1 / 1 / 3 / 2; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: subgrid; margin: 0; opacity: 0; visibility: hidden; transition: opacity .25s ease, visibility 0s linear .25s; }
.reel .track > figure.on { opacity: 1; visibility: visible; z-index: 1; transition: opacity .25s ease, visibility 0s; }
.reel img { width: 100%; height: auto; display: block; aspect-ratio: 16/10; object-fit: cover; object-position: top; }
.reel figcaption { display: flex; align-items: center; min-height: 3.5rem; padding: .625rem 1.25rem; font-size: var(--fs-small); line-height: 1.4; color: var(--muted); border-top: 1px solid var(--line); background: var(--white); text-wrap: pretty; }
/* site.js marks a reel as a region when it adds the controls; only then does the caption keep clear of them */
.reel[role="region"] figcaption { padding-right: 10rem; }
.reel figcaption .cap { display: block; min-width: 0; }
.reel figcaption b { color: var(--ink); font-weight: 600; }
/* on Home each caption is the project's name, a link on a line of its own and only as wide as its words, then what the
   project is on the line under it, so a line never starts partway through either. On phones, where they wrap, both
   are balanced, so no year is left alone on a last line. A no-break space before each "·" (set by tools/quotes.mjs)
   keeps a separator from starting a line. */
.workcard .reel figcaption { text-wrap: balance; }
.workcard .reel figcaption .cap > a { display: block; width: fit-content; }
.reel figcaption a { color: var(--ink); text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 3px; transition: color .2s var(--ease), text-decoration-color .2s var(--ease); }
.reel figcaption a:active { color: var(--clay-deep); text-decoration-color: currentColor; }
@media (hover: hover) and (pointer: fine) { .reel figcaption a:hover { color: var(--clay-deep); text-decoration-color: currentColor; } }
.reel figcaption a:focus-visible { outline: 2px solid var(--clay); outline-offset: 2px; }
.reel .ctl { grid-area: 2 / 1; align-self: center; justify-self: end; margin-right: .75rem; z-index: 2; display: flex; align-items: center; gap: .375rem; }
.reel .cnt { font-size: var(--fs-small); font-variant-numeric: tabular-nums; color: var(--muted); margin-right: .5rem; }
.reel .arrow { width: 2.5rem; height: 2.5rem; border-radius: 50%; border: 1px solid var(--line-strong); background: transparent; color: var(--ink-soft); padding: 0; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease); }
.reel .arrow svg { display: block; }
.reel .arrow:active { border-color: var(--clay); background: var(--clay-soft); color: var(--clay-deep); }
@media (hover: hover) and (pointer: fine) { .reel .arrow:hover { border-color: var(--clay); background: var(--clay-soft); color: var(--clay-deep); } }
.reel .arrow:focus-visible { outline: 2px solid var(--clay); outline-offset: 2px; }
.reel .vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (pointer: coarse) { .reel .arrow { width: 2.75rem; height: 2.75rem; } }
@media (max-width: 640px) {
  .reel .cnt { display: none; }
  .reel figcaption { min-height: 3.75rem; padding-left: 1rem; }
  .reel[role="region"] figcaption { padding-right: 7.25rem; }
}
@media (prefers-reduced-motion: reduce) { .reel .track > figure, .reel .track > figure.on, .reel .arrow { transition: none; } }
/* testimonials: ruled rows, each rule closer to the quote it introduces than to the one before; the opening quote mark
   hangs in the margin, and on the Testimonials page the list closes with a rule, like Work and Writing */
.testi { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
.tq { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.25rem; padding: 2.5rem 0; border-top: 1px solid var(--line); }
@media (min-width: 800px) { .tq { grid-template-columns: minmax(0,1fr) minmax(0,1.4fr); gap: 4rem; } }
.testi > .tq:last-child { border-bottom: 1px solid var(--line); }
.tq .pull { font-family: var(--serif); font-size: 1.35rem; line-height: 1.35; letter-spacing: -.01em; color: var(--ink); text-indent: -.4em; text-wrap: pretty; }
/* each quote and its attribution are a figure (blockquote + figcaption), set without the browser's indents; the pull
   line repeats a sentence of the quote, so screen readers skip it (aria-hidden in the markup) */
.tq .body, .tq blockquote { margin: 0; }
.tq .body p { margin: 0; font-size: var(--fs-body); line-height: 1.7; color: var(--ink-soft); text-wrap: pretty; }
.tq .body p + p { margin-top: 1em; }
.tq .who { display: flex; align-items: center; gap: .75rem; margin-top: 1.25rem; }
.tq .who .av { flex-shrink: 0; width: 2.25rem; height: 2.25rem; border-radius: 50%; background: var(--cream-2); border: 1px solid var(--line); display: flex; align-items: center; justify-content: center; font-family: var(--serif); font-weight: 500; font-size: .85rem; color: var(--ink-soft); }
.tq .who b { display: block; font-size: var(--fs-small); line-height: 1.35; color: var(--ink); font-weight: 600; }
.tq .who span { font-size: var(--fs-small); line-height: 1.35; color: var(--muted); }
.testi .more { padding-top: 1.5rem; border-top: 1px solid var(--line); }
/* work page rows: the screens take the wider column from 1024px (below that, the full width), the words start level
   with the top of the screen, and each status is a quiet mark: a filled dot when live, a ring while in progress. The
   mark stands in for the separator before it (still read out and copied, just not drawn), and the mark and its label
   wrap as one, so no line ends or starts on a stray dot. */
.wk { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.75rem; padding: 3rem 0; border-top: 1px solid var(--line); align-items: start; }
.wk:last-of-type { border-bottom: 1px solid var(--line); }
@media (min-width: 768px) { .wk { gap: 2.25rem; padding: 4rem 0; } .wk > :last-child { max-width: 40rem; } }
.wk h2 { margin: 0; font-family: var(--serif); font-size: var(--fs-title); font-weight: 500; line-height: 1.2; letter-spacing: -.015em; color: var(--ink); text-wrap: balance; }
@media (min-width: 1024px) { .wk { grid-template-columns: minmax(0,1.5fr) minmax(0,1fr); gap: 3rem; } .wk > :last-child { max-width: none; } .wk h2 { margin-top: -.4rem; } }
@media (min-width: 1200px) { .wk { gap: 3.5rem; } }
.wk .desc { margin-top: .5rem; font-size: var(--fs-small); line-height: 1.55; color: var(--muted); }
.wk .st { white-space: nowrap; }
.wk .st .sep { display: inline-block; width: 0; height: 0; overflow: hidden; }
.wk .st::before { content: ""; display: inline-block; box-sizing: border-box; width: .5rem; height: .5rem; margin: 0 .15em 0 .12em; border-radius: 50%; vertical-align: .06em; }
.wk .st.live::before { background: var(--clay); box-shadow: 0 0 0 3px var(--clay-soft); -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.wk .st.wip::before { border: 1.5px solid var(--muted); }
.wk p { margin: 1rem 0 0; font-size: var(--fs-body); line-height: 1.7; color: var(--ink-soft); text-wrap: pretty; }
.wk .desc + p { margin-top: 1.25rem; }
.wk p strong { color: var(--ink); }
.wk .links { margin-top: 1.5rem; display: flex; flex-wrap: wrap; gap: .5rem; }
.wk ul.chips { margin: 1.5rem 0 0; padding: 0; list-style: none; }
.wk ul.chips li { padding: .25rem .75rem; border-radius: 9999px; border: 1px solid var(--line); background: var(--cream); font-size: var(--fs-micro); font-weight: 500; line-height: 1.5; color: var(--ink-soft); }
/* the Events Manager screens are taller than the reels' 16:10 frame, so this reel takes their own shape and shows them
   whole instead of cutting their lower panels off mid-row */
#events-manager .reel img { aspect-ratio: 1400 / 1022; }
/* on paper the rows keep the text at full width and a smaller gap, so no row spills its padding onto a page of its own */
@media print { .wk { padding: 2rem 0; } .wk > :last-child { max-width: none; } }
/* contact, and the page head shared by About, Work, Writing, Testimonials and Contact: one title, one standfirst */
.plain-page { padding: 8.5rem 0 3rem; }
@media (min-width: 768px) { .plain-page { padding-top: 10rem; } }
.plain-page h1, .wr-head h1 { margin-top: 1rem; max-width: 16em; font-family: var(--serif); font-size: clamp(2.4rem, 1.6rem + 3vw, 3.5rem); font-weight: 500; line-height: 1.05; letter-spacing: -.025em; color: var(--ink); }
.plain-page .intro, .wr-head .intro { margin-top: 1.25rem; max-width: 36em; font-size: var(--fs-lead); line-height: 1.65; color: var(--ink-soft); text-wrap: pretty; }
.plain-page.contact { padding-bottom: 4rem; }
/* a page shorter than the window (the 404): it ends 4rem above the footer's own margin like every page, and on screen
   its main takes the spare height, so the footer rests at the foot of the window instead of stopping partway down with
   bare paper under it */
main.short > .plain-page { padding-bottom: 4rem; }
@media screen {
  body:has(> main.short) { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }
  main.short { flex: 1 0 auto; }
}
/* the ways to reach him: a ruled list the width of the page, like every other, its labels and values in the Writing
   list's columns. Each label shares its value's baseline, and each value is a link whose quiet underline fills in when
   pointed at */
.contact .ways { margin-top: 3rem; border-top: 1px solid var(--line); }
.contact .ways > div { display: grid; grid-template-columns: 10rem minmax(0,1fr); align-items: baseline; gap: .375rem 2rem; padding: 1.375rem 0; border-bottom: 1px solid var(--line); }
@media (max-width: 560px) { .contact .ways > div { grid-template-columns: minmax(0, 1fr); padding: 1.125rem 0 1.25rem; } }
.contact .ways a { color: var(--clay-deep); font-weight: 500; font-size: var(--fs-long); overflow-wrap: anywhere; text-decoration-line: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-color: color-mix(in srgb, currentColor 30%, transparent); transition: text-decoration-color .2s var(--ease); }
.contact .ways a:active { text-decoration-color: currentColor; }
@media (hover: hover) and (pointer: fine) { .contact .ways a:hover { text-decoration-color: currentColor; } }
.contact .ways p { margin: 0; font-size: var(--fs-long); color: var(--ink-soft); }
.contact .ways a + p { margin-top: .375rem; font-size: var(--fs-body); color: var(--muted); }

/* ---------- home: Anton-style work card + logo row ---------- */
.workcard { display: grid; grid-template-columns: minmax(0, 1fr); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; background: var(--card); box-shadow: inset 0 1px 0 rgba(255,255,255,.03); }
@media (min-width: 900px) { .workcard { grid-template-columns: minmax(0,1.6fr) minmax(0,1fr); } }
.workcard .reel { border: 0; border-radius: 0; }
.workcard .txt { padding: var(--inset-card); display: flex; flex-direction: column; justify-content: center; gap: .75rem; }
/* stacked (under 900px), the reel's caption starts on the same line as the words under it */
@media (max-width: 899px) { .workcard .reel figcaption { padding-left: var(--inset-card); } }
.workcard h2 { font-family: var(--serif); font-size: var(--fs-title); font-weight: 500; letter-spacing: -.01em; color: var(--ink); margin: 0; }
.workcard p { margin: 0; font-size: var(--fs-body); line-height: 1.7; color: var(--ink-soft); }
/* the link is only as wide as its words (a flex column would stretch it across the card), so pointing at the empty
   space beside it does nothing and its focus ring hugs it */
.workcard a.more { display: inline-flex; align-self: flex-start; align-items: center; gap: .4rem; margin-top: .25rem; color: var(--clay-deep); font-weight: 500; font-size: var(--fs-body); }
/* the arrow is drawn, not read: its alternative text is empty where browsers support it, and the plain arrow stays
   for those that don't */
.workcard a.more::after { content: "→"; content: "→" / ""; transition: transform .2s var(--ease); }
.workcard a.more:active { color: var(--clay); }
@media (hover: hover) and (pointer: fine) { .workcard a.more:hover { color: var(--clay); } .workcard a.more:hover::after { transform: translateX(3px); } }
/* logo row: every logo solid white on dark, solid ink on light, regardless of source colour. One row edge to edge
   from 1024px. Narrower, the marks sit in columns instead of wrapping raggedly: two equal left-aligned columns on
   phones; on tablets three content-sized columns spread edge to edge, so the first row is evenly spaced.
   Each mark has its own height, set by eye so the five carry equal weight (--h, at full size); the row scales them
   together (--k), and a mark never outgrows its column. The logos are not links, so they don't react to the pointer. */
.logos { --k: .65; margin-top: 3.5rem; }
@media (min-width: 640px) { .logos { --k: .82; } }
@media (min-width: 768px) { .logos { --k: 1; } }
.logos .lab { margin-bottom: 1.25rem; }
.logos .row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: center; gap: 1.75rem 2rem; }
@media (min-width: 640px) { .logos .row { grid-template-columns: repeat(3, auto); justify-content: space-between; justify-items: center; gap: 2rem; } }
@media (min-width: 1024px) { .logos .row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2rem; } }
.logos img { --h: 1.75rem; height: calc(var(--h) * var(--k)); width: auto; max-width: 100%; object-fit: contain; filter: brightness(0) invert(1); opacity: .72; }
.logos img[src*="logos/bofa"] { --h: 1.5rem; }
.logos img[src*="logos/digitas"] { --h: 1.375rem; }
.logos img[src*="logos/stjohns"] { --h: 2.75rem; }
/* FM's artwork sits in a square box: it is drawn larger to match the others, and its extra height is taken back
   with negative margins, so the row is no taller than its tallest mark (St. John's) */
.logos img[src*="logos/fm"] { --h: 3.4rem; margin-block: calc((2.75rem - 3.4rem) * var(--k) / 2); }
html.light .logos img { filter: brightness(0); opacity: .7; }
/* home writing list: the writing page's rows made quieter for a preview. Titles are h3 at the career-card size, rows
   are tighter, and the date keeps its own column from 768px. It closes like Testimonials: a rule, then the pill. */
.posts.brief { padding-bottom: 0; }
.posts.brief .post-row { padding: 1.5rem 0; row-gap: .375rem; }
.posts.brief .post-row h3 { font-family: var(--serif); font-size: var(--fs-title-sm); font-weight: 500; line-height: 1.3; letter-spacing: -.01em; color: var(--ink); transition: color .2s var(--ease); }
.posts.brief .post-row p { margin-top: 0; }
@media (min-width: 768px) {
  .posts.brief .post-row { padding: 1.75rem 0; }
  .posts.brief .post-row .date { grid-row: 1 / span 2; padding-top: .35rem; }
}
.posts.brief .post-row:focus-visible h3, .posts.brief .post-row:active h3 { color: var(--clay-deep); }
@media (hover: hover) and (pointer: fine) { .posts.brief .post-row:hover h3 { color: var(--clay-deep); } }
.posts.brief + .more { margin-top: 1.5rem; }
/* printed, the work card moves to the next page whole instead of leaving its empty top edge behind, and the logo
   label stays with its logos */
@media print { .workcard, .logos, .posts.brief .post-row { break-inside: avoid; } }

/* Career as Kevin-style cards (Diana's version) */
.jobs { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
/* phones: each logo tile sits close to its own card, with more room before the next job. From 768px the tiles sit
   beside the cards, and a hairline runs from each tile down to the next one, ending at the last tile */
@media (max-width: 767px) { .jobs { gap: 2rem; } }
@media (min-width: 768px) { .job:not(:last-child)::after { content: ""; position: absolute; left: 1.75rem; top: 3.5rem; bottom: -1.25rem; width: 1px; background: var(--line-strong); } }
.jobs + .more { margin-top: 2rem; }
/* the bullets keep to a reading measure (about 70 characters) even where the card is wide */
.job .body ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .75rem; max-width: 36rem; }
.job .body li { position: relative; padding-left: 1rem; font-size: var(--fs-body); line-height: 1.6; color: var(--muted); }
.job .body li::before { content: ""; position: absolute; left: 0; top: .7em; width: 6px; height: 6px; border-radius: 50%; background: var(--muted); }
.job .body li strong { color: var(--ink-soft); font-weight: 600; }
.job .body li.chiprow, .job .body li.links { padding-left: 0; }
.job .body li.chiprow::before, .job .body li.links::before { display: none; }
.job .label { display: block; margin-bottom: .5rem; }
.job .body ul.chips { display: flex; flex-direction: row; flex-wrap: wrap; gap: .4rem; margin: 0; padding: 0; }
.job .body ul.chips li { flex: 0 0 auto; padding: .3rem .7rem; border-radius: 9999px; border: 1px solid var(--line); background: var(--white); font-size: var(--fs-micro); line-height: 1.4; color: var(--ink-soft); }
.job .body ul.chips li::before { display: none; }
.job .body li.links { display: flex; flex-wrap: wrap; gap: .5rem 1.25rem; }
.job .body li.links a { font-size: var(--fs-small); font-weight: 500; color: var(--clay-deep); }
.job .body li.links a span { transition: transform .2s; display: inline-block; }
.job .body li.links a:active span { transform: translateX(3px); }
@media (hover: hover) and (pointer: fine) { .job .body li.links a:hover span { transform: translateX(3px); } }
/* on touch screens each link gets a 44px tall target, and wrapped rows sit far enough apart that targets never overlap */
@media (pointer: coarse) { .job .body li.links { row-gap: 1.5rem; } .job .body li.links a { padding-block: .75rem; margin-block: -.75rem; } }

/* career cards sit one step above the page in both themes */
.job .card { background: var(--card-raised); border-color: var(--line-strong); }
.job .body ul.chips li { border-color: var(--line-strong); background: var(--cream-2); }
/* logo tiles stay white in both themes (Kevin's look) so dark artwork stays legible */
html:not(.light) .job .mark { background: #fff; border-color: rgba(255,255,255,.22); }
html:not(.light) .job .mark:not(:has(img)) { color: #2a2420; }
/* square icon marks fill the tile */
.job .mark img[src$=".png"] { transform: scale(1.12); }

/* engineering evidence blocks in case studies: the architecture diagram is a figure, so it spans the page under its
   section's words (three columns from 800px, stacked with turned arrows below); the measured run and the decisions
   list stay in the text column. All of them use the case-study card: hairline, --r-md corners, the card fill. */
.arch { display: grid; grid-template-columns: minmax(0, 1fr); gap: .75rem; }
@media (min-width: 800px) { .arch { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.15fr) auto minmax(0, 1fr); align-items: stretch; } }
.arch .col { padding: var(--inset-block); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--card); }
.arch .col h3 { margin: 0 0 .2rem; font-family: var(--serif); font-size: var(--fs-title-sm); font-weight: 500; color: var(--ink); }
.arch .col .sub4 { margin-bottom: .75rem; }
.arch .col ul { list-style: none; margin: 0; padding: 0; }
/* diagram items are separated by rules; the case-study list bullet would sit on their first letter */
.arch .col li, .arch .col li + li { margin: 0; padding: .55rem 0; border-top: 1px dashed var(--line); font-size: var(--fs-small); line-height: 1.5; color: var(--muted); }
.arch .col li:first-child { border-top: 0; }
.arch .col li::before { content: none; }
.arch .col li strong { color: var(--ink-soft); font-weight: 600; }
.arch .arrow { align-self: center; text-align: center; color: var(--muted); font-size: 1.15rem; font-weight: 700; }
@media (max-width: 799px) { .arch .arrow { transform: rotate(90deg); } }
/* a note under a figure or a measurement reads like a caption */
.calm .d-text .arch-note { font-size: var(--fs-small); line-height: 1.55; color: var(--muted); max-width: 40em; }
.calm .d-text .wide .arch-note { margin-top: .875rem; }
.facts-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: .75rem; }
/* three across wherever each card has room for its figure on one line: on tablets, and beside the side column once
   the page is at its full width; one above the other in between and on phones */
@media (min-width: 700px) and (max-width: 899px), (min-width: 1080px) { .facts-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.facts-row div { padding: var(--inset-block); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--card); font-size: var(--fs-small); line-height: 1.5; color: var(--muted); }
.facts-row strong { display: block; margin-bottom: .25rem; font-family: var(--serif); font-size: var(--fs-title-sm); font-weight: 500; line-height: 1.15; color: var(--ink-soft); }
/* each decision is a short paragraph, so the list gives them paragraph spacing */
.calm .d-text .ev-list li + li { margin-top: 1.1em; }

/* Contact as the primary call to action in the header. It shares the class name of the home page's contact card, so
   the card's hairline border is coloured to match the fill here: a solid teal pill, the same size as before. */
.hdr .links a.cta { margin-left: .4rem; padding: .45rem 1.05rem; border-radius: 9999px; border-color: var(--clay);
  background: var(--clay); color: var(--clay-ink); font-weight: 600; transition: background .2s, border-color .2s; }
/* pointed at or pressed, it behaves like the filled button: a shade toward ink, and it stays where it is */
.hdr .links a.cta:active { background: color-mix(in srgb, var(--clay) 88%, var(--ink)); border-color: color-mix(in srgb, var(--clay) 88%, var(--ink)); color: var(--clay-ink); }
@media (hover: hover) and (pointer: fine) { .hdr .links a.cta:hover { background: color-mix(in srgb, var(--clay) 88%, var(--ink)); border-color: color-mix(in srgb, var(--clay) 88%, var(--ink)); color: var(--clay-ink); } }
.hdr .links a.cta::after { display: none; }
@media (max-width: 44.9375em) { .hdr .links a.cta { margin-left: .2rem; padding: .4rem .8rem; } }
/* the smallest phones (under 360px at the default text size): a slightly smaller menu, so Contact still ends on the
   page margin */
@media (max-width: 22.4375em) {
  .hdr .links a { font-size: .75rem; padding: .45rem .15rem; }
  .hdr .links a::after { left: .15rem; right: .15rem; }
  .hdr .links a:first-child::before { left: -.15rem; }
  .hdr .links a.cta { margin-left: 0; padding: .4rem .65rem; }
}
/* logo row: the row stays put and each mark rises in on its own beat once the row scrolls into view */
@media screen and (prefers-reduced-motion: no-preference) {
  .logos.reveal.pre:not(.in) { opacity: 1; transform: none; }
  .logos.reveal.pre:not(.in) img, .logos.reveal.pre:not(.in) .lab { opacity: 0; }
  .logos.reveal.pre.in { animation: none; }
  .logos.reveal.pre.in .lab { animation: logo-in .7s var(--ease) both; }
  .logos.reveal.pre.in img { animation: logo-in .7s var(--ease) both; animation-delay: calc(var(--i, 0) * 90ms + 120ms); }
}
@keyframes logo-in { from { opacity: 0; transform: translateY(10px); } }

/* print and save as PDF: every section in full, dark ink on white paper whatever the theme, the current screen of
   each slideshow, and no fixed or screen-only chrome */
@media print {
  *, *::before, *::after { transition: none !important; animation: none !important; }
  html:not(.light) {
    color-scheme: light;
    --paper: #fbf7f0; --cream: #f6f0e6; --cream-2: #eee5d5; --white: #ffffff;
    --card: rgba(255,255,255,.65); --card-raised: #ffffff; --card-hover: #ffffff;
    --ink: #1b1714; --ink-soft: #2f2924; --muted: #766b5e; --line: #e6ddd0; --line-strong: #d8cdbd;
    --clay: #0b7580; --clay-deep: #075f69; --clay-ink: #ffffff; --clay-soft: rgba(11,117,128,.08); --gold: #c69749;
  }
  html:not(.light) .logos img { filter: brightness(0); }
  .hdr { position: absolute; }
  .skip, .hdr .links, .progress, .reel .ctl, .deck-nav { display: none !important; }
  .reel .track > figure:not(.on) { display: none; }
  .btn.primary, .cta .ic { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .wk, .reel, figure, .card, .tq, .job, .tile, .side, .cta, .arch .col, .facts-row div, footer { break-inside: avoid; }
  /* a heading stays whole (a case study's section number is a line of its own inside it) and on the page with the text
     it introduces, and each "All …" pill with the list it closes */
  .calm .d-text h2, .prose-body h2, .prose-body h3 { break-inside: avoid; break-after: avoid; }
  .posts.brief + .more, .testi .more, .jobs + .more { break-before: avoid; }
  /* on paper the testimonials are a plain column: Chromium moves a grid to the next page whole rather than break
     between its rows, which left the home page's Testimonials heading alone on a page */
  .testi { display: block; }
  .testi > * + * { margin-top: 1.5rem; }
  /* on paper the page's own end space is enough before the footer, so the footer is less often left on a page alone */
  footer { margin-top: 2rem; }
}
