/* Self hosted, one variable file per family (Google's own latin subset, OFL).
   Three origins used to sit between the visitor and the first line of type. */
@font-face{font-family:"Outfit";font-style:normal;font-weight:100 900;font-display:swap;src:url("assets/fonts/outfit-latin.woff2") format("woff2")}
@font-face{font-family:"Inconsolata";font-style:normal;font-weight:200 900;font-display:swap;src:url("assets/fonts/inconsolata-latin.woff2") format("woff2")}
:root{
  /* Colour is named by role, because dark mode moves the roles in opposite
     directions. The page is --paper and --ink. The four surfaces that mean
     "opposite the page" redefine that pair for their subtree, so everything
     inside them keeps saying paper for ground and ink for text and gets the
     flipped values for free. In dark mode the band override changes with the
     page and those bands become light, because inverted was always relative
     to the page rather than a synonym for black.
     --on-accent never moves, because the accent never moves. */
  --paper:#fff;
  --ink:#0a0a0a;
  --ground:#f2f2f2;
  --rule:#e0e0e0;
  --ink-soft:#666;
  --ink-mid:#666;
  --accent:#fe5621;
  --accent-ink:#b33600;
  --on-accent:#0a0a0a;
  /* The fixed header sits outside every band, so it cannot inherit from the
     band it happens to be over. It carries its own reversed pair. */
  --rev-ink:#fff;
  --rev-plate:#0a0a0a;
  /* The menu trigger's bars are drawn in currentColor over arbitrary artwork
     and read by a halo in the opposite ink. */
  --halo:rgba(255,255,255,.92);
  --halo-rev:rgba(10,10,10,.92);
  /* The hairline that defines a media card's edge where the image runs pale. */
  --frame:rgba(10,10,10,.08);
  --logo-invert:0;
  --logo-invert-rev:1;
  /* The scrim behind the nav panel, and the edge the panel needs on a dark
     ground where its drop shadow does no work. */
  --scrim:rgba(0,0,0,.18);
  --panel-edge:transparent;
  color-scheme:light dark;
  --sans:'Outfit',system-ui,sans-serif;
  --mono:'Inconsolata',ui-monospace,monospace;
  --gutter:clamp(20px,10.625vw,204px);
  --radius-card:28px;
  --ease:cubic-bezier(.16,1,.3,1);
  --ease-viscous:cubic-bezier(.22,1,.36,1);
  --ease-in:cubic-bezier(.76,0,.24,1);
  --gap:clamp(20px,1.25vw,24px);
  /* The rail and the answer beside it: wider than the card gap, so a print or
     a clip in the rail never bumps the text. */
  --rail-gap:clamp(40px,4.167vw,80px);
}

/* The closed set of inverted bands. Nothing else flips. */
.footer,.chapter-now,.venture-statement,.card-special{
  --paper:#0a0a0a;
  --ink:#fff;
  --ink-soft:#aaa;
  --ink-mid:#bdbdbd;
  --accent-ink:#fe5621;
  --rule:rgba(255,255,255,.22);
}
.card-special{--paper:#111213}
@media (prefers-color-scheme:dark){

/* ---------------------------------------------------------------- dark mode
   Pure #fff on #0a0a0a halates on display type this large, so the ground
   lifts and the ink drops: 14.74:1, still two stops above AAA. The greys
   carry a slight warm bias, two to six units, which is below the threshold
   in isolation and only does work in adjacency, next to an accent that
   appears at 260px. --accent itself never changes; dark mode improves it as
   text from 3.20:1 to 5.90:1, so there is nothing to rescue. --accent-ink
   reverses direction, because on light it existed to rescue the accent
   against white and on dark that job is gone. */
:root:not([data-theme=light]){
  --paper:#121110;
  --ink:#e6e3de;
  --ground:#1c1b19;
  --rule:#2e2c29;
  --ink-soft:#8c8983;
  --ink-mid:#8c8983;
  --accent-ink:#ff7a4d;
  --rev-ink:#121110;
  --rev-plate:#deDad4;
  --halo:rgba(18,17,16,.96);
  --halo-rev:rgba(222,218,212,.96);
  --frame:rgba(230,227,222,.10);
  --logo-invert:1;
  --logo-invert-rev:0;
  --scrim:rgba(0,0,0,.5);
  --panel-edge:var(--rule);
  color-scheme:dark;
}
:root:not([data-theme=light]) :is(.footer,.chapter-now,.venture-statement,.card-special){
  --paper:#deDad4;
  --ink:#121110;
  --ground:#2a2724;
  --ink-soft:#3a3733;
  --ink-mid:#2a2724;
  --rule:rgba(18,17,16,.22);
  --accent-ink:#a83200;
}
:root:not([data-theme=light]) .card-special{--paper:#deDad4}
/* The pill is the loudest accent moment on the site and on cream it goes
   soft. One border, using a property the button already declares. */
:root:not([data-theme=light]) .footer .btn-accent{border-color:var(--ink)}
}

/* ---------------------------------------------------------------- dark mode
   Pure #fff on #0a0a0a halates on display type this large, so the ground
   lifts and the ink drops: 14.74:1, still two stops above AAA. The greys
   carry a slight warm bias, two to six units, which is below the threshold
   in isolation and only does work in adjacency, next to an accent that
   appears at 260px. --accent itself never changes; dark mode improves it as
   text from 3.20:1 to 5.90:1, so there is nothing to rescue. --accent-ink
   reverses direction, because on light it existed to rescue the accent
   against white and on dark that job is gone. */
:root[data-theme=dark]{
  --paper:#121110;
  --ink:#e6e3de;
  --ground:#1c1b19;
  --rule:#2e2c29;
  --ink-soft:#8c8983;
  --ink-mid:#8c8983;
  --accent-ink:#ff7a4d;
  --rev-ink:#121110;
  --rev-plate:#deDad4;
  --halo:rgba(18,17,16,.96);
  --halo-rev:rgba(222,218,212,.96);
  --frame:rgba(230,227,222,.10);
  --logo-invert:1;
  --logo-invert-rev:0;
  --scrim:rgba(0,0,0,.5);
  --panel-edge:var(--rule);
  color-scheme:dark;
}
:root[data-theme=dark] :is(.footer,.chapter-now,.venture-statement,.card-special){
  --paper:#deDad4;
  --ink:#121110;
  --ground:#2a2724;
  --ink-soft:#3a3733;
  --ink-mid:#2a2724;
  --rule:rgba(18,17,16,.22);
  --accent-ink:#a83200;
}
:root[data-theme=dark] .card-special{--paper:#deDad4}
/* The pill is the loudest accent moment on the site and on cream it goes
   soft. One border, using a property the button already declares. */
:root[data-theme=dark] .footer .btn-accent{border-color:var(--ink)}

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
::selection{background:var(--accent);color:var(--on-accent)}
html{overflow-x:hidden;scrollbar-width:none}
html::-webkit-scrollbar{display:none}
html.menu-open{overflow:hidden}
body{
  min-width:320px;
  overflow-x:hidden;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--sans);
  font-size:16px;
  font-weight:500;
  line-height:1.4;
  font-kerning:normal;
  font-optical-sizing:auto;
  font-variant-ligatures:common-ligatures contextual;
  font-feature-settings:"kern" 1,"liga" 1,"clig" 1,"calt" 1;
  font-synthesis:none;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
h1,h2,h3{font-weight:500;text-wrap:balance}
p{ text-wrap:pretty }
a{color:inherit;text-decoration:none}
img,video{display:block;max-width:100%}
button{border:0;background:none;color:inherit;font:inherit;cursor:pointer}
[hidden]{display:none!important}
.skip-link{
  position:fixed;
  left:var(--gutter);
  top:16px;
  z-index:10002;
  transform:translateY(-200%);
  padding:12px 18px;
  border-radius:100px;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--mono);
  transition:transform .3s var(--ease);
}
.skip-link:focus{transform:none}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* Version 2 is an interview. The visitor's question sits before the answer
   in the mono at the muted weight, never bold, never a heading. A block
   question is its own line; an inline one opens a note or a deck. */
/* A speaker's line is set in ink; chrome stays in soft ink. Questions keep
   the mono at the site's muted weight and take ink, so a question and a
   section label never share a register. Selectors carry enough weight to
   win over pages.css, which loads later. */
.q,p.q,.page-eyebrow.q,.story-label.q,.chapter-now-label.q,.clients-label.q,.project-card-note .q,.page-deck .q,.page-pointer .q,.human-note .q{font-family:var(--mono);color:var(--ink);font-weight:400;letter-spacing:0}
p.q{font-size:clamp(16px,1.042vw,20px);line-height:1.3;margin:0 0 clamp(10px,.833vw,16px)}
p+p.q{margin-top:clamp(20px,1.667vw,32px)}
.project-card-note .q,.page-deck .q,.page-pointer .q,.human-note .q{display:block;margin-bottom:.35em}
.venture-list-wrap>p.q{margin-bottom:clamp(20px,1.667vw,32px)}
.footer-contacts-label .q,.contact-context-label .q{color:inherit;font-weight:400}
/* Placement where a section has its own grid: the question over the four
   names takes the names' row, the names step down one; the question over
   the pull quote centers above it; the Venture band's display size yields
   to the question size. */
.story-body p.q,.chapter-now-copy p.q{font-size:clamp(16px,1.042vw,20px);line-height:1.3}
/* A question sits close to its answer and a step away from the answer before it. */
.story-body p.q+p,.chapter-now-copy p.q+p{margin-top:.5em}
.story-body p+p.q,.chapter-now-copy p+p.q,.chapter-now-copy details+p.q{margin-top:clamp(32px,3.333vw,56px)}
.human-asks+.human-note{margin-top:clamp(32px,3.333vw,56px)}
.chapter-now-copy a{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.14em}
.chapter-now-copy a:hover{color:var(--ink-soft)}

/* The interview's follow-up questions are the visitor's to ask. Each one is a
   native <details>: the question is the summary, the answer opens beneath it.
   Works with JS off (every answer is one click away, no script needed); the
   script only animates the height. One hairline per question, a plus that
   turns into a cross. */
.ask{border-top:1px solid var(--rule)}
.ask:last-child{border-bottom:1px solid var(--rule)}
.ask>summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:clamp(18px,1.667vw,28px) 0;font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);line-height:1.3;font-weight:400;letter-spacing:0;color:var(--ink);-webkit-tap-highlight-color:transparent}
.ask>summary::-webkit-details-marker{display:none}
.ask>summary:focus-visible{outline:3px solid var(--accent);outline-offset:6px;border-radius:2px}
.ask-plus{position:relative;flex:0 0 auto;width:1.125em;height:1.125em;transition:transform .5s var(--ease)}
.ask-plus::before,.ask-plus::after{content:"";position:absolute;left:50%;top:50%;background:currentColor;transform:translate(-50%,-50%)}
.ask-plus::before{width:100%;height:1.5px}
.ask-plus::after{width:1.5px;height:100%}
.ask[open]>summary .ask-plus{transform:rotate(45deg)}
.ask>summary{transition:color .3s ease}
@media (hover:hover){.ask>summary:hover{color:var(--ink-soft)}}
/* The body clips only while its height is easing. At rest it lets the
   fanned prints lean past the row, the way they lean past the column. */
.ask-body{overflow:visible}
.ask.is-animating>.ask-body{overflow:clip;overflow-clip-margin:0 48px}
.ask-body>p{padding-bottom:clamp(28px,2.5vw,44px);font-size:clamp(22px,2.083vw,40px);line-height:1.2;text-wrap:pretty}
.js .ask-body{transition:height .55s var(--ease)}
@media (min-width:768px){
  .story .story-body,.chapter-now .chapter-now-copy{grid-column:1/-1}
  .ask>summary,.ask-body>p{padding-left:calc((100% - var(--rail-gap)) / 3 + var(--rail-gap))}
}
@media (prefers-reduced-motion:reduce){.ask-plus,.js .ask-body{transition:none}}
.venture-statement p.q{max-width:none;font-size:clamp(16px,1.042vw,20px);line-height:1.3;letter-spacing:0;margin:0 0 .35em}
.page-deck .q{font-size:clamp(16px,1.042vw,20px);line-height:1.3;display:block;margin-bottom:.35em}
.venture-statement p+p.q{margin-top:clamp(28px,2.5vw,48px)}

/* Neither Outfit nor Inconsolata ships U+2197, so the "↗" character these
   links used was painted by whatever the OS had: Menlo here, at .42 of the em,
   which is why the three arrow families each picked a different size trying to
   fix a glyph none of them owned. The mark is markup now, and its box is the
   cap height of the type beside it. .694em is Outfit's measured cap ratio, and
   a baseline aligned box sits bottom on baseline, so the mark spans exactly
   baseline to cap. No nudge, one number. */
.link-arrow{display:inline-block;vertical-align:baseline;width:.694em;height:.694em;overflow:visible;stroke-linecap:square;stroke-linejoin:miter}
/* The stroke matches the stem of the type it stands beside, measured off a
   painted capital I: Outfit Medium's stem is .163 of its cap, which is 2 units
   in this 12 unit box. Inconsolata Medium's is .134 of a .623em cap, so the one
   mark set in mono is both smaller and lighter, the way its neighbours are. */
.link-arrow{stroke-width:2}
.project-card-meta .link-arrow{width:.623em;height:.623em;stroke-width:1.6}
:focus-visible{outline:3px solid var(--accent);outline-offset:5px}
/* The skip link's target is focusable only so focus can land there; a
   ring drawn around the whole page body would be noise. Every real
   control keeps the ring above. */
main:focus{outline:none}
.footer :focus-visible,.chapter-now :focus-visible,.chapter-now .ask>summary:focus-visible{outline-color:var(--ink)}

.loader{
  position:fixed;
  inset:0;
  z-index:10000;
  display:none;
  place-items:center;
  background:#0a0a0a;
  transform:translateY(0);
  transition:transform .34s var(--ease),opacity .34s var(--ease);
}
.js:not(.reduced-motion) .loader{display:grid;animation:loader-failsafe .4s var(--ease) 1.4s forwards}
.loader.is-leaving{transform:translateY(-100%);opacity:.98;pointer-events:none}
.loader-mark{
  --loader-mark-size:clamp(52px,4.167vw,80px);
  position:relative;
  width:var(--loader-mark-size);
  aspect-ratio:1;
  transition:transform .3s var(--ease),opacity .2s ease;
}
.loader-mark img{
  width:100%;height:100%;object-fit:contain;filter:invert(1);
  opacity:0;
  transform:translateX(-6px) scale(.98);
  animation:loader-mark-settle .34s var(--ease) .04s both;
}
.loader-mark::before{
  content:"";
  position:absolute;
  inset:0;
  background:var(--accent);
  -webkit-mask:url("assets/le_monogram.webp") center/contain no-repeat;
  mask:url("assets/le_monogram.webp") center/contain no-repeat;
  opacity:0;
  transform:translateX(6px) scale(.98);
  animation:loader-mark-register .42s var(--ease) both;
}
.loader.is-leaving .loader-mark{transform:scale(1.045);opacity:0}
@keyframes loader-mark-settle{35%{opacity:1}to{opacity:1;transform:none}}
@keyframes loader-mark-register{28%{opacity:1}72%{opacity:.9;transform:none}to{opacity:0;transform:none}}
@keyframes loader-failsafe{to{transform:translateY(-100%);opacity:.98;visibility:hidden}}
.page-transition{
  position:fixed;
  inset:0;
  z-index:9990;
  display:grid;
  place-items:center;
  pointer-events:none;
}
.page-transition::before{
  content:"";
  position:absolute;
  inset:0;
  background:#0a0a0a;
  transform:scaleY(0);
  transform-origin:bottom;
}
/* The curtain is a black wipe and nothing else. It used to draw the monogram
   on itself as well, which meant the mark assembled twice per navigation:
   once on the way out of the page a visitor was leaving, and again on the
   loader of the page arriving. It assembles once now, on arrival, and the
   wipe is 420ms of black, which is what the 440ms navigation delay in
   inner.js is covering. */
.page-transition.is-covering::before{animation:page-cover .42s var(--ease) both}
@keyframes page-cover{to{transform:scaleY(1)}}

/* The custom cursor lives in motion.css, one vocabulary for all six pages. */

.header{
  position:fixed;
  inset:0 0 auto;
  z-index:300;
  display:flex;
  align-items:center;
  justify-content:space-between;
  padding:clamp(20px,2.5vw,48px) var(--gutter);
  color:var(--ink);
  pointer-events:none;
}
.header a,.header button,.header-right{pointer-events:auto}
.header-logo{
  --logo-size:clamp(28px,1.875vw,36px);
  display:grid;
  place-items:center;
  width:44px;
  height:44px;
  margin:calc((var(--logo-size) - 44px)/2);
  transition:transform .4s var(--ease),opacity .4s var(--ease),filter .2s linear;
}
.header-logo img{width:var(--logo-size);height:var(--logo-size);object-fit:contain}
@media (hover:hover){.header-logo:hover{opacity:.68}}
.header-fallback-nav{display:flex;align-items:center;gap:clamp(14px,1.25vw,24px);margin-left:auto;font-family:var(--mono);font-size:clamp(13px,.833vw,16px)}
.header-fallback-nav a[aria-current="page"]{text-decoration:underline;text-underline-offset:.28em}
.header-right{display:flex;align-items:center;gap:24px;color:inherit}
.header-menu-text{font-family:var(--mono);font-size:clamp(18px,1.25vw,24px);letter-spacing:0;transition:transform .4s var(--ease),opacity .4s var(--ease)}
.menu-trigger{position:relative;width:44px;height:44px;margin:-10px;z-index:1001;--trigger-halo:var(--halo)}
/* Solid bars in the header’s own ink, which is what a filled mark asks for. The header
   answers to the tone of the section under it, but a card’s artwork can be any tone at
   all, so the bars carry a halo in the opposite ink: over the Nebula card the black
   bars keep a white edge and the mark still reads. A halo rather than a ring, because
   a ring is what made it look outlined. */
.menu-trigger span{
  position:absolute;
  left:10px;
  width:24px;
  height:2px;
  border-radius:2px;
  background:currentColor;
  filter:drop-shadow(0 0 1.5px var(--trigger-halo)) drop-shadow(0 0 3px var(--trigger-halo));
}
.menu-trigger span:first-child{top:17px}
.menu-trigger span:last-child{top:24px}
.menu-trigger[aria-expanded="true"] span:first-child{top:21px;transform:rotate(45deg)}
.menu-trigger[aria-expanded="true"] span:last-child{top:21px;transform:rotate(-45deg)}
.header.is-compact .header-menu-text{transform:translateY(calc(-100% - 24px));opacity:0;pointer-events:none}
/* Out of the flow for the keyboard too, so a tab walk cannot park on an invisible mark
   40px above the viewport. The delay hands the visibility back only after the travel. */
.header.is-inverse{color:var(--rev-ink)}
.header.is-inverse .menu-trigger{--trigger-halo:var(--halo-rev)}
/* Over a surface that is dark in BOTH schemes, the header's ink is white in
   both. --rev-ink follows the theme, which is right over a flipping band and
   wrong over the Contact field or the portrait band. */
.header.is-inverse.is-over-fixed{color:#fff}
.header.is-inverse.is-over-fixed .menu-trigger{--trigger-halo:rgba(10,10,10,.92)}
.header-logo{filter:invert(var(--logo-invert))}
.header.is-inverse .header-logo{filter:invert(var(--logo-invert-rev))}
/* Over a surface that is dark in both schemes the mark always inverts. */
.header.is-inverse.is-over-fixed .header-logo{filter:invert(1)}

/* An open menu always hands the mark back from the compact state, at every
   width, because the menu is where a visitor goes to leave. What it does not
   always hand back is the tone: only where the panel is full bleed (767 and
   under) is the header sitting on the panel's white. See syncHeader in
   inner.js, which stops calling the page dark under the same condition. */
.menu-open .header-logo{transform:none!important;opacity:1!important;pointer-events:auto!important;visibility:visible!important}
@media (max-width:767px){
  .menu-open .header{color:var(--ink)}
  .menu-open .header-logo{filter:invert(var(--logo-invert))!important}
}
.menu-open .header-menu-text{opacity:0!important}
.no-js .header-right{display:none}
/* Nothing switches the header's tone as sections pass under it with JS off,
   and the fallback nav would otherwise sit in near black type over the work
   photographs and the black footer. One fixed dark scrim carries it instead:
   68 percent black over the brightest ground a page can put behind it still
   leaves white type at 7:1. */
.no-js .header{background:rgba(10,10,10,.68);color:#fff}
.no-js .header-logo{filter:invert(1)}
/* No JS means no click handler and no autoplay, so both Pause controls
   are hidden. */
.no-js .project-card-video-pause{display:none}
.no-js .running-pause{display:none}

/* The theme control. No sun, no moon: this site has one pictorial mark and no
   icon set, so a glyph pair would be foreign to it. It is a text pill in the
   vocabulary the ticker's Pause control already established, and the label
   names the destination rather than the state, which is why it needs no
   aria-pressed. A button whose visible label is the action it performs is
   already unambiguous; a changing label plus a pressed state is what makes
   these confusing to read aloud. */
.theme-toggle{
  width:fit-content;align-self:start;justify-self:start;
  min-width:44px;min-height:44px;padding:0 18px;
  border:1px solid var(--rule);border-radius:100px;
  background:transparent;color:var(--ink);
  font-family:var(--mono);font-size:13px;letter-spacing:0;
  transition:border-color .3s ease,color .3s ease;
}
@media (hover:hover){.theme-toggle:hover{border-color:var(--ink)}}
/* With scripting off prefers-color-scheme governs and the site is complete,
   so a control that cannot do anything is not shown. */
.no-js .theme-toggle{display:none}

.nav-overlay{position:fixed;inset:0;z-index:250;pointer-events:none}
.nav-overlay.is-open{pointer-events:auto}
.nav-backdrop{position:absolute;inset:0;background:var(--scrim);opacity:0;transition:opacity .4s ease}
/* The panel slides. It used to open on scaleX, and at 250ms that frame showed
   Home, Work and About condensed to half their width: a drawer whose type is
   the whole design cannot squash its type. The content follows in a short
   stagger, each row a small rise and fade, the foot landing just after the
   panel. Closing is a plain fade and a faster slide, no stagger. */
.nav-panel{
  position:absolute;
  inset:0 0 0 auto;
  width:min(100%,640px);
  height:100dvh;
  overflow:auto;
  background:var(--paper);
  border-left:1px solid var(--panel-edge);
  transform:translateX(100%);
  transition:transform .64s var(--ease);
  box-shadow:-28px 0 80px rgba(0,0,0,.08);
}
.nav-panel-inner{
  min-height:100%;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  gap:48px;
  /* Verified fitting with no scroll at 1440x900 and 1280x720; the old
     140px inset overflowed a 900px screen by 87px. */
  padding:clamp(80px,12vh,128px) 120px clamp(32px,5vh,56px);
}
.nav-overlay.is-open .nav-backdrop{opacity:1}
.nav-overlay.is-open .nav-panel{transform:none}
.nav-overlay.is-closing .nav-backdrop{opacity:0;transition-duration:.3s}
.nav-overlay.is-closing .nav-panel{transform:translateX(100%);transition:transform .36s var(--ease-in)}
.nav-list li,.nav-group,.nav-foot{opacity:0;transform:translateY(12px);transition:opacity .4s ease,transform .5s var(--ease)}
.nav-overlay.is-open :is(.nav-list li,.nav-group,.nav-foot){opacity:1;transform:none}
.nav-overlay.is-open .nav-list li:nth-child(1){transition-delay:.12s}
.nav-overlay.is-open .nav-list li:nth-child(2){transition-delay:.16s}
.nav-overlay.is-open .nav-list li:nth-child(3){transition-delay:.2s}
.nav-overlay.is-open .nav-group:nth-child(1){transition-delay:.24s}
.nav-overlay.is-open .nav-group:nth-child(2){transition-delay:.28s}
.nav-overlay.is-open .nav-foot{transition-delay:.32s}
.nav-overlay.is-closing :is(.nav-list li,.nav-group,.nav-foot){opacity:0;transform:none;transition:opacity .2s ease}
@media (prefers-reduced-motion:reduce){
  /* The per-item delays above outrank this selector, so the zero is forced. */
  .nav-overlay.is-open :is(.nav-list li,.nav-group,.nav-foot){transition-delay:0s!important}
  .nav-list li,.nav-group,.nav-foot{transform:none}
}
.nav-panel-body{display:flex;flex-direction:column;gap:0}
.nav-panel-title{color:var(--ink-soft);font-family:var(--mono);font-size:13px;line-height:20px;letter-spacing:0}
.nav-list{display:flex;flex-direction:column;align-items:flex-start;gap:16px;list-style:none}
/* The item clips. The clip is widened by 8px, the reach of a focus ring (3px at
   5px offset), so every item's ring is drawn whole. The box is exactly as tall as
   the link's line and, once a focused link has slid its 14px, only 6px of the
   padding is left to its right, so the ring used to lose both horizontal strokes
   and two thirds of its right one on every item but the current page's. A clip
   margin costs no layout, where padding would have moved the line, and
   overflow:hidden stays as the fallback for a browser that does not know
   overflow:clip. The current page's item opens the clip altogether instead: its
   marker dot sits .38em outside the link's left edge, far past the reach a ring
   asks for. */
.nav-list li{width:fit-content;overflow:hidden;overflow:clip;overflow-clip-margin:8px;padding-right:20px}
.nav-list li:has(a[aria-current="page"]){overflow:visible}
.nav-list a{display:inline-block;position:relative;font-size:90px;line-height:1;letter-spacing:-.009em;transition:left .4s var(--ease),opacity .3s ease}
.nav-list li:hover a,.nav-list a:focus-visible{left:14px}
.nav-list a[aria-current="page"]::before{content:"";position:absolute;left:-.38em;top:50%;width:.14em;height:.14em;border-radius:50%;background:currentColor;transform:translateY(-50%)}
.nav-socials{display:flex;flex-direction:column;gap:30px}

/* Three groups now, and the grouping is done by a quiet label and whitespace
   rather than by a rule. The panel already owned that vocabulary in
   .nav-panel-title; it was only using it once, over six links that were three
   different kinds of thing. "Also here" against "Elsewhere" is the whole
   distinction, and the arrow makes it visible rather than only announced. */
/* Two short groups side by side rather than stacked. Stacked, they pushed
   the foot below the fold at a 900px viewport while the right half of a
   640px panel sat empty. */
.nav-socials{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(28px,2.5vw,40px) var(--gap)}
.nav-group{display:flex;flex-direction:column;gap:16px}
.nav-group .nav-social-list{flex-direction:column;gap:12px}
.nav-foot{grid-column:1/-1}
/* The arrow is the site's own mark at the cap height of the link beside it,
   the same rule the Work, Venture and Contact links use. These were the only
   external links on the site announcing themselves to a screen reader and to
   nobody else. */
.nav-arrow{display:inline-block;margin-left:.34em;color:var(--ink-soft);transition:color .3s ease}
.nav-social-list a:focus-visible .nav-arrow{color:var(--ink-soft)}
/* The two actions sit together under the destinations, because that is what
   they are: one opens a mail client, one changes the page. Neither is a place. */
.nav-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:16px;margin-top:clamp(8px,1.25vw,20px)}
/* One pinned action. The email keeps the pill; the theme control steps
   down to bare mono so the two are not read as equals. */
.nav-foot .theme-toggle{padding:0;border-color:transparent;color:var(--ink-soft);transition:color .3s ease}
@media (hover:hover){.nav-foot .theme-toggle:hover{border-color:transparent;color:var(--ink)}}
.nav-action{
  display:inline-flex;align-items:center;
  min-height:44px;padding:0 18px;
  border:1px solid var(--rule);border-radius:100px;
  font-family:var(--mono);font-size:13px;letter-spacing:0;
  transition:border-color .3s ease;
}
@media (hover:hover){.nav-action:hover{border-color:var(--ink)}}
.nav-social-list{display:flex;gap:32px;flex-wrap:wrap;list-style:none}
/* No underline: it existed nowhere else on the site, so it was noise, not
   vocabulary. The secondary set steps down by size and by losing the rule. */
.nav-social-list a{font-size:20px;line-height:28px;transition:color .3s ease}
@media (hover:hover){.nav-social-list a:hover,.nav-social-list a:hover .nav-arrow{color:var(--ink-soft)}}
.nav-social-list a[aria-current="page"]{font-weight:600}

.about-hero{
  height:clamp(560px,39vw,750px);
  padding:0 var(--gutter) clamp(48px,4.6875vw,90px);
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  justify-content:flex-end;
  position:relative;
}
.about-hero-title{
  width:100%;
  font-size:clamp(64px,7.5vw,144px);
  font-weight:500;
  line-height:.91;
  letter-spacing:-.038em;
}
.about-hero-chip{
  position:absolute;
  right:var(--gutter);
  top:32%;
  display:block;
  width:clamp(75px,9.479vw,182px);
  height:clamp(46px,5.833vw,112px);
  overflow:hidden;
  border-radius:100px;
  background:var(--ground);
}
.about-hero-chip img{width:100%;height:100%;object-fit:cover}
.about-hero-chip:hover img,.about-hero-chip:focus-visible img{transform:scale(1.08)}
.about-hero-line{display:flex;align-items:center;overflow:hidden;padding:.04em 0 .12em;margin-bottom:-.12em}
.about-hero-line-inner{display:flex;align-items:center;gap:clamp(16px,2.083vw,40px)}
/* The stage reserves the widest word it will ever hold and the wipe is cut to
   the word under it, both measured by inner.js once the face has loaded and
   again on resize. The authored 6.7ch is the no-JS fallback: it was the shipped
   width, and it left a 474px slot around a 401px word, so the bar that crossed
   the line was 73px wider than any word it covered. */
.word-stage{position:relative;display:inline-block;width:var(--word-stage-w,6.7ch);height:.96em;color:var(--accent);isolation:isolate}
.word-item{position:absolute;inset:0 auto auto 0;display:block;opacity:0}
.word-item.is-current{opacity:1}
.no-js .word-item:first-child{opacity:1}
/* The rise itself, its curve and its 90ms step are the shared
   data-reveal-lines mechanism in motion.css. The two rules left here are
   the geometry that only these lines need: a flex row that can hold the
   chip, and a clip box deep enough for the descenders. */
/* The word fills rather than being covered. The accent is a gradient clipped to
   the glyphs, so the orange rises inside the letterforms instead of crossing the
   slot as a bar: at rest the fill sits at the top of its travel and the word is
   solid, and a word that becomes current pours in from its own baseline. A
   browser without background-clip on text keeps the solid accent the stage sets. */
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .word-item{
    background-image:linear-gradient(to top,var(--accent) 50%,transparent 50%);
    background-size:100% 200%;
    background-position:0 100%;
    background-repeat:no-repeat;
    -webkit-background-clip:text;
    background-clip:text;
    color:transparent;
  }
  @media (prefers-reduced-motion:no-preference){
    .word-item.is-current{animation:word-fill .55s cubic-bezier(.4,0,0,1) both}
  }
}
@keyframes word-fill{
  from{background-position:0 0}
  to{background-position:0 100%}
}
.word-cycle-pause{
  margin-top:clamp(16px,1.667vw,32px);
  display:inline-flex;
  align-items:center;
  min-height:44px;
  padding:0 16px;
  border:1px solid var(--rule);
  border-radius:100px;
  font-family:var(--mono);
  font-size:clamp(14px,.833vw,16px);
  line-height:1;
  letter-spacing:0;
  white-space:nowrap;
  color:var(--ink-soft);
  background:none;
  transition:color .3s ease,border-color .3s ease;
}
.word-cycle-pause:hover,.word-cycle-pause:focus-visible{color:var(--ink);border-color:var(--ink-soft)}

.portrait-band{
  position:relative;
  height:clamp(520px,43vw,820px);
  overflow:hidden;
  background:#0a0a0a;
  color:#fff;
}
.portrait-band-media{position:absolute;inset:0;display:grid;place-items:center;overflow:hidden}
.portrait-band-media::before{
  content:"";
  position:absolute;
  width:min(66vw,1120px);
  aspect-ratio:1;
  border-radius:50%;
  background:var(--accent);
  opacity:.92;
  transform:translate3d(-11%,8%,0);
}
.portrait-band img{
  position:relative;
  z-index:1;
  width:min(58vw,960px);
  height:min(58vw,960px);
  object-fit:contain;
  transform:translate3d(12%,calc(8% + var(--parallax-y,0px)),0) scale(1.04);
  will-change:transform;
}
.portrait-band-note{
  position:absolute;
  left:var(--gutter);
  bottom:clamp(28px,3.125vw,60px);
  z-index:2;
  max-width:18ch;
  font-family:var(--mono);
  font-size:clamp(16px,1.042vw,20px);
  line-height:1.25;
  color:var(--ink);
  background:var(--paper);
  padding:.55em .9em;
  border-radius:100px;
  color:var(--ink);
}

.story{padding:clamp(72px,6.25vw,120px) var(--gutter);display:grid;grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:var(--gap) var(--rail-gap);align-items:start}
.story-intro{display:contents}
.story-label{grid-column:1;font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);line-height:1.3;color:var(--ink-soft)}
.story-lede{grid-column:2;font-size:clamp(36px,4.167vw,80px);line-height:1.04;letter-spacing:-.025em;text-wrap:pretty}
/* The four companies the paragraph beside them counts, named once, in the
   mono column that was carrying one label and an empty run under it. The
   paragraph says how many and what it cost. The column says which. Both sit
   on the story grid's second row, so the names start where the paragraph
   starts. */
.story-names{grid-column:1;grid-row:2;margin-top:clamp(64px,6.25vw,120px);list-style:none;font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);line-height:1.65;color:var(--ink-soft)}
.story-body{grid-column:2;grid-row:2;margin-top:clamp(48px,4.167vw,72px)}
.story-body p{font-size:clamp(22px,2.083vw,40px);line-height:1.2;text-wrap:pretty}
.story-body p+p{margin-top:1.25em}
.story-body strong{font-weight:500;color:var(--accent-ink)}
.story-body a,.human-note-text a{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.14em}
.story-body a:hover,.human-note-text a:hover{color:var(--ink-soft)}

.philosophy{
  min-height:clamp(440px,36vw,690px);
  padding:clamp(72px,6.25vw,120px) var(--gutter);
  display:flex;
  align-items:center;
  justify-content:center;
  text-align:center;
}
.philosophy blockquote{max-width:13ch;font-size:clamp(64px,8.4375vw,162px);line-height:.94;letter-spacing:-.038em;text-wrap:balance}
.philosophy-quote{display:inline;color:var(--accent)}
.philosophy-quote--open{margin-left:-.42em}
.philosophy-quote--close{margin-right:-.28em}
.philosophy-mark{color:var(--accent)}

.chapter-now{
  padding:clamp(72px,6.25vw,120px) var(--gutter);
  background:var(--paper);
  color:var(--ink);
  display:grid;
  grid-template-columns:minmax(150px,1fr) minmax(0,2fr);
  gap:var(--gap) var(--rail-gap);
  align-items:start;
}
.chapter-now-head{display:contents}
.chapter-now-label{grid-column:1;font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);line-height:1.3;color:var(--ink-soft)}
.chapter-now-title{grid-column:2;font-size:clamp(60px,7.5vw,144px);line-height:.94;letter-spacing:-.038em;text-wrap:balance}
.chapter-now-copy{grid-column:2;margin-top:clamp(48px,4.167vw,72px)}
.chapter-now-copy p{font-size:clamp(22px,2.083vw,40px);line-height:1.2;text-wrap:pretty}
.chapter-now-copy p+p{margin-top:1.25em}
.chapter-now-proof{margin-top:clamp(48px,5vw,96px);border-top:1px solid color-mix(in srgb,var(--ink) 22%,transparent);padding-top:clamp(24px,2.083vw,40px);display:flex;justify-content:space-between;gap:32px;font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);color:#bdbdbd}

.conversations{--rule:#d6d6d6;padding:clamp(72px,6.25vw,120px) var(--gutter);background:var(--ground)}
.conversations-head{display:grid;grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:var(--gap);align-items:start;margin-bottom:clamp(48px,4.167vw,72px)}
.conversations-label{font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);line-height:1.3;color:var(--ink-soft)}
.conversations-title{max-width:12ch;font-size:clamp(48px,5.625vw,108px);line-height:.97;letter-spacing:-.035em;text-wrap:balance}
/* The mat scales with what it brackets. Row two is a 465px clip now, not a
   line of type, so the article needs more inset than a text only record did.
   clamp(48px,5vw,96px) is the next rung already in this file, and its floor
   carries through the narrow breakpoint, so that override drops out. */
.conversation{display:grid;grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:var(--gap) var(--rail-gap);padding:clamp(36px,3.333vw,64px) 0 0;border-top:1px solid var(--rule)}
.conversation-meta{font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);line-height:1.35;color:var(--ink-soft)}
.conversation-meta span{display:block}
.conversation-copy>p{max-width:34ch;font-size:clamp(22px,2.083vw,40px);line-height:1.2;text-wrap:pretty}
.conversation-links{margin-top:clamp(36px,3.333vw,64px);list-style:none;border-top:1px solid var(--rule)}
.conversation-links a{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--gap);align-items:baseline;padding:clamp(18px,1.667vw,32px) 0;border-bottom:1px solid var(--rule);font-size:clamp(20px,1.667vw,32px);line-height:1.15}
.conversation-links .episode-arrow{font:inherit;color:var(--ink-soft);transition:transform .35s var(--ease),color .35s ease}
@media (hover:hover){.conversation-links a:hover .episode-arrow{color:var(--accent-ink);transform:translate(4px,-4px)}}
.conversation-links a:focus-visible .episode-arrow{color:var(--accent-ink);transform:translate(4px,-4px)}
/* At 810 and up the title holds one line, so the arrow centres on it. Below that the
   title wraps and the row keeps its baseline. */
/* The last episode closes the list, so it carries no rule under it. */
.conversation-links li:last-child a{border-bottom:0}
@media (min-width:810px){.conversation-links a{align-items:center}}
/* The episode clip sits in the rail under the meta, on the same grid row as
   the link list, so the frame's top edge and the list's first rule land level
   at every width. Both row two children carry the list's own margin-top, so
   there is no measured number holding them together. Under 768px the row
   collapses to source order: meta, sentence, clip, links. */
.conversation-meta{grid-column:1;grid-row:1}
.conversation-copy{grid-column:2;grid-row:1}
.conversation-clip{grid-column:1;grid-row:2;align-self:start;margin-top:clamp(36px,3.333vw,64px)}
.conversation-links{grid-column:2;grid-row:2;align-self:start}
.conversation-asks{grid-column:1/-1;grid-row:2;margin-top:clamp(36px,3.333vw,64px)}
.conversation-more{display:grid;grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:var(--gap) var(--rail-gap);padding-bottom:clamp(28px,2.5vw,44px)}
.conversation-more>.conversation-clip{grid-column:1;grid-row:1;margin-top:0}
.conversation-more>.conversation-links{grid-column:2;grid-row:1;margin-top:0}
.conversation-clip-frame{position:relative;overflow:hidden;aspect-ratio:4/5;border-radius:var(--radius-card);background:#0a0a0a}
.conversation-clip img,.conversation-clip video{display:block;width:100%;height:auto;aspect-ratio:4/5;object-fit:cover}
/* Same stack as the Work page clips: the first frame is a lazy <img> under
   the <video>, so it is what paints with scripting off, under reduced
   motion, and before the clip's first frame arrives. */
.conversation-clip .project-card-video-poster{position:absolute;inset:0;z-index:0}
.conversation-clip video{position:relative;z-index:1}
.conversation-clip .project-card-video-pause{position:absolute;z-index:2;left:clamp(12px,1.25vw,20px);bottom:clamp(12px,1.25vw,20px);min-width:44px;min-height:44px;padding:0 16px;border:1px solid rgba(10,10,10,.6);border-radius:100px;background:#fff;color:#0a0a0a;font-family:var(--mono);font-size:13px;box-shadow:0 0 0 1px rgba(255,255,255,.5);transition:border-color .3s ease}
/* The white double ring rather than the global focus outline: the accent is
   rationed and a control is not where it gets spent. */
.conversation-clip .project-card-video-pause:focus-visible{outline:3px solid #fff;outline-offset:3px;box-shadow:0 0 0 6px rgba(10,10,10,.85)}
@media (hover:hover){.conversation-clip .project-card-video-pause:hover{border-color:rgba(10,10,10,.8)}}
.conversation-clip figcaption{margin-top:clamp(12px,1.042vw,20px);font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);line-height:1.3;color:var(--ink-soft)}
@media (prefers-reduced-motion:reduce){.conversation-clip:not(.is-video-playing) video{display:none}}
.no-js .conversation-clip video{display:none}

.human{padding:clamp(72px,6.25vw,120px) var(--gutter);display:grid;grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:var(--gap) var(--rail-gap);align-items:start}
.human-label{grid-column:1;font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);line-height:1.3;color:var(--ink-soft)}
.human-title{grid-column:2;max-width:12ch;font-size:clamp(58px,7.5vw,144px);line-height:.95;letter-spacing:-.038em;text-wrap:balance;margin-bottom:0}
.human-list{grid-column:1/-1;list-style:none;border-top:1px solid var(--rule)}
.human-list li{display:grid;grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:var(--gap);padding:clamp(20px,2.2vw,42px) 0;border-bottom:1px solid var(--rule);align-items:baseline}
.human-key{display:block;font-family:var(--mono);font-size:clamp(16px,1.042vw,20px);color:var(--ink-soft)}
.human-value{display:block;font-size:clamp(30px,3.333vw,64px);line-height:1.05;letter-spacing:-.02em;text-wrap:pretty}
.human-note{grid-column:1/-1;display:grid;grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:var(--gap) var(--rail-gap);margin-top:clamp(48px,4.167vw,72px)}
.human-note-text{grid-column:2;font-size:clamp(22px,2.083vw,40px);line-height:1.2;text-wrap:pretty}
.human-note+.human-note{margin-top:clamp(20px,1.667vw,32px)}
/* Off the record's rail carries the evidence for the answer beside it, the
   way Story carries the four names and Conversations carries the clip. Each
   print is shown at the size of a print: the rail is 343px at 1440, within
   three percent of an instant print's 88mm at 96dpi, so actual size and
   rail width are the same number. The scan already owns the border and
   the grain, so no rotation, no shadow, no radius. */
.human-note{align-items:start}
.human-note>.print{grid-column:1;grid-row:1}
.human-note>.human-note-text{grid-column:2;grid-row:1}
/* The three Henry prints are a handful set down together: they lap and
   tilt inside the answer column, and their three exchanges come out of the
   pile into the rail as a label column. A print beside text sits square;
   only a print in a handful tilts. Tilts alternate and stay under four
   degrees, the middle print is on top and lifted, and the pile sits on
   the same baseline as the label column. */
.human-note--fan{margin-top:clamp(64px,6.25vw,120px)}
.human-note--fan+.human-note{margin-top:clamp(36px,3.333vw,64px)}
.human-asks{grid-column:1/-1;margin-top:clamp(48px,4.167vw,72px)}
.ask-body>.human-note{margin-top:0;padding-bottom:clamp(28px,2.5vw,44px)}
.ask-body .story-names{grid-column:1;grid-row:1;margin-top:0}
.human-asks .ask-body>.human-note--fan{margin-top:0}
.human-asks .ask-body>.human-note>.print{margin-top:0}
.fan-notes{grid-column:1;list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:clamp(20px,1.667vw,32px);align-self:end}
.fan-notes li{font-size:clamp(16px,1.042vw,20px);line-height:1.3}
.fan-notes .q{display:block;margin-bottom:.35em}
.fan{grid-column:2;display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-items:end;padding-top:clamp(24px,2.5vw,48px)}
.fan>.print{grid-row:1;margin:0;transition:transform .9s var(--ease)}
/* Three slots, not three prints: a print can be brought forward, and the
   pile keeps its composition because prints trade slots. The stagger is
   vertical, so the pile leans instead of fanning. */
.fan>.is-a{grid-column:1/7;transform:rotate(-2deg);z-index:1;transform-origin:70% 100%}
.fan>.is-b{grid-column:4/10;transform:rotate(1deg) translateY(-8%);z-index:3;transform-origin:50% 100%}
.fan>.is-c{grid-column:7/13;transform:rotate(3deg) translateY(-4%);z-index:2;transform-origin:30% 100%}
/* Bringing a print forward reuses the entrance: it lifts square, then
   settles into the front slot while the front print settles into its old
   one. */
.fan>.print.is-lifting{transform:translateY(-16px) rotate(0);z-index:4}
.print-lift{display:block;width:100%;padding:0;border:0;background:none;cursor:pointer;color:inherit;border-radius:0}
.print-lift img{display:block;width:100%;height:auto}
@media (hover:hover){.js .fan>.print:not(.is-b) .print-lift:hover img{transform:translateY(-4px)}}
.print-lift img{transition:transform .4s var(--ease)}
.print-lift:focus-visible{outline:3px solid var(--accent);outline-offset:6px}
.fan-notes li{transition:color .4s ease}
.js .fan-notes li:not(.is-current){color:var(--ink-soft)}
.js .fan-notes li:not(.is-current) .q,.js .fan-notes li:not(.is-current) .print-a{color:var(--ink-soft)}
.js .fan-notes .print-a{transition:color .4s ease}
.fan>.print>img{box-shadow:0 0 0 1px var(--frame),0 14px 36px -18px rgba(0,0,0,.4)}
.print{margin:0}
.print img{display:block;width:100%;height:auto;box-shadow:0 0 0 1px var(--frame)}
.print figcaption{margin-top:clamp(12px,1.042vw,20px);font-size:clamp(16px,1.042vw,20px);line-height:1.3}
.print figcaption .q{display:block;margin-bottom:.35em}
.print-a{display:block;font-family:var(--sans);color:var(--ink);text-wrap:pretty}
/* Motion: a handful set down. Each print lands from a few pixels up and
   square into its tilt, the middle one last. At rest is the final state, so
   reduced motion simply shows it. */
@media (prefers-reduced-motion:no-preference){
  .js .fan>.print{transition:transform .9s var(--ease)}
  .js .fan[data-reveal]:not(.is-visible)>.print{transform:translateY(16px) rotate(0)}
  .js .fan.is-visible>.is-a{transition-delay:.05s}
  .js .fan.is-visible>.is-c{transition-delay:.15s}
  .js .fan.is-visible>.is-b{transition-delay:.3s}
  .js .fan.is-visible.is-settled>.print{transition-delay:0s}
}
.signature{grid-column:2;margin-top:clamp(56px,5vw,96px);font-size:clamp(96px,13.542vw,260px);line-height:.82;letter-spacing:-.04em;color:var(--accent)}

.btn{
  position:relative;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-height:clamp(56px,5.3125vw,102px);
  padding:0 clamp(24px,2.083vw,40px);
  overflow:hidden;
  border:1px solid currentColor;
  border-radius:100px;
  font-size:clamp(20px,1.458vw,28px);
  line-height:1.35;
  letter-spacing:0;
  isolation:isolate;
  transition:color .4s var(--ease),transform .45s var(--ease-viscous);
}
.btn::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--ink);border-radius:50% 50% 0 0;transform:translateY(101%);transition:transform .5s cubic-bezier(.4,0,0,1),border-radius .5s cubic-bezier(.4,0,0,1)}
@media (hover:hover){.btn:hover{color:var(--paper)}.btn:hover::before{transform:none;border-radius:0}}
.btn-light{color:var(--ink)}
.btn-light::before{background:var(--ink)}
@media (hover:hover){.btn-light:hover{color:var(--paper)}}
.btn-accent{background:var(--accent);border-color:transparent;color:var(--on-accent)}
.btn-accent::before{background:var(--ink)}
@media (hover:hover){.btn-accent:hover{color:var(--paper)}}

.footer{position:relative;overflow:hidden;background:var(--paper);color:var(--ink);padding:clamp(64px,8.333vw,160px) 0 clamp(24px,2.5vw,48px)}
.footer-inner{padding:0 var(--gutter)}
.footer-top{display:flex;flex-direction:column;gap:clamp(64px,8.333vw,160px);margin-bottom:clamp(64px,8.333vw,160px)}
.footer-heading{display:flex;flex-direction:column;gap:clamp(4px,.52vw,10px)}
/* The same clip box the hero lines are built as, for the same reason: the
   heading is set at line-height .9, so a box drawn at the line box would cut
   the y of Say. The bottom padding is pulled back off as margin, so the two
   line heading occupies exactly the height it did before it could move. */
.footer-heading-line{overflow:hidden;padding-bottom:.16em;margin-bottom:-.16em;font-size:clamp(64px,8.4375vw,162px);line-height:.9;letter-spacing:-.038em;white-space:nowrap}
.footer-heading-line-inner{display:flex;align-items:center;gap:clamp(20px,2.083vw,40px)}
.footer-heading-line--bottom .footer-heading-line-inner{display:block}
.footer-chip{display:inline-flex;align-items:center;justify-content:center;width:clamp(75px,9.479vw,182px);height:clamp(46px,5.833vw,112px);border-radius:100px;background:var(--ground);overflow:hidden;flex:0 0 auto}
.footer-chip img{width:100%;height:100%;object-fit:cover}
/* Two page groups stack in the wide column, the drawer's Elsewhere and Also
   here, and the email spans both rows on the right. */
.footer-contacts{display:grid;grid-template-columns:minmax(0,1fr) max-content;justify-content:space-between;gap:48px 40px}
.footer-contacts-group--email{justify-self:end;grid-column:2;grid-row:1/3}
.footer-contacts-label{margin-bottom:clamp(12px,2.083vw,40px);font-family:var(--mono);font-size:clamp(16px,1.458vw,28px);line-height:1.35}
.footer-contacts-btns{display:flex;gap:var(--gap);flex-wrap:wrap}
.footer .btn{min-height:clamp(56px,5.833vw,112px);padding:0 clamp(24px,2.5vw,48px);font-size:clamp(20px,2.083vw,40px);line-height:1.2}
.running-wrap{position:relative}
.running-pause{position:absolute;right:var(--gutter);top:-64px;z-index:2;min-width:44px;min-height:44px;border:1px solid color-mix(in srgb,var(--ink) 50%,transparent);border-radius:100px;color:var(--ink);font-family:var(--mono);font-size:13px;padding:0 16px;transition:border-color .3s ease}
/* Same border-strengthening hover the card's Pause pill uses, at the
   alpha this pill's light-on-dark border needs. */
@media (hover:hover){.running-pause:hover{border-color:color-mix(in srgb,var(--ink) 80%,transparent)}}
.running-line{width:100%;overflow:hidden;margin-bottom:clamp(64px,5.417vw,104px)}
.running-track{display:flex;width:max-content;white-space:nowrap;will-change:transform}
.js .running-track{animation:running-line-loop 24s linear infinite}
.running-track[data-paused="true"]{animation-play-state:paused}
@keyframes running-line-loop{to{transform:translateX(-50%)}}
.running-sequence{display:flex;align-items:center;gap:var(--gap);padding-right:var(--gap);flex:0 0 auto}
.running-text{font-size:clamp(160px,18.4375vw,354px);line-height:.92;letter-spacing:-.038em}
.running-card{position:relative;width:clamp(252px,29.0390625vw,558px);height:clamp(112px,12.90625vw,248px);overflow:hidden;flex:0 0 auto;border-radius:999px;background:#222}
.running-card img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;visibility:hidden}
.running-card img.is-active{visibility:visible}
/* Every frame carries its address in data-src, so the marquee asks for
   nothing until the footer is within a viewport of the fold. With JS off
   nothing hands those addresses over, so each pill paints the frame the
   script would have started it on as its own background: frame 0 for the
   pill at offset 0, frame 5 for the pill at offset 5. */
.no-js .running-card{background-size:cover;background-position:50% 50%}
.no-js .running-card[data-frame-offset="0"]{background-image:url("assets/work/ticker/brightwell-sign.webp")}
.no-js .running-card[data-frame-offset="5"]{background-image:url("assets/work/ticker/tt-05-punk-rocker.webp")}
.footer-bottom{border-top:1px solid color-mix(in srgb,var(--ink) 14%,transparent)}
.footer-bottom-inner{padding:clamp(20px,1.25vw,24px) var(--gutter) 0;display:flex;justify-content:space-between;align-items:center;gap:32px;font-family:var(--mono);font-size:13px;line-height:18px;letter-spacing:0;}
.footer-bottom-left,.footer-bottom-right{display:flex;gap:24px;flex-wrap:wrap}
/* The last stops on the page sat flush with the viewport floor when focus
   scrolled them in, which cut the bottom side off the ring. The margin is the
   ring's own reach, 3px of outline past a 5px offset, plus 2px. */
.footer-bottom a{display:inline-flex;align-items:center;min-height:44px;scroll-margin-block:10px;transition:opacity .3s ease}
.footer-bottom a:hover{opacity:.68}

/* The sign-off carries the mark once more, small, on the band's own ink,
   the way a letterhead repeats at the foot. It is the same monogram the
   header wears, and the same one-line rule sets its colour on either band. */
.footer-mark{display:inline-flex;align-items:center;min-height:44px;margin-left:8px}
.footer-mark img{width:16px;height:16px;object-fit:contain;filter:invert(var(--logo-invert-rev));transition:opacity .3s ease}
.footer-mark:hover img{opacity:.68}
.footer-bottom-left,.footer-bottom-right{align-items:center}
/* A button says one thing on one line. */
.btn>span{white-space:nowrap}

.skip-link,.header-fallback-nav,.header-menu-text,.nav-panel-title,.cb-cursor-label,
.portrait-band-note,.story-label,.story-names,.chapter-now-label,.chapter-now-proof,.conversations-label,.conversation-meta,.human-key,.human-label,
.footer-contacts-label,.running-pause,.footer-bottom-inner,
.project-card-meta,.reading-author,.venture-kind,.venture-status{
  font-kerning:normal;
  font-variant-ligatures:none;
  font-variant-numeric:lining-nums tabular-nums slashed-zero;
  /* Google's Inconsolata ships none of kern, liga, tnum, lnum or zero (measured:
     identical widths on and off, zero already slashed), so nothing is asked for. */
  font-feature-settings:normal;
}

/* Both reveal presets, [data-reveal] and [data-reveal-peak], live in
   motion.css, one set of numbers for all six pages. */

/* Content columns keep a right-side reserve at tablet/desktop so they clear the fixed
   header's trigger instead of running under it. */
@media (min-width:768px){
  body.page-about .about-hero,
  body.page-about .story,
  body.page-about .chapter-now,
  body.page-about .conversations,
  body.page-about .human{
    padding-right:calc(var(--gutter) + clamp(56px,5.833vw,112px));
  }
  body.page-about .about-hero-chip{
    right:calc(var(--gutter) + clamp(56px,5.833vw,112px));
  }
  /* .philosophy centers its blockquote; pad both sides equally so it stays centered
     while still clearing the trigger. */
  body.page-about .philosophy{
    padding-left:calc(var(--gutter) + clamp(56px,5.833vw,112px));
    padding-right:calc(var(--gutter) + clamp(56px,5.833vw,112px));
  }
}

@media (max-width:1279px) and (min-width:768px){
  :root{--gutter:60px}
  .about-hero{height:560px}
  .portrait-band{height:620px}
  .story,.chapter-now,.human,.conversations-head,.conversation,.human-list li,.human-note{grid-template-columns:1fr 2fr}
  .footer-contacts{grid-template-columns:1fr}
  .footer-contacts-group--email{justify-self:start;grid-column:auto;grid-row:auto}
}

@media (max-width:767px){
  :root{--gutter:20px}
  .header{padding:20px var(--gutter)}
  .header-logo{--logo-size:28px}
  .header-fallback-nav{gap:14px;font-size:13px}
  .header-menu-text{display:none}
  .nav-panel{width:100%}
  .nav-panel-inner{padding:88px 20px 32px;justify-content:flex-start;gap:40px}
  .nav-panel-body,.nav-socials{margin-top:auto}
  .nav-list{gap:20px}
  .nav-list a{font-size:64px;line-height:58px;letter-spacing:-.038em}
  .nav-list a[aria-current="page"]::before{display:none}
  /* The dot sits 20px after the word, inside the item's own padding, not
     at the far edge of the panel. */
  .nav-list li:has(a[aria-current="page"]){position:relative;width:fit-content}
  .nav-list li:has(a[aria-current="page"])::after{content:"";position:absolute;right:0;top:50%;width:10px;height:10px;border-radius:50%;background:currentColor;transform:translateY(-50%)}
  .nav-social-list{gap:16px}
  .nav-socials{grid-template-columns:1fr;gap:28px}
  .nav-group .nav-social-list{flex-direction:row;flex-wrap:wrap;gap:8px 20px}
  /* The padding holds the 44px target on a 20px line. */
  .nav-social-list a{display:flex;align-items:center;min-height:44px;padding-block:12px;font-size:15px;line-height:20px}
  .about-hero{height:440px;padding:20px var(--gutter) 32px}
  .about-hero-title{font-size:56px;line-height:52px;letter-spacing:-2.13px}
  .about-hero-chip{top:112px;right:20px;width:75px;height:46px}
  .about-hero-line-inner{display:block}
  .about-hero-line:nth-child(2) .about-hero-line-inner{width:100%}
  .word-stage{display:block;width:var(--word-stage-w,100%);height:1em;margin-top:6px}
  .portrait-band{height:400px}
  .portrait-band-media::before{width:430px;transform:translate3d(-20%,20%,0)}
  .portrait-band img{width:410px;height:410px;max-width:none;transform:translate3d(14%,calc(18% + var(--parallax-y,0px)),0) scale(1.04)}
  .portrait-band-note{bottom:24px;font-size:14px}
  .story,.chapter-now,.conversations,.human{padding:64px var(--gutter)}
  .story,.chapter-now{display:block}
  .story-intro,.chapter-now-head,.conversations-head{display:block;margin-bottom:48px}
  .story-label,.chapter-now-label,.conversations-label,.human-label{margin-bottom:20px}
  .story-lede{font-size:36px;line-height:40px}
  /* The column becomes a stack here, so the names land under the paragraph
     that counts them rather than above it, which is the order they are read
     in at every width now. The space moves with them. */
  .story-names{margin:28px 0 0}
  .story-body,.chapter-now-copy{margin-top:0}
  .story-body p,.chapter-now-copy p,.human-note-text{font-size:20px;line-height:27px}
  .ask>summary{font-size:16px;padding:18px 0}
  .ask-body>p{padding-bottom:24px}
  .philosophy{min-height:360px;padding:64px var(--gutter)}
  .philosophy blockquote{font-size:52px;line-height:50px;letter-spacing:-.038em}
  .chapter-now{min-height:0}
  .chapter-now-title{font-size:56px;line-height:52px}
  .conversations-title{font-size:48px;line-height:46px}
  .conversation{display:block}
  .conversation-meta{margin-bottom:28px;font-size:15px}
  .conversation-copy>p{font-size:22px;line-height:28px}
  .conversation-clip{margin-top:36px}
  .conversation-clip figcaption{font-size:15px}
  .conversation-links{margin-top:36px}
  .conversation-asks{margin-top:28px}
  .conversation-more{display:block;padding-bottom:24px}
  .conversation-more>.conversation-clip{margin-top:0}
  .conversation-more>.conversation-links{margin-top:36px}
  .conversation-links a{grid-template-columns:minmax(0,1fr) auto;gap:12px;padding:18px 0;font-size:20px;line-height:26px}
  .human{display:block}
  .human-title{font-size:56px;line-height:52px;margin-bottom:0}
  .human-list li{grid-template-columns:1fr;gap:8px;padding:20px 0}
  .human-key{font-size:16px}
  .human-value{font-size:28px;line-height:31px;letter-spacing:-.01em}
  .human-note{display:block;margin-top:48px}
  .human-note+.human-note{margin-top:20px}
  .human-note>.print{margin-top:36px}
  .ask-body>.human-note{padding-bottom:24px}
  .ask-body .story-names{margin-top:28px}
  .human-asks .ask-body>.human-note>.print{margin-top:0}
  .human-note>.print+.human-note-text{margin-top:36px}
  /* On a phone the handful is a deck: the front print sits square and the
     other two peek out behind it. A swipe, a tap, or the arrow keys bring
     the next one forward with the same settle. */
  .fan{display:grid;grid-template-columns:1fr;padding:6% 8% 4%;touch-action:pan-y}
  .fan>.print{grid-column:1;grid-row:1;width:100%}
  .fan>.is-a{transform:rotate(-4deg) translate(-7%,3%);z-index:1;transform-origin:50% 100%}
  .fan>.is-b{transform:none;z-index:3;transform-origin:50% 100%}
  .fan>.is-c{transform:rotate(4deg) translate(7%,3%);z-index:2;transform-origin:50% 100%}
  .human-note--fan{display:flex;flex-direction:column}
  .fan-notes{order:2;margin-top:32px;gap:20px}
  .signature{margin-top:48px;font-size:96px}
  .btn{min-height:56px;padding:0 24px;font-size:20px;line-height:24px}
  .footer{padding:64px 0 24px}
  .footer-top{gap:64px;margin-bottom:64px}
  .footer-heading{gap:4px}
  .footer-heading-line{font-size:64px;line-height:58px;letter-spacing:-2.43px}
  .footer-heading-line:first-child .footer-heading-line-inner{gap:12px}
  .footer-chip{width:75px;height:46px}
  .footer-contacts{display:flex;flex-direction:column;gap:32px}
  .footer-contacts-group--email{justify-self:auto}
  .footer-contacts-label{font-size:16px;line-height:22px;margin-bottom:12px}
  .footer .btn{min-height:56px;padding:0 24px;font-size:20px;line-height:24px}
  .running-wrap{display:none}
  .footer-bottom{border-top:0}
  .footer-bottom-inner,.footer-bottom-left{display:flex;flex-direction:column;align-items:flex-start;gap:12px}
  /* Back to top and the mark share one row, opposite corners. */
  .footer-bottom-right{display:flex;flex-direction:row;align-items:center;justify-content:space-between;align-self:stretch;gap:24px}
  .footer-mark{margin:0}
  .footer-bottom-inner{padding:0 var(--gutter)}
}

/* At this breakpoint the fixed header carries an opaque ground on every inner page,
   so content scrolls under a solid band. The tone matches the section passing under
   the header: white by default, black over [data-header-inverse] sections, gray over
   [data-header-tone="gray"] sections. The tone snaps at the section boundary with no
   transition. */
@media (max-width:767px){
  .header{
    background:var(--paper);
  }
  .header.is-inverse{
    background:var(--rev-plate);
  }
  .header.is-gray{
    background:var(--ground);
  }
  /* Except on Contact, where a band cannot be right. Every other page passes
     one flat ground under the header at a time, so the band can name it.
     Contact passes two at once: the page is black, and the composer sits on
     it as a white card inset by the gutter, so for the whole stretch the card
     is what the header is over, the black band cut a 67px bar across the top
     of the card and through the first route's cap height, and a white band
     would cut the same bar across the black page beside it. The header goes
     back to carrying no ground here. The mark and the label are already gone
     by then (the header is compact by 24px of scroll), and the trigger's bars
     are built to read on either tone, which is exactly the case this page is.

     Scripting on only, because with it off the header carries the fixed dark
     scrim set below and a white fallback nav sitting on it, and that nav has
     to stay legible when the white card passes under it. */
  .js body.page-contact .header,
  .js body.page-contact .header.is-inverse{
    background:transparent;
  }
  body.page-about #main,
  body.page-about #story{
    scroll-margin-top:84px;
  }
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .loader{display:none!important}
  .running-track{animation:none!important}
  *,*::before,*::after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}
  html.motion-opt-in .running-track[data-paused="false"]{animation:running-line-loop 24s linear infinite!important;animation-duration:24s!important;animation-iteration-count:infinite!important}
  /* At rest the marquee cannot travel, so the frame it parks on has to be a whole
     wordmark. Left alone it stops on "Lee" and the first five letters of the surname,
     and a visitor who never presses Play never reads the name. The sequence is sized
     to the line instead of overflowing it: one copy, one frame, both words. Pressing
     Play adds motion-opt-in and hands the marquee back its travelling size. */
  html:not(.motion-opt-in) .running-track{width:100%}
  html:not(.motion-opt-in) .running-track>.running-sequence+.running-sequence{display:none}
  html:not(.motion-opt-in) .running-sequence{width:100%;gap:2vw;padding-right:0}
  html:not(.motion-opt-in) .running-sequence>.running-card:last-child{display:none}
  html:not(.motion-opt-in) .running-text{font-size:12.4vw}
  html:not(.motion-opt-in) .running-card{width:19.5vw;height:11.6vw}
}
