/* ============================================================
   Mike Munroe portfolio
   Shared stylesheet for index.html and all /work/ case pages.
   Tokens at the top; everything derives from them.
   ============================================================ */

:root{
  /* graded dark ground - near-black, leaning cool */
  --ground:#0b0c0e;
  --glow:#3f5878;              /* the light source behind the grade. never used as a fill */
  --raise:#121418;             /* media wells, surfaces */
  --ink:#e9ebee;
  --ink-dim:#878b94;
  --hairline:#20242a;
  --paper:#ffffff;             /* light well for artwork made for a white page. only behind media */
  --brass:#c7a468;             /* the one metal: link hover and focus */

  --max:1140px;
  --pad:clamp(20px, 5vw, 56px);
  --measure:60ch;
  --nav-pad:clamp(34px, 4.4vw, 48px);            /* vertical breathing room in the header */
  --nav-h:calc(var(--nav-pad) * 2 + 25px);     /* header height: the hero plate slides up behind it */
}
:root:not([data-theme="light"]){ color-scheme: dark; }
:root[data-theme="dark"]{ color-scheme: dark; }

*{box-sizing:border-box; margin:0; padding:0}
html{scroll-behavior:smooth}

body{
  background:var(--ground);
  color:var(--ink);
  font-family:'Hanken Grotesk', system-ui, sans-serif;
  font-size:16.5px;
  font-weight:330;
  line-height:1.65;
  letter-spacing:.004em;
  -webkit-font-smoothing:antialiased;
  position:relative;
}

/* ---- the flourish: graded light + grain ----
   One faint cool glow from the top, like light falloff in a
   graded frame, plus film grain that scrolls with the page.
   The grain is high-contrast noise centred on mid-grey and blended
   with overlay, so it pushes the ground lighter and darker in equal
   measure: texture without lifting the near-black. Its opacity is
   the strength dial. */
body::before{
  content:""; position:fixed; inset:0; z-index:-2; pointer-events:none;
  background:
    radial-gradient(130% 70% at 50% -12%,
      color-mix(in srgb, var(--glow) 13%, transparent) 0%,
      transparent 62%);
}
/* absolute, not fixed: a fixed layer stays put during the elastic
   overscroll at the top of the page and shows as raw noise there */
body::after{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  opacity:.36; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='5' intercept='-2'/%3E%3CfeFuncG type='linear' slope='5' intercept='-2'/%3E%3CfeFuncB type='linear' slope='5' intercept='-2'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px;
}

::selection{background:var(--brass); color:var(--ground)}

a{color:var(--ink); text-decoration:none;
  border-bottom:1px solid color-mix(in srgb, var(--brass) 45%, transparent);
  transition:border-color .18s ease, color .18s ease}
a:hover{color:var(--brass); border-bottom-color:var(--brass)}
a:focus-visible{outline:1.5px solid var(--brass); outline-offset:4px; border-radius:1px}

/* ---- type scale ----
   Luxury at display size = lighter weight, large scale, tight
   tracking. Bold is for emphasis within text, never headlines. */
h1,h2,h3{font-weight:430; line-height:1.04; letter-spacing:-0.022em; text-wrap:balance}
h1{font-size:clamp(40px,6.4vw,78px)}
h2{font-size:clamp(26px,3.2vw,40px)}
h3{font-size:clamp(19px,2vw,24px); letter-spacing:-0.012em}
p{max-width:var(--measure)}
strong{font-weight:560}

.wrap{max-width:var(--max); margin-inline:auto; padding-inline:var(--pad)}

/* ================= SITE HEADER ================= */
header.site{
  display:flex; justify-content:space-between; align-items:baseline;
  max-width:var(--max); margin-inline:auto;
  padding:var(--nav-pad) var(--pad);
}
/* the name as a wordmark: small tracked capitals. Uppercased in CSS so it is still read as "Mike Munroe" */
header.site .mark{font-weight:560; font-size:13px; line-height:1; letter-spacing:.2em; text-transform:uppercase; border:0}
header.site nav{display:flex; gap:clamp(18px, 4vw, 28px)}
header.site nav a{color:var(--ink-dim); border:0; font-size:15px}
header.site nav a:hover{color:var(--ink)}
header.site nav a[aria-current="page"]{color:var(--ink)}

/* ================= PHOTO HERO =================
   Shared by the homepage and every case page.
   A heavily graded photo plate: desaturated, cool-toned, pulled
   down to near-black, feathered on every edge so it dissolves
   into the ground, with its own heavier grain.

   Per-page controls (set inline on .plate img):
     --fx / --fy  where the subject sits in the photo - the
                  feather centres on that point (default 55% 40%)
   The one motion moment: the plate "exposes" up from black on
   load, like a grade being lifted. Nothing else animates. */
.hero-photo{
  position:relative; overflow:hidden;
  min-height:clamp(500px, 76vh, 780px);
  margin-top:calc(-1 * var(--nav-h));   /* plate sits behind the header */
  padding-top:var(--nav-h);
  display:grid; align-items:end;
}
.hero-photo.short{min-height:clamp(440px, 68vh, 700px)}
.hero-photo.brief{min-height:clamp(300px, 42vh, 420px)}   /* text-only pages: CV */

.hero-photo .plate{position:absolute; inset:0; isolation:isolate; pointer-events:none}
/* two masks, intersected: --feather dissolves every edge around the
   focal point, --settle fades the bottom out so the photo ends
   before the next section starts */
.hero-photo .plate :is(img,video){
  position:absolute; top:0; bottom:0;
  right:max(0px, calc((100vw - var(--max)) / 2 - 60px));
  height:112%; width:auto; max-width:none;
  filter:grayscale(1) sepia(.3) hue-rotate(178deg) saturate(.7) brightness(.34) contrast(1.12);
  --feather:radial-gradient(ellipse 58% 54% at var(--fx,55%) var(--fy,40%),
    #000 22%, rgba(0,0,0,.55) 52%, transparent 82%);
  --settle:linear-gradient(to bottom, #000 62%, transparent 88%);
  -webkit-mask-image:var(--feather), var(--settle);
          mask-image:var(--feather), var(--settle);
  -webkit-mask-composite:source-in;
          mask-composite:intersect;
}
/* landscape stills on case pages, and the homepage loop: fill the width instead */
.hero-photo .plate :is(img,video).wide{
  left:0; right:0; width:100%; height:100%; object-fit:cover;
  /* project stills are already dark, so they are pulled down less than the portrait */
  filter:grayscale(1) sepia(.3) hue-rotate(178deg) saturate(.7) brightness(var(--plate,.62)) contrast(1.12) blur(var(--hero-blur));   /* --plate: per-image override */
  --feather:radial-gradient(ellipse 62% 70% at var(--fx,50%) var(--fy,45%),
    #000 18%, rgba(0,0,0,.5) 50%, transparent 85%);
  --settle:linear-gradient(to bottom, #000 70%, transparent 98%);
}
/* homepage loop on wider screens: held to the right, dissolving
   progressively toward the left so the copy sits on the ground */
@media (min-width:761px){
  .hero-photo .plate video.side{
    left:auto; right:0; width:66%;
    --feather:linear-gradient(to right, transparent 0%, rgba(0,0,0,.06) 20%, rgba(0,0,0,.4) 46%, #000 76%);
    --settle:linear-gradient(to bottom, rgba(0,0,0,.1) 0%, #000 24%, #000 68%, transparent 97%);
  }
}
/* the plate's own grain - heavier than the page grain. it lays a soft grey
   wash over the whole hero and textures the photo, and its mask fades it
   out toward the bottom so the hero settles into the ground with no seam */
.hero-photo .plate::after{
  content:""; position:absolute; inset:0;
  opacity:.12;
  -webkit-mask-image:linear-gradient(to bottom, #000 62%, transparent 100%);
          mask-image:linear-gradient(to bottom, #000 62%, transparent 100%);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:220px 220px;
}

.hero-copy{
  position:relative; z-index:1;         /* above the plate */
  width:100%; max-width:var(--max); margin-inline:auto;
  padding:0 var(--pad) clamp(56px, 10vh, 110px);
}
.hero-copy h1{margin-bottom:.4em; max-width:11ch}
.hero-copy .lede{font-size:clamp(17px,1.9vw,20px); color:var(--ink-dim); max-width:36ch}
.hero-copy .lede strong{color:var(--ink); font-weight:480}
.hero-copy .cta{margin-top:clamp(24px,3.4vh,36px); font-size:16px}
.hero-photo.short .hero-copy h1{font-size:clamp(34px,4.8vw,62px); max-width:18ch}
.hero-copy .where{color:var(--ink-dim); font-size:15px; margin-bottom:14px}
/* case pages: the client's white logo stands in for the company name */
.hero-copy .where:has(img.brand){display:flex; align-items:center; gap:14px; max-width:none; margin-bottom:20px}
.hero-copy .where img.brand{display:block; height:calc(28px * var(--k)); width:auto; max-width:none}

/* phones: the plate sits behind the copy, pulled down further */
@media (max-width:760px){
  .hero-photo .plate img:not(.wide){
    right:50%; translate:50% 0;         /* not transform: the expose animation owns that */
    filter:grayscale(1) sepia(.3) hue-rotate(178deg) saturate(.7) brightness(.27) contrast(1.12);
  }
}

/* ---- the motion moment: exposure lift ---- */
/* registered so the blur amount can be animated smoothly inside the plate's filter */
@property --hero-blur{syntax:'<length>'; inherits:false; initial-value:0px}
.reveal{opacity:0; transform:translateY(12px)}
@media (prefers-reduced-motion: no-preference){
  .js .hero-photo .plate :is(img,video){animation:expose 2.2s cubic-bezier(.4,0,.2,1) .1s both}
  /* case pages: as the title arrives, the plate eases slightly out of focus behind it */
  .js .hero-photo.short .plate img{
    animation:expose 2.2s cubic-bezier(.4,0,.2,1) .1s both, soften 1.6s cubic-bezier(.65,0,.35,1) 1.2s both}
  .js .reveal{animation:settle .9s cubic-bezier(.65,0,.35,1) .9s forwards}
  .js .reveal.r2{animation-delay:1.05s}
  .js .reveal.r3{animation-delay:1.2s}
  /* case pages: the logo lands first, then the heading follows as a separate beat */
  .js .hero-photo.short .reveal.r2{animation-delay:1.5s}
}
@media (prefers-reduced-motion: reduce){ .reveal{opacity:1; transform:none} }
.no-js .reveal{opacity:1; transform:none}

@keyframes expose{from{opacity:0; transform:scale(1.025)} to{opacity:1; transform:none}}
@keyframes settle{to{opacity:1; transform:none}}
@keyframes soften{to{--hero-blur:1.75px}}

/* header floats over the plate */
header.site{position:relative; z-index:2}

/* ================= HOME: WORK INDEX ================= */

.entry{
  display:block; border:0;
  padding-block:40px 56px;
  color:var(--ink);
}
.entry + .entry{border-top:1px solid var(--hairline)}
/* index entries, and the media, headings and paragraphs of a case page,
   fade in the first time they are scrolled into view (media.js adds .in) */
@media (prefers-reduced-motion: no-preference){
  .js .index .entry{opacity:0; transition:opacity 1.1s cubic-bezier(.4,0,.2,1), color .18s ease}
  .js :is(.case-media, .case-body h2, .case-body .text > p, .case-body .text > h3){
    opacity:0; transition:opacity 1.1s cubic-bezier(.4,0,.2,1)}
  .js .index .entry.in,
  .js :is(.case-media, .case-body h2, .case-body .text > p, .case-body .text > h3).in{opacity:1}
}
.entry:hover{color:var(--ink)}

.entry .media{
  background:var(--raise); border-radius:4px; overflow:hidden;
  aspect-ratio:16/9; margin-bottom:26px;
  display:grid; place-items:center;
}
.entry .media video,.entry .media img,.entry .media iframe{
  width:100%; height:100%; object-fit:cover; display:block; border:0}
/* pinned to the well, so any crop is taken equally from both sides */
.entry .media video,.entry .media img:not(.brand),.entry .media iframe{position:absolute; inset:0}
/* thumbnails play in the site's cool monochrome. On hover or keyboard
   focus a veil darkens and blurs the loop and a prompt appears over it */
.entry .media{position:relative}
.entry .media video,.entry .media img{
  filter:grayscale(1) sepia(.3) hue-rotate(178deg) saturate(.7) brightness(.6)}
.entry .media:has(video,img)::after{
  content:"View project";
  position:absolute; inset:0; display:grid; place-items:center;
  font-size:14.5px; font-weight:400; letter-spacing:.01em; color:var(--ink);
  background:color-mix(in srgb, var(--ground) 74%, transparent);
  -webkit-backdrop-filter:blur(7px); backdrop-filter:blur(7px);
  opacity:0; transition:opacity .25s ease;
}
.entry:hover .media::after,.entry:focus-visible .media::after{opacity:1}
/* optical sizing: --k scales each logo's height so they all read as the same
   size. Measured from each file's proportions and ink density, then tuned by eye; a wide, thin
   wordmark needs less height than a compact mark. Add a line per new logo. */
img.brand{--k:1}
img.brand[src$="animoto.svg"]{--k:.96}
img.brand[src$="delivra.svg"]{--k:1.42}
img.brand[src$="paved.svg"]{--k:1.12}
img.brand[src$="redbrick.svg"]{--k:.62}
img.brand[src$="tedxvictoria.svg"]{--k:.7}
/* the client's logo, white, above the prompt on the hover veil */
.entry .media img.brand{
  position:absolute; left:50%; top:50%; translate:-50% calc(-100% + 8px); z-index:1;
  height:calc(clamp(34px,4.8vw,58px) * var(--k)); width:auto; max-width:72%;
  object-fit:contain; filter:none; opacity:0; transition:opacity .25s ease;
}
.entry:hover .media img.brand,.entry:focus-visible .media img.brand{opacity:1}
.entry .media:has(img.brand)::after{padding-top:clamp(58px,6.4vw,80px)}
.entry .media .placeholder{color:var(--ink-dim); font-size:14.5px; padding:24px; text-align:center; max-width:46ch}

.entry .row{display:flex; flex-wrap:wrap; gap:6px 28px; justify-content:space-between; align-items:baseline}
.entry .row h3{transition:color .18s ease}
.entry:hover .row h3{color:var(--brass)}
.entry .row .where{color:var(--ink-dim); font-size:14.5px}
.entry .line{color:var(--ink-dim); margin-top:6px; font-size:15.5px; max-width:70ch}

/* ================= CASE PAGES ================= */

/* production metadata. information, not decoration */
.specs{
  max-width:var(--max); margin-inline:auto;
  padding:0 var(--pad) 40px;
  display:flex; flex-wrap:wrap; gap:14px 44px;
  font-size:13.5px; color:var(--ink-dim);
}
.specs div span{color:var(--ink); display:block; margin-top:3px; font-size:15px}
/* phones: one spec per row */
@media(max-width:560px){
  .specs{flex-direction:column; gap:16px}
}
/* desktop: always one row. Columns share the width and long values wrap inside their own column */
@media(min-width:900px){
  .specs{flex-wrap:nowrap; gap:0 clamp(24px,3vw,44px)}
  .specs div{flex:0 1 auto; min-width:15ch}   /* short values keep to one line; long ones give up the width */
  .specs div span{line-height:1.4}
}

.case-media{
  max-width:var(--max); margin-inline:auto; padding-inline:var(--pad);
}
.case-media figure{
  background:var(--raise); border-radius:4px; overflow:hidden; margin-bottom:10px;
  display:grid; place-items:center;
}
.case-media figure.ratio{aspect-ratio:16/9}
.case-media video,.case-media img,.case-media iframe{
  width:100%; height:auto; display:block; border:0}
.case-media figure.ratio video,.case-media figure.ratio iframe{height:100%; object-fit:cover}
/* video player before it is played: darkened poster under a play button.
   media.js adds .is-poster and the button, and removes both on play */
.case-media figure.is-poster > *{grid-area:1/1}
.case-media figure.is-poster video{filter:brightness(.72); cursor:pointer}
.case-media .play{
  z-index:1; width:clamp(64px, 9vw, 104px); aspect-ratio:1;
  background:none; border:0; border-radius:50%; padding:0;
  color:var(--ink); cursor:pointer; transition:color .18s ease;
}
.case-media .play svg{display:block; width:100%; height:100%}
.case-media .play:hover,.case-media figure.is-poster video:hover + .play{color:var(--brass)}
.case-media .play:focus-visible{outline:1.5px solid var(--brass); outline-offset:6px}
/* contact sheet of small loops (reaction GIFs) */
.case-media.sheet{display:grid; grid-template-columns:repeat(2,1fr); gap:10px}
@media(min-width:760px){ .case-media.sheet{grid-template-columns:repeat(4,1fr)} }
.case-media.sheet figure{margin:0; aspect-ratio:4/3}
.case-media.sheet figure video{height:100%; object-fit:cover}
.case-media.sheet figcaption{grid-column:1/-1}
/* .pair: larger clips of mixed proportions, two across, on a light well */
.case-media.sheet.pair{grid-template-columns:1fr; align-items:start}
@media(min-width:760px){ .case-media.sheet.pair{grid-template-columns:repeat(2,1fr)} }
.case-media.sheet.pair figure{aspect-ratio:auto}
.case-media.sheet.pair figure video{height:auto}
.case-media.sheet.pair figure.ratio{aspect-ratio:16/9}
.case-media.sheet.pair figure.ratio video{height:100%}
@media(min-width:760px){ .case-media.sheet.pair figure.wide{grid-column:1/-1} }
/* .light: a padded light frame, so artwork made for a white page gets breathing room */
.case-media figure.light{background:var(--paper); padding:7%}
.case-media figure.light .lottie-slot{width:100%; padding:0}
/* .bleed: a Lottie with its own background, shown edge to edge */
.case-media figure.bleed .lottie-slot{width:100%; padding:0}
.case-media figure.bleed svg{display:block}
.case-media.sheet.pair figure.bleed{aspect-ratio:auto}
/* in a sheet every light frame is the same 3:2 box; the artwork is
   centred and scaled to fit inside it, whatever its own proportions */
.case-media.sheet figure.light{aspect-ratio:3/2; position:relative; padding:0}
.case-media.sheet figure.light .lottie-slot{position:absolute; inset:14% 13%; width:auto}
.case-media figure.light svg{display:block}
.case-media figcaption a{color:var(--ink-dim)}
.case-media figcaption a:hover{color:var(--brass)}
.case-media .lottie-slot{width:min(55%,420px); padding-block:40px}
.case-media .placeholder{color:var(--ink-dim); font-size:14.5px; padding:28px; text-align:center; max-width:46ch}
.case-media figcaption{color:var(--ink-dim); font-size:13.5px; padding:4px 2px 0; max-width:70ch}

.case-body{
  max-width:var(--max); margin-inline:auto;
  padding:clamp(36px,6vh,64px) var(--pad);
  display:grid; gap:40px;
}
.case-body section p + p{margin-top:1em}
.case-body section h2{font-size:17px; font-weight:500; letter-spacing:0;
  color:var(--ink-dim); margin-bottom:14px}
@media(min-width:900px){
  .case-body{grid-template-columns:160px 1fr; column-gap:64px; row-gap:56px}
  .case-body section{display:contents}
  .case-body section h2{grid-column:1; padding-top:3px}
  .case-body section .text{grid-column:2}
}
.case-body .text .case-media{max-width:none; padding:0; margin-block:28px}
/* subheadings name the separate pieces within a section */
.case-body .text h3{font-size:clamp(19px,1.9vw,22px); line-height:1.2; margin:clamp(44px,6vh,60px) 0 12px}
.case-body .text h3:first-child{margin-top:0}
.case-body .text h3 + .case-media{margin-top:18px}

/* ================= CV ================= */
.hero-photo.brief .hero-copy{padding-bottom:clamp(28px, 5vh, 48px)}
.hero-photo.brief .hero-copy h1{font-size:clamp(34px,4.8vw,62px); max-width:none; margin-bottom:.5em}
.cv-download{font-size:15px}
.cv .role + .role{margin-top:30px}
.cv .role h3{font-size:clamp(18px,1.8vw,21px); line-height:1.25}
.cv .role .meta{color:var(--ink-dim); font-size:14.5px; margin-top:4px}
.cv .role .meta + p{margin-top:8px}
.cv .role h3 + p{margin-top:6px}
.cv .role p + p:not(.meta + p){margin-top:8px}
.cv blockquote + blockquote{margin-top:32px}
.cv blockquote footer{color:var(--ink-dim); font-size:14.5px; margin-top:10px}

/* pagination between cases */
.case-next{border-top:1px solid var(--hairline); margin-top:40px}
/* the two links always share one row; long titles wrap inside their half */
.case-next .wrap{padding-block:48px 64px; display:flex; justify-content:space-between; gap:clamp(20px,5vw,48px)}
.case-next a{flex:1 1 0; min-width:0}
.case-next .next{text-align:right}
.nb{white-space:nowrap}   /* keeps a hyphenated word on one line */
.case-next .label,.case-next h2{max-width:none}
.case-next h2{font-size:clamp(19px,2.8vw,36px)}
.case-next a{border:0; display:block}
.case-next .label{color:var(--ink-dim); font-size:14.5px; margin-bottom:8px}
.case-next h2{transition:color .18s ease}
.case-next a:hover h2{color:var(--brass)}

/* ================= ABOUT / FOOTER ================= */
section.about{padding-block:clamp(36px,6vh,64px) 72px}
section.about .wrap{display:grid; gap:40px; grid-template-columns:1fr}
@media(min-width:900px){ section.about .wrap{grid-template-columns:1.1fr .9fr; gap:72px} }
section.about p + p{margin-top:1em}
section.about .portrait{
  position:relative; background:var(--raise); border-radius:4px; aspect-ratio:11/14; max-width:400px;
  display:grid; place-items:center; color:var(--ink-dim); font-size:14.5px; overflow:hidden}
/* same cool monochrome as the hero plates, at close to full brightness */
/* the photo at its full width, from just above the head down to its bottom edge */
section.about .portrait img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:50% 100%;
  filter:grayscale(1) sepia(.3) hue-rotate(178deg) saturate(.7) brightness(.85) contrast(1.05)}

footer.site{border-top:1px solid var(--hairline); padding-block:56px 80px}
footer.site .wrap{display:grid; gap:18px 44px;
  grid-template-areas:"contact" "where" "nav" "tagline"}
footer.site .contact{grid-area:contact}
footer.site small{grid-area:where}
footer.site nav{grid-area:nav; display:flex; gap:clamp(18px,3vw,28px)}
footer.site nav a{color:var(--ink-dim); border:0; font-size:14px}
footer.site nav a:hover,footer.site nav a[aria-current]{color:var(--ink)}
/* wider screens: the nav sits at the right on the label's line, and the
   LinkedIn line under it on the address's baseline */
@media(min-width:760px){
  footer.site .wrap{grid-template-columns:1fr auto; row-gap:0; align-items:baseline;
    grid-template-areas:"label nav" "email where" "tagline tagline"}
  footer.site .contact{display:contents}
  footer.site .contact .label{grid-area:label}
  footer.site .email{grid-area:email; justify-self:start}
  footer.site small,footer.site nav{justify-self:end}
  footer.site .tagline{margin-top:18px}
}
/* the address is the site's one call to action, shown in full so it can be
   read or copied as well as clicked */
footer.site .contact .label{color:var(--ink-dim); font-size:14px; margin-bottom:10px}
footer.site .email{display:inline-block; font-weight:430; letter-spacing:-.015em;
  font-size:clamp(20px,2.8vw,30px); border-bottom-width:1.5px; overflow-wrap:anywhere}
footer.site .email .arrow{margin-left:.32em; color:var(--ink-dim); transition:color .18s ease}
footer.site .email:hover .arrow,footer.site .email:focus-visible .arrow{color:var(--brass)}
footer.site small{color:var(--ink-dim); font-size:14px}
footer.site small a{color:var(--ink-dim); border-bottom-color:var(--hairline)}
footer.site small a:hover{color:var(--brass)}
footer.site .tagline{grid-area:tagline; max-width:none; color:var(--ink-dim); font-size:14px}

/* ================= 404 =================
   The page grain turned up into television static: one noise tile,
   jumped to a new position several times a second. The numerals are
   cut from the same static, brighter than the screen around them. */
:root{--static:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='6' intercept='-2.5'/%3E%3CfeFuncG type='linear' slope='6' intercept='-2.5'/%3E%3CfeFuncB type='linear' slope='6' intercept='-2.5'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
.lost{
  position:relative; overflow:hidden;
  min-height:calc(100svh - var(--nav-h));
  display:grid; place-items:center; text-align:center;
  padding:0 var(--pad) clamp(60px,14vh,140px);
}
.lost .static{
  position:fixed; inset:-240px; z-index:0; pointer-events:none;
  background-image:var(--static); background-size:240px 240px;
  opacity:.09;
}
.lost-copy{position:relative; z-index:1}
.lost h1{
  font-size:clamp(132px,31vw,420px); line-height:.86; letter-spacing:-.045em;
  padding-inline:.06em;   /* room for the tight tracking, so the last numeral is not clipped */
  color:color-mix(in srgb, var(--ink-dim) 48%, transparent);   /* a grey veil over the static softens its contrast */
  background:var(--static) 0 0/240px 240px, var(--ink);
  background-blend-mode:multiply;
  -webkit-background-clip:text; background-clip:text;
}
.lost p{color:var(--ink-dim); margin-top:clamp(18px,3vh,30px)}
.lost p + p{margin-top:14px}
@media (prefers-reduced-motion: no-preference){
  .lost .static{animation:static-screen .5s steps(1) infinite}
  .lost h1{animation:static-type .4s steps(1) infinite}
}
@keyframes static-screen{
  0%{transform:translate(0,0)} 12.5%{transform:translate(-97px,61px)}
  25%{transform:translate(143px,-178px)} 37.5%{transform:translate(-201px,-33px)}
  50%{transform:translate(58px,119px)} 62.5%{transform:translate(-152px,-211px)}
  75%{transform:translate(217px,24px)} 87.5%{transform:translate(-39px,-126px)}
}
@keyframes static-type{
  0%{background-position:0 0, 0 0} 16.6%{background-position:-83px 47px, 0 0}
  33.3%{background-position:121px -152px, 0 0} 50%{background-position:-177px -29px, 0 0}
  66.6%{background-position:39px 103px, 0 0} 83.3%{background-position:-131px -187px, 0 0}
}
