:root{
  /* dark from the first paint: these match the neutral palette the colour engine starts on,
     so nothing light ever shows while the scripts load. The accent here is only a fallback;
     every accent on the page follows the walking colour once the engine runs. */
  --bg:21,21,24; --ink:240,238,232; --ac:236,122,82; --acq:236,122,82; --walk:236,122,82;
  color-scheme:dark;
  --sans:'Figtree',system-ui,-apple-system,sans-serif;
  --gut:clamp(20px,5vw,80px); --max:1340px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:rgb(var(--bg));color:rgb(var(--ink));font:400 17px/1.55 var(--sans);-webkit-font-smoothing:antialiased}
img{display:block;max-width:100%;height:auto}
a{color:inherit}
p{margin:0 0 1em}
h1,h2,h3{margin:0;font-weight:900;letter-spacing:-.035em;line-height:.98}
em{font-style:normal;color:rgb(var(--ac))}
/* the walking words: one colour that cycles the whole hue ring, constantly, guarded for contrast */
em.cyc,.cyc em{color:rgb(var(--walk,var(--ac)))}
.wrap{max-width:var(--max);margin:0 auto;padding:0 var(--gut)}
.mute{color:color-mix(in oklab,rgb(var(--ink)) 74%,rgb(var(--bg)))}
.rule{border:0;border-top:1px solid color-mix(in oklab,rgb(var(--ink)) 18%,rgb(var(--bg)));margin:0}
.kicker{font-size:12.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:rgb(var(--acq));margin-bottom:14px}

/* nav */
.nav{position:sticky;top:0;z-index:20;background:rgb(var(--bg))}
.nav .in{max-width:var(--max);margin:0 auto;padding:18px var(--gut);display:flex;align-items:baseline;gap:18px}
.nav .brand{text-decoration:none;font-weight:900;font-size:19px;letter-spacing:-.04em}
.nav .brand b{color:rgb(var(--ac));font-weight:900}
.nav ul{display:flex;gap:22px;list-style:none;margin:0 0 0 auto;padding:0;font-size:14.5px;font-weight:500;flex-wrap:wrap;row-gap:6px;justify-content:flex-end}
.nav a{text-decoration:none}
.nav ul a{padding-bottom:2px;border-bottom:1.5px solid transparent}
.nav ul a:hover{border-color:rgb(var(--ac))}
.nav .ask{font-weight:600;color:rgb(var(--ac));border-bottom:1.5px solid rgb(var(--ac))!important}

/* hero */
.hero{padding-top:clamp(52px,9vw,124px);padding-bottom:clamp(36px,5vw,64px);position:relative}
.hero h1{font-size:clamp(42px,7vw,104px);max-width:15ch}
.hero .sub{font-size:clamp(17px,1.45vw,21px);max-width:36em;margin-top:clamp(24px,3vw,38px)}
.hero .sub em{font-weight:600}
.hero .avail{display:flex;gap:10px 30px;flex-wrap:wrap;font-size:14.5px;margin-top:clamp(26px,3vw,40px);padding-top:18px;border-top:1px solid color-mix(in oklab,rgb(var(--ink)) 18%,rgb(var(--bg)))}

/* two-column band */
.band{padding:clamp(40px,5.5vw,76px) 0;position:relative}
.band .in{max-width:var(--max);margin:0 auto;padding:0 var(--gut);display:grid;grid-template-columns:minmax(0,4.2fr) minmax(0,7.4fr);gap:clamp(26px,5vw,80px);align-items:start}
.band h2{font-size:clamp(26px,3.2vw,44px);max-width:22ch}
.band .lede{margin-top:18px;max-width:34em}

/* services */
.svc{display:grid;gap:1px;background:color-mix(in oklab,rgb(var(--ink)) 16%,rgb(var(--bg)))}
.svc article{background:rgb(var(--bg));padding:clamp(22px,2.6vw,32px) 0 clamp(22px,2.6vw,32px)}
.svc h3{font-size:clamp(20px,2.1vw,27px);max-width:24ch}
.svc p{margin:10px 0 0;max-width:40em}
.svc dl{margin:16px 0 0;display:grid;grid-template-columns:auto 1fr;gap:4px 16px;font-size:14px}
.svc dt{font-weight:600;color:rgb(var(--acq))}
.svc dd{margin:0}

/* steps */
.steps{counter-reset:s;display:grid;gap:clamp(18px,2vw,26px)}
.steps li{list-style:none;counter-increment:s;display:grid;grid-template-columns:auto 1fr;gap:18px;align-items:start}
.steps li::before{content:counter(s,decimal-leading-zero);font-weight:900;font-size:15px;letter-spacing:-.02em;color:rgb(var(--acq));padding-top:3px}
.steps h3{font-size:clamp(18px,1.9vw,23px)}
.steps p{margin:6px 0 0;max-width:40em;font-size:16px}

/* spec list */
.facts{display:grid;grid-template-columns:auto 1fr;gap:10px 22px;font-size:15px;margin:0}
.facts dt{font-weight:600;color:rgb(var(--acq));white-space:nowrap}
.facts dd{margin:0}

/* a job block */
.job{padding:clamp(44px,6.5vw,92px) 0;position:relative}
.job .in{max-width:var(--max);margin:0 auto;padding:0 var(--gut);display:grid;grid-template-columns:minmax(0,4.6fr) minmax(0,7fr);gap:clamp(28px,5vw,80px);align-items:start}
.job.flip .media{order:-1}
.spec{font-size:13.5px;display:flex;flex-direction:column;gap:3px;padding-bottom:16px;margin-bottom:22px;border-bottom:1px solid color-mix(in oklab,rgb(var(--ink)) 24%,rgb(var(--bg)))}
.spec b{font-weight:600;color:rgb(var(--ac))}
.job h2{font-size:clamp(28px,3.5vw,50px);max-width:20ch}
.job .lede{margin-top:20px;max-width:34em}
.hard{margin-top:26px;padding-left:16px;border-left:2px solid rgb(var(--ac))}
.hard>span{display:block;font-size:12.5px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;color:rgb(var(--acq));margin-bottom:5px}
.hard p{margin:0;max-width:32em}
.more{display:inline-block;margin-top:30px;font-weight:600;font-size:16px;text-decoration:none;padding-bottom:3px;background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 1.5px no-repeat;transition:background-size .35s}
.more:hover{background-size:100% 100%;color:rgb(var(--bg))}

/* work, clickable */
.media{display:flex;flex-direction:column;gap:clamp(16px,2.2vw,26px)}
.media .pair{display:grid;grid-template-columns:1fr 1fr;gap:clamp(16px,2.2vw,26px)}
.media .trio{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.8vw,22px)}
figure.shot{margin:0;cursor:zoom-in;position:relative}
figure.shot .fr{position:relative;overflow:hidden;background:color-mix(in oklab,rgb(var(--ink)) 8%,rgb(var(--bg)))}
figure.shot img{width:100%;transition:transform .6s cubic-bezier(.2,.7,.2,1)}
figure.shot:hover img{transform:scale(1.025)}
figure.shot .fr::after{content:"⤢";position:absolute;right:0;bottom:0;width:38px;height:38px;display:grid;place-items:center;font-size:15px;background:rgb(var(--ac));color:rgb(var(--bg));opacity:0;transform:translateY(6px);transition:opacity .3s,transform .3s}
figure.shot:hover .fr::after{opacity:1;transform:none}
figure.shot figcaption{font-size:13px;margin-top:9px;max-width:48ch;color:color-mix(in oklab,rgb(var(--ink)) 76%,rgb(var(--bg)))}
figure.shot figcaption b{font-weight:600;color:rgb(var(--ink))}
.media .hid{display:none}
.story{font-size:13.5px;font-weight:600;display:inline-flex;gap:9px;align-items:center;background:none;border:0;padding:0;font-family:inherit;color:rgb(var(--ac));cursor:pointer}
.story::after{content:"→"}
.story i{width:8px;height:8px;border-radius:50%;background:rgb(var(--ac));display:inline-block}

/* quotes */
.quotes{display:grid;grid-template-columns:1fr 1fr;gap:clamp(22px,3vw,44px)}
.quotes blockquote{margin:0;font-size:clamp(18px,1.9vw,23px);line-height:1.3;letter-spacing:-.02em;font-weight:500;padding-top:18px;border-top:2px solid rgb(var(--ac))}
.quotes cite{display:block;margin-top:14px;font-style:normal;font-size:14px}
.quotes cite b{font-weight:600;color:rgb(var(--acq))}

/* marks */
.marks{padding-top:clamp(44px,6.5vw,88px);padding-bottom:clamp(44px,6.5vw,88px);position:relative}
.marks h2{font-size:clamp(26px,3.2vw,44px);max-width:26ch}
.marks .head{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,4fr);gap:clamp(24px,4vw,64px);align-items:end;margin-bottom:clamp(26px,3vw,44px)}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(168px,1fr));gap:1px}
@media (min-width:1060px){.grid{grid-template-columns:repeat(7,minmax(0,1fr))}}
.grid figure{margin:0;background:#fff;aspect-ratio:2/1;overflow:hidden;cursor:zoom-in}
.grid figure .fr{height:100%}
.grid img{width:100%;height:100%;object-fit:cover}
.grid figcaption{display:none}

/* contact */
.contact{padding-top:clamp(56px,8vw,110px);padding-bottom:clamp(56px,8vw,110px);position:relative}
.contact h2{font-size:clamp(32px,5.4vw,78px);max-width:17ch}
.contact p{margin-top:24px;max-width:32em}
.contact a.big{display:inline-block;margin-top:14px;font-size:clamp(22px,2.6vw,34px);font-weight:900;letter-spacing:-.03em;text-decoration:none;background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 2px no-repeat;transition:background-size .4s}
.contact a.big:hover{background-size:100% 100%;color:rgb(var(--bg))}
.contact ul{margin:26px 0 0;padding:0;list-style:none;font-size:15px;display:grid;gap:7px;max-width:40em}
.contact li::before{content:"—";color:rgb(var(--acq));margin-right:10px}
.foot{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;padding:20px 0 34px;font-size:13px}

/* lightbox */
.lb{position:fixed;inset:0;z-index:60;display:none;background:rgb(var(--bg));color:rgb(var(--ink))}
.lb.on{display:grid;grid-template-rows:auto 1fr auto}
.lb .bar{display:flex;align-items:center;gap:16px;padding:16px var(--gut);font-size:13.5px}
.lb .bar .who{font-weight:600;color:rgb(var(--ac))}
.lb .bar .n{margin-left:auto;font-variant-numeric:tabular-nums;opacity:.65}
.lb button{font:inherit;background:none;border:0;color:inherit;cursor:pointer;padding:6px 10px}
.lb .x{font-size:20px;line-height:1}
.lb .stage{display:grid;place-items:center;padding:0 var(--gut);min-height:0}
.lb .stage img{max-height:100%;max-width:100%;object-fit:contain;filter:drop-shadow(0 30px 70px rgba(0,0,0,.18))}
.lb .cap{padding:16px var(--gut) 26px;display:flex;gap:20px;align-items:flex-start;max-width:1100px;margin:0 auto;width:100%;font-size:14.5px}
.lb .cap p{margin:0}
.lb .cap b{color:rgb(var(--ac))}
.lb .nav2{display:flex;gap:4px;margin-left:auto;flex:0 0 auto}
.lb .nav2 button{border:1px solid color-mix(in oklab,rgb(var(--ink)) 25%,rgb(var(--bg)))}
.lb .nav2 button:hover{background:rgb(var(--ac));color:rgb(var(--bg));border-color:rgb(var(--ac))}
body.locked{overflow:hidden}

/* case study page */
.case-hero{padding-top:clamp(44px,7vw,100px);padding-bottom:clamp(30px,4vw,54px);position:relative}
.case-hero h1{font-size:clamp(34px,5.4vw,76px);max-width:20ch}
.case-hero .sub{font-size:clamp(17px,1.5vw,22px);max-width:34em;margin-top:26px}
.chap{padding:clamp(44px,7vw,100px) 0;position:relative}
.chap .in{max-width:var(--max);margin:0 auto;padding:0 var(--gut);display:grid;grid-template-columns:minmax(0,4.2fr) minmax(0,7.4fr);gap:clamp(26px,5vw,80px);align-items:start}
.chap h2{font-size:clamp(24px,3vw,40px);max-width:22ch}
.chap .body{max-width:36em}
.chap .body p{font-size:17.5px}
.pull{font-size:clamp(22px,2.6vw,34px);font-weight:900;letter-spacing:-.03em;line-height:1.08;max-width:24ch;margin:28px 0}
.full{max-width:var(--max);margin:0 auto;padding:0 var(--gut)}
.next{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;align-items:baseline;padding-top:clamp(36px,5vw,70px);padding-bottom:clamp(36px,5vw,70px)}
.next a{text-decoration:none;font-weight:900;font-size:clamp(20px,2.4vw,32px);letter-spacing:-.03em}
.next a em{color:rgb(var(--ac))}

@media (max-width:900px){
  .job .in,.band .in,.chap .in,.marks .head,.quotes{grid-template-columns:1fr}
  .job .media,.job.flip .media{order:-1}
  .nav .in{flex-wrap:wrap}.nav ul{margin-left:0;justify-content:flex-start;width:100%}
  .lb .cap{flex-direction:column;gap:12px}.lb .nav2{margin-left:0}
  .media .trio{grid-template-columns:1fr 1fr}
}

/* ===== pass five ===== */

/* four rules, his own words */
.rules{padding:clamp(40px,5.5vw,72px) 0;position:relative}
.rules .in{max-width:var(--max);margin:0 auto;padding:0 var(--gut)}
.rules h2{font-size:clamp(24px,3vw,40px);max-width:24ch;margin-bottom:clamp(26px,3vw,44px)}
.rules ul,.rules ol{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:1px;background:color-mix(in oklab,rgb(var(--ink)) 20%,rgb(var(--bg)))}
.rules li{background:rgb(var(--bg));padding:clamp(20px,2.4vw,30px) clamp(18px,2vw,26px)}
.rules b{display:block;font-weight:900;letter-spacing:-.025em;font-size:clamp(17px,1.7vw,21px);line-height:1.1;margin-bottom:9px}
.rules p{margin:0;font-size:14.5px}
.rules .src{margin-top:22px;font-size:13.5px}

/* repeat-business table, the proof that needs nobody's permission */
.kept{display:grid;gap:1px;background:color-mix(in oklab,rgb(var(--ink)) 18%,rgb(var(--bg)));margin-top:4px}
.kept .row{background:rgb(var(--bg));display:grid;grid-template-columns:minmax(0,3fr) minmax(0,2fr) minmax(0,6fr);gap:14px clamp(14px,2vw,30px);padding:16px 0;align-items:baseline}
.kept .row.hd{font-size:12.5px;letter-spacing:.09em;text-transform:uppercase;font-weight:600;color:rgb(var(--acq));padding-bottom:9px}
.kept .c1{font-weight:600}
.kept .c2{font-variant-numeric:tabular-nums;font-weight:900;letter-spacing:-.03em;font-size:clamp(17px,1.8vw,22px)}
.kept .c3{font-size:15px}

/* poster strip */
.strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:clamp(10px,1.4vw,18px);margin-top:clamp(20px,2.4vw,30px)}
.strip figure{margin:0}
.strip figcaption{font-size:12px;margin-top:7px}

/* four options, compared like for like */
.quad{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:clamp(12px,1.6vw,20px)}
.quad figcaption{font-size:12.5px}

/* process band */
.proc{display:grid;gap:clamp(30px,4vw,54px)}
.proc .ex{display:grid;grid-template-columns:minmax(0,4fr) minmax(0,7.4fr);gap:clamp(20px,3vw,46px);align-items:start}
.proc .ex h3{font-size:clamp(19px,2vw,25px);max-width:20ch}
.proc .ex p{margin:10px 0 0;font-size:15.5px;max-width:34em}
@media (max-width:900px){.proc .ex{grid-template-columns:1fr}}

/* the rest of the work, honest shelf */
.shelf{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:1px;background:color-mix(in oklab,rgb(var(--ink)) 16%,rgb(var(--bg)));margin-top:clamp(24px,3vw,40px)}
.shelf article{background:rgb(var(--bg));padding:clamp(20px,2.3vw,28px) clamp(16px,1.8vw,24px)}
.shelf h3{font-size:clamp(17px,1.7vw,21px);margin-bottom:8px}
.shelf p{margin:0;font-size:14.5px}
.shelf .cnt{display:block;font-size:12.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:rgb(var(--acq));margin-bottom:10px}

/* four facts in place of artwork */
.fourup ol{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:1px;background:color-mix(in oklab,rgb(var(--ink)) 24%,rgb(var(--bg)))}
.fourup li{background:rgb(var(--bg));padding:clamp(16px,1.8vw,22px)}
.fourup b{display:block;font-weight:900;letter-spacing:-.025em;font-size:clamp(16px,1.5vw,19px);line-height:1.1;margin-bottom:8px}
.fourup p{margin:0;font-size:14px}
@media (max-width:560px){.fourup ol{grid-template-columns:1fr}}
.strip{grid-template-columns:repeat(3,1fr)}

/* ===== page changes: the colour stays, the content fades ===== */
html{background:rgb(var(--bg))}
body{transition:opacity .38s ease}
.hero,.case-hero{transition:transform .5s cubic-bezier(.2,.7,.2,1),opacity .5s ease}
html.entering body,html.leaving body{opacity:0}
html.entering .hero,html.entering .case-hero{transform:translateY(16px)}
html.leaving .hero,html.leaving .case-hero{transform:translateY(-10px)}
html.entering body{transition:none}
@media (prefers-reduced-motion:reduce){body,.hero,.case-hero{transition:none}html.entering .hero,html.entering .case-hero,html.leaving .hero,html.leaving .case-hero{transform:none}}

/* dark ground: frames and the detail view */
figure.shot .fr{background:color-mix(in oklab,rgb(var(--ink)) 6%,rgb(var(--bg)))}
.lb .stage img{box-shadow:none;filter:drop-shadow(0 24px 50px rgba(0,0,0,.5))}
.grid figure{background:#fff;opacity:.92;transition:opacity .3s}.grid figure:hover{opacity:1}
.nav{background:color-mix(in srgb,rgb(var(--bg)) 86%,transparent);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
.note{background:#FFF4BF;color:#3a3000}
.lb.on{animation:lbin .28s ease}
@keyframes lbin{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){.lb.on{animation:none}}

/* named tiles, for a project whose artwork is held */
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1px}
.tiles>div{box-shadow:0 0 0 1px color-mix(in oklab,rgb(var(--ink)) 20%,rgb(var(--bg)))}
.tiles>div{background:rgb(var(--bg));padding:clamp(18px,2vw,26px) clamp(16px,1.8vw,22px);min-height:150px}
.tiles .k{display:block;font-size:11.5px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;color:rgb(var(--acq));margin-bottom:10px}
.tiles b{display:block;font-weight:900;letter-spacing:-.025em;font-size:clamp(16px,1.5vw,19px);line-height:1.1;margin-bottom:8px}
.tiles p{margin:0;font-size:13.5px;color:color-mix(in oklab,rgb(var(--ink)) 78%,rgb(var(--bg)))}

/* ===== pass six: navigation and use ===== */
:focus-visible{outline:2px solid rgb(var(--ac));outline-offset:3px;border-radius:2px}
.skip{position:absolute;left:-999px;top:8px;z-index:100;background:rgb(var(--ac));color:rgb(var(--bg));padding:8px 12px;font-weight:600;text-decoration:none}
.skip:focus{left:var(--gut)}
section[id],div[id]{scroll-margin-top:72px}
html{scroll-padding-top:72px}

/* nav: five plain words, the current one marked, the ask on the right */
.nav .in{padding:14px var(--gut);gap:14px}
.nav ul{gap:4px 18px;font-size:14px}
.nav ul a{padding:6px 0 4px;border-bottom:1.5px solid transparent;transition:border-color .25s,color .25s}
.nav ul a.cur{border-color:rgb(var(--ac));color:rgb(var(--ac))}
.nav .ask{padding:6px 12px 5px;border:1.5px solid rgb(var(--ac));border-radius:3px;color:rgb(var(--ac));border-bottom-width:1.5px!important}
.nav .ask:hover{background:rgb(var(--ac));color:rgb(var(--bg))}
@media (max-width:900px){
  .nav .in{flex-wrap:nowrap;align-items:center;padding:10px var(--gut)}
  .nav .brand{font-size:17px}
  .nav ul{width:auto;margin-left:auto;gap:12px;font-size:13px;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .nav ul::-webkit-scrollbar{display:none}
  .nav ul a{white-space:nowrap}
  .nav .ask{padding:5px 9px 4px}
}

/* the project switcher on a case page: where am I, what's next, how do I get back */
.subnav{position:sticky;top:50px;z-index:19;background:color-mix(in srgb,rgb(var(--bg)) 86%,transparent);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border-top:1px solid color-mix(in oklab,rgb(var(--ink)) 14%,rgb(var(--bg)));border-bottom:1px solid color-mix(in oklab,rgb(var(--ink)) 14%,rgb(var(--bg)))}
.subnav .in{max-width:var(--max);margin:0 auto;padding:9px var(--gut);display:flex;gap:18px;align-items:baseline;font-size:13.5px}
.subnav a{text-decoration:none;white-space:nowrap}
.subnav a:hover{color:rgb(var(--ac))}
.subnav .all{font-weight:600}
.subnav .where{color:color-mix(in oklab,rgb(var(--ink)) 70%,rgb(var(--bg)))}
.subnav .where b{color:rgb(var(--ink));font-weight:600}
.subnav .pn{margin-left:auto;display:flex;gap:16px}
.subnav .pn span{opacity:.55}
@media (max-width:900px){.subnav{top:44px}.subnav .where{display:none}}

/* the way in: four projects, one line, right under the promise */
.jump{display:flex;flex-wrap:wrap;gap:8px 10px;margin-top:clamp(22px,3vw,34px);font-size:14px}
.jump span{align-self:center;color:color-mix(in oklab,rgb(var(--ink)) 70%,rgb(var(--bg)));margin-right:4px}
.jump a{text-decoration:none;padding:7px 12px;border:1px solid color-mix(in oklab,rgb(var(--ink)) 30%,rgb(var(--bg)));border-radius:3px;transition:border-color .25s,color .25s}
.jump a:hover{border-color:rgb(var(--ac));color:rgb(var(--ac))}
.jump a b{font-weight:600}
.jump a i{font-style:normal;opacity:.65}

/* the headline is a link too, not just the small line under it */
.job h2 a{text-decoration:none}

/* the detail view: a way to the story from inside it, and a tap target that is a target */
.lb .bar .go{text-decoration:none;font-weight:600;color:rgb(var(--ac));margin-left:18px}
.lb .nav2 button{min-width:44px;min-height:40px}
.lb .x{min-width:44px;min-height:44px}
.story{min-height:40px}

/* case page: the ask is always one screen away */
.ask-band{padding:clamp(40px,6vw,80px) 0;position:relative}
.ask-band .in{max-width:var(--max);margin:0 auto;padding:0 var(--gut);display:grid;grid-template-columns:minmax(0,4.2fr) minmax(0,7.4fr);gap:clamp(20px,4vw,60px);align-items:center}
.ask-band h2{font-size:clamp(22px,2.6vw,34px);max-width:18ch}
.ask-band a.big{display:inline-block;font-size:clamp(20px,2.2vw,30px);font-weight:900;letter-spacing:-.03em;text-decoration:none;background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 2px no-repeat;transition:background-size .4s}
.ask-band a.big:hover{background-size:100% 100%;color:rgb(var(--bg))}
.ask-band p{margin:10px 0 0;font-size:15px;max-width:40em}
@media (max-width:900px){.ask-band .in{grid-template-columns:1fr}}

/* contact: the email is the action, the list is the help */
.contact .ways{display:flex;gap:10px 22px;flex-wrap:wrap;align-items:center;margin-top:18px;font-size:14.5px}
.contact .ways button{font:inherit;background:none;border:1px solid color-mix(in oklab,rgb(var(--ink)) 30%,rgb(var(--bg)));color:inherit;padding:7px 12px;border-radius:3px;cursor:pointer}
.contact .ways button:hover{border-color:rgb(var(--ac));color:rgb(var(--ac))}
/* phone: three words in the nav, arrows in the switcher, nothing clipped */
@media (max-width:600px){
  .nav ul li.lo{display:none}
  .nav ul{overflow:visible}
  .subnav .in{gap:12px}
  .subnav .pn a .nm{display:none}
  .subnav .pn a{font-weight:600}
  .jump a{padding:6px 10px;font-size:13.5px}
}

/* ===== hero, two columns on the sections' own grid ===== */
.hero .hgrid{display:grid;grid-template-columns:minmax(0,6.4fr) minmax(0,5.2fr);gap:clamp(28px,5vw,80px);align-items:end}
.hero .hgrid h1{font-size:clamp(42px,6.2vw,92px);max-width:none}
.hero .hside .sub{margin-top:0;font-size:clamp(16.5px,1.3vw,19.5px)}
.kept-mini{margin:clamp(20px,2.4vw,30px) 0 0;display:grid;gap:0;border-top:1px solid color-mix(in oklab,rgb(var(--ink)) 24%,rgb(var(--bg)))}
.kept-mini>div{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.5fr);gap:14px;padding:9px 0;border-bottom:1px solid color-mix(in oklab,rgb(var(--ink)) 14%,rgb(var(--bg)));font-size:14px;align-items:baseline}
.kept-mini dt a{text-decoration:none;font-weight:600}
.kept-mini dt a:hover{color:rgb(var(--ac))}
.kept-mini dd{margin:0;color:color-mix(in oklab,rgb(var(--ink)) 76%,rgb(var(--bg)))}
.kept-mini dd b{color:rgb(var(--ink));font-weight:900;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.hero .hside .avail{margin-top:18px;padding-top:14px;border-top:0;gap:8px 22px}
.hero .hside .avail a{text-decoration:none;font-weight:600;background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 1.5px no-repeat}
.hero .hside .avail a:hover{color:rgb(var(--ac))}
@media (max-width:900px){.hero .hgrid{grid-template-columns:1fr;gap:22px}.hero .hgrid h1{font-size:clamp(40px,10vw,64px)}.kept-mini>div{grid-template-columns:1fr;gap:2px}}

/* hero: headline top-aligned with the paragraph, and pinned while the first screen scrolls past */
.hero .hgrid{align-items:start;min-height:calc(100svh - 150px)}
.hero .hgrid h1{position:sticky;top:84px;align-self:start}
@media (max-width:900px){.hero .hgrid{min-height:0}.hero .hgrid h1{position:static}}
@media (prefers-reduced-motion:reduce){.hero .hgrid h1{position:static}}

/* 2026-11-07: the heading column of every two-column band and chapter (kicker, headline, lede)
   stays put while the longer column scrolls past, the way the hero headline does. Static on
   phones, where the columns stack, and under Reduce motion, matching the hero. */
.band .in>div:first-child,.chap .in>div:first-child{position:sticky;top:84px;align-self:start}
.chap .in>div:first-child{top:108px}
@media (max-width:900px){.band .in>div:first-child,.chap .in>div:first-child{position:static}}
@media (prefers-reduced-motion:reduce){.band .in>div:first-child,.chap .in>div:first-child{position:static}}

/* ===== case pages: the takeaway on the left, pinned; the details on the right ===== */
.case-hero .hgrid{display:grid;grid-template-columns:minmax(0,6.4fr) minmax(0,5.2fr);gap:clamp(28px,5vw,80px);align-items:start;min-height:calc(100svh - 190px)}
.case-hero .hgrid h1{font-size:clamp(40px,5.8vw,86px);max-width:none;position:sticky;top:108px;align-self:start}
.case-hero .hside .spec{margin-bottom:18px}
.case-hero .hside .sub{margin-top:0;font-size:clamp(16.5px,1.3vw,19.5px)}
.case-hero .hside .kept-mini>div{grid-template-columns:minmax(0,1fr) minmax(0,2.2fr)}
.case-hero .hside .kept-mini dt{font-weight:600;font-size:14px}
.case-hero .hside .next-in{margin-top:18px;font-size:14px}
.case-hero .hside .next-in a{text-decoration:none;font-weight:600;background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 1.5px no-repeat}
@media (max-width:900px){.case-hero .hgrid{grid-template-columns:1fr;gap:22px;min-height:0}.case-hero .hgrid h1{position:static;font-size:clamp(36px,9vw,56px)}}
@media (prefers-reduced-motion:reduce){.case-hero .hgrid h1{position:static}}

/* ===== the work, shown at one height that fits the screen ===== */
:root{--shelf:clamp(300px,56vh,640px)}
.job{padding-top:clamp(48px,6vw,96px);padding-bottom:clamp(48px,6vw,96px)}
.job .in>*{min-width:0}
.media.rail{flex-direction:row;align-items:flex-start;gap:clamp(12px,1.6vw,22px);overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x proximity;padding-bottom:10px;scrollbar-width:thin;scrollbar-color:color-mix(in oklab,rgb(var(--ink)) 30%,rgb(var(--bg))) transparent;flex-wrap:nowrap}
.media.rail figure.shot{flex:0 0 auto;scroll-snap-align:start;display:flex;flex-direction:column;max-width:100%}
.media.rail figure.shot .fr{height:var(--shelf);max-height:none}
.media.rail figure.shot img{height:100%;width:auto;max-width:none;display:block}
.media.rail figcaption{width:0;min-width:100%;max-width:none}
.media.rail+.story,.media.rail+.mute{margin-top:8px}
.rail-hint{font-size:12.5px;margin:4px 0 0;color:color-mix(in oklab,rgb(var(--ink)) 60%,rgb(var(--bg)))}
@media (hover:none){.media.rail{scroll-snap-type:x mandatory}}

/* case pages: nothing stands taller than the screen */
.full .media figure.shot .fr{max-height:calc(100svh - 200px);display:flex;justify-content:center}
.full .media figure.shot img{max-height:calc(100svh - 200px);width:auto;max-width:100%;object-fit:contain}
@media (max-width:900px){:root{--shelf:clamp(260px,52vh,520px)}.job .media,.job.flip .media{order:-1}}
.media.rail figure.shot.hid{display:none}

/* ===== every piece in a square: no tint, nothing cropped, grows into the square on hover ===== */
figure.shot .fr{background:none;aspect-ratio:1;display:grid;place-items:center;overflow:hidden}
figure.shot img{width:auto;height:auto;max-width:94%;max-height:94%;object-fit:contain;transition:transform .55s cubic-bezier(.2,.7,.2,1)}
figure.shot:hover img{transform:scale(1.064)}
figure.shot .fr::after{background:none;color:rgb(var(--ac));font-size:18px}
/* the rail: squares sized from the column, two in view and the next one showing its edge */
.media.rail figure.shot{flex:0 0 clamp(240px,56%,var(--shelf))}
.media.rail figure.shot .fr{height:auto;width:100%}
.media.rail figure.shot img{height:auto;width:auto;max-width:94%;max-height:94%}
/* case pages: squares that never exceed the screen */
.full .media figure.shot .fr{max-height:none;max-width:calc(100svh - 220px);width:100%;margin:0 auto}
.full .media figure.shot img{max-height:94%}
.full .media figure.shot figcaption{max-width:calc(100svh - 220px);margin-left:auto;margin-right:auto}
@media (max-width:900px){.media.rail figure.shot{flex-basis:clamp(220px,72%,var(--shelf))}}

/* ===== pass seven: no arrows, no sideways scroll, marks restored, the rest pictured ===== */
figure.shot .fr::after{display:none}
/* squares apply to project media only — the marks grid keeps its own tiles */
.grid figure .fr{aspect-ratio:auto;display:block;height:100%;overflow:hidden}
.grid img{width:100%;height:100%;max-width:none;max-height:none;object-fit:cover;transition:none}
.grid figure:hover img{transform:none}
/* a project's work: a fixed 2 × 2 of squares, the rest in the viewer */
.media.four{display:grid;grid-template-columns:1fr 1fr;gap:clamp(12px,1.6vw,20px);overflow:visible}
.media.four figure.shot{display:block}
.media.four figure.shot .fr{width:100%}
.media.four figcaption{display:none}
.media.four figure.shot.hid{display:none}
/* the rest of it: one tile per group, three across */
.media.three{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.6vw,20px);overflow:visible}
.media.three figure.shot{display:block}
.media.three figcaption{font-size:12.5px;margin-top:7px}
.media.three figcaption b{display:block;font-size:13.5px}
.media.three figure.shot.hid{display:none}
@media (max-width:900px){.media.three{grid-template-columns:1fr 1fr}}
@media (max-width:480px){.media.four{grid-template-columns:1fr 1fr}.media.three{grid-template-columns:1fr 1fr}}

/* ===== pass eight ===== */
.hero .hgrid,.case-hero .hgrid{min-height:0}
/* grids live inside the media block again, so buttons and captions stay with their pictures */
.media .four{display:grid;grid-template-columns:1fr 1fr;gap:clamp(12px,1.6vw,20px)}
.media .four figure.shot{display:block}.media .four figure.shot .fr{width:100%}.media .four figcaption{display:none}.media .four figure.shot.hid{display:none}
.media .three{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.6vw,20px)}
.media .three figure.shot{display:block}.media .three figcaption{font-size:12.5px;margin-top:7px}.media .three figcaption b{display:block;font-size:13.5px}.media .three figure.shot.hid{display:none}
@media (max-width:900px){.media .three{grid-template-columns:1fr 1fr}}
/* wide sheets and the process band keep their own proportions */
figure.shot.wide .fr,.proc figure.shot .fr{aspect-ratio:auto;display:block}
figure.shot.wide img,.proc figure.shot img{width:100%;max-width:100%;max-height:none;height:auto}
figure.shot.wide:hover img,.proc figure.shot:hover img{transform:none}
.proc .quad figure.shot .fr,.proc .trio figure.shot .fr{aspect-ratio:1;display:grid}
.proc .quad figure.shot img,.proc .trio figure.shot img{width:auto;max-width:94%;max-height:94%}
.proc .quad figure.shot:hover img,.proc .trio figure.shot:hover img{transform:scale(1.064)}
/* headline sizes so the takeaway breaks in three lines, not five */
.hero .hgrid h1{font-size:clamp(40px,5.4vw,80px)}
.case-hero .hgrid h1{font-size:clamp(36px,4.9vw,72px)}
.foot a{text-decoration:none}.foot a:hover{color:rgb(var(--ac))}

/* pass nine: step lists in the case studies are prose under small heads */
.did h3{font-size:clamp(18px,1.9vw,23px);margin-top:clamp(22px,2.6vw,32px);max-width:24ch}
.did h3:first-child{margin-top:0}
.chap .body .did p{margin:8px 0 0;font-size:17px}
.job .media .jobfacts{font-size:15px;gap:12px 22px;align-self:center}

/* pass eleven: the viewer fits the picture to the stage. Percent sizes inside a grid cell
   resolve against nothing, so the picture ran at natural size; absolute positioning makes
   the stage the containing block and max-width/height mean what they say. */
.lb .stage{position:relative;min-height:0;padding:0}
.lb .stage img{position:absolute;top:0;bottom:0;left:var(--gut);right:var(--gut);margin:auto;width:auto;height:auto;max-width:calc(100% - 2*var(--gut));max-height:100%;object-fit:contain}
.hero .offer{margin:14px 0 0;font-size:14.5px;line-height:1.7;color:color-mix(in oklab,rgb(var(--ink)) 82%,rgb(var(--bg)))}
.hero .offer a{text-decoration:none;font-weight:600;color:rgb(var(--ink));background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 1px no-repeat}
.hero .offer a:hover{color:rgb(var(--ac))}

/* pass twelve: image slots after Work, drawn as briefs until the pictures exist */
figure.shot.ph{cursor:default}
figure.shot.ph .fr{aspect-ratio:1;border:1.5px dashed color-mix(in oklab,rgb(var(--ac)) 55%,transparent);background:color-mix(in oklab,rgb(var(--ink)) 4%,rgb(var(--bg)));display:grid;place-items:center;padding:12px;text-align:center}
figure.shot.ph .fr::after{display:none}
figure.shot.ph .fr span{font-size:12px;line-height:1.4;max-width:24ch;color:color-mix(in oklab,rgb(var(--ink)) 72%,rgb(var(--bg)))}
figure.shot.ph .fr span b{display:block;font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:rgb(var(--ac));margin-bottom:5px;font-weight:600}
figure.shot.ph.wide .fr{aspect-ratio:2}
.svc article>div{min-width:0}
/* the four stages, on a rail */
.tl{--g:clamp(14px,1.8vw,26px);list-style:none;margin:0;padding:0;position:relative;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--g)}
.tl::before{content:"";position:absolute;left:6px;right:calc((100% - 3*var(--g))/4 - 6px);top:5px;height:2px;background:currentColor;opacity:.22}
.tl li{position:relative;padding-top:24px}
.tl li::before{content:"";position:absolute;left:0;top:0;width:12px;height:12px;border-radius:50%;background:rgb(var(--ac))}
.tl li:last-child::before{background:none;border:2.5px solid rgb(var(--ac))}
.tl .st{font-size:12px;font-weight:900;letter-spacing:.12em;color:rgb(var(--acq));opacity:.8}
.tl h3{font-size:clamp(17px,1.7vw,20px);margin:4px 0 0;letter-spacing:-.02em}
.tl p{margin:8px 0 0;font-size:15px}
@media (max-width:860px){
  .tl{grid-template-columns:1fr;gap:22px}
  .tl::before{display:none}
  .tl li:not(:last-child)::after{content:"";position:absolute;left:5px;top:6px;bottom:-22px;width:2px;background:currentColor;opacity:.22}
  .tl li{padding:0 0 0 30px}
  .tl li::before{top:4px}
}
.proc .ex.tight{grid-template-columns:minmax(0,3fr) minmax(0,6.4fr);gap:clamp(16px,2vw,28px)}
.proc .trio.pair{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(12px,1.6vw,20px)}
.proc .trio.pair figure.shot .fr{aspect-ratio:3/4}
@media (max-width:900px){.proc .ex.tight{grid-template-columns:1fr}}
.rules .dia{margin:0 0 16px;width:120px;height:44px;color:rgb(var(--ac))}
.rules .dia svg{display:block;width:100%;height:100%;overflow:visible}
.band #about .in>div:first-child figure.shot,.band .in>div:first-child figure.shot.ph{margin-top:clamp(22px,3vw,40px);max-width:300px}
#about .facts+figure.shot{margin-top:26px;max-width:420px}
@media (max-width:640px){
}
/* sampler: pieces as page frames */
.sheet{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:clamp(14px,2vw,24px)}
.sheet figure.shot.ph.page .fr{aspect-ratio:3/4}
.sheet figure.shot.ph.wide{grid-column:span 2}
.sheet figure.shot.ph.wide .fr{aspect-ratio:2}
.sheet figcaption b{display:block}
@media (max-width:480px){.sheet{grid-template-columns:1fr 1fr}.sheet figure.shot.ph.wide{grid-column:1/-1}}

/* pass twenty-seven: the address is base64 in one attribute and decoded by the script (shared.js)
   into two spans; the @ between them is drawn here, so it is never in the page text. Without
   scripts the link reads as an invitation rather than an address */
a.mail:empty::after{content:"Email me"}
a.mail .u::after{content:"\0040"}
/* the copy button after the address: two squares, a tooltip above, "Copied" for a moment after a click */
.cp{position:relative;display:inline-flex;align-items:center;justify-content:center;width:1.35em;height:1.35em;margin-left:.35em;padding:0;border:0;border-radius:.2em;background:none;color:inherit;opacity:.55;cursor:pointer;vertical-align:-.15em;font:inherit;line-height:1;transition:opacity .2s,color .2s}
.cp svg{width:.8em;height:.8em}
.cp:hover,.cp:focus-visible{opacity:1;color:rgb(var(--ac));outline:none}
.cp.did{opacity:1;color:rgb(var(--ac))}
.cp::after{content:attr(data-tip);position:absolute;left:50%;bottom:calc(100% + 8px);transform:translate(-50%,4px);white-space:nowrap;font-size:12.5px;font-weight:600;letter-spacing:0;line-height:1;padding:6px 9px;border-radius:5px;background:rgb(var(--ink));color:rgb(var(--bg));opacity:0;pointer-events:none;transition:opacity .18s,transform .18s}
.cp::before{content:"";position:absolute;left:50%;bottom:calc(100% + 3px);transform:translateX(-50%);border:5px solid transparent;border-top-color:rgb(var(--ink));border-bottom:0;opacity:0;transition:opacity .18s;pointer-events:none}
.cp:hover::after,.cp:focus-visible::after,.cp.did::after{opacity:1;transform:translate(-50%,0)}
.cp:hover::before,.cp:focus-visible::before,.cp.did::before{opacity:1}
.contact a.big+.cp{font-size:clamp(14px,1.6vw,21px);vertical-align:.1em;margin-left:.5em}
.ask-band a.big+.cp{font-size:clamp(13px,1.4vw,19px);vertical-align:.1em;margin-left:.5em}
.mw{white-space:nowrap}
.hero .avail .cp{font-size:1em}

/* ---- shelf tiles that have their own page (pass seventeen) ---- */
.media .three figcaption b a{color:inherit;text-decoration:none}
.media .three figcaption b a:hover{text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:3px}
.media .three figure.shot[data-case]{cursor:pointer}
.media .three figure.shot[data-case] .fr::after{display:none}
.media .three figcaption .rd{display:block;margin-top:6px;font-weight:600;color:rgb(var(--ac));text-decoration:none}
.media .three figcaption .rd::after{content:" →"}
.media figure.shot.ph.page .fr{aspect-ratio:3/4}
.full .media figure.shot.ph .fr{max-height:none}

/* ===== 2026-11-01: pictures are never cropped ===== */
/* square tiles: the picture sits inside the frame at 94% and keeps its own proportions */
figure.shot .fr{position:relative}
figure.shot img{position:absolute;inset:3%;width:94%;height:94%;max-width:none;max-height:none;object-fit:contain}
figure.shot.wide img,.proc figure.shot img,.media.rail figure.shot img,.full .media figure.shot img{position:static;inset:auto;width:100%;height:auto;max-width:100%;max-height:none}
.proc .quad figure.shot img,.proc .trio figure.shot img{position:absolute;inset:3%;width:94%;height:94%}
.full .media figure.shot img{width:auto;max-height:calc(100svh - 200px)}
.media.rail figure.shot img{width:auto;max-width:94%}
/* the marks: whole tile, never cover */
.grid img{position:static;inset:auto;width:100%;height:100%;object-fit:contain;background:#fff}
/* case and project pages: every picture whole, at its own proportion; only a lone full-width picture is capped to the screen */
.full .media figure.shot .fr{aspect-ratio:auto;display:block;max-height:none;max-width:none;overflow:visible}
.full .media figure.shot img{position:static;inset:auto;width:100%;height:auto;max-width:100%;max-height:none;object-fit:contain}
.full .media figure.shot:hover img{transform:none}
.full .media>figure.shot{max-width:calc(100svh - 220px);margin-left:auto;margin-right:auto;width:100%}
.full .media .pair figure.shot,.full .media .trio figure.shot{align-self:start}

/* project pages: the pieces live inside the story, description beside each */
.chap.pics .body{max-width:none}
.chap.pics .body>p{max-width:34em}
.chap .pc{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:clamp(16px,2.2vw,30px);align-items:center;margin:clamp(18px,2.4vw,30px) 0}
.chap .pc .fr{aspect-ratio:auto;display:block;overflow:visible}
.chap .pc img{position:static;inset:auto;width:100%;height:auto;max-width:100%;max-height:none;object-fit:contain}
.chap .pc figcaption{margin-top:0;font-size:15.5px;max-width:36ch}
.chap .pc.flip .fr{order:2}
.chap .pc.ph .fr{aspect-ratio:4/3}
.chap .pc+.pc{margin-top:clamp(22px,2.8vw,36px)}
@media (max-width:760px){
  .chap .pc{grid-template-columns:1fr;gap:12px}
  .chap .pc.flip .fr{order:0}
  .chap .pc figcaption{margin-top:6px;max-width:none}
}

/* case studies: a set of thumbnails with one description beside them */
.chap .pcset{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:clamp(16px,2.2vw,30px);align-items:center;margin:clamp(22px,2.8vw,36px) 0}
.chap .pcset .g4{display:grid;grid-template-columns:1fr 1fr;gap:clamp(8px,1.2vw,14px)}
.chap .pcset figure.shot .fr{aspect-ratio:auto;display:block}
.chap .pcset figure.shot img{position:static;inset:auto;width:100%;height:auto;max-width:100%;max-height:none;object-fit:contain}
.chap .pcset figcaption{font-size:12.5px;margin-top:6px}
.chap .pcset .pcnote{font-size:15.5px;max-width:36ch;color:color-mix(in oklab,rgb(var(--ink)) 80%,rgb(var(--bg)))}
.chap .pcset .pcnote b{color:rgb(var(--ink));font-weight:600}
.chap .pcset.flip .g4{order:2}
.chap .body .did .pc,.chap .body .did .pcset{margin-left:0}
@media (max-width:760px){.chap .pcset{grid-template-columns:1fr}.chap .pcset.flip .g4{order:0}}
/* a row of small pictures that wraps: five pins at 30% each read as three then two */
.chap .pcset .gf{display:flex;flex-wrap:wrap;justify-content:center;gap:clamp(8px,1.2vw,14px)}
.chap .pcset .gf figure.shot{flex:0 0 calc(33.333% - 10px);text-align:center}
.chap .pcset .gf.three figure.shot{flex-basis:calc(33.333% - 10px)}
.chap .pcset.flip .gf{order:2}
@media (max-width:760px){.chap .pcset.flip .gf{order:0}}
/* the pins: one grid, every pin the same size, no words */
.chap .pingrid{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(10px,1.6vw,22px);margin:clamp(18px,2.4vw,30px) 0}
.chap .pingrid figure.shot .fr{aspect-ratio:1;display:grid;place-items:center;overflow:visible}
.chap .pingrid figure.shot img{position:static;width:auto;height:auto;max-width:88%;max-height:88%;object-fit:contain}
@media (max-width:900px){.chap .pingrid{grid-template-columns:repeat(3,1fr)}}
@media (max-width:560px){.chap .pingrid{grid-template-columns:repeat(2,1fr)}}
/* thumbnails: small, side by side, not in the viewer (chameleon.js skips .tn) */
.chap .tnrow{display:flex;flex-wrap:wrap;gap:clamp(12px,2vw,24px);margin:clamp(18px,2.4vw,30px) 0;align-items:start}
.chap .tnrow figure.shot{flex:1 1 0;min-width:140px;max-width:300px;cursor:default}
.chap .tnrow figure.shot .fr{aspect-ratio:auto;display:block;overflow:visible}
.chap .tnrow figure.shot img{position:static;width:100%;height:auto;max-width:100%;max-height:none;object-fit:contain}
.chap .tnrow figure.shot:hover img{transform:none}
.chap .tnrow figure.shot .fr::after{display:none}
.chap .tnrow figure.shot figcaption{font-size:12.5px;margin-top:6px}
.chap .tnrow figure.shot.ph .fr{aspect-ratio:900/726;padding:8px}
.chap .tnrow figure.shot.ph .fr span{font-size:11px}
.chap .body>p.tnline{font-size:14px;max-width:none;margin-top:-6px;color:color-mix(in oklab,rgb(var(--ink)) 70%,rgb(var(--bg)))}

/* ===== 2026-11-03: a shelf tile opens the set its caption names ===== */
/* the wrapper groups the pictures for the viewer and stays out of the layout */
.gset{display:contents}

/* ===== 2026-11-04: sides that alternate, and rows that are never half empty ===== */

/* Every other job band puts the pictures on the right. `.flip` used to only re-order
   the two cells, so the media still landed in the narrow first track and all three
   bands read the same way down the page. The track widths swap with the order now. */
.job.flip .in{grid-template-columns:minmax(0,7fr) minmax(0,4.6fr)}
.job.flip .media{order:0}
@media (max-width:900px){.job.flip .in{grid-template-columns:1fr}.job.flip .media{order:-1}}

/* Same thing inside a story page: a flipped row kept the picture but handed it the
   narrower track, so alternating rows were not the same size. */
.chap .pc.flip{grid-template-columns:minmax(0,1fr) minmax(0,1.25fr)}
.chap .pcset.flip{grid-template-columns:minmax(0,1fr) minmax(0,1.25fr)}
@media (max-width:760px){.chap .pc.flip,.chap .pcset.flip{grid-template-columns:1fr}}

/* Four rules: four across, then two, then one. The old auto-fit went through three,
   which left the fourth rule alone beside a hole. */
.rules ul,.rules ol{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:1100px){.rules ul,.rules ol{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:560px){.rules ul,.rules ol{grid-template-columns:1fr}}

/* The shelf: eight tiles, so three across always ended on a short row. Four, then two. */
.media .three,.media.three{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:1100px){.media .three,.media.three{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* 2026-11-06: the shelf is five tiles, so it goes three across with the TrippNT tile two columns wide (its picture is a few spreads side by side): 2+1 then 3 at width, 2 then 2+2 below 1100, one column on a phone. No short rows. */
#more .media .three{grid-template-columns:repeat(3,minmax(0,1fr))}
#more .media .three figure.shot.wide{grid-column:span 2}
@media (max-width:1100px){#more .media .three{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:480px){#more .media .three figure.shot.wide{grid-column:auto}}

/* The marks wall: fourteen tiles divide by seven and by two and by nothing else, so any
   other number of columns ends on a short row. It stays at seven until seven would be too
   small to read, then goes to two — never five across with four underneath. */
.marks .grid{grid-template-columns:repeat(7,minmax(0,1fr))}
@media (max-width:820px){.marks .grid{grid-template-columns:repeat(2,minmax(0,1fr))}}

/* The four stages stand up side by side only while they have room for a sentence. */
@media (max-width:1060px){
  .tl{grid-template-columns:1fr;gap:22px}
  .tl::before{display:none}
  .tl li:not(:last-child)::after{content:"";position:absolute;left:5px;top:6px;bottom:-22px;width:2px;background:currentColor;opacity:.22}
  .tl li{padding:0 0 0 30px}
  .tl li::before{top:4px}
}

/* ===== 2026-11-04: things arrive, and things leave ===== */

/* Pass one had one reveal: a band faded up once, on the way in, and then sat there.
   Where the browser can tie an animation to scroll position (Chrome, Edge), a band now
   fades up as it arrives and softens back out as it goes, so the page is always moving
   in the direction you are. Everywhere else the old reveal still runs, unchanged. */
/* 2026-11-07, last word: no scroll-driven reveals. Tying opacity to the scroll position
   meant a band's fade followed the wheel pixel by pixel and never read as an animation. Every
   reveal is now triggered: the script marks a thing once it is far enough up the screen and the
   transition below plays through on its own; scroll past it and the mark comes off, the way out
   plays quicker, and it is armed for the next time in either direction. */
/* the stagger: a set's items arrive one after another */
.stg>*,.stg>.gset>figure.shot{transition:opacity 1s cubic-bezier(.2,.7,.2,1) calc(var(--i,0) * 110ms),
                  transform 1s cubic-bezier(.2,.7,.2,1) calc(var(--i,0) * 110ms)}
.stg:not(.shown)>*,.stg:not(.shown)>.gset>figure.shot{opacity:0;transform:translateY(18px) scale(.97)}
.stg>.gset{opacity:1;transform:none;transition:none}
@media (prefers-reduced-motion:reduce){
  .stg>*,.stg:not(.shown)>*,.stg>.gset>figure.shot,.stg:not(.shown)>.gset>figure.shot{
    opacity:1;transform:none;transition:none;animation:none}
}

/* a lazy picture does not snap in: it fades once it has actually decoded */
figure.shot img{transition:transform .55s cubic-bezier(.2,.7,.2,1),opacity .45s ease}
figure.shot img.pend{opacity:0}
figure.shot img.ld{opacity:1}
@media (prefers-reduced-motion:reduce){figure.shot img.pend{opacity:1}}

/* the viewer closes the way it opened */
.lb.off{display:grid;animation:lbout .2s ease forwards}
@keyframes lbout{from{opacity:1}to{opacity:0}}
@media (prefers-reduced-motion:reduce){.lb.off{animation:none;display:none}}

/* ===== 2026-11-04: links ===== */
/* Four treatments, chosen in hover-lab.html. The shared idea: a highlight grows out of
   the underline it was already drawing, and the text turns over to the ground colour as
   it is covered — the reverse-text trick, done with one gradient and no second layer. */

/* 1. the wipe: an underline that draws itself in from the left. Nav and footer. */
.nav ul a{border-bottom:0;padding-bottom:3px;position:relative}
.nav ul a::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1.5px;
  background:rgb(var(--ac));transform:scaleX(0);transform-origin:0 50%;
  transition:transform .32s cubic-bezier(.2,.7,.2,1)}
.nav ul a:hover::after,.nav ul a:focus-visible::after,.nav ul a.cur::after{transform:none}
.nav ul a:hover{border-color:transparent}
.nav .ask{border-bottom:0!important}
.nav .ask::after{transform:none}

/* 2. the growing highlight with reverse text. The hero offer, Read the story, the footer. */
.hero .offer a,.more,.rd,.contact a.big,.foot a,.next a,.next-in a,.subnav .all{
  background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 1.5px no-repeat;
  transition:background-size .34s cubic-bezier(.2,.7,.2,1),color .22s ease .06s;
  padding:0 .14em;margin:0 -.14em}
.hero .offer a:hover,.more:hover,.rd:hover,.contact a.big:hover,.foot a:hover,
.next a:hover,.next-in a:hover,.subnav .all:hover,
.hero .offer a:focus-visible,.more:focus-visible,.rd:focus-visible,.foot a:focus-visible{
  background-size:100% 100%;color:rgb(var(--bg))}
.contact a.big{background-size:100% 2px}
.foot a{background-size:100% 1px}
.next a em,.contact a.big em,.more em{transition:color .22s ease .06s}
.next a:hover em,.contact a.big:hover em{color:rgb(var(--bg))}

/* 3. the arrow walks on. Anything that ends in one. */
.more,.rd,.story{position:relative}
.more::after{content:" →";display:inline-block;transition:transform .3s cubic-bezier(.2,.7,.2,1)}
.more:hover::after{transform:translateX(5px)}
.rd::after{display:inline-block;transition:transform .3s cubic-bezier(.2,.7,.2,1)}
.rd:hover::after{transform:translateX(5px)}
.story::after{display:inline-block;transition:transform .3s cubic-bezier(.2,.7,.2,1)}
.story:hover::after{transform:translateX(5px)}

/* 4. a picture that leads somewhere says so: the caption's name underlines with it */
figure.shot[data-case]:hover figcaption b a{background-size:100% 100%;color:rgb(var(--bg))}
.media .three figcaption b a{text-decoration:none;
  background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 1.5px no-repeat;
  transition:background-size .34s cubic-bezier(.2,.7,.2,1),color .22s ease .06s;
  padding:0 .14em;margin:0 -.14em}
.media .three figcaption b a:hover{text-decoration:none;background-size:100% 100%;color:rgb(var(--bg))}
@media (prefers-reduced-motion:reduce){
  .nav ul a::after,.hero .offer a,.more,.rd,.contact a.big,.foot a,.next a,
  .more::after,.rd::after,.story::after,.media .three figcaption b a{transition:none}
}

/* ===== 2026-11-04: the phone is not "pictures, then words" ===== */
/* Until now every band collapsed the same way on a phone: the whole picture block, then
   the whole text block. Four bands in a row of that and a skimmer has scrolled past
   twelve pictures before reading a sentence. Three layouts, switchable from the mock bar
   so they can be compared on a real phone; A is the default.
     A  interleaved — client and headline, the pictures, then the detail and the link
     B  words first — the full write-up, pictures underneath
     C  pictures first — what the page did before                                      */
@media (max-width:900px){
  .job .in{gap:0}
  .job .media{margin:clamp(20px,5vw,30px) 0 0}
  .job .in>div:not(.media){display:contents}
  .job .spec{order:1}
  .job h2{order:2}
  .job .media,.job.flip .media{order:3}
  .job .lede{order:4;margin-top:clamp(18px,4vw,24px)}
  .job .hard{order:5}
  .job .more{order:6;justify-self:start}

  /* B: the argument whole, then the evidence */
  body[data-m="b"] .job .in>div:not(.media){display:block}
  body[data-m="b"] .job .media,body[data-m="b"] .job.flip .media{order:2;margin-top:clamp(22px,5vw,32px)}

  /* C: the pictures first, as it was */
  body[data-m="c"] .job .in>div:not(.media){display:block}
  body[data-m="c"] .job .media,body[data-m="c"] .job.flip .media{order:-1;margin:0 0 clamp(22px,5vw,32px)}

  /* a band of pictures and prose, same treatment: the heading leads, the lede follows it,
     and the pictures sit between the lede and whatever closes the band */
  .band .in{gap:clamp(20px,5vw,28px)}
  /* two pictures to a row is right on a phone; four on a 360px screen is a thumbnail sheet */
  .media .four,.media.four{grid-template-columns:1fr 1fr;gap:10px}
}
@media (max-width:560px){
  /* the marks wall and the shelf: one across, big enough to read, captions showing */
  .marks .grid{grid-template-columns:1fr}
  .marks .grid figure{aspect-ratio:2.4/1}
  .media .three,.media.three{grid-template-columns:1fr;gap:clamp(18px,5vw,26px)}
  .media .three figcaption,.media.three figcaption{font-size:14px}
  .media .three figcaption b,.media.three figcaption b{font-size:15.5px}
  /* a tile on its own row can carry its description beside the picture */
  .media .three>.gset>figure.shot:first-child,.media.three>.gset>figure.shot:first-child{
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:14px;align-items:center}
  .media .three>.gset>figure.shot:first-child figcaption{margin-top:0}
  /* the hero list: label over value, not a two-column squeeze */
  .hero .offer{line-height:1.9}
  .job h2{font-size:clamp(26px,8vw,36px)}
  .band h2,.marks h2,.rules h2{font-size:clamp(24px,7.4vw,34px)}
}

/* ===== 2026-11-04, later: the highlight on display type, and a footer that is a mark ===== */

/* Scott: the growing highlight should run on the bold headline links too — the ones whose
   coloured phrase ("eight brands") was the only thing that answered. At rest the phrase
   alone carries the accent rule, so the headline is not underlined three lines deep; on
   hover the whole headline fills and turns over, one box per line.

   Pass twenty-five, the clipping: an inline background covers the font's content area —
   for Figtree that is 1.2em, .95 above the baseline and .25 below — whatever the leading.
   At 1.06 leading the boxes overlap by .14em, and each line's box paints over the line
   before it, so on a two-line headline the descenders of line one vanished under line
   two. There is no way to paint line two under line one, so the box is trimmed instead:
   .03em of padding below the text, and the fill .11em short of the content area's top.
   Each fill then runs from .84em above the baseline to .28em below — ascenders and
   descenders clear by .06em each way — and the next line's fill starts exactly where
   this one stops, with no gap and no overlap. On a one-line headline nothing changes. */
.job h2,.band h2:has(a),.marks h2:has(a),.chap h2:has(a){line-height:1.06}
.job h2 a,.band h2 a,.marks h2 a,.chap h2 a{
  text-decoration:none;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
  --fill:calc(100% - .11em);
  background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/0 var(--fill) no-repeat;
  padding:0 .07em .03em;margin:0 -.07em;
  transition:background-size .42s cubic-bezier(.2,.7,.2,1),color .24s ease .08s}
/* Scott (pass twenty-five, second note): the phrase never carries a rule, and after a hover
   it must come back in the accent colour. It was not coming back on the Mac — the phrase's
   colour was transitioning towards rgb(var(--ac)) while the colour engine moved --ac every
   frame, and the transition never settled. So: no rule, and no transition on the phrase at
   all. It snaps to the page colour when the fill arrives and snaps back when it leaves;
   the fill itself still animates, which is the part the eye follows. */
.job h2 a em,.band h2 a em,.marks h2 a em,.chap h2 a em{
  background:none;text-decoration:none;color:rgb(var(--ac));transition:none}
.job h2 a:hover,.band h2 a:hover,.marks h2 a:hover,.chap h2 a:hover,
.job h2 a:focus-visible,.band h2 a:focus-visible,.marks h2 a:focus-visible{
  background-size:100% var(--fill);color:rgb(var(--bg))}
.job h2 a:hover em,.band h2 a:hover em,.marks h2 a:hover em,.chap h2 a:hover em,
.job h2 a:focus-visible em,.band h2 a:focus-visible em{color:rgb(var(--bg))}
@media (prefers-reduced-motion:reduce){
  .job h2 a,.band h2 a,.marks h2 a,.chap h2 a{transition:none}
}

/* Scott: "Read the story" sat too close to the paragraph above it. */
.more{margin-top:clamp(34px,4vw,50px);padding:.1em .14em;margin-left:-.14em}
.media .three figcaption .rd,.media.three figcaption .rd{margin-top:12px}
.chap .body .more,.full .more{margin-top:clamp(30px,3.4vw,42px)}

/* ===== the footer ===== */
/* Scott: the copyright line is not important and the three links add nothing — every one
   of them is already in the nav at the top of the same page. What is left is a sign-off:
   the wordmark, set small, with room around it. */
.foot{display:block;padding:clamp(26px,3.4vw,44px) 0 clamp(34px,4vw,54px);font-size:13px}
.foot .sig{display:inline-block;text-decoration:none;font-weight:900;font-size:17px;
  letter-spacing:-.04em;color:color-mix(in oklab,rgb(var(--ink)) 62%,rgb(var(--bg)));
  background:none;padding:0;margin:0;transition:color .25s ease}
.foot .sig b{color:rgb(var(--ac));font-weight:900;transition:color .25s ease}
.foot .sig:hover{color:rgb(var(--ink));background:none}

/* ===== 2026-11-04, later: two sheets on the page, fourteen on a page of their own ===== */
/* Scott: the wall of fourteen tiles becomes two real branding sheets here, with the rest
   on marks.html, a section per logo with what it had to solve. A wall proves range in one
   glance and explains nothing; two sheets show what a client actually receives. */
.marks .sheets{display:grid;grid-template-columns:1fr 1fr;gap:clamp(14px,2vw,26px);
  margin-bottom:clamp(24px,3vw,38px)}
.marks .sheets figure.shot{margin:0}
.marks .sheets figure.shot .fr{aspect-ratio:4/3;background:#fff;display:grid;place-items:center}
.marks .sheets figure.shot img{position:absolute;inset:7%;width:86%;height:86%;object-fit:contain}
.marks .sheets figure.shot.ph .fr{background:color-mix(in oklab,rgb(var(--ink)) 4%,rgb(var(--bg)))}
.marks .sheets figcaption{font-size:13.5px;margin-top:10px;max-width:40ch}
.marks .sheets figcaption b{display:block;font-size:15px;font-weight:600;color:rgb(var(--ink))}
@media (max-width:640px){.marks .sheets{grid-template-columns:1fr}}

/* the page of fourteen: one row per mark, sides alternating */
.msheet{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,6fr);
  gap:clamp(20px,3vw,48px);align-items:center;
  padding:clamp(26px,3.4vw,46px) 0;
  border-top:1px solid color-mix(in oklab,rgb(var(--ink)) 16%,rgb(var(--bg)))}
.msheet:first-of-type{border-top:0}
.msheet>figure.shot{margin:0}
.msheet figure.shot .fr{aspect-ratio:16/9;background:#fff;display:grid;place-items:center}
.msheet figure.shot img{position:absolute;inset:6%;width:88%;height:88%;object-fit:contain}
.msheet figcaption{display:none}
.msheet h2{font-size:clamp(23px,2.6vw,34px);letter-spacing:-.03em}
.msheet .kind{margin:7px 0 0;font-size:13px;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:rgb(var(--acq))}
.msheet dl{margin:18px 0 0;display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:9px 20px;font-size:15.5px}
.msheet dt{font-weight:600;color:rgb(var(--acq));white-space:nowrap}
.msheet dd{margin:0;max-width:44ch}
.msheet:nth-of-type(even)>figure.shot{order:2}
@media (max-width:820px){
  .msheet{grid-template-columns:1fr;gap:16px;padding:clamp(24px,5vw,34px) 0}
  .msheet:nth-of-type(even)>figure.shot{order:0}
  .msheet dl{grid-template-columns:1fr;gap:3px}
  .msheet dt{margin-top:10px}
}

/* ===== 2026-11-04, evening: more air above the link, the branding band, no footer ===== */
/* Scott, twice: "Read the story" still sits too close. Now a full step. */
.more{margin-top:clamp(48px,5.5vw,72px)}
.media .three figcaption .rd,.media.three figcaption .rd{margin-top:18px}
.chap .body .more,.full .more{margin-top:clamp(40px,4.6vw,60px)}
/* on a phone the link follows the hard-part block; same step there */
@media (max-width:900px){.job .more{margin-top:clamp(40px,9vw,56px)}}

/* the two reference sheets on the home page: letter-proportion frames, side by side, each
   one a plain link to the branding page with only the name under it. The frames hold the
   marks as stand-ins until the real sheets exist, so the picture sits small inside. */
.media .pair.refs{gap:clamp(14px,2vw,26px);align-items:start}
.media .pair.refs .ref{display:block;text-decoration:none;color:inherit;cursor:pointer;background:none;padding:0;margin:0}
.media .pair.refs .ref .fr{display:block;position:relative;overflow:hidden;aspect-ratio:8.5/11;background:#fff}
.media .pair.refs .ref img{position:absolute;inset:0;width:100%;height:100%;padding:12%;object-fit:contain;transition:transform .55s cubic-bezier(.2,.7,.2,1)}
.media .pair.refs .ref:hover img{transform:scale(1.04)}
.media .pair.refs .ref .cap{display:block;width:fit-content;margin-top:10px;font-size:13.5px;font-weight:600;color:rgb(var(--ink));
  background:linear-gradient(rgb(var(--ac)),rgb(var(--ac))) 0 100%/100% 1.5px no-repeat;padding:0 .14em;margin-left:-.14em;
  transition:background-size .34s cubic-bezier(.2,.7,.2,1),color .34s ease}
.media .pair.refs .ref:hover .cap,.media .pair.refs .ref:focus-visible .cap{background-size:100% 100%;color:rgb(var(--bg))}
@media (max-width:480px){.media .pair.refs{grid-template-columns:1fr 1fr;gap:10px}.media .pair.refs .ref .cap{font-size:12.5px}}

/* the branding page: two full packages as job bands, then the rest as a quiet grid */
.logos{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(14px,2vw,24px) clamp(12px,1.6vw,20px)}
.logos figure.shot{margin:0}
.logos figure.shot .fr{aspect-ratio:16/10;background:#fff}
.logos figure.shot img{inset:8%;width:84%;height:84%}
.logos figcaption{font-size:13px;margin-top:9px;max-width:none}
.logos figcaption b{display:block;font-size:14.5px;font-weight:600}
@media (max-width:1100px){.logos{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (max-width:700px){.logos{grid-template-columns:repeat(2,minmax(0,1fr))}}
.job .media .pair.pkg figure.shot .fr{aspect-ratio:4/3}
.job .media .pair.pkg figure.shot:not(.ph) .fr{background:#fff}
.job .media .pair.pkg figure.shot img{inset:8%;width:84%;height:84%}

/* ===== 2026-11-04, night: the branding page, every entry an alternating row ===== */
/* Three full packages as job bands (left, right, left), then eleven simple rows that keep
   the alternation going: the first simple row puts its picture on the right. */
.logos-list{padding-bottom:clamp(40px,5.5vw,76px)}
.logos-list .msheet{border-top:0;padding:clamp(22px,3vw,40px) 0}
.logos-list .msheet:nth-of-type(odd)>figure.shot{order:2}
.logos-list .msheet:nth-of-type(even)>figure.shot{order:0}
.logos-list .msheet figure.shot .fr{aspect-ratio:16/10}
.logos-list .msheet .blurb{margin:12px 0 0;font-size:16px;max-width:40ch}
.logos-list .msheet h2{font-size:clamp(22px,2.4vw,30px)}
@media (max-width:820px){.logos-list .msheet:nth-of-type(odd)>figure.shot{order:0}}

/* ===== 2026-11-04, late: the branding page stays side by side at every width ===== */
/* Scott saw the rows stacked, picture on top and too big. On this page the picture never
   goes above the words: the simple rows are a smaller picture beside the blurb at any
   width, and the package bands keep the mark beside the text on a phone too, with the
   sheet frame tucked under the mark instead of the whole band collapsing. */
.logos-list .msheet{grid-template-columns:minmax(0,2fr) minmax(0,3fr);align-items:center;gap:clamp(18px,3vw,48px)}
.logos-list .msheet>figure.shot{max-width:420px;width:100%}
.logos-list .msheet:nth-of-type(odd)>figure.shot{order:2;justify-self:end}
.logos-list .msheet:nth-of-type(even)>figure.shot{order:0;justify-self:start}
@media (max-width:820px){
  .logos-list .msheet{grid-template-columns:minmax(0,2fr) minmax(0,3fr);gap:16px;padding:clamp(18px,4vw,28px) 0}
  .logos-list .msheet:nth-of-type(odd)>figure.shot{order:2}
  .logos-list .msheet h2{font-size:clamp(18px,4.6vw,24px)}
  .logos-list .msheet .kind{font-size:11px}
  .logos-list .msheet .blurb{font-size:14px;margin-top:8px}
}
@media (max-width:900px){
  .pkgs .job .in{grid-template-columns:minmax(0,2fr) minmax(0,3fr);gap:16px;align-items:start}
  .pkgs .job .in>div:not(.media){display:block}
  .pkgs .job .media,.pkgs .job.flip .media{order:0;margin:0}
  .pkgs .job.flip .media{order:2}
  .pkgs .job .media .pair.pkg{grid-template-columns:1fr;gap:10px}
  .pkgs .job .media figcaption{display:none}
  .pkgs .job h2{font-size:clamp(20px,5.2vw,28px)}
  .pkgs .job .lede,.pkgs .job .hard p{font-size:14.5px}
  .pkgs .job .spec{font-size:12px}
}

/* ===== 2026-11-07: motion at a finer grain ===== */
/* Until now a band arrived as one block. Now the words inside it arrive one after another
   (kicker, headline, lede, the hard part, the link), the rules draw themselves, and the
   first screen comes in as a cascade on load. Same easing, same direction, same restraint
   as the band reveal from 2026-11-04: things rise a little and fade in, nothing slides
   sideways or bounces. Everything is off under prefers-reduced-motion. */

/* a cascade: a column of words whose children arrive in order. It is a stagger set (.stg)
   with a gentler move, no scale, so type never looks like it is zooming. */
@keyframes arrive-text{
  0%{opacity:0;transform:translateY(14px)}
  100%{opacity:1;transform:none}
}
.stg.cas:not(.shown)>*{transform:translateY(14px)}

/* a set inside a cascade (the timeline, the services, the rules) arrives on its own terms,
   not twice */
.cas>.stg,.stg.cas:not(.shown)>.stg{opacity:1;transform:none;transition:none;animation:none}

/* the rules draw themselves as their band is revealed: the hard part's bar grows down,
   the spec's underline and the process timeline grow across */
.hard{border-left:0;position:relative}
.hard::before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:rgb(var(--ac));
  transform-origin:0 0;transition:transform 1s cubic-bezier(.2,.7,.2,1) .45s}
.stg:not(.shown) .hard::before{transform:scaleY(0)}
.spec{border-bottom:0;position:relative}
.spec::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:color-mix(in oklab,rgb(var(--ink)) 24%,rgb(var(--bg)));
  transform-origin:0 50%;transition:transform 1.1s cubic-bezier(.2,.7,.2,1) .2s}
.stg:not(.shown) .spec::after{transform:scaleX(0)}
.tl::before{transform-origin:0 50%;transition:transform 1.4s cubic-bezier(.2,.7,.2,1) .3s}
.tl:not(.shown)::before{transform:scaleX(0)}

/* the first screen: headline first, then the right column line by line. Pure CSS, so
   it needs no script and runs on a cold load as well as on a page change. */
@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
.hero .hgrid>h1,.case-hero .hgrid>h1{animation:rise .8s cubic-bezier(.2,.7,.2,1) both}
.hero .hside>*,.case-hero .hside>*{animation:rise .7s cubic-bezier(.2,.7,.2,1) both}
.hero .hside>:nth-child(1),.case-hero .hside>:nth-child(1){animation-delay:.14s}
.hero .hside>:nth-child(2),.case-hero .hside>:nth-child(2){animation-delay:.22s}
.hero .hside>:nth-child(3),.case-hero .hside>:nth-child(3){animation-delay:.30s}
.hero .hside>:nth-child(4),.case-hero .hside>:nth-child(4){animation-delay:.38s}
.hero .hside>:nth-child(5),.case-hero .hside>:nth-child(5){animation-delay:.46s}

/* the nav grows a hairline once the page has moved under it, so the sticky bar reads as
   a bar and not as the top of the page. Story pages have the subnav's rule already. */
.nav::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:color-mix(in oklab,rgb(var(--ink)) 16%,rgb(var(--bg)));opacity:0;transition:opacity .3s}
.nav.scrolled::after{opacity:1}
.nav:has(+.subnav)::after{display:none}
@keyframes navline{from{opacity:0}to{opacity:1}}
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    .nav::after{transition:none;animation:navline linear both;animation-timeline:scroll(root);animation-range:0 60px}
  }
}

@media (prefers-reduced-motion:reduce){
  .stg.cas:not(.shown)>*{transform:none}
  .hard::before,.spec::after,.tl::before,.stg:not(.shown) .hard::before,.stg:not(.shown) .spec::after,.tl:not(.shown)::before{transform:none;transition:none}
  .hero .hgrid>h1,.case-hero .hgrid>h1,.hero .hside>*,.case-hero .hside>*{animation:none}
  .nav::after{transition:none}
}

/* 2026-11-07, later: Scott wants the reveals later, slower, and every time. The timed path
   (words, and everything in a browser without scroll-driven animation) now un-reveals once a
   set has left the screen entirely, so it plays again on the way back; the scroll-driven bands
   and tiles already reverse and replay by themselves. The way out is quicker than the way in. */
.stg:not(.shown)>*,.stg:not(.shown)>.gset>figure.shot{transition-duration:.35s;transition-delay:0s}
.rv:not(.in){transition-duration:.35s}

/* 2026-11-07, phone pass: the shelf's three-across rule (2026-11-06) outranked the phone's
   one-column rule, so a phone got two cramped columns with every caption squeezed beside a
   thumbnail. One column below 560px, as intended; the TrippNT frame runs full width with
   its caption beneath, the other tiles keep picture beside caption. */
@media (max-width:560px){
  #more .media .three{grid-template-columns:1fr}
  #more .media .three figure.shot.ph.wide{grid-column:auto;display:block}
  #more .media .three figure.shot.ph.wide figcaption{margin-top:10px}
}
/* the shelf's "Read the story" is a block so it sits on its own line, but its underline then
   ran the whole column: shrink it to the words */
.media .three figcaption .rd,.media.three figcaption .rd{display:table}
/* a band whose media is one composite picture: the frame follows the picture, not a square */
.media .one figure.shot .fr{aspect-ratio:1600/1232}
.media .one figure.shot img{max-width:100%;max-height:100%}
.media .one figcaption{display:none}
