/* ==========================================================
   AV. — shared stylesheet
   Design tokens carried over from the cinematic single-page build.
   ========================================================== */
:root{
  /* ---- palette: light monochrome -------------------------------------
     The only colour block in the file. For a black-and-white *dark*
     theme instead, swap these eight values for the commented set below. */
  --bg:#FFFFFF;
  --bg-2:#F5F5F6;
  --bg-3:#EBEBED;
  --edge:rgba(0,0,0,.15);
  --edge-soft:rgba(0,0,0,.07);
  --ink:#0B0B0C;
  --ink-2:#5C5C61;
  --ink-3:#74747A;
  --accent:#0B0B0C;
  --accent-2:#33333A;
  --on-accent:#FFFFFF;

  /* dark monochrome alternative:
  --bg:#08080A; --bg-2:#101012; --bg-3:#1A1A1D;
  --edge:rgba(255,255,255,.16); --edge-soft:rgba(255,255,255,.08);
  --ink:#F2F2F3; --ink-2:#A0A0A6; --ink-3:#6E6E74;
  --accent:#F2F2F3; --accent-2:#C8C8CE; --on-accent:#08080A;
  */

  --display:"Space Grotesk","Helvetica Neue",Helvetica,Arial,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  --ease-out:cubic-bezier(.16,1,.3,1);
  --ease-in-out:cubic-bezier(.76,0,.24,1);

  --gutter:clamp(20px,4.5vw,72px);
  --maxw:1320px;
}

*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;padding:0}
html{
  background:var(--bg);
  scroll-behavior:smooth;
  -webkit-text-size-adjust:100%;
}
body{
  font-family:var(--display);
  color:var(--ink);
  background:var(--bg);
  overflow-x:clip;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img,canvas,svg{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
::selection{background:rgba(0,0,0,.12)}

.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter)}
.mono{font:400 11.5px/1.6 var(--mono);letter-spacing:.17em;color:var(--ink-3);text-transform:uppercase}

/* ---------- atmosphere ---------- */
#grain,#vignette{position:fixed;inset:0;pointer-events:none;z-index:120}
#grain{opacity:.05;mix-blend-mode:overlay}
#vignette{
  z-index:118;
  background:radial-gradient(120% 90% at 50% 42%,transparent 38%,rgba(0,0,0,.045) 100%);
}
#atmos{position:fixed;inset:0;pointer-events:none;z-index:105}

/* ---------- skip link ---------- */
.skip{
  position:fixed;top:-60px;left:14px;z-index:400;
  padding:11px 16px;background:var(--ink);color:var(--on-accent);
  font:500 11px/1 var(--mono);letter-spacing:.14em;border-radius:2px;
  transition:top .25s var(--ease-out);
}
.skip:focus{top:14px}

/* ---------- cursor ---------- */
#cur,#cur-dot{
  position:fixed;top:0;left:0;z-index:210;pointer-events:none;
  border-radius:50%;opacity:0;transition:opacity .3s ease;
}
/* The ring was a dark border, which disappeared entirely over the inverted
   masthead, page head and footer. mix-blend-mode:difference inverts it
   against whatever is underneath, so one white ring reads on black and on
   white without needing to know which section it is over. */
#cur{
  width:38px;height:38px;margin:-19px 0 0 -19px;
  border:1.5px solid #FFFFFF;
  mix-blend-mode:difference;
  transition:opacity .3s ease,width .35s var(--ease-out),height .35s var(--ease-out),margin .35s var(--ease-out);
}
#cur-dot{
  width:6px;height:6px;margin:-3px 0 0 -3px;
  background:#FFFFFF;
  mix-blend-mode:difference;
}
body.cursor-on #cur,body.cursor-on #cur-dot{opacity:1}
body.cursor-on{cursor:none}
#cur.hot{width:62px;height:62px;margin:-31px 0 0 -31px;border-width:1.5px}

/* ---------- header ---------- */
.site-head{
  position:fixed;top:0;left:0;right:0;z-index:150;
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:16px var(--gutter);
  background:rgba(255,255,255,.82);
  backdrop-filter:blur(18px) saturate(1.25);
  -webkit-backdrop-filter:blur(18px) saturate(1.25);
  border-bottom:1px solid var(--edge-soft);
}
.brand{font:600 13px/1 var(--mono);letter-spacing:.18em;color:var(--ink)}
.brand i{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--accent);
  box-shadow:0 0 9px var(--accent);margin-left:7px;vertical-align:1px}
.site-nav{display:flex;align-items:center;gap:4px;flex-wrap:wrap}
.site-nav a{
  padding:8px 13px;border-radius:999px;
  font:400 11.5px/1 var(--mono);letter-spacing:.14em;color:var(--ink-2);
  text-transform:uppercase;transition:color .3s ease,background-color .3s ease;
}
.site-nav a:hover{color:var(--ink);background:rgba(0,0,0,.05)}
.site-nav a.on{color:var(--on-accent);background:var(--ink)}
.nav-cta{
  padding:9px 16px;border:1px solid var(--edge);border-radius:999px;
  font:500 10.5px/1 var(--mono);letter-spacing:.16em;color:var(--ink);
  transition:background-color .3s ease,border-color .3s ease;
}
.nav-cta:hover{background:var(--accent-2);color:var(--on-accent)}
.nav-toggle{display:none}
@media (max-width:1080px){
  .site-nav{display:none}
  .site-head.open .site-nav{
    display:flex;flex-direction:column;align-items:stretch;gap:2px;
    position:absolute;top:100%;left:0;right:0;
    padding:12px var(--gutter) 20px;
    background:var(--bg-2);border-bottom:1px solid var(--edge);
    box-shadow:0 40px 80px -30px rgba(0,0,0,.95);
  }
  .site-head.open .site-nav a{padding:13px 12px;border-radius:2px;text-align:left}
  .nav-toggle{
    display:block;background:none;border:1px solid var(--edge);border-radius:2px;
    color:var(--ink);font:400 10px/1 var(--mono);letter-spacing:.18em;
    padding:11px 14px;cursor:pointer;
  }
}

/* ---------- page head ---------- */
.page-head{padding:calc(clamp(90px,14vh,150px) + 58px) 0 clamp(40px,6vh,74px);position:relative}
.eyebrow{
  display:flex;align-items:center;gap:12px;margin-bottom:clamp(20px,3vh,34px);
  font:400 11px/1 var(--mono);letter-spacing:.2em;color:var(--ink-3);text-transform:uppercase;
}
.eyebrow s{text-decoration:none;width:34px;height:1px;background:var(--edge);flex:0 0 auto}
h1.title{
  margin:0;font-size:clamp(2.1rem,6.2vw,5.1rem);font-weight:600;
  letter-spacing:-.045em;line-height:.96;text-transform:uppercase;
  color:transparent;
  background:linear-gradient(176deg,#0B0B0C 8%,#232328 44%,#45454D 82%,#5C5C61 100%);
  -webkit-background-clip:text;background-clip:text;
}
h1.title em{
  font-style:normal;
  background:linear-gradient(176deg,#4A4A52 4%,#1C1C20 46%,#0B0B0C 96%);
  -webkit-background-clip:text;background-clip:text;
}
.standfirst{
  margin:clamp(22px,3.4vh,38px) 0 0;max-width:62ch;
  font-size:clamp(1.12rem,1.7vw,1.42rem);line-height:1.6;color:var(--ink-2);letter-spacing:-.01em;
}
.head-meta{
  margin-top:clamp(30px,5vh,52px);display:flex;flex-wrap:wrap;gap:0;
  border-top:1px solid var(--edge-soft);padding-top:18px;
}
.head-meta div{padding-right:26px;margin-right:26px;border-right:1px solid var(--edge-soft)}
.head-meta div:last-child{padding-right:0;margin-right:0;border-right:0}
.head-meta dt{font:400 10px/1 var(--mono);letter-spacing:.18em;color:var(--ink-3);text-transform:uppercase}
.head-meta dd{margin:8px 0 0;font:400 11.5px/1 var(--mono);letter-spacing:.1em;color:var(--ink)}
@media (max-width:680px){
  .head-meta{display:grid;grid-template-columns:1fr 1fr;gap:20px 18px}
  .head-meta div{padding:0;margin:0;border-right:0}
  .head-meta dd{margin-top:7px;line-height:1.35}
}
@media (max-width:380px){.head-meta{grid-template-columns:1fr}}

/* ---------- body prose ---------- */
main{position:relative;z-index:2}
.body{padding:0 0 clamp(70px,11vh,130px)}
.cols{
  display:grid;grid-template-columns:minmax(0,1fr) 300px;
  gap:clamp(34px,5vw,86px);align-items:start;
}
@media (max-width:980px){.cols{grid-template-columns:1fr;gap:48px}}
.prose{max-width:70ch}
.prose h2{
  margin:clamp(44px,6vh,72px) 0 18px;
  font-size:clamp(1.18rem,2vw,1.62rem);font-weight:600;letter-spacing:-.03em;
  text-transform:uppercase;color:var(--ink);
}
.prose h2:first-child{margin-top:0}
.prose h2 b{color:var(--accent);font-weight:600;margin-right:12px;font-size:.7em;vertical-align:2px}
.prose p{margin:0 0 21px;font-size:1.11rem;line-height:1.78;color:var(--ink-2);letter-spacing:-.005em}
.prose p strong{color:var(--ink);font-weight:500}
.prose p code,.prose li code{
  font:400 .88em/1 var(--mono);color:var(--accent);
  background:rgba(0,0,0,.05);padding:3px 6px;border-radius:2px;
}
.prose ul{margin:0 0 22px;padding:0;list-style:none;font-size:1.08rem}
.prose li{
  position:relative;padding-left:22px;margin-bottom:12px;
  font-size:1.005rem;line-height:1.75;color:var(--ink-2);
}
.prose li::before{
  content:"";position:absolute;left:0;top:.72em;
  width:7px;height:1px;background:var(--accent);opacity:.75;
}
blockquote{
  margin:clamp(30px,4vh,46px) 0;padding:24px 0 24px 26px;
  border-left:1px solid var(--edge);
}
blockquote p{
  margin:0;font-size:clamp(1.06rem,1.7vw,1.32rem);line-height:1.55;
  color:var(--ink);letter-spacing:-.02em;font-weight:500;
}

/* ---------- side panel ---------- */
.aside{position:sticky;top:100px;display:flex;flex-direction:column;gap:18px}
@media (max-width:980px){.aside{position:static}}
.card{
  border:1px solid var(--edge);background:var(--bg-2);
  backdrop-filter:blur(8px);padding:22px;
}
.card h3{
  margin:0 0 16px;font:400 10.5px/1 var(--mono);letter-spacing:.19em;
  color:var(--ink-2);text-transform:uppercase;font-weight:400;
}
.card dl{margin:0}
.card dt{font:400 10px/1 var(--mono);letter-spacing:.16em;color:var(--ink-2);text-transform:uppercase}
.card dd{margin:7px 0 16px;font-size:1rem;color:var(--ink);letter-spacing:-.01em}
.card dd:last-child{margin-bottom:0}
.card ul{margin:0;padding:0;list-style:none}
.card li{
  font:400 10.5px/1 var(--mono);letter-spacing:.12em;color:var(--ink-2);
  padding:11px 0;border-bottom:1px solid var(--edge-soft);
}
.card li:last-child{border-bottom:0;padding-bottom:0}
.card a li:hover{color:var(--ink)}
.tags{display:flex;flex-wrap:wrap;gap:7px}
.tags span{
  font:400 10.5px/1 var(--mono);letter-spacing:.11em;color:var(--ink-2);
  padding:8px 11px;border:1px solid var(--edge-soft);border-radius:2px;
}

/* ---------- figure ---------- */
figure.fig{margin:clamp(34px,5vh,56px) 0;border:1px solid var(--edge);position:relative;overflow:hidden}
figure.fig .plate{height:clamp(200px,30vh,320px);position:relative;overflow:hidden;background:var(--bg-2)}
figure.fig figcaption{
  padding:13px 16px;border-top:1px solid var(--edge-soft);
  font:400 9.5px/1.5 var(--mono);letter-spacing:.16em;color:var(--ink-3);text-transform:uppercase;
}
.plate .grid-persp{
  position:absolute;inset:-30% -10% -10%;
  background-image:linear-gradient(rgba(0,0,0,.06) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(0,0,0,.06) 1px,transparent 1px);
  background-size:44px 44px;
  transform:perspective(420px) rotateX(58deg);
  transform-origin:50% 100%;
}
.plate .beam{
  position:absolute;left:50%;top:0;bottom:0;width:44%;translate:-50% 0;
  background:radial-gradient(60% 60% at 50% 30%,rgba(0,0,0,.07),transparent 70%);
}
.plate .orb{
  position:absolute;left:50%;top:50%;translate:-50% -50%;
  width:110px;height:110px;border-radius:50%;
  background:radial-gradient(38% 34% at 34% 28%,#FFFFFF,#B4B4BA 40%,#4A4A52 76%,#141418);
  box-shadow:0 0 60px rgba(0,0,0,.10);
}
.plate .ring{
  position:absolute;left:50%;top:50%;translate:-50% -50%;
  border:1px solid rgba(0,0,0,.16);border-radius:50%;
}

/* ---------- next / prev ---------- */
.pager{
  border-top:1px solid var(--edge-soft);
  display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--edge-soft);
}
@media (max-width:760px){.pager{grid-template-columns:1fr}}
.pager a{
  background:var(--bg);padding:clamp(26px,4vh,44px) 0;
  transition:background-color .35s ease;
}
.pager a:hover{background:rgba(0,0,0,.04)}
.pager .inner{padding:0 clamp(18px,3vw,40px)}
.pager .lbl{font:400 9px/1 var(--mono);letter-spacing:.22em;color:var(--ink-3);text-transform:uppercase}
.pager .nm{
  margin-top:12px;font-size:clamp(1.05rem,2vw,1.5rem);font-weight:600;
  letter-spacing:-.035em;text-transform:uppercase;color:var(--ink);
}
.pager a.nx{text-align:right}

/* ---------- index grid ---------- */
.grid-cards{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));
  gap:1px;background:var(--edge-soft);border:1px solid var(--edge-soft);
  margin-top:clamp(30px,5vh,54px);
}
.gc{
  background:var(--bg);padding:26px 24px 30px;
  display:flex;flex-direction:column;gap:12px;
  transition:background-color .35s ease;
}
.gc:hover{background:rgba(0,0,0,.045)}
.gc .n{font:400 9.5px/1 var(--mono);letter-spacing:.2em;color:var(--accent)}
.gc h3{
  margin:0;font-size:1.12rem;font-weight:600;letter-spacing:-.03em;
  text-transform:uppercase;color:var(--ink);
}
.gc p{margin:0;font-size:.9rem;line-height:1.65;color:var(--ink-2)}

/* ---------- footer ---------- */
.site-foot{
  border-top:1px solid var(--edge-soft);
  padding:clamp(44px,7vh,80px) 0 clamp(30px,4vh,44px);
}
.foot-top{display:flex;flex-wrap:wrap;justify-content:space-between;gap:36px}
.foot-cta h2{
  margin:0;font-size:clamp(1.5rem,4vw,2.9rem);font-weight:600;
  letter-spacing:-.045em;line-height:1;text-transform:uppercase;max-width:20ch;
}
.foot-cta a.big{
  display:inline-flex;align-items:center;gap:12px;margin-top:26px;
  padding:16px 24px;border:1px solid var(--edge);
  font:500 11px/1 var(--mono);letter-spacing:.18em;color:var(--ink);
  transition:background-color .3s ease,color .3s ease;
}
.foot-cta a.big:hover{background:var(--accent-2);color:var(--on-accent)}
.foot-links{display:flex;gap:clamp(26px,4vw,64px);flex-wrap:wrap}
.foot-links div h3{
  margin:0 0 15px;font:400 10px/1 var(--mono);letter-spacing:.19em;
  color:var(--ink-3);text-transform:uppercase;font-weight:400;
}
.foot-links a{
  display:block;padding:7px 0;font:400 11.5px/1.5 var(--mono);
  letter-spacing:.1em;color:var(--ink-2);
}
.foot-links a:hover{color:var(--ink)}
.foot-bot{
  margin-top:clamp(38px,6vh,64px);padding-top:20px;
  border-top:1px solid var(--edge-soft);
  display:flex;flex-wrap:wrap;justify-content:space-between;gap:14px;
  font:400 10.5px/1.7 var(--mono);letter-spacing:.14em;color:var(--ink-3);text-transform:uppercase;
}
.led{
  display:inline-block;width:5px;height:5px;border-radius:50%;
  background:var(--accent);box-shadow:0 0 9px var(--accent);margin-right:8px;
  animation:pulse 2.6s var(--ease-in-out) infinite;
}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}

/* ---------- reveal ---------- */
/* Gated on html.js: with scripting off, or if a script error lands before
   the reveal observer runs, these must not leave the page blank. */
.js .rv{opacity:0;transform:translateY(26px)}
.rv{transition:opacity .9s var(--ease-out),transform 1.05s var(--ease-out)}
.rv.in{opacity:1;transform:none}
.rv[data-d="1"]{transition-delay:.09s}
.rv[data-d="2"]{transition-delay:.18s}
.rv[data-d="3"]{transition-delay:.27s}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation-duration:.001s !important;transition-duration:.001s !important}
  .rv{opacity:1 !important;transform:none !important}
  #atmos{display:none}
  body.cursor-on{cursor:auto}
  #cur,#cur-dot{display:none}
}

/* ============================================================
   IMAGERY
   Explicit width/height on every <img> plus aspect-ratio here:
   nothing reflows while images load.
   ============================================================ */
.hero-media{padding:clamp(6px,1vh,14px) 0 clamp(10px,2vh,26px)}
figure.shot{margin:0;position:relative}
figure.shot picture{display:block}
.shot-img{
  display:block;width:100%;height:auto;
  border:1px solid var(--edge);
  background:linear-gradient(135deg,rgba(0,0,0,.05),rgba(0,0,0,.10));
  filter:saturate(1.02) contrast(1.02);
}
figure.shot figcaption{
  margin-top:13px;
  font:400 10.5px/1.6 var(--mono);letter-spacing:.16em;
  color:var(--ink-3);text-transform:uppercase;
}
figure.shot.inline{margin:clamp(30px,4.5vh,52px) 0}
figure.shot.inline .shot-img{border-color:var(--edge-soft)}

/* the hero sits flush under the page head, edge-lit */
.hero-media .shot-img{
  box-shadow:0 30px 60px -40px rgba(0,0,0,.28),
             inset 0 1px 0 rgba(0,0,0,.04);
}

/* reveal, matching the rest of the page */
figure.shot.rv{opacity:0;transform:translateY(18px);
  transition:opacity .9s var(--ease-out),transform 1s var(--ease-out)}
figure.shot.rv.in{opacity:1;transform:none}

@media (prefers-reduced-motion:reduce){
  figure.shot.rv{opacity:1 !important;transform:none !important}
}

/* contact email links inside meta / card lists */
.head-meta dd a,.aside .card dd a{
  color:var(--accent);text-decoration:none;
  border-bottom:1px solid rgba(0,0,0,.28);
}
.head-meta dd a:hover,.aside .card dd a:hover{border-bottom-color:var(--accent)}

/* ============================================================
   BREADCRUMBS
   Sits above .page-head, so it carries the clearance for the
   fixed header and .page-head drops its own top padding.
   ============================================================ */
.crumbs{padding:calc(clamp(70px,11vh,118px) + 58px) 0 0;position:relative;z-index:2}
.crumbs ol{
  list-style:none;margin:0;padding:0;
  display:flex;flex-wrap:wrap;align-items:center;gap:7px;
  font:400 10.5px/1.7 var(--mono);letter-spacing:.17em;
  color:var(--ink-3);text-transform:uppercase;
}
.crumbs li{display:flex;align-items:center;gap:7px}
.crumbs li+li::before{content:"/";color:rgba(0,0,0,.25)}
.crumbs a{color:var(--ink-2);text-decoration:none;transition:color .25s ease}
.crumbs a:hover{color:var(--ink)}
.crumbs li[aria-current="page"]{color:var(--ink-2)}
.crumbs + .page-head{padding-top:clamp(20px,3vh,34px)}

@media (max-width:760px){
  .crumbs{padding-top:calc(clamp(60px,9vh,90px) + 54px)}
  .crumbs ol{font-size:9px;letter-spacing:.14em}
}

/* ============================================================
   TOUCH TARGETS
   Measured on a 390px viewport: breadcrumb links were 27x15 (below the
   WCAG 2.5.8 minimum of 24px) and nav, footer, brand and toggle all sat
   under the 44px Google recommends. Grown with padding so the visual
   design is unchanged.
   ============================================================ */
@media (max-width:760px){
  .site-head .brand{
    display:inline-flex;align-items:center;
    min-height:44px;padding:0 8px;margin-left:-8px;
  }
  .site-nav a{min-height:44px;display:flex;align-items:center}
  .nav-cta{min-height:44px;display:inline-flex;align-items:center}
  .nav-toggle{min-height:44px;min-width:44px}
  .crumbs ol{gap:2px 7px}
  .crumbs a{display:inline-flex;align-items:center;min-height:28px;padding:2px 0}
  .foot-links a{display:inline-flex;align-items:center;min-height:36px}
  .pager a{min-height:56px;display:flex;align-items:center}
  .skip:focus{min-height:44px;display:inline-flex;align-items:center}
}

/* ============================================================
   RESPONSIVE PASS — tablet and mobile
   Written against a measured audit of every page at 320 / 390 /
   768 / 1024: undersized tap targets, sub-12px type, and
   decorative elements running past the viewport.
   ============================================================ */

/* ---------- tablet portrait and below (768px) ---------- */
@media (max-width:900px){
  /* the two-column body stacks earlier; give the aside room to breathe */
  .cols{gap:40px}
  .aside{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px}
  figure.fig .plate{height:clamp(180px,26vh,260px)}
  .stats{grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}
}

/* ---------- touch: every interactive element reachable ---------- */
@media (hover:none),(max-width:900px){
  /* 44px is the accessible minimum; these were 17-28px tall */
  .site-nav a{padding:13px 12px;min-height:44px;display:flex;align-items:center}
  .nav-cta{padding:13px 18px;min-height:44px;display:inline-flex;align-items:center}
  .crumbs ol{gap:2px 8px}
  .crumbs a{padding:10px 2px;min-height:40px;display:inline-flex;align-items:center}
  .crumbs li{min-height:40px}
  /* flex, not inline-flex: inline-flex made adjacent footer links flow
     into one another ("Overview Interface engineering"), which merged
     their anchor text. Block-level flex keeps the 42px touch target. */
  .foot-links a{padding:11px 0;min-height:42px;display:flex;align-items:center}
  /* inline prose links can't be 44px tall without wrecking leading,
     but they can have a larger hit box than the glyph height */
  .prose a,.head-meta a,.aside a{padding:6px 0;display:inline-block}
  .brand{padding:10px 6px;min-height:44px;display:inline-flex;align-items:center}
  .foot-links a{padding-left:2px;padding-right:2px}
  /* email shown as a value, not mid-sentence: give it a real hit box */
  .head-meta dd a,.aside .card dd a{
    padding:11px 0;min-height:44px;display:inline-flex;align-items:center;
  }
  a,button{-webkit-tap-highlight-color:rgba(0,0,0,.06)}
}

/* ---------- type floor: phones AND tablets ----------
   The audit showed 9-11px mono labels surviving at 768 and 1024, where a
   device is still held in the hand. The floor therefore runs to 1080px,
   not just to phone widths. */
@media (max-width:1080px){
  /* nothing carrying meaning should sit under 11px, and anything a
     visitor actually reads is lifted to 12px+ */
  .eyebrow{font-size:12px;letter-spacing:.16em}
  .crumbs ol{font-size:12px;letter-spacing:.1em}
  .head-meta dt{font-size:12px;letter-spacing:.12em}
  .head-meta dd{font-size:14px}
  .aside .card h3{font-size:12px;letter-spacing:.14em}
  .aside .card dt{font-size:12px}
  .aside .card dd{font-size:14px}
  .aside .card .tags span,.tag{font-size:12px;letter-spacing:.06em;padding:9px 11px}
  figure.fig figcaption,figure.shot figcaption{font-size:12px;letter-spacing:.1em}
  .foot-links a{font-size:14px}
  .foot-top h2,.foot-links h2{font-size:12px;letter-spacing:.16em}
  .pager .lbl{font-size:12px}
  .mono{font-size:12px}
  .prose p,.prose li{font-size:1rem;line-height:1.78}
  .skip{font-size:12px}
  .stats span{font-size:12px;letter-spacing:.1em}
  /* footer CTA button and the footer status line were the last two
     sub-12px items in the audit */
  .foot-cta a.big{font-size:12.5px;letter-spacing:.16em;padding:18px 26px}
  .foot-bot,.foot-bot span,.foot-bot a{font-size:12px;letter-spacing:.12em;line-height:1.8}
  .aside .card h3{font-size:12px}
}

/* ---------- very narrow (320px) ---------- */
@media (max-width:380px){
  /* decorative plate art was drawn wider than the frame */
  figure.fig{overflow:hidden}
  .plate .grid-persp{inset:-30% 0 -10%}
  .plate .ring{max-width:92vw;max-height:92vw}
  .plate .orb{width:84px;height:84px}
  .aside{grid-template-columns:1fr}
  .stats{grid-template-columns:1fr}
  .site-nav a{padding:12px 9px;letter-spacing:.1em}
}

/* ---------- touch targets on the homepage footer sitemap ---------- */
/* (.ft-map is injected by homepage.py; its base styles live inline) */
@media (hover:none),(max-width:900px){
  .ft-map a{padding:11px 0;min-height:42px;display:inline-flex;align-items:center}
}

/* ============================================================
   SELF-HOSTED WEBFONTS — no third-party request
   Previously the fonts loaded from fonts.googleapis.com. That sends the
   visitor's IP address to Google before any consent, which the Munich
   regional court (LG München I, 20 Jan 2022, 3 O 17493/20) held to be a
   GDPR violation; it triggered a wave of German demand letters. For a site
   claiming a Berlin base that is real exposure, so the external request is
   gone.
   Drop the two woff2 files into /assets/fonts/ and the typography appears.
   Until then these rules resolve to nothing and the system stack below
   takes over — the layout is built to survive the substitution.
   Get them from fonts.google.com (both are Open Font License).
   ============================================================ */
/*  UNCOMMENT THIS BLOCK once the two woff2 files are in
    /assets/fonts/. Left commented because rules pointing at missing
    files make every page fire three requests that 404 -- three wasted
    round trips per page load and a noisy error log. With them off the
    system stack below renders immediately and nothing 404s.

  @font-face{
    font-family:"Space Grotesk";
    src:url("/assets/fonts/space-grotesk-variable.woff2") format("woff2-variations"),
        url("/assets/fonts/space-grotesk-600.woff2") format("woff2");
    font-weight:400 700;
    font-display:swap;
    font-style:normal;
  }
  @font-face{
    font-family:"IBM Plex Mono";
    src:url("/assets/fonts/ibm-plex-mono-400.woff2") format("woff2");
    font-weight:400 500;
    font-display:swap;
    font-style:normal;
  }
*/

/* ============================================================
   HEADING ANCHORS / TABLE OF CONTENTS / RELATED
   ============================================================ */

/* The header is fixed, so an anchor jump would otherwise land with the
   heading hidden underneath it. */
.prose h2[id]{scroll-margin-top:calc(clamp(70px,11vh,118px) + 34px)}

.prose h2 .anchor{
  margin-left:10px;font-weight:400;text-decoration:none;
  color:var(--ink-3);opacity:0;
  transition:opacity .2s ease,color .2s ease;
}
.prose h2:hover .anchor,.prose h2 .anchor:focus-visible{opacity:1}
.prose h2 .anchor:hover{color:var(--ink)}

.toc{
  margin:0 0 clamp(34px,5vh,52px);padding:22px 24px;
  border:1px solid var(--edge);background:var(--bg-2);
}
.toc-h{
  margin:0 0 14px !important;font:400 9.5px/1 var(--mono) !important;
  letter-spacing:.22em !important;color:var(--ink-2) !important;
  text-transform:uppercase;
}
.toc ol{margin:0;padding:0;list-style:none;counter-reset:toc}
.toc li{counter-increment:toc;margin:0 0 9px}
.toc li:last-child{margin-bottom:0}
.toc li::before{
  content:counter(toc,decimal-leading-zero);
  margin-right:12px;font:400 9.5px/1 var(--mono);color:var(--ink-3);
}
.toc a{
  color:var(--ink);text-decoration:none;font-size:1.03rem;
  border-bottom:1px solid transparent;transition:border-color .2s ease;
}
.toc a:hover{border-bottom-color:var(--ink)}

.related-wrap{padding:0 0 clamp(50px,8vh,90px)}
.rl-h{
  margin:0 0 22px;font:400 9.5px/1 var(--mono);letter-spacing:.22em;
  color:var(--ink-3);text-transform:uppercase;font-weight:400;
}
.related ul{
  margin:0;padding:0;list-style:none;display:grid;gap:1px;
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  background:var(--edge);border:1px solid var(--edge);
}
.related li{background:var(--bg)}
.related a{
  display:flex;flex-direction:column;gap:8px;height:100%;
  padding:20px 22px;text-decoration:none;
  transition:background-color .3s ease;
}
.related a:hover{background:var(--bg-2)}
.rl-t{
  font-size:1.08rem;font-weight:600;letter-spacing:-.02em;color:var(--ink);
  line-height:1.25;
}
.rl-d{font:400 12.5px/1.65 var(--mono);color:var(--ink-2)}

@media (max-width:760px){
  .toc{padding:18px 18px}
  .prose h2[id]{scroll-margin-top:calc(clamp(60px,9vh,90px) + 30px)}
}
@media (prefers-reduced-motion:reduce){
  .prose h2 .anchor{opacity:1}
}

/* ============================================================
   IN-CONTENT LINKS
   These had no style at all: identical colour to body text, no underline,
   indistinguishable from prose. That fails WCAG 1.4.1 (colour alone cannot
   be the only distinguishing signal) and, here, there was not even a colour
   difference. Underlined, because in a monochrome palette an underline is
   the only honest signal available.
   Scoped to paragraphs and body lists so the table of contents, the related
   cards and the heading anchors keep their own treatment.
   ============================================================ */
.prose p a[href],
.prose > ul li a[href],
.prose blockquote a[href]{
  color:var(--ink);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  text-decoration-color:rgba(0,0,0,.38);
  transition:text-decoration-color .2s ease,background-color .2s ease;
}
.prose p a[href]:hover,
.prose > ul li a[href]:hover,
.prose blockquote a[href]:hover{
  text-decoration-color:var(--ink);
  text-decoration-thickness:2px;
  background:rgba(0,0,0,.04);
}
.prose p a[href]:focus-visible,
.prose > ul li a[href]:focus-visible{
  outline:2px solid var(--ink);outline-offset:2px;text-decoration:none;
}

/* ============================================================
   INVERTED BANDS — black against white
   The all-white page read as washed out. Rather than repaint every
   rule, .invert flips the palette tokens for a subtree, so anything
   inside it picks up the dark values through normal inheritance.
   Applied to the masthead, the page head and the footer: dark top,
   light reading column, dark foot.
   ============================================================ */
.invert{
  --bg:#0B0B0C;
  --bg-2:#16161A;
  --bg-3:#212126;
  --edge:rgba(255,255,255,.18);
  --edge-soft:rgba(255,255,255,.09);
  --ink:#F4F4F5;      /* 18.1:1 on --bg */
  --ink-2:#B9B9C0;    /* 9.6:1  */
  --ink-3:#9A9AA2;    /* 6.4:1  */
  --accent:#F4F4F5;
  --accent-2:#D8D8DE;
  --on-accent:#0B0B0C;
  background:var(--bg);
  color:var(--ink);
}

/* masthead */
.site-head.invert{
  background:rgba(11,11,12,.88);
  border-bottom:1px solid rgba(255,255,255,.12);
}
.site-head.invert .site-nav a.on{background:var(--ink);color:var(--on-accent)}
.site-head.invert .nav-cta{border-color:rgba(255,255,255,.28)}
.site-head.invert .nav-cta:hover{background:var(--ink);color:var(--on-accent)}

/* the dark head band runs from the masthead through the page title */
.page-head.invert{
  background:var(--bg);
  padding-bottom:clamp(46px,7vh,80px);
  position:relative;
}
.crumbs.invert{background:var(--bg)}
/* No gradient on the dark band. At 176deg the axis is near-vertical, so on a
   short wide single-line title it renders as a left-to-right fade and the end
   of the heading drops to roughly 5:1 against black. Solid ink instead. */
.page-head.invert .title{
  background:none;-webkit-background-clip:border-box;background-clip:border-box;
  color:var(--ink);
}
.page-head.invert .rule{background:rgba(255,255,255,.14)}

/* the hero image sits directly under the dark band, so no white gap */
/* literal value, not var(--bg): .on-dark carries no inverted tokens, so
   var(--bg) resolved to white and left a white band under the dark head */
.hero-media.on-dark{background:#0B0B0C;padding-top:0;padding-bottom:clamp(30px,5vh,60px)}
.hero-media.on-dark .shot-img{border-color:rgba(255,255,255,.16)}

/* footer */
.site-foot.invert{background:var(--bg);border-top:0}
.site-foot.invert .foot-cta a.big{
  border-color:rgba(255,255,255,.3);color:var(--ink);
}
.site-foot.invert .foot-cta a.big:hover{background:var(--ink);color:var(--on-accent)}

/* the pager sits between light body and dark footer: keep it light but
   give it a firm edge so the transition reads as intentional */
.pager{border-top:1px solid var(--edge)}

/* ============================================================
   MOTION
   Everything here is transform/opacity/clip-path only, so nothing
   triggers layout and CLS stays at 0. All of it collapses under
   prefers-reduced-motion at the end of this block.
   ============================================================ */

/* ---- 1. cross-document view transitions --------------------------------
   Navigating between pages morphs the shared furniture instead of cutting
   to a new document. Chrome and Edge honour this today; everywhere else
   simply navigates as before, so it costs nothing to include. */
@view-transition{ navigation:auto }

.site-head{view-transition-name:masthead}
.site-foot{view-transition-name:footfall}
.page-head .title{view-transition-name:page-title}
.hero-media .shot-img{view-transition-name:hero-shot}

::view-transition-group(page-title),
::view-transition-group(hero-shot){
  animation-duration:.52s;
  animation-timing-function:cubic-bezier(.16,1,.3,1);
}
::view-transition-old(root){
  animation:vt-out .3s cubic-bezier(.4,0,1,1) both;
}
::view-transition-new(root){
  animation:vt-in .42s cubic-bezier(0,0,.2,1) both;
}
@keyframes vt-out{to{opacity:0;transform:translateY(-8px)}}
@keyframes vt-in{from{opacity:0;transform:translateY(10px)}}

/* ---- 2. per-word title reveal -----------------------------------------
   The h1 used to fade in as one block. Splitting it into words and
   sliding each out from behind its own clipped line reads as the type
   being set rather than switched on. */
.title .w{
  display:inline-block;
  overflow:hidden;
  vertical-align:bottom;
  padding-bottom:.06em;      /* room for descenders inside the clip */
}
.title .w > span{
  display:inline-block;
  transform:translateY(106%) rotate(2.5deg);
  transform-origin:0 100%;
  opacity:0;
  transition:transform .82s cubic-bezier(.16,1,.3,1),
             opacity .5s ease;
  transition-delay:calc(var(--i) * 62ms);
}
.title.in .w > span{transform:none;opacity:1}

/* ---- 3. reading progress ----------------------------------------------
   A hairline under the masthead that fills as you read. */
/* Sits on the masthead's bottom edge rather than at viewport top: the
   masthead is position:fixed at z-index 150 and covers the first 64px, so a
   bar at top:0/z-index:70 was painted underneath it and never once visible.
   As a child it also tracks the masthead's height, which changes on mobile. */
#progress{
  position:absolute;left:0;bottom:-1px;height:2px;width:100%;
  transform:scaleX(0);transform-origin:0 50%;
  background:#F4F4F5;
  pointer-events:none;
  transition:transform .12s linear;
}

/* ---- 4. figures wipe in rather than fade ------------------------------ */
figure.shot.rv picture{
  display:block;
  transition:clip-path 1.05s cubic-bezier(.16,1,.3,1);
}
.js figure.shot.rv picture{clip-path:inset(0 0 100% 0)}
figure.shot.rv.in picture{clip-path:inset(0 0 0 0)}
figure.shot.rv{opacity:1;transform:none}          /* the wipe replaces the slide */
figure.shot.rv figcaption{transition:opacity .6s ease .45s}
.js figure.shot.rv figcaption{opacity:0}
figure.shot.rv.in figcaption{opacity:1}

/* ---- 5. table of contents follows the reading position --------------- */
.toc a{
  position:relative;padding-left:0;
  transition:color .25s ease,padding-left .3s var(--ease-out);
}
.toc a::before{
  content:"";position:absolute;left:-14px;top:50%;
  width:9px;height:1px;background:var(--ink);
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform .3s var(--ease-out);
}
.toc li.here a{padding-left:15px;color:var(--ink)}
.toc li.here a::before{transform:scaleX(1)}

/* ---- 6. links and cards sweep on hover -------------------------------- */
.prose p a,.prose li a{
  background-image:linear-gradient(var(--ink),var(--ink));
  background-size:0% 1px;
  background-position:0 100%;
  background-repeat:no-repeat;
  border-bottom:1px solid var(--edge);
  text-decoration:none;
  transition:background-size .4s var(--ease-out);
}
.prose p a:hover,.prose li a:hover{background-size:100% 1px}

.related li{position:relative;overflow:hidden}
.related li::after{
  content:"";position:absolute;inset:auto 0 0 0;height:2px;
  background:var(--ink);
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform .45s var(--ease-out);
}
.related li:hover::after{transform:scaleX(1)}
.related a .rl-t{transition:transform .45s var(--ease-out)}
.related li:hover .rl-t{transform:translateX(5px)}

/* ---- 7. the anchor mark draws itself in ------------------------------- */
.prose h2 .anchor{transform:translateX(-4px)}
.prose h2:hover .anchor{transform:none;transition:opacity .2s ease,transform .3s var(--ease-out)}

@media (prefers-reduced-motion:reduce){
  @view-transition{ navigation:none }
  .title .w > span{transform:none !important;opacity:1 !important;transition:none !important}
  .title .w{overflow:visible}
  figure.shot.rv picture{clip-path:none !important;transition:none !important}
  figure.shot.rv figcaption{opacity:1 !important}
  #progress{display:none}
  .toc a,.toc a::before,.related li::after,.related a .rl-t,
  .prose p a,.prose li a{transition:none !important}
  .toc li.here a{padding-left:15px}
}
