/* ==========================================================================
   genevako.com — design system
   Typography: PP Neue Montreal (Book 400 / Medium 500), PP Editorial New
   Layout:     one fluid container; every block shares a single rail.
   ========================================================================== */

/* --- fonts ---------------------------------------------------------------- */
@font-face{font-family:"Neue Montreal";src:url("../fonts/neue-montreal-book.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Neue Montreal";src:url("../fonts/neue-montreal-medium.woff2") format("woff2");
  font-weight:500;font-style:normal;font-display:swap}
/* That That New Pixel (square), trial build: licence is "free for personal use"; confirm before launch */
@font-face{font-family:"That That New Pixel";src:url("../fonts/that-that-new-pixel-square.otf") format("opentype");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Editorial New";src:url("../fonts/editorial-new.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Editorial New";src:url("../fonts/editorial-new-italic.woff2") format("woff2");
  font-weight:400;font-style:italic;font-display:swap}

/* --- tokens --------------------------------------------------------------- */
:root{
  --ink:#000;
  --soft:#2b2b2b;   /* prose            14.2:1 */
  --body:#555;      /* secondary prose   7.3:1 */
  --muted:#6b6b6b;  /* captions, meta    5.4:1 — was #808080 at 3.9:1, under AA */
  --bg:#fff;
  --panel:#f5f5f5;
  --line:#000;
  --navy:#101050;
  --green:#4db72e;  /* ink on it is 8.0:1; white would be 2.6:1, so the band keeps ink text */
  --moss:#406457;   /* darkened: white on the old #538172 was 4.4:1, just under AA */

  --sans:"Neue Montreal",-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
  --serif:"Editorial New",Georgia,"Times New Roman",serif;

  /* Type scale. Still restrained — this is not a site that shouts — but with
     real steps between the levels. Before, a section heading, its body copy,
     the metadata and the links were all 16px, so hierarchy rested entirely on
     colour, and the colours had drifted apart. Six roles, each with one job:

       display  cover titles
       lead     the statement that opens a section
       sub      sub-heads and card titles
       body     prose
       meta     metadata values, secondary lists
       cap      captions
       label    uppercase labels                                            */
  /* Matched to lausandoval.com/work/uber/affordability-on-uber-eats, measured
     at 1440: 32 / 22 / 16 / 14, four sizes and no more. Their title is 32px
     w560 lh1.2 ls-.02em; the lead 22px w420 lh1.4 ls-.03em; body 16px w420
     lh1.6 in pure black; captions and meta 14px in grey. Neue Montreal has
     static 400/500, so their variable 420/560 map to Book and Medium.
     One deviation, deliberate: their grey is #888b90, which is 3.45:1 on
     white and under AA. Ours is #6b6b6b at 5.4:1 — same role, same quietness,
     legible. */
  --fs-display:clamp(26px,2.4vw,32px);
  --fs-lead:clamp(19px,1.6vw,22px);
  --fs-sub:16px;
  --fs-body:16px;
  --fs-meta:14px;
  --fs-cap:14px;
  --fs-label:14px;
  /* older names kept as aliases so every rule need not change at once */
  --fs-xl:var(--fs-display);
  --fs-lg:var(--fs-lead);
  --fs-md:var(--fs-body);
  --fs-sm:var(--fs-cap);
  --fs-xs:var(--fs-label);

  /* one rail for the whole site */
  --maxw:1080px;
  --rail:clamp(20px,5.2vw,72px);
  --measure:62ch;
  --measure-cs:50ch;   /* case-study prose: narrower editorial column */

  --gap-col:clamp(28px,4.4vw,64px);
  --sp-section:clamp(56px,8vw,104px);
}

/* --- reset ---------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:var(--sans);font-size:var(--fs-md);font-weight:500;line-height:1.6;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
img{max-width:100%;height:auto;display:block}
h1,h2,h3,h4,h5,h6{margin:0;font-size:inherit;font-weight:500;line-height:1.3}
p{margin:0}
ul,ol{margin:0;padding:0}
a{color:inherit}
:focus-visible{outline:2px solid var(--navy);outline-offset:3px;border-radius:2px}

/* --- layout --------------------------------------------------------------- */
.container{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--rail)}
.stack{display:flex;flex-direction:column}
.measure{max-width:var(--measure)}
.nowrap{white-space:nowrap}
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* --- type ----------------------------------------------------------------- */
.label{font-size:var(--fs-label);font-weight:400;letter-spacing:.06em;
  text-transform:uppercase;color:var(--body);line-height:1.4}
.label--muted{color:var(--muted)}
.lede{font-size:var(--fs-lead);font-weight:400;line-height:1.4;letter-spacing:-.03em;color:var(--ink)}
.prose{font-weight:400;color:var(--body);line-height:1.6}
.prose strong{font-weight:500;color:var(--ink)}
.title{font-size:var(--fs-display);line-height:1.2;letter-spacing:-.02em}
.tagline{font-family:var(--serif);font-style:italic;font-size:15.7px;
  line-height:1.2;color:var(--ink)}

/* inline images that must flow with the text (avatar, company marks) */
.inline-img{display:inline-block;width:20px;height:20px;vertical-align:-4px;
  margin-inline:2px;border-radius:2px}
.inline-img--round{border-radius:50%}

/* underlined in-text links */
.link{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;
  text-decoration-color:var(--ink);transition:text-decoration-color .15s ease}
.link:hover{text-decoration-color:var(--muted)}

/* --- site header ---------------------------------------------------------- */
.masthead{padding-block:clamp(24px,3.4vw,40px) clamp(40px,6vw,72px)}
.masthead__inner{display:flex;align-items:center;justify-content:space-between;gap:24px}
.wordmark{display:inline-flex;align-items:center;margin:0;font-size:0;line-height:0}
.wordmark img{width:clamp(104px,9vw,128px);height:auto}
.masthead__nav{display:flex;align-items:center;gap:clamp(16px,2.6vw,40px)}
.navlink{font-size:var(--fs-md);color:var(--body);text-decoration:none;
  transition:color .15s ease}   /* sentence case (2026-10-01): labels keep the uppercase voice, nav doesn't */
.navlink:hover{color:var(--ink)}
.btn{display:inline-flex;align-items:center;justify-content:center;
  background:var(--navy);color:#fff;text-decoration:none;
  font-size:var(--fs-md);
  padding:16px 32px;border-radius:999px;transition:opacity .15s ease}
.btn:hover{opacity:.86}

/* --- hero ----------------------------------------------------------------- */
.hero{padding-bottom:clamp(40px,6vw,64px)}
.hero__body{display:flex;flex-direction:column;gap:1.6em;max-width:var(--measure)}
.hero p{font-size:var(--fs-body);font-weight:400;line-height:1.6;color:var(--ink)}
/* "Selected projects" was a 16px black heading sitting at the same size and
   colour as the body around it; it does the same job as every other label */
.projects__head{font-size:var(--fs-label);font-weight:400;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}

.worked{margin-top:clamp(32px,4.4vw,48px);display:flex;flex-direction:column;gap:8px}
.worked__list{list-style:none;display:flex;flex-direction:column;gap:2px}
.worked__row{color:var(--body)}
.worked__row .role{color:var(--body)}
.worked__row .org{color:var(--ink)}

/* --- rule ----------------------------------------------------------------- */
.rule{border:0;border-top:1px solid var(--line);margin:0}

/* --- projects ------------------------------------------------------------- */
.projects{padding-top:clamp(28px,3.6vw,40px)}
.projects__head{margin-bottom:clamp(28px,3.6vw,44px);padding-top:12px;
  font-size:var(--fs-md);text-transform:uppercase;color:var(--ink)}
.projects__list{list-style:none;display:flex;flex-direction:column;
  gap:clamp(40px,5.6vw,72px)}

.project{display:grid;grid-template-columns:minmax(0,414fr) minmax(0,428fr);
  gap:var(--gap-col);align-items:center;
  text-decoration:none;color:inherit}
.project__media{background:var(--panel);overflow:hidden;aspect-ratio:414/374}
.project__media img{width:100%;height:100%;object-fit:cover;
  transition:transform .5s cubic-bezier(.2,.6,.2,1)}
.project:hover .project__media img{transform:scale(1.02)}
.project__text{display:flex;flex-direction:column;gap:4px}
.project__title{font-size:var(--fs-sub);color:var(--ink);line-height:1.6}
.project__blurb{line-height:1.55;font-weight:400;color:var(--body);line-height:1.4}

/* --- clients strip -------------------------------------------------------- */
.clients{margin-top:clamp(36px,4.4vw,64px)}
.clients img{width:100%;height:auto}

/* ==========================================================================
   case study pages
   ========================================================================== */
.cs-hero{padding-block:clamp(32px,4.4vw,56px) clamp(40px,5.6vw,72px)}
.cs-hero--tint{padding-inline:0}
.cs-hero__band{padding:clamp(36px,5.4vw,64px) 0;color:#fff}
/* The brand green is light: white on it is 2.1:1, nowhere near AA. Ink on
   the same green is 9.9:1, so the band keeps its colour and flips its text. */
.cs-hero__band--green{background:var(--green);color:var(--ink)}
.cs-hero__band--moss{background:var(--moss)}
.cs-hero__band--ink{background:var(--ink)}
.cs-hero__title{font-size:var(--fs-display);line-height:1.2;letter-spacing:-.02em;margin-bottom:16px}
.cs-hero__sub{font-weight:400;line-height:1.4;max-width:var(--measure)}
.cs-hero__question{font-size:var(--fs-lead);font-weight:400;line-height:1.4;letter-spacing:-.03em;max-width:46ch;
  margin-top:clamp(28px,3.6vw,40px)}

/* hero band: centred content on a colour field */
.cs-hero__center{max-width:560px;margin-inline:auto;text-align:center;
  display:flex;flex-direction:column;gap:clamp(20px,2.4vw,28px);align-items:center}
.cs-hero__center p{font-weight:400;line-height:1.6}
.cs-hero__figure{margin:clamp(28px,3.8vw,44px) auto 0;max-width:544px}
.cs-hero__figure img{width:100%;height:auto}

/* meta: facts rail beside the project summary */
.cs-meta{display:grid;grid-template-columns:minmax(150px,240px) minmax(0,1fr);
  gap:clamp(28px,5vw,76px);align-items:start;
  padding-block:clamp(48px,6.4vw,88px)}
.cs-meta__facts{display:flex;flex-direction:column;gap:clamp(24px,2.8vw,36px);margin:0}
.cs-meta__summary{max-width:var(--measure-cs);display:flex;flex-direction:column;gap:1.1em}
.cs-meta__summary .statement{font-size:var(--fs-lead);font-weight:400;line-height:1.4;letter-spacing:-.03em;color:var(--ink)}
.cs-meta__summary p{font-weight:400;color:var(--ink);line-height:1.6}

.fact{display:flex;flex-direction:column;gap:4px}
.fact dt{font-size:var(--fs-label);font-weight:400;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.fact dd{margin:0;font-size:var(--fs-meta);font-weight:400;color:var(--ink);line-height:1.6}
.fact ul{list-style:none;display:flex;flex-direction:column;gap:2px}
.fact li{font-size:var(--fs-meta);font-weight:400;color:var(--ink);line-height:1.6}

@media (max-width:640px){
  .cs-meta{grid-template-columns:1fr;gap:clamp(28px,5vw,40px)}
}

/* generic case-study section */
.cs-section{padding-block:clamp(40px,5.6vw,72px)}
/* labelled sections are separated by a hairline rule */
.cs-section--ruled{border-top:1px solid var(--line);
  padding-top:clamp(28px,3.6vw,44px)}
.cs-section__label{margin-bottom:12px;font-size:var(--fs-label);font-weight:500;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.cs-section__statement{font-size:var(--fs-lead);font-weight:400;line-height:1.4;letter-spacing:-.03em;
  color:var(--ink);max-width:var(--measure-cs);margin-bottom:clamp(20px,2.6vw,28px)}
.cs-body{display:flex;flex-direction:column;gap:1.2em;max-width:var(--measure-cs);
  font-weight:400;color:var(--ink);line-height:1.6}
.cs-body ul{padding-left:1.15em;display:flex;flex-direction:column;gap:.4em}
.cs-section li{color:var(--ink)}
.cs-body li{list-style:disc}

.cs-learnings{margin-top:clamp(36px,4.6vw,60px)}
.cs-figure{margin-top:clamp(28px,3.6vw,44px)}
.cs-figure img{width:100%;height:auto}
/* --- expandable figures ---------------------------------------------------
   The trigger is a plain button wrapped round the image by lightbox.js, so
   the figure keeps its layout and gains keyboard access. */
.zoomable{display:block;width:100%;padding:0;border:0;background:none;
  cursor:zoom-in;position:relative;line-height:0;color:inherit}
.zoomable img{width:100%;height:auto;display:block}
.zoomable::after{
  content:"Expand";position:absolute;right:12px;bottom:12px;
  font-size:var(--fs-cap);line-height:1;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink);background:rgb(255 255 255 / .92);
  padding:8px 12px;border:1px solid var(--ink);
  opacity:0;transition:opacity .15s ease;pointer-events:none;
}
.zoomable:hover::after,.zoomable:focus-visible::after{opacity:1}

dialog.zoom{
  max-width:100vw;max-height:100vh;width:100%;height:100%;
  margin:0;padding:0;border:0;background:transparent;overflow:hidden;
  display:none;place-items:center;
}
dialog.zoom[open]{display:grid}
/* second stage: the file at 100%, with the dialog panning around it */
dialog.zoom.is-actual{overflow:auto;place-items:start center}
dialog.zoom.is-actual .zoom__figure{max-width:none;max-height:none;padding:clamp(12px,2vw,28px) 0}
dialog.zoom.is-actual .zoom__img{max-width:none;max-height:none;width:var(--nw);cursor:zoom-out}
dialog.zoom::backdrop{background:rgb(255 255 255 / .94);backdrop-filter:blur(3px)}
.zoom__figure{margin:0;display:flex;flex-direction:column;gap:12px;align-items:center;
  max-width:92vw;max-height:90vh}
/* two ceilings: a share of the screen, and the file's own size — whichever
   is smaller, so nothing is ever scaled past 100% */
.zoom__img{
  max-width:min(92vw, var(--nw, 92vw));
  max-height:min(90vh, var(--nh, 90vh));
  width:auto;height:auto;display:block;cursor:zoom-out;
  background:var(--panel);box-shadow:0 18px 60px rgb(0 0 0 / .18);
  animation:zoom-in .22s cubic-bezier(.2,.7,.2,1);
}
.zoom__cap{font-size:var(--fs-cap);line-height:1.5;color:var(--muted);
  max-width:70ch;text-align:center}
.zoom__bar{position:fixed;top:clamp(12px,2vw,24px);right:clamp(12px,2vw,24px);z-index:1;
  display:flex;gap:8px}
.zoom__bar button{
  display:flex;align-items:center;gap:8px;cursor:pointer;
  font:inherit;font-size:var(--fs-cap);letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink);background:var(--bg);border:1px solid var(--ink);padding:8px 12px;
}
.zoom__bar button:hover{background:var(--ink);color:var(--bg)}
@keyframes zoom-in{from{opacity:0;transform:scale(.97)}}
.zoom--instant .zoom__img{animation:none}
@media (prefers-reduced-motion:reduce){.zoom__img{animation:none}}

.fig-stack{display:flex;flex-direction:column;gap:clamp(16px,1.8vw,24px);
  margin-top:clamp(24px,3.2vw,40px)}
.fig-stack figure{margin:0}
/* these two are 844×118 strips: side by side or in a rail they shrink to
   nothing, so each one takes the full column */
.fig-stack img{width:100%;height:auto;display:block}

.cs-figure figcaption{margin-top:12px;font-size:var(--fs-cap);font-weight:400;line-height:1.6;color:var(--muted)}
.cs-figure--panel img{background:var(--panel)}

/* three-up card row */
.cards{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:clamp(20px,3vw,36px);margin-top:clamp(28px,3.6vw,40px)}
.card{display:flex;flex-direction:column;gap:8px}
.card h3{font-size:var(--fs-sub);color:var(--ink);line-height:1.6}
.card p{font-weight:400;color:var(--body);line-height:1.5}

/* pull quotes */
.quotes{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:clamp(20px,3vw,36px);margin-top:clamp(28px,3.6vw,40px)}
.quote{display:flex;flex-direction:column;gap:12px}
.quote blockquote{margin:0;font-weight:400;color:var(--ink);line-height:1.5}

/* outcomes */
.outcomes{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:clamp(24px,3.4vw,44px);margin-top:clamp(28px,3.6vw,40px)}
.outcome{display:flex;flex-direction:column;gap:8px}
.outcome h3{font-size:var(--fs-sub);color:var(--ink);line-height:1.6}
.outcome p{font-weight:400;color:var(--body);line-height:1.5}

/* next project */
.next{border-top:1px solid var(--line);margin-top:var(--sp-section);
  padding-top:clamp(28px,3.6vw,40px)}
.next a{display:flex;flex-direction:column;gap:8px;text-decoration:none;
  align-items:flex-end;text-align:right;margin-left:auto;max-width:var(--measure)}
.next__label{color:var(--ink);text-decoration:underline;
  text-decoration-thickness:1px;text-underline-offset:3px}
.next__title{font-size:var(--fs-lead);font-weight:400;line-height:1.4;letter-spacing:-.03em;color:var(--body)}
.next a:hover .next__title{color:var(--ink)}

/* Inner Bloom closes on a full-bleed black band instead of a rule */
.next--dark{border-top:0;background:var(--ink);color:#fff;
  padding-block:clamp(32px,4vw,48px);margin-top:clamp(40px,5.4vw,72px)}
.next--dark .next__label{color:#fff}
.next--dark .next__title{color:rgba(255,255,255,.82)}
.next--dark a:hover .next__title{color:#fff}

/* main column with a narrow figure column beside it */
.cs-split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,auto);
  gap:clamp(28px,4.4vw,64px);align-items:start}
.cs-split__aside{display:flex;flex-direction:column;gap:clamp(16px,2.2vw,24px);
  width:clamp(152px,20vw,240px)}
.cs-split__aside--narrow{width:clamp(120px,16vw,180px)}
/* A staggered pair: two columns, the second dropped, each figure keeping its
   own height. The second image is a 263×3000 screenshot, so it stays cropped
   to a portrait window rather than running off down the page. */
.cs-split__aside--pair{
  width:clamp(200px,30vw,380px);
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(12px,1.4vw,16px);align-items:start;
}
.cs-split__aside--pair .pair__item:nth-child(even){margin-top:clamp(20px,3.6vw,44px)}
.cs-split__aside--pair figure.crop{aspect-ratio:3/5}
@media (max-width:560px){
  .cs-split__aside--pair{width:100%;grid-template-columns:repeat(2,minmax(0,1fr))}
}
.cs-split__aside--wide{width:clamp(200px,32vw,432px)}
/* a long scrolling screenshot shown through a fixed window, as on the live site */
.cs-split__aside figure.crop{aspect-ratio:142/278;overflow:hidden}
.cs-split__aside figure.crop img{width:100%;height:100%;object-fit:cover;object-position:top}
.cs-split__aside img{width:100%;height:auto}
.cs-split__aside figure{margin:0}
@media (max-width:720px){
  .cs-split{grid-template-columns:1fr}
  .cs-split__aside{flex-direction:row;flex-wrap:wrap;width:100%}
  .cs-split__aside figure{flex:1 1 140px}
}

/* a highlighted question / lead-in sentence inside body copy */
.cs-question{font-size:var(--fs-body);line-height:1.6;color:var(--ink);
  max-width:var(--measure-cs);margin-top:clamp(20px,2.6vw,28px)}
.cs-body .lead-in{color:var(--ink)}

.btn--ink{background:var(--ink)}
.btn-row{display:flex;justify-content:center;margin-top:clamp(36px,4.6vw,60px)}

/* re-entry: icon locked beside its list */
.icon-list{display:flex;gap:16px;align-items:flex-start;
  margin-top:clamp(20px,2.6vw,28px)}
.icon-list img{width:40px;height:auto;flex:none;margin-top:2px}
.icon-list ul{padding-left:1.15em;display:flex;flex-direction:column;gap:.4em;
  font-weight:400;color:var(--body)}
.icon-list li{list-style:disc}


/* --- responsive ----------------------------------------------------------- */
@media (max-width:720px){
  .project{grid-template-columns:1fr;gap:20px}
  .masthead__inner{gap:12px}
  .btn{padding:12px 24px}
}
@media (max-width:420px){
  .masthead__nav{gap:12px}
  .btn{padding:12px 20px;font-size:var(--fs-sm)}
  .navlink{font-size:var(--fs-sm)}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
  .project:hover .project__media img{transform:none}
}
@media print{.masthead__nav,.social{display:none}}

/* --- case-study components (Complex) -------------------------------------- */
.cs-body strong{font-weight:500;color:var(--ink)}

.cs-hero__figure--narrow{max-width:224px}
.cs-hero__figure--wide{max-width:800px}
.cs-figure--narrow{max-width:240px;margin-inline:auto}

.figure-pair{display:flex;flex-wrap:wrap;justify-content:center;
  gap:clamp(24px,4vw,64px);margin-top:clamp(28px,3.6vw,44px)}
.figure-pair .cs-figure{margin-top:0;flex:0 1 240px;max-width:240px}

/* research stats: icon locked to its label so they can never drift apart */
.stats{list-style:none;display:flex;flex-direction:column;gap:16px;
  margin-top:clamp(28px,3.6vw,40px)}
/* fixed icon column so every label starts on the same x */
.stat{display:grid;grid-template-columns:68px minmax(0,1fr);align-items:center;
  gap:16px;font-weight:400;color:var(--body)}
.stat img{height:24px;width:auto;justify-self:start}

.personas{list-style:none;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:clamp(16px,2.4vw,28px);margin-top:clamp(28px,3.6vw,40px)}
.persona{display:flex;flex-direction:column;gap:12px}
.persona__who{font-size:var(--fs-label);font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--ink);
  align-self:flex-start}
/* "For everyone" is marked with an inline black highlight, not a card */
.persona--dark .persona__who{background:var(--ink);color:#fff;padding:1px 8px}
.persona p{font-weight:400;line-height:1.5;color:var(--ink)}

.quote .label{color:var(--body)}

/* pull-to-peek (assets/js/peekaboo.js): pixel sky pinned behind the sheet.
   The canvas is drawn at 1/4 size and scaled up with no smoothing, so every
   art pixel lands as a crisp 4×4 block. */
.has-peekaboo{overscroll-behavior-y:none}
.peekaboo{position:fixed;top:0;left:0;width:100%;height:170px;z-index:0;
  visibility:hidden;pointer-events:none;image-rendering:pixelated}

/* --- field notes (homepage photography teaser) ---------------------------- */
/* Two layouts share one markup; data-layout on the section picks.
   Photos keep their true shape (--ar) — no square crops — and never move on
   hover. The only motion in the section is the print stack on "See all". */
.field-notes{padding-block:var(--sp-section)}
.field-notes[data-layout="none"]{display:none}
.fn-top{display:grid;grid-template-columns:minmax(0,1fr);gap:0;margin-bottom:clamp(28px,3.6vw,44px)}
.fn-top .projects__head{margin-bottom:12px}
.fn-top .projects__head:last-child{margin-bottom:0}   /* no intro under it: the same gap as "Selected projects" */
.fn-intro{font-family:var(--serif);font-style:italic;font-size:var(--fs-lead);font-weight:400;
  line-height:1.4;letter-spacing:-.01em;max-width:34ch;color:var(--ink)}
.fn{margin:0;display:flex;flex-direction:column;gap:8px}
.fn img{width:100%;height:auto;aspect-ratio:var(--ar);object-fit:cover;background:var(--panel)}

/* A · editorial: wide+tall pair, then flipped and stepped in a column */
[data-layout="editorial"] .fn-grid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));
  column-gap:24px;row-gap:clamp(48px,7vw,96px);align-items:start}
[data-layout="editorial"] .fn:nth-child(1){grid-column:1 / span 7}
[data-layout="editorial"] .fn:nth-child(2){grid-column:8 / span 5}
[data-layout="editorial"] .fn:nth-child(3){grid-column:2 / span 4}
[data-layout="editorial"] .fn:nth-child(4){grid-column:7 / span 6}

/* B · strip: one row, equal heights — each figure grows by its aspect ratio,
   so width ∝ ratio and every image lands at the same height */
[data-layout="strip"] .fn-grid{display:flex;gap:16px;align-items:flex-start}
[data-layout="strip"] .fn{flex:var(--grow) 1 0;min-width:0}
[data-layout="strip"] .fn--wide{--grow:1.5}
[data-layout="strip"] .fn--tall{--grow:.8}

@media (max-width:720px){
  [data-layout="editorial"] .fn-grid{grid-template-columns:minmax(0,1fr);row-gap:40px}
  [data-layout="editorial"] .fn:nth-child(n){grid-column:auto}
  /* strip becomes a swipe row at a fixed height */
  [data-layout="strip"] .fn-grid{overflow-x:auto;scroll-snap-type:x mandatory;
    margin-inline:calc(var(--rail) * -1);padding-inline:var(--rail);scroll-padding-inline:var(--rail);scrollbar-width:none}
  [data-layout="strip"] .fn{flex:none;scroll-snap-align:start}
  [data-layout="strip"] .fn img{height:200px;width:auto}   /* short enough that the next photo peeks in */
}

/* "See all" + print stack: three small prints piled slightly askew; on hover
   the top print translates up off the pile and the others fan a touch */
.fn-more{display:inline-flex;align-items:center;gap:20px;margin-top:clamp(40px,5vw,64px);
  color:var(--ink);text-decoration:none}
.fn-more__text{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}
.fn-stack{position:relative;width:64px;height:48px;flex:none}
.fn-stack img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  border:3px solid #fff;box-shadow:0 2px 8px rgba(0,0,0,.18);
  transition:transform .35s cubic-bezier(.2,.8,.2,1)}
.fn-stack img:nth-child(1){transform:rotate(-5deg) translate(-3px,2px)}
.fn-stack img:nth-child(2){transform:rotate(3deg) translate(3px,1px)}
.fn-stack img:nth-child(3){transform:rotate(-1deg)}
.fn-more:hover .fn-stack img:nth-child(1),.fn-more:focus-visible .fn-stack img:nth-child(1){transform:rotate(-9deg) translate(-8px,3px)}
.fn-more:hover .fn-stack img:nth-child(2),.fn-more:focus-visible .fn-stack img:nth-child(2){transform:rotate(7deg) translate(8px,1px)}
.fn-more:hover .fn-stack img:nth-child(3),.fn-more:focus-visible .fn-stack img:nth-child(3){transform:rotate(-2deg) translateY(-18px)}
@media (prefers-reduced-motion:reduce){.fn-stack img{transition:none}}


/* --- field notes page (/field-notes) --------------------------------------- */
/* One editorial column on the shared rail, paced like a magazine spread:
   full-width frames, 60% frames pushed left or right, and staggered pairs.
   True aspect ratios throughout; nothing moves on hover. */
.fn-page__head{padding-block:var(--fnheadpad,56px) clamp(28px,3.6vw,44px)}   /* bottom: the homepage Field Notes block's own spacing */
.fn-page__head .label{margin-bottom:12px}
/* the title is the homepage's Field Notes heading (it carries .projects__head,
   so it follows Layout options → Headings: style, size, case); only the
   spacing under it is set here, as on the homepage */
.fn-page .fn-page__title{margin-bottom:12px}
.fn-flow{display:flex;flex-direction:column;gap:clamp(64px,9vw,128px)}
.fp{margin:0;display:flex;flex-direction:column;gap:8px}
.fp img{width:100%;height:auto;aspect-ratio:var(--ar);object-fit:cover;background:var(--panel)}
.fp--left{width:60%}
.fp--right{width:60%;align-self:flex-end}
.fp-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px;align-items:start}
.fp-pair .fp:nth-child(2){margin-top:clamp(40px,6vw,96px)}
.fp__open{display:block;padding:0;border:0;background:none;cursor:zoom-in;width:100%}
.fp figcaption{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap}
.fp__gear{font-size:var(--fs-label);font-weight:400;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.fn-page__back{padding-block:clamp(64px,9vw,120px) var(--sp-section)}
@media (max-width:720px){
  .fp--left,.fp--right{width:100%}
  .fp-pair{grid-template-columns:minmax(0,1fr);gap:clamp(64px,9vw,128px)}
  .fp-pair .fp:nth-child(2){margin-top:0}
}
/* entrance: a single 400ms fade-up as each frame arrives, staggered by the
   script. Only applied when JS runs and motion is allowed. */
.fp.is-waiting{opacity:0;transform:translateY(16px)}
.fp{transition:opacity .4s ease,transform .4s cubic-bezier(.2,.8,.2,1)}

/* lightbox: black field, photo, caption bottom-left, count bottom-right */
.fn-box{margin:0;padding:0;border:0;max-width:none;max-height:none;width:100vw;height:100dvh;
  background:#000;color:#fff;overflow:hidden}
.fn-box::backdrop{background:#000}
.fn-box[open]{display:grid;grid-template-rows:auto 1fr auto}
.fn-box__bar,.fn-box__foot{display:flex;justify-content:space-between;align-items:center;gap:16px;
  padding:16px clamp(16px,3vw,32px)}
.fn-box__bar{justify-content:flex-end}
/* the photo runs the full width of the viewer, edge to edge with no black
   side bars; one taller than the window scrolls inside the stage (nothing is
   cropped). The arrows sit on the dialog, so they stay put while it scrolls. */
.fn-box__stage{display:grid;align-items:safe center;min-height:0;padding:0;overflow-y:auto;overscroll-behavior:contain}
.fn-box__img{display:block;width:100%;height:auto}
.fn-box button{font:500 var(--fs-label)/1 var(--sans);letter-spacing:.06em;text-transform:uppercase;
  color:#fff;background:none;border:0;padding:12px;cursor:pointer}
.fn-box button:hover{opacity:.6}
.fn-box :focus-visible{outline-color:#fff}
.fn-box__prev,.fn-box__next{position:absolute;top:50%;transform:translateY(-50%);font-size:22px!important;text-shadow:0 1px 6px rgba(0,0,0,.6)}
.fn-box__prev{left:clamp(0px,1.5vw,24px)}
.fn-box__next{right:clamp(0px,1.5vw,24px)}
.fn-box__cap,.fn-box__count{font-size:var(--fs-label);letter-spacing:.06em;text-transform:uppercase;color:#a3a3a3}
@media (max-width:720px){.fn-box__prev,.fn-box__next{display:none}}   /* swipe instead */

/* Scroll reveal on /field-notes (field-notes-reveal.js): a sticky 5×4 grid
   scrubbed by scroll, directly under the page header. The track runs
   full-bleed for 300vh and the stage sticks for the whole run.
   4-point grid: 8 gap, 8 inset, 4 radius. */
.fn-track{position:relative;height:300vh;margin-bottom:clamp(64px,9vw,128px)}
.fn-stage{position:sticky;top:0;height:100vh;
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));grid-template-rows:repeat(3,minmax(0,1fr));   /* 12 photos */
  gap:8px;padding:8px;perspective:200px;transform-style:preserve-3d;overflow:hidden}
.fn-stage img{width:100%;height:100%;object-fit:cover;display:block;border-radius:4px;
  will-change:transform,opacity;background:var(--panel)}
/* hidden until scrolled in, but only once the script is running */
.has-fn-reveal .fn-stage img{opacity:0}
@media (max-width:640px){
  .fn-stage{grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:repeat(4,minmax(0,1fr));gap:4px;padding:4px}
}
@media (prefers-reduced-motion:reduce){.has-fn-reveal .fn-stage img{opacity:1}}

@font-face{font-family:"That That New Pixel";src:url("../fonts/that-that-new-pixel-italic-square.otf") format("opentype");
  font-weight:400;font-style:italic;font-display:swap}

/* --- homepage layout B: two columns (Layout options, Page layout) ----------
   The intro and "Places I've worked" stick in a left sidebar while Selected
   projects scroll past on the right. Field Notes then runs full width below.
   Stacks back to one column under 768px. */
@media (min-width:768px){
  :root[data-home="split"] #main{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);
    column-gap:var(--gap-col);align-items:start;
    width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--rail)}
  :root[data-home="split"] #main > section > .container{padding-inline:0;max-width:none}
  /* The hero stretches down its whole grid row and its contents stick inside
     it. Sticking the hero itself would ride the whole #main (a sticky box's
     limit is its containing block, not its grid row) and slide over Field Notes. */
  :root[data-home="split"] .hero{grid-column:1;grid-row:1;align-self:stretch;padding-bottom:0}
  :root[data-home="split"] .hero > .container{position:sticky;top:32px}
  :root[data-home="split"] .hero__body{gap:1.2em}
  :root[data-home="split"] .projects{grid-column:2;grid-row:1;padding-top:0}
  :root[data-home="split"] .projects .rule{display:none}
  :root[data-home="split"] .projects__head{padding-top:0}
  :root[data-home="split"] .project{grid-template-columns:minmax(0,1fr);gap:16px}
  :root[data-home="split"] .field-notes{grid-column:1 / -1}
}

/* --- splash screen (assets/js/splash.js; tuned on /splash) -----------------
   Black, pixel-starred cover with the wordmark. The intro (fade-up and the
   star's twinkles) is built by splash.js from the motion settings, so it
   isn't keyframed here. The exits are, and their length comes from --exit,
   which splash.js sets from the same settings. */
.splash{position:fixed;inset:0;z-index:100;display:grid;place-items:center;--exit:.9s;--word:.6s}
/* the black and the pixel stars are drawn on this canvas, so the pixel exit can break it up */
.splash__sky{position:absolute;inset:0;width:100%;height:100%;image-rendering:pixelated}
.splash__mark{position:relative;z-index:2;width:min(56vw,480px);aspect-ratio:var(--ar)}
.splash__word{position:absolute;inset:0;width:100%;height:100%;
  clip-path:inset(0 100% 0 var(--cut));transition:clip-path var(--word) cubic-bezier(.6,0,.2,1)}
.splash.is-word .splash__word{clip-path:inset(0 0 0 var(--cut))}
.splash[data-intro="mark"] .splash__word{transition:none}
.splash__star{position:absolute;left:var(--sx);top:var(--sy);width:var(--sw);height:var(--sh);opacity:0}
.splash__star img{width:100%;height:100%;display:block;
  filter:drop-shadow(0 0 6px #fff) drop-shadow(0 0 20px rgb(255 255 255 / .7))}
.splash__star::before,.splash__star::after{content:"";position:absolute;left:50%;top:50%;translate:-50% -50%;
  opacity:0;pointer-events:none}
.splash__star::before{width:520%;height:2px;background:linear-gradient(90deg,transparent,#fff 45%,#fff 55%,transparent)}
.splash__star::after{width:2px;height:400%;background:linear-gradient(180deg,transparent,#fff 45%,#fff 55%,transparent)}

/* lift: the cover slides up off the page */
.splash[data-exit="lift"]{transition:transform var(--exit) cubic-bezier(.7,0,.2,1)}
.splash[data-exit="lift"].is-leaving{transform:translateY(-100%)}

/* warp: the canvas streaks the stars; the mark rushes past the viewer */
.splash[data-exit="warp"]{transition:opacity var(--exit) cubic-bezier(.8,0,1,1)}
.splash[data-exit="warp"] .splash__mark{transition:transform var(--exit) cubic-bezier(.6,0,1,1),opacity calc(var(--exit) * .66) ease-in}
.splash[data-exit="warp"].is-leaving{opacity:0}
.splash[data-exit="warp"].is-leaving .splash__mark{transform:scale(3.2);opacity:0}

/* crt: squeeze to a bright horizontal line, then to a dot, then gone */
.splash[data-exit="crt"].is-leaving{animation:crt-off var(--exit) cubic-bezier(.6,0,.4,1) forwards}
@keyframes crt-off{
  0%{transform:scale(1,1);filter:brightness(1)}
  40%{transform:scale(1,.004);filter:brightness(4)}
  75%{transform:scale(.004,.004);filter:brightness(6);opacity:1}
  100%{transform:scale(0,0);opacity:0}
}

/* pixel: the canvas drops its 16px blocks at random; the mark blinks out first */
.splash[data-exit="pixel"] .splash__mark{transition:opacity .2s steps(2)}
.splash[data-exit="pixel"].is-leaving .splash__mark{opacity:0}

/* iris: a star-shaped hole, centred on the wordmark's star, grows until the
   page shows through. Two mask layers (the star and a solid fill) excluded
   from each other; --ir animates through @property. */
@property --ir{syntax:"<length>";inherits:false;initial-value:0px}
/* the hole is the wordmark's own star as a vector (star-mask.svg, lifted from
   wordmark.svg), so its edge stays crisp at any size; the 167px star.png
   bitmap went pixelated when stretched ~40×. Its box is 86.452 × 122.5. */
.splash[data-exit="iris"]{
  -webkit-mask:url("/assets/img/star-mask.svg") no-repeat, linear-gradient(#000 0 0);
  mask:url("/assets/img/star-mask.svg") no-repeat, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
  -webkit-mask-size:var(--ir) calc(var(--ir) * 1.417),100% 100%;mask-size:var(--ir) calc(var(--ir) * 1.417),100% 100%;
  -webkit-mask-position:calc(var(--ix,50%) - var(--ir) / 2) calc(var(--iy,50%) - var(--ir) * .7085),0 0;
  mask-position:calc(var(--ix,50%) - var(--ir) / 2) calc(var(--iy,50%) - var(--ir) * .7085),0 0;
  transition:--ir var(--exit) cubic-bezier(.6,0,.8,.4)}
.splash[data-exit="iris"].is-leaving{--ir:520vmax}

/* nova, "Star burst" (default): one soft swell of the star while the words
   dim, then its white bloom eases out to every corner and the cover fades,
   white into the white page, so the handoff has no visible edge. */
@property --fr{syntax:"<length>";inherits:false;initial-value:0px}
.splash::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;opacity:0;
  background:radial-gradient(circle at var(--ix,50%) var(--iy,50%),#fff 0,#fff var(--fr),rgb(255 255 255 / 0) calc(var(--fr) + 24vmax))}
.splash[data-exit="nova"].is-leaving::after{animation:nova-bloom var(--exit) ease-in-out forwards}
.splash[data-exit="nova"].is-leaving .splash__word{transition:opacity .35s ease-out;opacity:0}
.splash[data-exit="nova"].is-leaving .splash__star{animation:nova-star var(--exit) cubic-bezier(.55,0,.6,1) forwards}
.splash[data-exit="nova"].is-leaving .splash__star img{filter:drop-shadow(0 0 4px #fff)}
.splash[data-exit="nova"].is-leaving .splash__star::before,
.splash[data-exit="nova"].is-leaving .splash__star::after{animation:nova-flare var(--exit) ease-out forwards}
.splash[data-exit="nova"].is-leaving{animation:nova-fade var(--exit) linear forwards}
@keyframes nova-star{                        /* opacity is restated: the star's base style is 0 */
  0%{transform:scale(1);opacity:1}
  100%{transform:scale(18) rotate(20deg);opacity:1}
}
@keyframes nova-flare{                       /* the rays brighten once, softly, and are gone before the star grows large */
  0%{opacity:0;transform:scale(.6)}
  10%{opacity:.4;transform:scale(1)}
  24%,100%{opacity:0;transform:scale(1.2)}
}
@keyframes nova-bloom{
  0%,20%{opacity:0;--fr:0px}
  40%{opacity:1;--fr:0px}
  82%,100%{opacity:1;--fr:160vmax}
}
@keyframes nova-fade{0%,84%{opacity:1}100%{opacity:0}}

@media (prefers-reduced-motion:reduce){
  .splash,.splash__word,.splash__mark{transition:none}
  .splash.is-leaving{animation:none;opacity:0}
}

/* --- /field-notes version B: the grid sits, already settled, under the header.
   No 300vh scrub and no sticky stage; square tiles in the same 5×4 grid. */
:root[data-fnpage="grid"] .fn-track{height:auto}
:root[data-fnpage="grid"] .fn-stage{position:static;height:auto;perspective:none;
  grid-template-rows:none;grid-auto-rows:auto}
:root[data-fnpage="grid"] .fn-stage img{aspect-ratio:1;height:auto;opacity:1;transform:none}

/* --- floating back-to-top (assets/js/back-to-top.js) ------------------------
   Appears once you're a screen down; 48px target, on the 4-point grid. Sits
   above the Layout options panel when that's showing. */
.fab-top{position:fixed;right:16px;bottom:16px;z-index:55;width:48px;height:48px;border-radius:50%;
  display:grid;place-items:center;border:0;cursor:pointer;
  background:var(--ink);color:#fff;font:400 20px/1 var(--sans);
  box-shadow:0 4px 16px rgb(0 0 0 / .2);
  opacity:0;translate:0 12px;pointer-events:none;transition:opacity .2s ease,translate .2s ease}
.fab-top.is-shown{opacity:1;translate:0 0;pointer-events:auto}
.fab-top:hover{background:#222}
.fab-top:focus-visible{outline:2px solid var(--navy);outline-offset:4px}
.has-hlab .fab-top{bottom:76px}
@media (prefers-reduced-motion:reduce){.fab-top{transition:none}}

/* /field-notes version C: B's layout (grid in the flow under the header), with
   the photos still flying in; field-notes-reveal.js drives it from load + scroll */
:root[data-fnpage="early"] .fn-track{height:calc(100svh - var(--fnhead,0px) + 150vh)}
:root[data-fnpage="early"] .fn-stage{top:var(--fnhead,0px);height:calc(100svh - var(--fnhead,0px))}

/* homepage layout C: two columns, with Field Notes also in the scrolling right
   column. Same rules as "split"; the intro sticks across both rows. */
@media (min-width:768px){
  :root[data-home="split-fn"] #main{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);
    column-gap:var(--gap-col);align-items:start;
    width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--rail)}
  :root[data-home="split-fn"] #main > section > .container{padding-inline:0;max-width:none}
  :root[data-home="split-fn"] .hero{grid-column:1;grid-row:1 / span 2;align-self:stretch;padding-bottom:0}
  :root[data-home="split-fn"] .hero > .container{position:sticky;top:32px}
  :root[data-home="split-fn"] .hero__body{gap:1.2em}
  :root[data-home="split-fn"] .projects{grid-column:2;grid-row:1;padding-top:0}
  :root[data-home="split-fn"] .projects .rule{display:none}
  :root[data-home="split-fn"] .projects__head{padding-top:0}
  :root[data-home="split-fn"] .project{grid-template-columns:minmax(0,1fr);gap:16px}
  :root[data-home="split-fn"] .field-notes{grid-column:2;grid-row:2}
  :root[data-home="split-fn"] .fn-intro{max-width:none}
  /* the editorial grid needs the full width; in a column it stacks */
  :root[data-home="split-fn"] [data-layout="editorial"] .fn-grid{grid-template-columns:minmax(0,1fr);row-gap:40px}
  :root[data-home="split-fn"] [data-layout="editorial"] .fn:nth-child(n){grid-column:auto}
  /* the strip is too thin at column width; a 2×2 grid keeps the photos readable */
  :root[data-home="split-fn"] [data-layout="strip"] .fn-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px 16px}
  :root[data-home="split-fn"] [data-layout="strip"] .fn img{aspect-ratio:4/3}
}

/* two-column layouts: generous room between the last of the sticky intro
   ("Places I've worked") and the end of the white sheet (cut 25% on 2026-10-01) */
@media (min-width:768px){
  :root[data-home="split"] .hero{padding-bottom:clamp(72px,9vw,144px)}
  :root[data-home="split-fn"] #main{padding-bottom:clamp(144px,16.5vw,240px)}
}

/* --- homepage layout D: sidebar (home-lab.js moves the wordmark, intro and
   nav into <aside class="sidebar">). One sticky, full-height left column:
   wordmark at the top, intro below it, Work + Resume anchored to the bottom.
   Projects and Field Notes scroll on the right. */
.sidebar{display:flex;flex-direction:column;gap:32px;padding:24px var(--rail)}
:root[data-home="sidebar"] .masthead{display:none}
@media (min-width:768px){
  :root[data-home="sidebar"] .sheet{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);
    column-gap:var(--gap-col);align-items:start;
    padding-inline:max(var(--rail), calc((100% - var(--maxw)) / 2 + var(--rail)));
    padding-bottom:clamp(72px,9vw,144px)}
  :root[data-home="sidebar"] .sidebar{grid-column:1;grid-row:1;position:sticky;top:0;
    height:100vh;height:100svh;padding:40px 0 32px;gap:0}
  :root[data-home="sidebar"] .sidebar .hero{flex:1 1 auto;min-height:0;overflow:auto;
    padding:clamp(48px,8vh,96px) 0 32px}
  :root[data-home="sidebar"] .sidebar .hero > .container{padding-inline:0;max-width:none}
  :root[data-home="sidebar"] .sidebar .hero__body{gap:1.2em}
  :root[data-home="sidebar"] .sidebar .masthead__nav{margin-top:auto;justify-content:flex-start}
  :root[data-home="sidebar"] #main{grid-column:2;grid-row:1;padding-top:40px}
  :root[data-home="sidebar"] #main > section > .container{padding-inline:0;max-width:none}
  :root[data-home="sidebar"] .projects{padding-top:0}
  :root[data-home="sidebar"] .projects .rule{display:none}
  :root[data-home="sidebar"] .projects__head{padding-top:0}
  :root[data-home="sidebar"] .project{grid-template-columns:minmax(0,1fr);gap:16px}
  :root[data-home="sidebar"] .fn-intro{max-width:none}
  :root[data-home="sidebar"] [data-layout="editorial"] .fn-grid{grid-template-columns:minmax(0,1fr);row-gap:40px}
  :root[data-home="sidebar"] [data-layout="editorial"] .fn:nth-child(n){grid-column:auto}
  :root[data-home="sidebar"] [data-layout="strip"] .fn-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px 16px}
  :root[data-home="sidebar"] [data-layout="strip"] .fn img{aspect-ratio:4/3}
}

/* right-column case-study tiles in the two-column and sidebar layouts:
   8px rounded corners (overflow clips the image and its hover zoom) */
:root:is([data-home="split"],[data-home="split-fn"],[data-home="sidebar"]) .project__media{border-radius:8px}

/* both columns of the two-column and sidebar layouts: +8px of breathing room
   left and right inside each column */
@media (min-width:768px){
  :root:is([data-home="split"],[data-home="split-fn"]) #main > section{padding-inline:8px}
  :root[data-home="sidebar"] .sidebar,
  :root[data-home="sidebar"] #main{padding-inline:8px}
}

/* sidebar layout: the links stack at the foot of the left column, and each can
   be hidden from Layout options (data-sn-*). Playground and LinkedIn are
   sidebar-only; the top header keeps just Work and Resume. */
.navlink--sidebar{display:none}
@media (min-width:768px){
  :root[data-home="sidebar"] .sidebar .masthead__nav{flex-direction:column;align-items:flex-start;gap:16px}
  :root[data-home="sidebar"] .sidebar .navlink--sidebar{display:inline-flex}
}
:root[data-home="sidebar"] .sidebar .navlink--sidebar{display:inline-flex}
:root[data-snwork="off"] .sidebar [data-nav="work"],
:root[data-snplayground="off"] .sidebar [data-nav="playground"],
:root[data-snlinkedin="off"] .sidebar [data-nav="linkedin"],
:root[data-snresume="off"] .sidebar [data-nav="resume"]{display:none}

/* --- footer name option: PP Editorial New, typeset (Layout options) --------
   All six styles are loaded under their own family name so the existing
   "Editorial New" (the Field Notes accent) is untouched. A star slot leads the
   name in the wordmark's proportion: the star is ~.95 of the cap height wide
   and sits a hair off the "g". star.png stands in until the real icon exists. */
@font-face{font-family:"PP Editorial New";src:url("../fonts/pp-editorial-new-ultralight.otf") format("opentype");font-weight:200;font-style:normal;font-display:swap}
@font-face{font-family:"PP Editorial New";src:url("../fonts/pp-editorial-new-regular.otf") format("opentype");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"PP Editorial New";src:url("../fonts/pp-editorial-new-ultrabold.otf") format("opentype");font-weight:800;font-style:normal;font-display:swap}
@font-face{font-family:"PP Editorial New";src:url("../fonts/pp-editorial-new-ultralightitalic.otf") format("opentype");font-weight:200;font-style:italic;font-display:swap}
@font-face{font-family:"PP Editorial New";src:url("../fonts/pp-editorial-new-italic.otf") format("opentype");font-weight:400;font-style:italic;font-display:swap}
@font-face{font-family:"PP Editorial New";src:url("../fonts/pp-editorial-new-ultrabolditalic.otf") format("opentype");font-weight:800;font-style:italic;font-display:swap}

/* sidebar nav icons: 16px line icons in the text colour, before each link.
   Shown only in the Sidebar layout; the top header stays text-only. */
.nav-ico{display:none;width:16px;height:16px;flex:none;fill:none;stroke:currentColor;
  stroke-width:1.25;stroke-linecap:round;stroke-linejoin:round}
:root[data-home="sidebar"] .sidebar .nav-ico{display:inline-block}
:root[data-home="sidebar"] .sidebar .masthead__nav a{display:inline-flex;align-items:center;gap:8px}
:root[data-snwork="off"] .sidebar [data-nav="work"],
:root[data-snplayground="off"] .sidebar [data-nav="playground"],
:root[data-snlinkedin="off"] .sidebar [data-nav="linkedin"],
:root[data-snresume="off"] .sidebar [data-nav="resume"]{display:none}

/* sidebar link show/hide, at a specificity above the icon layout rule
   (:root[data-home="sidebar"] .sidebar .masthead__nav a), which was
   overriding the hide and made the toggles do nothing */
:root[data-snwork="off"][data-home] .sidebar .masthead__nav a[data-nav="work"],
:root[data-snplayground="off"][data-home] .sidebar .masthead__nav a[data-nav="playground"],
:root[data-snlinkedin="off"][data-home] .sidebar .masthead__nav a[data-nav="linkedin"],
:root[data-snresume="off"][data-home] .sidebar .masthead__nav a[data-nav="resume"]{display:none}

/* two-column and sidebar layouts: wider and less compressed. The frame grows
   to 1280px and the outer margins tighten; the gap between the columns
   (--gap-col plus 8px each side) stays exactly as it was. */
@media (min-width:768px){
  /* outer margins from the Column padding slider (--colpad, 4-pt steps); no width cap, so the
     margins alone decide how wide the columns run, up to the full window at 0 */
  :root:is([data-home="split"],[data-home="split-fn"],[data-home="sidebar"]){--maxw:100%;--rail:var(--colpad,48px)}
  :root:is([data-home="split"],[data-home="split-fn"]) #main > section{padding-inline:0}
  :root:is([data-home="split"],[data-home="split-fn"]) #main > .hero,
  :root[data-home="split-fn"] #main > .field-notes{padding-inline:0 8px}
  :root:is([data-home="split"],[data-home="split-fn"]) #main > .projects,
  :root[data-home="split-fn"] #main > .field-notes{padding-inline:8px 0}
  :root[data-home="sidebar"] .sidebar{padding-inline:0 8px}
  :root[data-home="sidebar"] #main{padding-inline:8px 0}
}

/* --- About me (homepage) ----------------------------------------------------
   Portrait placeholder beside (or above) a short bio. Layout options:
   data-about="off" hides it; data-aboutpos = left (default) / right / top. */
.about{padding-top:clamp(28px,3.6vw,40px)}
.about__grid{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:var(--gap-col);align-items:start}
.about__portrait{margin:0}
.about__ph{aspect-ratio:4/5;border-radius:8px;background:var(--panel);border:1px dashed #c8c8c8;
  display:grid;place-items:center;color:var(--muted)}
.about__ph span{font-size:var(--fs-label);letter-spacing:.06em;text-transform:uppercase}
.about__text{display:flex;flex-direction:column;gap:1.2em;max-width:var(--measure)}
.about__text p{font-weight:400;color:var(--ink);line-height:1.6}
.about__text .about__lead{font-size:var(--fs-lead);line-height:1.4;letter-spacing:-.03em}
:root[data-about="off"] .about{display:none}
:root[data-aboutpos="right"] .about__portrait{order:2}
:root[data-aboutpos="right"] .about__grid{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
:root[data-aboutpos="top"] .about__grid{grid-template-columns:minmax(0,1fr)}
:root[data-aboutpos="top"] .about__portrait{max-width:320px}
@media (max-width:720px){
  .about__grid{grid-template-columns:minmax(0,1fr)}
  .about__portrait{max-width:280px}
}
/* in the column layouts: Two-column keeps it full width under the intro and
   projects; Two-column + Field Notes puts it in the right column; Sidebar's
   right column already flows projects → about → field notes */
@media (min-width:768px){
  :root[data-home="split"] .about{grid-column:1 / -1;grid-row:2}
  :root[data-home="split"] .field-notes{grid-row:3}
  :root[data-home="split-fn"] .hero{grid-row:1 / span 3}
  :root[data-home="split-fn"] .about{grid-column:2;grid-row:2;padding-inline:8px 0}
  :root[data-home="split-fn"] .field-notes{grid-row:3}
  :root:is([data-home="split-fn"],[data-home="sidebar"]) .about .rule{display:block}
  :root:is([data-home="split-fn"],[data-home="sidebar"]) .about__grid{grid-template-columns:minmax(0,2fr) minmax(0,3fr)}
}

/* clients & companies logo strip: hidden from Layout options (data-clients="off") */
:root[data-clients="off"] .clients{display:none}

/* homepage Field Notes thumbnails: 8px corner radius, and each opens in the
   photo viewer (fn-home-viewer.js wraps it in a .fn__open button) */
.field-notes .fn img{border-radius:8px}
.fn__open{display:block;width:100%;padding:0;border:0;background:none;cursor:zoom-in;border-radius:8px}
.fn__open img{transition:opacity .2s ease}
.fn__open:hover img{opacity:.9}
.fn__open:focus-visible{outline:2px solid var(--navy);outline-offset:4px}

/* --- section headings ("Selected projects", "About me", "Field Notes") ------
   Layout options can set them in the footer's display faces instead of the
   small uppercase label: the pixel font (lowercase, as in the footer) or
   Editorial New, sized by the 4px-step --sechs slider. */
:root:is([data-sechead="pixel"],[data-sechead="pixelroman"],[data-sechead="editorial"]) .projects__head{
  font-size:var(--sechs,48px);line-height:1;letter-spacing:1px;text-transform:lowercase;color:var(--ink);
  padding-top:16px;margin-bottom:clamp(24px,3.2vw,40px)}
:root[data-sechead="pixel"] .projects__head{font-family:"That That New Pixel",var(--sans);font-style:italic;font-weight:400;-webkit-font-smoothing:none}
:root[data-sechead="pixelroman"] .projects__head{font-family:"That That New Pixel",var(--sans);font-style:normal;font-weight:400;-webkit-font-smoothing:none}
:root[data-sechead="editorial"] .projects__head{font-family:"PP Editorial New",var(--serif);font-style:normal;font-weight:var(--edw,400);letter-spacing:-.02em}

/* nav icon sets (Layout options, data-navicons): Lucide (default), the custom
   hand-drawn set, or none. Lucide is drawn on a 24px grid at stroke 2, which
   renders ~1.33px at 16px, close to the custom set's 1.25 */
:root[data-home="sidebar"] .sidebar .nav-ico--custom{display:none}
:root[data-navicons="custom"][data-home="sidebar"] .sidebar .nav-ico--lucide{display:none}
:root[data-navicons="custom"][data-home="sidebar"] .sidebar .nav-ico--custom{display:inline-block}
:root[data-navicons="none"][data-home="sidebar"] .sidebar .nav-ico{display:none}
.nav-ico--lucide{stroke-width:2}

/* section headings: "Match footer name" follows the footer's name style, in
   lowercase. The pixel styles map straight across; Editorial New carries its
   weight, style and tracking; the two wordmark images (not type) map to the
   nearest Editorial New cut (bold → Ultrabold, thin → Regular). */
:root[data-sechead="match"] .projects__head{font-size:var(--sechs,48px);line-height:1;letter-spacing:1px;
  text-transform:lowercase;color:var(--ink);padding-top:16px;margin-bottom:clamp(24px,3.2vw,40px);
  font-family:"That That New Pixel",var(--sans);font-style:italic;font-weight:400;-webkit-font-smoothing:none}
:root[data-sechead="match"][data-fname="roman"] .projects__head{font-style:normal}
:root[data-sechead="match"]:is([data-fname="editorial"],[data-fname="wordmark"],[data-fname="thin"]) .projects__head{
  font-family:"PP Editorial New",var(--serif);-webkit-font-smoothing:antialiased}
:root[data-sechead="match"][data-fname="editorial"] .projects__head{font-weight:var(--edw,400);font-style:var(--eds,normal);letter-spacing:var(--edk,0em)}
:root[data-sechead="match"][data-fname="wordmark"] .projects__head{font-weight:800;font-style:normal;letter-spacing:-.02em}
:root[data-sechead="match"][data-fname="thin"] .projects__head{font-weight:400;font-style:normal;letter-spacing:-.01em}
/* never uppercase in any display style, whatever else sets the label voice */
:root:is([data-sechead="match"],[data-sechead="pixel"],[data-sechead="pixelroman"],[data-sechead="editorial"]) :is(.projects__head,#fn-head,#about-head){text-transform:lowercase}

/* --- Places I've worked: order (Layout options, data-worked) -----------------
   The ▪ is drawn here, so it always sits between the two parts. Default:
   role ▪ company years [logo]. "org": [logo] company years ▪ role. */
.worked__row .role::after{content:" ▪"}
:root[data-worked="org"] .worked__row{display:flex;align-items:center;flex-wrap:wrap;gap:0 8px}
:root[data-worked="org"] .worked__row .nowrap{display:contents}
:root[data-worked="org"] .worked__row .inline-img{order:0;margin:0}
:root[data-worked="org"] .worked__row .org{order:1}
:root[data-worked="org"] .worked__row .org::after{content:"▪";margin-left:8px;color:var(--body)}   /* 8px each side: this margin + the row gap */
:root[data-worked="org"] .worked__row .role{order:2}
:root[data-worked="org"] .worked__row .role::after{content:none}

/* header wordmark size (Layout options → Page): --hwm is unset at the default,
   keeping the original responsive 104–128px; otherwise a fixed width that
   shrinks to fit its column */
.masthead .wordmark, .sidebar .wordmark{max-width:100%}
.wordmark img{width:var(--hwm, clamp(104px,9vw,128px));max-width:100%}

/* Playground icon alternatives (Layout options → Sidebar): Lucide's telescope
   and orbit, astronomy-textbook motifs. They replace the sparkles in either
   icon set; with the custom set the stroke matches its 1.25-in-16 weight. */
:root[data-home="sidebar"] .sidebar .nav-ico--alt{display:none;stroke-width:2}
:root[data-navicons="custom"] .sidebar .nav-ico--alt{stroke-width:1.875}
:root:is([data-pgicon="telescope"],[data-pgicon="orbit"])[data-home="sidebar"] .sidebar [data-nav="playground"] :is(.nav-ico--lucide,.nav-ico--custom){display:none}
:root[data-pgicon="telescope"][data-home="sidebar"]:not([data-navicons="none"]) .sidebar .nav-ico--alt[data-icon="telescope"],
:root[data-pgicon="orbit"][data-home="sidebar"]:not([data-navicons="none"]) .sidebar .nav-ico--alt[data-icon="orbit"]{display:inline-block}

/* --- Field Notes · Bento: four tiles of different sizes (one big, one tall,
   two small), cropped to fill; the caption sits on the photo as a small pill.
   Narrow columns (sidebar, two-column) fold it to two columns. */
.field-notes[data-layout="bento"] .container{container-type:inline-size}
.field-notes[data-layout="bento"] .fn-grid{display:grid;gap:12px;grid-template-columns:repeat(4,minmax(0,1fr));grid-auto-rows:20cqi}
[data-layout="bento"] .fn{position:relative;gap:0;min-height:0}
[data-layout="bento"] .fn:nth-child(1){grid-column:1 / 3;grid-row:1 / 3}
[data-layout="bento"] .fn:nth-child(2){grid-column:3;grid-row:1 / 3}
[data-layout="bento"] .fn:nth-child(3){grid-column:4;grid-row:1}
[data-layout="bento"] .fn:nth-child(4){grid-column:4;grid-row:2}
[data-layout="bento"] .fn__open{height:100%}
[data-layout="bento"] .fn img{height:100%;aspect-ratio:auto}
[data-layout="bento"] .fn figcaption{position:absolute;left:8px;bottom:8px;padding:4px 8px;border-radius:999px;
  background:rgba(255,255,255,.88);color:var(--ink);font-size:12px;line-height:1;pointer-events:none}
@container (max-width:560px){
  .field-notes[data-layout="bento"] .fn-grid{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:36cqi}
  [data-layout="bento"] .fn:nth-child(2){grid-column:1;grid-row:3 / 5}
  [data-layout="bento"] .fn:nth-child(3){grid-column:2;grid-row:3}
  [data-layout="bento"] .fn:nth-child(4){grid-column:2;grid-row:4}
}

/* --- Field Notes · Pile: a loose stack of prints (fn-pile.js deals them).
   Each print keeps its own tilt (--r) and nudge (--x/--y); depth (--d) shrinks
   the ones underneath a touch. Flying out is a translate + rotate. */
.field-notes[data-layout="pile"] .fn-grid{position:relative;aspect-ratio:3/2;touch-action:pan-y}   /* the full column width; carousel keeps this same box, so nothing below moves */
[data-layout="pile"] .fn{position:absolute;left:50%;top:50%;width:84%;gap:0;padding:8px;background:#fff;border-radius:6px;
  box-shadow:0 1px 2px rgba(0,0,0,.08),0 12px 28px rgba(0,0,0,.14);
  transform:translate(-50%,-50%) translate(calc(var(--x,0%) + var(--pfx,0%)),calc(var(--y,0%) + var(--pfy,0%)))
            rotate(calc(var(--r,0deg) + var(--pfr,0deg))) scale(calc(1 - var(--d,0) * .03));
  transition:transform .26s cubic-bezier(.3,.7,.2,1)}
[data-layout="pile"] .fn--tall{width:46%}
[data-layout="pile"] .fn img{border-radius:3px}
[data-layout="pile"] .fn figcaption{display:none}
[data-layout="pile"] .fn:not(.is-top) .fn__open{cursor:pointer}
[data-layout="pile"] .fn:not(.is-top) .fn__open:hover img{opacity:1}
[data-layout="pile"] .fn.is-top:hover{--pfr:calc(var(--r) * -.4)}
[data-layout="pile"] .fn.is-fly-next{--pfx:72%;--pfy:-6%;--pfr:10deg}
[data-layout="pile"] .fn.is-fly-prev{--pfx:-72%;--pfy:-6%;--pfr:-10deg}

/* the pile's controls: ← count · caption → · Enlarge (or Back to stack) */
.fn-pile__bar{display:none}
.field-notes[data-layout="pile"] .fn-pile__bar{display:flex;align-items:center;gap:8px;margin-top:24px}
.fn-pile__meta{flex:1;display:flex;gap:12px;align-items:baseline;min-width:0;font-size:var(--fs-label)}
.fn-pile__count{font-variant-numeric:tabular-nums;letter-spacing:.06em}
.fn-pile__cap{color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fn-pile__bar button{font:500 var(--fs-label)/1 var(--sans);color:var(--ink);background:none;cursor:pointer;
  border:1px solid #d4d4d4;border-radius:999px;min-height:32px;padding:0 12px}
.fn-pile__bar button:hover{border-color:var(--ink)}
.fn-pile__bar button:focus-visible{outline:2px solid var(--navy);outline-offset:2px}
.fn-pile__prev,.fn-pile__next{width:32px;padding:0 !important;font-size:16px !important}
.fn-pile__meta{order:-1}   /* count and caption first; ← → sit together beside Enlarge / Back to stack */
.fn-pile__back{display:none}
.fn-pile__bar[data-view="carousel"] .fn-pile__enlarge{display:none}
.fn-pile__bar[data-view="carousel"] .fn-pile__back{display:inline-block}

/* expanded in the column: one photo the full width of the column */
[data-layout="pile"] [data-view="carousel"] .fn{display:none}
[data-layout="pile"] [data-view="carousel"] .fn.is-top{display:flex;inset:0;left:0;top:0;width:100%;height:100%;
  padding:0;background:none;box-shadow:none;transform:none;transition:none;animation:fn-in .3s ease}
[data-layout="pile"] [data-view="carousel"] .fn__open{height:100%}
[data-layout="pile"] [data-view="carousel"] .fn img{height:100%;aspect-ratio:auto;object-fit:contain;background:var(--panel);border-radius:8px}
[data-layout="pile"] [data-view="carousel"] .fn-pile__zoom{display:none}
[data-layout="pile"] [data-view="carousel"] .fn__open{cursor:e-resize}
@keyframes fn-in{from{opacity:0}}
@media (prefers-reduced-motion:reduce){
  [data-layout="pile"] .fn{transition:none}
  [data-layout="pile"] [data-view="carousel"] .fn.is-top{animation:none}
}

/* the pile's "Modal overlay": the viewer as a framed box over the page */
.fn-box.fn-box--modal{width:min(1040px,calc(100vw - 48px));height:auto;max-height:calc(100dvh - 48px);
  margin:auto;border-radius:12px;box-shadow:0 24px 64px rgba(0,0,0,.4)}
.fn-box--modal::backdrop{background:rgba(0,0,0,.55)}
.fn-box--modal .fn-box__stage{margin:0 16px;border-radius:4px;max-height:calc(100dvh - 160px)}

/* /field-notes version C: the head ("Photography / Field Notes / intro") sticks
   to the top while the grid scrolls up beneath it and finishes its reveal;
   it lets go when the grid ends (both share .fn-reveal-wrap) */
:root[data-fnpage="early"] .fn-page__head{position:sticky;top:var(--mastheadh,0px);z-index:2;background:var(--bg);
  padding-block:var(--fnheadpad,56px) 24px;margin-bottom:0;
  box-shadow:0 0 0 100vmax var(--bg);clip-path:inset(0 -100vmax)}   /* white edge to edge, though the text keeps the column */

/* every grid photo opens in the viewer (field-notes.js) */
.fs__open{cursor:zoom-in}
.fs__open:focus-visible{outline:2px solid var(--navy);outline-offset:2px}

/* the pile: a click on a print flips to the next; the ⤢ corner button on the
   top print (and "Enlarge" below) opens it; a sideways swipe flips too */
.fn-pile__zoom{display:none}
[data-layout="pile"] .fn.is-top .fn-pile__zoom{display:grid;place-items:center;position:absolute;top:16px;right:16px;z-index:1;
  width:32px;height:32px;border:0;border-radius:50%;cursor:zoom-in;background:rgba(255,255,255,.92);color:var(--ink);
  box-shadow:0 1px 4px rgba(0,0,0,.2);opacity:.85;transition:opacity .15s, scale .15s}
[data-layout="pile"] .fn.is-top .fn-pile__zoom:hover{opacity:1;scale:1.08}
.fn-pile__zoom svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
[data-layout="pile"] .fn:not([data-view="carousel"] .fn) .fn__open{cursor:pointer}

/* case study eyebrow (Layout options → Sections): the "Web app / Live project"
   text line, or the same keywords as pills (outlined) or chips (filled). Only
   one version is ever displayed, so screen readers hear it once. */
.project .chips{display:none}
:root:is([data-eyebrow="pills"],[data-eyebrow="chips"]) .project .label{display:none}
:root:is([data-eyebrow="pills"],[data-eyebrow="chips"]) .project .chips{display:flex;flex-wrap:wrap;gap:var(--chipgap,8px)}   /* a fixed space between chips (Tags → Space between chips) */
.chip{display:inline-flex;align-items:center;gap:4px;border-radius:999px;
  font:400 var(--chipfs,12px)/1 var(--sans);padding:var(--chippy,4px) var(--chippx,8px);letter-spacing:.01em;color:var(--body);border:1px solid #d4d4d4;white-space:nowrap}
:root[data-eyebrow="chips"] .chip{border-color:transparent;background:var(--panel);color:var(--soft)}

/* live projects: a small green dot (with a soft ring) by the title, or the dot
   plus the word. When it's on, the pills drop their own "Live" pill. */
.live-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--green);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--green) 22%, transparent);flex:none}
.live-mark{display:none;align-items:center;gap:8px;margin-left:8px;vertical-align:middle;
  font:400 12px/1 var(--sans);color:var(--body);letter-spacing:.01em}
.live-mark__word{display:none}
:root[data-live="dot"] .live-mark, :root[data-live="word"] .live-mark{display:inline-flex}
:root[data-live="word"] .live-mark__word{display:inline}
:root[data-live="dot"] .live-mark::after{content:"Live";position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}   /* still says "Live" to screen readers */
:root:is([data-live="dot"],[data-live="word"]) .chip--live{display:none}

/* case study eyebrow at body size (the default; "Label" keeps the old 14px):
   the text line and the pills/chips alike follow the body size token */


/* pills / chips below the description (the default), smaller: a quiet tag
   row that closes each tile rather than heading it. "Eyebrow size" still
   sizes the text eyebrow and the pills when they sit above. */


/* the text eyebrow at body size (default) or the old 14px label */
:root:not([data-ebsize="label"]) .project .label{font-size:var(--fs-body)}

/* where the pills / chips go (Layout options → Case studies): flex order
   inside the text column, or laid over the image's top-left corner */
.project{position:relative}
.project__title{order:1}
.project__blurb{order:3}
:root[data-ebpos="above"] .project .chips{order:0;margin-bottom:4px}
:root[data-ebpos="title"] .project .chips{order:2;margin-bottom:4px}
:root:not([data-ebpos]) .project .chips, :root[data-ebpos="below"] .project .chips{order:4;margin-top:8px}
:root[data-ebpos="image"] .project .chips{position:absolute;top:12px;left:12px;right:12px;z-index:1;pointer-events:none}
:root[data-ebpos="image"] .project .chip{background:rgba(255,255,255,.92);border-color:transparent;color:var(--ink);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}

/* industry chips lead the row, a touch darker so they read as the category */
.chip--industry{color:var(--soft);border-color:#bdbdbd}
:root[data-eyebrow="chips"] .chip--industry{background:#ebebeb}

/* version C, continued: the grid pins just under the sticky head, sized to
   the rest of the window, while scrolling flies every photo in; only once all
   of them have landed does the page move on and the head and grid scroll
   away together. Nothing ever passes under the head. --fnhead is the head's
   height (field-notes.js measures it). */
:root[data-fnpage="early"] .fn-page__head{z-index:10}

/* the live marker sits on the title's centre line, and its ring breathes:
   a soft halo grows and fades every 2.4s (no blink; still under reduced motion) */
/* the marker follows the title's last word on the same line, 16px clear of it
   (on the 4px grid) and centred on that line; it only drops to the next line
   when there's no room left on it */
:root:is([data-live="dot"],[data-live="word"]) .project__title .live-mark{margin-left:16px;vertical-align:middle;white-space:nowrap;
  position:relative;top:-.08em}
.live-mark{vertical-align:baseline}
.live-dot{position:relative}
.live-dot::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--green);
  animation:live-ring 2.4s cubic-bezier(.2,.6,.3,1) infinite}
@keyframes live-ring{0%{transform:scale(1);opacity:.45}70%,100%{transform:scale(2.6);opacity:0}}
@media (prefers-reduced-motion:reduce){.live-dot::after{animation:none;opacity:0}}

/* which case studies show on the homepage (Layout options → Cases → Projects) */
:root[data-pcib="off"] .projects [data-case="innerbloom"],
:root[data-pccx="off"] .projects [data-case="complex-c"],
:root[data-pcwa="off"] .projects [data-case="hixy"]{display:none}

/* the "Selected projects" heading, shown or hidden (Layout options → Cases).
   Hidden visually only: screen readers still get the section's name. */
:root[data-phead="hide"] #work .projects__head{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;margin:0;padding:0}
/* …and so the head lets go at the same moment as the grid, the wrapper that
   holds the head ends where the grid's pin ends (the track hangs out of it by
   one pinned-grid height; the wrapper's margin gives that space back) */
:root[data-fnpage="early"] .fn-track{margin-bottom:calc(var(--fnhead,0px) - 100svh)}
:root[data-fnpage="early"] .fn-reveal-wrap{display:flow-root;margin-bottom:calc(100svh - var(--fnhead,0px) + clamp(64px,9vw,128px))}

/* Field Notes grid, "In the grid (bento)": the enlarged photo spans 3×3 cells
   over its neighbours (field-notes.js places it); covered thumbnails step
   aside; Collapse sits in the big tile's corner */
.fn-stage img.is-big{z-index:5;cursor:zoom-out;box-shadow:0 12px 32px rgba(0,0,0,.18)}
/* the enlarged photo keeps its own proportions: full width of its columns,
   height from the photo set by field-notes.js spanOf (at most 3 rows) */
:root .fn-stage img.is-big[aria-expanded]{aspect-ratio:auto;align-self:start;object-fit:cover}
.fn-stage img.is-covered{visibility:hidden}
.fs__collapse{z-index:6;justify-self:end;align-self:start;margin:12px;padding:8px 12px;border:0;border-radius:999px;
  background:rgba(255,255,255,.92);color:var(--ink);font:500 var(--fs-label)/1 var(--sans);cursor:pointer;
  box-shadow:0 1px 4px rgba(0,0,0,.2)}
.fs__collapse[hidden]{display:none}
.fs__collapse:focus-visible{outline:2px solid var(--navy);outline-offset:2px}
::view-transition-group(*){animation-duration:.35s;animation-timing-function:cubic-bezier(.3,.7,.2,1)}

/* nav: Resume takes Work's place as a plain link (the default), and the
   Resume button goes; "before" keeps Work + the button */
.navlink--resume{display:none}
:root:not([data-navswap="work"]) .masthead__nav [data-nav="work"],
:root:not([data-navswap="work"]) .masthead__nav .btn[data-nav="resume"]{display:none !important}
:root:not([data-navswap="work"]) .masthead__nav .navlink--resume{display:inline-flex;align-items:center;gap:8px}
:root[data-snresume="off"] .sidebar [data-nav="resumelink"]{display:none !important}

/* /field-notes: hide the photo flow under the grid, so the page ends with it */
:root[data-fnflow="hide"] .fn-page .fn-flow{display:none}

/* Field Notes: the masthead (wordmark home + nav) stays at the top, so the
   way back is always in reach; the page's own sticky head sits under it */
.masthead--sticky{position:sticky;top:0;z-index:20;background:var(--bg);padding-block:clamp(24px,3.4vw,40px) clamp(16px,2vw,24px)}   /* top: the homepage masthead's */
.navlink--fn{display:none}
:root:not([data-navswap="work"]) .masthead--sticky .navlink--fn{display:inline-flex}
.masthead--sticky .masthead__nav{gap:clamp(16px,2vw,28px)}

/* seamless page changes (browsers with cross-document view transitions):
   the wordmark and the nav glide from where they were to where they land,
   everything else crossfades */
@media (prefers-reduced-motion:no-preference){
  @view-transition{navigation:auto}
}
.wordmark img{view-transition-name:gk-wordmark}
.masthead__nav{view-transition-name:gk-nav}
:root[data-home="sidebar"] .sidebar .masthead__nav{view-transition-name:gk-nav}
/* version A's pinned grid starts under the sticky masthead too */
.fn-page .fn-stage{top:var(--mastheadh,0px);height:calc(100vh - var(--mastheadh,0px))}

/* "See all field notes" → the page: the little photo stack grows into the
   Field Notes grid (option). The homepage names the stack only when the
   option is on; the Field Notes grid always carries the matching name. */
:root[data-fntrans="grow"] .fn-more .fn-stack{view-transition-name:gk-fn-stack}
.fn-page .fn-stage{view-transition-name:gk-fn-stack}
::view-transition-group(gk-fn-stack){animation-duration:.55s}

/* Field Notes header: the same nav icons as the homepage sidebar, following
   its icon set (Lucide / custom / none) and Playground icon choices */
.masthead--sticky .masthead__nav a.navlink{display:inline-flex;align-items:center;gap:8px}
.masthead--sticky .masthead__nav a[data-nav="work"]{display:none}
:root[data-navswap="work"] .masthead--sticky .masthead__nav a[data-nav="work"]{display:inline-flex}
.masthead--sticky .nav-ico{display:none}
.masthead--sticky .nav-ico--lucide{display:inline-block}
:root[data-navicons="custom"] .masthead--sticky .nav-ico--lucide{display:none}
:root[data-navicons="custom"] .masthead--sticky .nav-ico--custom{display:inline-block}
:root[data-navicons="none"] .masthead--sticky .nav-ico{display:none !important}
.masthead--sticky .nav-ico--alt{display:none;stroke-width:2}
:root[data-navicons="custom"] .masthead--sticky .nav-ico--alt{stroke-width:1.875}
:root:is([data-pgicon="telescope"],[data-pgicon="orbit"]) .masthead--sticky [data-nav="playground"] :is(.nav-ico--lucide,.nav-ico--custom){display:none}
:root[data-pgicon="telescope"] .masthead--sticky .nav-ico--alt[data-icon="telescope"],
:root[data-pgicon="orbit"] .masthead--sticky .nav-ico--alt[data-icon="orbit"]{display:inline-block}
:root[data-navswap="work"] .masthead--sticky .navlink--resume{display:none}

/* Field Notes: a quiet ← Back beside the "Photography" label */
.fn-page__eyebrow{display:flex;align-items:baseline;gap:16px;margin:0 0 12px}
.fn-page__eyebrow .label{margin:0}
.fn-back{font-size:var(--fs-label);color:var(--muted);text-decoration:none;transition:color .15s}
.fn-back:hover{color:var(--ink)}
.fn-back:focus-visible{outline:2px solid var(--navy);outline-offset:4px;border-radius:2px}

/* "Below the grid: nothing" (the default): the page ends with the last row
   of the grid. The photo flow, the back link and the footer go, and the
   grid's trailing space closes up, so there's nothing to scroll past. */
:root:not([data-fnflow="show"]) .fn-page .fn-flow,
:root:not([data-fnflow="show"]) .fn-page .fn-page__back,
:root:not([data-fnflow="show"]) .fn-page ~ .site-footer{display:none}
:root:not([data-fnflow="show"]) .fn-page .fn-track{margin-bottom:0}
:root:not([data-fnflow="show"]) .fn-page .fn-track + .container{display:none}
:root:not([data-fnflow="show"])[data-fnpage="early"] .fn-reveal-wrap{margin-bottom:calc(100svh - var(--fnhead,0px))}
:root:not([data-fnflow="show"])[data-fnpage="early"] .fn-page .fn-track{margin-bottom:calc(var(--fnhead,0px) - 100svh)}

/* "Prints fly into the grid": the three prints in the homepage's "See all"
   stack each fly to a photo in the middle row of the Field Notes grid
   (field-notes-reveal.js lands those three straight away, so they're there
   to fly to), while the rest of the grid reveals as usual */
:root[data-fntrans="prints"] .fn-more .fn-stack img:nth-child(1){view-transition-name:gk-print-1}
:root[data-fntrans="prints"] .fn-more .fn-stack img:nth-child(2){view-transition-name:gk-print-2}
:root[data-fntrans="prints"] .fn-more .fn-stack img:nth-child(3){view-transition-name:gk-print-3}
:root[data-prints] .fn-page .fn-stage img:nth-child(7){view-transition-name:gk-print-1}
:root[data-prints] .fn-page .fn-stage img:nth-child(6){view-transition-name:gk-print-2}
:root[data-prints] .fn-page .fn-stage img:nth-child(8){view-transition-name:gk-print-3}
:root[data-prints] .fn-page .fn-stage img:nth-child(n+6):nth-child(-n+8){opacity:1 !important;transform:none !important}
::view-transition-group(gk-print-1),::view-transition-group(gk-print-2),::view-transition-group(gk-print-3){
  animation-duration:.7s;animation-timing-function:cubic-bezier(.2,.8,.2,1)}
::view-transition-group(gk-print-2){animation-delay:.05s}
::view-transition-group(gk-print-3){animation-delay:.1s}

/* "Stack zooms off, page opens from it": the homepage's photo stack swells
   to about three times its size, then sweeps up off the screen, while the
   Field Notes page opens through a print-shaped cutout that grows from where
   the stack was until it fills the window (like the splash's iris). The
   cutout's start comes from the homepage (--cut-*, set before first paint). */
:root[data-cut]::view-transition-old(root){animation:fn-hold 1.1s both}
:root[data-cut]::view-transition-new(root){animation:fn-cutout 1.1s linear both}
::view-transition-group(gk-fn-zoom){animation-duration:1.1s}
::view-transition-old(gk-fn-zoom){animation:fn-zoom-off 1.1s linear both}
@keyframes fn-hold{from,to{opacity:1}}
/* first the stack swells (0–40%), then it sweeps off as the cutout opens */
@keyframes fn-cutout{
  0%,35%{clip-path:inset(var(--cut-t,45%) var(--cut-r,45%) var(--cut-b,45%) var(--cut-l,45%) round 6px);animation-timing-function:cubic-bezier(.65,0,.25,1)}
  100%{clip-path:inset(0 0 0 0 round 0)}}
@keyframes fn-zoom-off{
  0%{transform:none;animation-timing-function:cubic-bezier(.2,.8,.3,1)}
  40%{transform:scale(3.2);animation-timing-function:cubic-bezier(.6,0,.9,.5)}
  100%{transform:translateY(-140vh) scale(3.5) rotate(-6deg)}}


/* the zoom-off overlay (fn-home-viewer.js) */
.fz{position:fixed;inset:0;z-index:2147483000;pointer-events:none}
.fz__sheet{position:absolute;inset:0;background:var(--bg)}
.fz__stack{position:fixed;transform-origin:50% 50%}

/* /field-notes version D: two columns, like the homepage. The head (← Back,
   title, intro) sticks in the left column; the scroll reveal plays only in
   the right column, its grid pinned there until every photo has landed.
   Photos flying in are clipped to the column, never crossing into the left. */
@media (min-width:768px){
  :root[data-fnpage="split"] .fn-reveal-wrap{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);
    column-gap:var(--gap-col);align-items:start;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--rail)}
  :root[data-fnpage="split"] .fn-page__head{position:sticky;top:var(--mastheadh,0px);padding-inline:0;max-width:none;margin:0}
  :root[data-fnpage="split"] .fn-track{height:260vh;margin:0}
  :root[data-fnpage="split"] .fn-stage{top:var(--mastheadh,0px);height:calc(100vh - var(--mastheadh,0px));
    grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:repeat(4,minmax(0,1fr));padding:8px 0 16px}
}

/* /field-notes title in the homepage's display font: the same family, style,
   weight, tracking and lowercase as the homepage section headings (Layout
   options → Section headings), at the page title's own size */
:root[data-sechead="pixel"] .fn-page__title{font-family:"That That New Pixel",var(--sans);font-style:italic;font-weight:400;letter-spacing:1px;-webkit-font-smoothing:none}
:root[data-sechead="pixelroman"] .fn-page__title{font-family:"That That New Pixel",var(--sans);font-style:normal;font-weight:400;letter-spacing:1px;-webkit-font-smoothing:none}
:root[data-sechead="editorial"] .fn-page__title{font-family:"PP Editorial New",var(--serif);font-style:normal;font-weight:var(--edw,400);letter-spacing:-.02em}
:root[data-sechead="match"] .fn-page__title{font-family:"That That New Pixel",var(--sans);font-style:italic;font-weight:400;letter-spacing:1px;-webkit-font-smoothing:none}
:root[data-sechead="match"][data-fname="roman"] .fn-page__title{font-style:normal}
:root[data-sechead="match"]:is([data-fname="editorial"],[data-fname="wordmark"],[data-fname="thin"]) .fn-page__title{font-family:"PP Editorial New",var(--serif);-webkit-font-smoothing:antialiased}
:root[data-sechead="match"][data-fname="editorial"] .fn-page__title{font-weight:var(--edw,400);font-style:var(--eds,normal);letter-spacing:var(--edk,0em)}
:root[data-sechead="match"][data-fname="wordmark"] .fn-page__title{font-weight:800;font-style:normal;letter-spacing:-.02em}
:root[data-sechead="match"][data-fname="thin"] .fn-page__title{font-weight:400;font-style:normal;letter-spacing:-.01em}
:root:is([data-sechead="match"],[data-sechead="pixel"],[data-sechead="pixelroman"],[data-sechead="editorial"]) .fn-page__title{text-transform:lowercase}

/* Field Notes description as regular body text (the default; "Editorial New
   italic" brings back the serif accent): Neue Montreal at body size, like the intro */
:root:not([data-fnintrofont="serif"]) .fn-intro{font-family:var(--sans);font-style:normal;font-size:var(--fs-body);
  line-height:1.6;letter-spacing:normal;max-width:var(--measure)}

/* arriving on /field-notes by a night transition: black until the entrance
   starts (fn-transition.js), so there's no flash of the page first */
:root[data-enter]{background:#000}
:root[data-enter]:not([data-entering]) body{visibility:hidden}
:root[data-enter]:not([data-entering]) body{animation:fn-unhide 0s 2s forwards}   /* safety: never stuck hidden */
@keyframes fn-unhide{to{visibility:visible}}

/* /field-notes "in space" (fn-space.js): the homepage footer's night as the
   page, white type. The colour tokens flip, so every rule that reads them
   follows; the stars canvas sits behind everything, kept off the words. */
:root[data-space]{--bg:#000;--ink:#fff;--soft:#e8e8e8;--body:#cfcfcf;--muted:#a3a3a3;--panel:#121212;--hair:#2a2a2a;--line:#fff;
  background:#000;color-scheme:dark}
:root[data-space] body{background:transparent;color:#fff}
.fn-space-stars{position:fixed;left:0;top:0;z-index:-1;pointer-events:none;image-rendering:pixelated}
:root[data-space] .wordmark img{filter:invert(1)}
:root[data-space] .masthead--sticky{background:#000}
:root[data-space] .btn{background:#fff;color:#000}
:root[data-space] .fn-back:hover{color:#fff}
:root[data-space] .fn-stage img{background:#121212}

/* the homepage, arriving by the reversed SS: held until the way back plays */
:root[data-ssback]:not([data-ssplay]) body{visibility:hidden;animation:fn-unhide 0s 2s forwards}

/* Field Notes on a phone: a down arrow under the intro, so it's clear the
   photos are below (the reveal makes the page look finished at first). It
   bobs gently, and fades away once you start scrolling. Lucide arrow-down. */
.fn-scrollcue{display:none}
@media (max-width:720px){
  :root:not([data-fnpage="grid"]) .fn-scrollcue{display:block;width:24px;height:24px;margin-top:24px;color:var(--ink);
    transition:opacity .3s ease;animation:fn-bob 1.8s ease-in-out infinite}
  .fn-scrollcue svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
  .fn-scrolled .fn-scrollcue{opacity:0}
}
@keyframes fn-bob{0%,100%{translate:0 0}50%{translate:0 6px}}
@media (prefers-reduced-motion:reduce){.fn-scrollcue{animation:none}}

/* SS, "plays by itself": the grid in the flow under the intro (no 300vh
   scroll track), square photos, so the page ends with the complete grid */
:root[data-fnauto] .fn-track{height:auto}
:root[data-fnauto] .fn-stage{position:static;height:auto;grid-template-rows:none;grid-auto-rows:auto}
:root[data-fnauto] .fn-stage img{aspect-ratio:1;height:auto}
:root[data-fnauto] .fn-track{margin-bottom:0 !important}
:root[data-fnauto] .fn-reveal-wrap{margin-bottom:0 !important}
/* ...and in version D the right column never scrolls: each square is the
   smaller of a third of the column and a quarter of the height left under
   the masthead (8 top + 16 bottom padding, three 8px gaps) */
@media (min-width:768px){
  :root[data-fnauto][data-fnpage="split"] .fn-track{container-type:inline-size}
  :root[data-fnauto][data-fnpage="split"] .fn-stage{--cell:min((100cqw - 16px) / 3,(100svh - var(--mastheadh,0px) - 48px) / 4);
    grid-template-columns:repeat(3,var(--cell));grid-auto-rows:var(--cell);justify-content:end}   /* flush with the nav's right edge */
  :root[data-fnauto][data-fnpage="split"] .fn-stage img{height:100%}
}

/* the expanded grid photo needs no Collapse pill (click it, or press Esc);
   the button stays for keyboard users and appears when focused */
.fs__collapse:not(:focus-visible){position:absolute;width:1px;height:1px;padding:0;margin:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* Sidebar layout: when the intro is longer than the column (a short window,
   a big zoom), it scrolls on its own; make that obvious. The text fades out
   at the bottom edge, and a small round ↓ invites a scroll (click to jump);
   both go away once you reach the end. */
.side-more{display:none}
@media (min-width:768px){
  :root[data-home="sidebar"] .sidebar .hero.has-more{-webkit-mask-image:linear-gradient(#000 calc(100% - 72px),transparent);
    mask-image:linear-gradient(#000 calc(100% - 72px),transparent)}
  /* (all:unset clears the browser's button padding, which had stretched the old round button into an ellipse) */
  :root[data-home="sidebar"] .sidebar.has-more .side-more{all:unset;box-sizing:border-box;display:inline-flex;align-items:center;gap:12px;
    align-self:flex-start;margin:8px 0 16px;padding:4px 0;cursor:pointer;color:var(--muted);transition:color .15s ease}
  .side-more:hover{color:var(--ink)}
  .side-more__label{font-size:12px;letter-spacing:.08em;text-transform:uppercase;line-height:1}
  .side-more__track{position:relative;width:1px;height:28px;background:currentColor;opacity:.4}
  .side-more__track i{position:absolute;left:-2px;top:0;width:5px;height:5px;border-radius:50%;background:var(--ink);
    animation:side-meteor 1.8s cubic-bezier(.5,0,.5,1) infinite}
  .side-more:focus-visible{outline:2px solid var(--navy);outline-offset:4px;border-radius:2px}
}
@keyframes side-meteor{0%{top:-2px;opacity:0}15%{opacity:1}85%{opacity:1}100%{top:26px;opacity:0}}
@media (prefers-reduced-motion:reduce){.side-more__track i{animation:none;top:24px}}

/* compact sidebar (side-more.js): the nav as a row of icons, names on hover */
@media (min-width:768px){
  :root[data-home="sidebar"] .sidebar.is-tight .hero{padding-top:clamp(24px,4vh,48px);padding-bottom:16px}
  :root[data-home="sidebar"] .sidebar.is-tight .hero__body{gap:.9em}
  :root[data-home="sidebar"] .sidebar.is-tight .masthead__nav{flex-direction:row !important;align-items:center;gap:20px;margin-top:auto}
  :root[data-home="sidebar"] .sidebar.is-tight .masthead__nav a{font-size:0 !important;gap:0;padding:6px;margin:-6px}
  :root[data-home="sidebar"] .sidebar.is-tight .masthead__nav .nav-ico{width:20px;height:20px}
  /* "See more opens the column": the panel lets go of its fixed height */
  :root[data-home="sidebar"] .sidebar.is-open{position:static;height:auto}
  :root[data-home="sidebar"] .sidebar.is-open .hero{overflow:visible;flex:none}
}

/* homepage case study titles at lead size (Layout options → Cases → Projects) */
.project .project__title{font-size:var(--ptfs,22px);line-height:1.3;letter-spacing:-.015em;font-weight:500;text-wrap:balance}

/* homepage: each project image is capped to the window, so with a project in
   view the top of the next one always peeks in below it, an invitation to keep
   scrolling (Layout options → Cases → Projects → Next project peeks in).
   The image is cropped to fit, not squashed. */
:root:not([data-ppeek="off"]) .project__media{width:100%;max-height:max(275px,calc((100svh - 400px) * 1.25))}   /* +25% taller (2026-10-06) */   /* width set, so the cap crops instead of narrowing */
:root:not([data-ppeek="off"]) .project__media img{height:100%;object-fit:cover}


/* homepage project tiles, padded (Layout options → Cases → Projects → Project
   images): the thumbnails are squares with a solid backdrop, cropped into a
   wider tile, so a tall device (Complex's phone) ran into the edges. Here the
   tile takes the image's own backdrop colour and the image is placed so the
   device itself (--cw/--ch: its share of the square, measured from the art)
   clears every edge by the padding. It only ever shrinks from the cropped
   fill, never grows past it. */
.projects [data-case="innerbloom"] .project__media{--tilebg:#f6f6f6;--cw:.899;--ch:.534}
.projects [data-case="complex-c"]  .project__media{--tilebg:#000;--cw:.295;--ch:.605}
.projects [data-case="hixy"]       .project__media{--tilebg:#8ec245;--cw:.716;--ch:.494}
:root:not([data-ptpad="fill"]) .projects .project__media{position:relative;container-type:size;background:var(--tilebg,var(--panel));
  --tpad:clamp(32px,10cqh,64px)}
:root:not([data-ptpad="fill"]) .projects .project__media img{position:absolute;left:50%;top:50%;translate:-50% -50%;
  max-width:none;aspect-ratio:1;height:auto;object-fit:contain;
  top:calc(50% + var(--tchip,0px) / 2);
  width:min(max(100cqw,100cqh),calc((100cqh - var(--tchip,0px) - 2 * var(--tpad)) / var(--ch,1)),calc((100cqw - 2 * var(--tpad)) / var(--cw,1)))}

/* chips in the tile, top left (Layout options → Cases → Tags → "In the tile"):
   styled as on the image, but the image is moved down and shrunk so the
   device never sits under them (--tchip: the chip row plus its inset) */
:root[data-ebpos="tile"] .project .chips{position:absolute;top:16px;left:16px;right:16px;z-index:1;pointer-events:none}
:root[data-ebpos="tile"] .project .chip{background:rgba(255,255,255,.92);border-color:transparent;color:var(--ink);box-shadow:0 0 0 1px rgb(0 0 0 / .07)}   /* the hairline keeps a white chip visible on a light tile */
:root[data-ebpos="tile"] .projects .project__media{--tchip:calc(16px + var(--chiprow,28px))}
:root[data-ebpos="tile"][data-ptpad="fill"] .projects .project__media{background:var(--tilebg,var(--panel))}
:root[data-ebpos="tile"][data-ptpad="fill"] .projects .project__media img{height:calc(100% - var(--tchip));margin-top:var(--tchip)}

/* case study titles at display size (Layout options → Cases → Projects → title style) */
:root[data-ptsize="display"] .projects .project .project__title{font-size:var(--fs-display);line-height:1.2;letter-spacing:-.02em}

/* golden-ratio columns (Layout options → Layout → Column widths): the left
   column is 1 / 2.618 (38.2%) of the space beside the gap, rounded down to a
   whole 4px; the right column takes the rest (1.618 parts) */
@media (min-width:768px){
  :root[data-colratio="golden"]:is([data-home="split"],[data-home="split-fn"]) #main,
  :root[data-colratio="golden"][data-home="sidebar"] .sheet{
    grid-template-columns:round(down, calc((100% - var(--gap-col)) * .382), 4px) minmax(0,1fr)}
}

/* Playground (/playground): a single column, its one line centred in the space
   between the header and the footer */
.pg-soon{min-height:calc(100svh - 160px);display:grid;place-items:center;padding-block:clamp(48px,8vw,96px);text-align:center}
.pg-soon__line{margin:0;max-width:22ch;font-size:clamp(28px,4vw,48px);font-weight:400;line-height:1.2;letter-spacing:-.02em;color:var(--ink);text-wrap:balance}
.pg-soon__more{display:block;margin-top:.5em;font-size:calc(clamp(28px,4vw,48px) - 4px);color:var(--muted)}
.masthead__nav [aria-current="page"]{color:var(--ink)}
