/* Intrio — palette sampled from the studio's own built work (hue 20–30°) */
:root{
  --paper:#FBFAF8;        /* warm white — reads white, not cream */
  --paper-2:#F2EEE9;      /* raised surface */
  --ink:#17120F;          /* warm near-black type */
  --taupe:#756A5F;        /* secondary type — sampled; dark enough for AA on --paper-2 too */
  --line:#E3DCD3;         /* hairlines */
  --brass:#86653F;        /* accent — their fixtures; AA on both --paper and --paper-2 */

  --pad: clamp(1.25rem, 5vw, 5.5rem);
  --rule: 1px solid var(--line);

  --step--1: clamp(.72rem,.70rem + .08vw,.80rem);   /* 12-13px  labels   */
  --step-0 : clamp(.95rem,.92rem + .14vw,1.02rem);  /* 15-16px  body     */
  --step-1 : clamp(1.05rem,1rem + .42vw,1.32rem);   /* 17-21px  lede     */
  --step-2 : clamp(1.45rem,1.2rem + 1.1vw,2.05rem); /* 23-33px  section  */
  --step-3 : clamp(2rem,1.5rem + 2.4vw,3.3rem);     /* 32-53px  page ttl */
  --step-4 : clamp(2.4rem,1.7rem + 3.5vw,4.5rem);   /* 38-72px  hero     */
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:Inter,system-ui,-apple-system,"Segoe UI",sans-serif;
  font-size:var(--step-0);line-height:1.65;
  font-optical-sizing:auto;-webkit-font-smoothing:antialiased;
  /* No overflow rule on html or body, deliberately. Setting overflow-x on body
     (hidden or clip) — and especially on html AND body together — stops iOS Safari
     scrolling the document. Nothing overflows horizontally (checked at 360/390/414
     on every page), so there is nothing to clip. */
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--brass);outline-offset:3px;}

.display{
  font-family:Fraunces,Georgia,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1,"opsz" 96;
  font-weight:300;line-height:.94;letter-spacing:-.02em;
}
.meta{
  font-size:var(--step--1);text-transform:uppercase;
  letter-spacing:.14em;color:var(--taupe);font-weight:500;line-height:1.5;
}
/* content that is information, not a label: never uppercase, never tracked */
.date{margin:0 0 .35rem;font-size:var(--step--1);color:var(--taupe);
  letter-spacing:0;text-transform:none;line-height:1.5}
/* same weight and colour as every other contact line — the heading above it is the
   only thing that should read differently */
.hours{margin:0;font-size:var(--step-0);color:var(--ink);
  letter-spacing:0;text-transform:none;line-height:1.65}
.shell{padding-inline:var(--pad)}

/* ---------- nav ---------- */
.nav{
  position:fixed;inset:0 0 auto;z-index:60;display:flex;
  align-items:center;justify-content:space-between;
  padding:1.15rem var(--pad);
  background:var(--paper);
  border-bottom:var(--rule);
}
.wordmark{display:block;line-height:0}
.wordmark img{width:clamp(84px,9vw,116px);height:auto}
.nav-links{display:flex;gap:clamp(1rem,2.5vw,2.4rem)}
.nav-links a{font-size:var(--step--1);text-transform:uppercase;letter-spacing:.16em;
  color:var(--taupe);transition:color .35s}
.nav-links a:hover{color:var(--ink)}

/* ---------- hero ---------- */
.hero{padding:clamp(7rem,16vh,10rem) var(--pad) clamp(1.5rem,4vw,2.5rem)}
.hero h1{margin:0;max-width:20ch;font-size:var(--step-4);text-wrap:balance}
.hero-arch{
  position:absolute;inset:0;z-index:-1;overflow:hidden;
  -webkit-mask-image:linear-gradient(to bottom,#000 62%,transparent);
  mask-image:linear-gradient(to bottom,#000 62%,transparent);
}
.hero-arch img{
  width:100%;height:100%;object-fit:cover;opacity:1;
  filter:saturate(.98);
}
.hero-arch::after{content:"";position:absolute;inset:0;
  background:radial-gradient(120% 90% at 50% 0%,transparent 34%,var(--paper) 94%)}
.hero-head{align-self:end;max-width:none}
.hero-eyebrow{margin:0 0 1.1rem}
.hero-head h1{margin:0;font-size:var(--step-4);text-wrap:balance}
.hero-head h1 em,.hero h1 em{font-style:normal;color:var(--brass)}
.hero-foot{display:flex;justify-content:space-between;align-items:end;
  gap:2rem;flex-wrap:wrap;border-top:var(--rule);padding-top:1.2rem;margin-top:clamp(2rem,5vw,3.5rem)}
.hero-foot p{margin:0;max-width:38ch;color:var(--taupe)}

/* ---------- work index ---------- */
.section-head{display:flex;justify-content:space-between;align-items:baseline;
  gap:1rem;border-bottom:var(--rule);padding-bottom:.9rem;margin-bottom:clamp(2rem,5vw,4rem)}
.section-head h2{margin:0;font-size:var(--step-1);font-weight:400;font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1}

.work{padding-block:clamp(4rem,10vw,9rem)}
/* four projects, so the grid is an explicit 2x2 at desktop rather than auto-fit —
   auto-fit gives 3 columns and strands the fourth card alone on its own row. */
.grid{display:grid;gap:clamp(2rem,4.5vw,4.5rem);grid-template-columns:1fr}
@media (min-width:760px){.grid{grid-template-columns:repeat(2,1fr)}}
.card{display:block;position:relative}
/* fail-safe: images are visible by default; JS opts in to the reveal */
.card.is-pending .card-fig{opacity:0;transform:translateY(18px)}
.card-fig{
  /* <figure> carries a UA default margin:1em 40px — without this reset the image
     sits inset from the caption and rule below it. */
  margin:0;
  position:relative;overflow:hidden;background:var(--paper-2);
  aspect-ratio:4/3;
  /* transform+opacity are composited; clip-path repainted the whole figure every frame */
  transition:opacity .9s cubic-bezier(.16,1,.3,1),transform .9s cubic-bezier(.16,1,.3,1);
}
.card-fig img{width:100%;height:100%;object-fit:cover;
  transition:transform 1.2s cubic-bezier(.16,1,.3,1),filter .6s;
  filter:saturate(.98)}
.card:hover .card-fig img,
.card:focus-visible .card-fig img{transform:scale(1.05);filter:saturate(1) brightness(1)}
.card-body{display:flex;justify-content:space-between;gap:1rem;
  align-items:baseline;margin-top:1rem;border-top:var(--rule);padding-top:.75rem}
.card-body h2,.card-body h3{margin:0;font-size:var(--step-1);font-weight:400;font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;line-height:1.1}
.card-idx{font-size:var(--step--1);color:var(--brass);letter-spacing:.14em}

/* first card runs full width — newest work leads */
/* ---------- studio ---------- */
.studio{padding-block:clamp(4rem,10vw,9rem);border-top:var(--rule)}
.studio-grid{display:grid;gap:clamp(2rem,5vw,5rem);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,22rem),1fr));align-items:start}
.lede{font-family:Fraunces,serif;font-variation-settings:"SOFT" 60,"WONK" 1;
  font-weight:300;font-size:var(--step-2);line-height:1.25;margin:0 0 1.4rem}
.studio p{color:var(--taupe);max-width:52ch}
.stats{display:grid;gap:1.5rem;grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));margin-top:2.5rem}
.stat b{display:block;font-family:Fraunces,serif;font-variation-settings:"SOFT" 60;
  font-size:var(--step-2);font-weight:300;color:var(--ink);line-height:1}
.stat span{font-size:var(--step--1);text-transform:uppercase;letter-spacing:.16em;color:var(--taupe)}

/* ---------- contact ---------- */
.contact{padding-block:clamp(4rem,10vw,9rem) 5rem;border-top:var(--rule)}
.contact h2{font-family:Fraunces,serif;font-variation-settings:"SOFT" 60,"WONK" 1;
  font-weight:300;font-size:var(--step-3);margin:0 0 2rem;max-width:14ch}
.contact-links{display:flex;flex-wrap:wrap;gap:2.5rem}
.clink{border-bottom:1px solid var(--line);padding-bottom:.35rem;transition:border-color .4s,color .4s}
.clink:hover{border-color:var(--brass);color:var(--brass)}
footer{border-top:var(--rule);padding:1.5rem var(--pad);display:flex;
  justify-content:space-between;gap:1rem;flex-wrap:wrap;color:var(--taupe);font-size:var(--step--1)}

/* ---------- reveal ---------- */
.reveal{opacity:0;transform:translateY(18px);
  transition:opacity .9s cubic-bezier(.16,1,.3,1),transform .9s cubic-bezier(.16,1,.3,1)}
.reveal.in{opacity:1;transform:none}

@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition-duration:.01ms!important}
  .reveal{opacity:1;transform:none}
  .card.is-pending .card-fig{opacity:1;transform:none}
}

.card{position:relative}
.card-loc{position:absolute;top:1rem;left:1rem;z-index:2;
  background:color-mix(in srgb,var(--ink) 74%,transparent);
  background:color-mix(in oklab,var(--ink) 74%,transparent);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);padding:.3rem .6rem;
  font-size:var(--step--1);letter-spacing:.14em;color:var(--paper);opacity:0;transition:opacity .5s}
.card:hover .card-loc,.card:focus-visible .card-loc{opacity:1}
.card-body h2{font-size:var(--step-1)}

.hero-plate{margin:0 var(--pad) clamp(3rem,7vw,6rem);overflow:hidden;background:var(--paper-2)}
.hero-plate img{width:100%;height:auto;display:block;aspect-ratio:16/9;object-fit:cover}
@media (max-width:640px){.hero-plate img{aspect-ratio:4/5}}
.card-new{position:absolute;top:1rem;right:1rem;z-index:2;background:var(--ink);
  color:var(--paper);padding:.3rem .6rem;font-size:var(--step--1);letter-spacing:.14em}

/* ---------- interior pages ---------- */
.page-head{padding-block:clamp(7rem,16vh,10rem) clamp(1.5rem,4vw,2.5rem)}
.page-head h1{margin:.4rem 0 0;font-size:var(--step-3);max-width:18ch;text-wrap:balance}
.page-head .meta a{color:var(--taupe);border-bottom:1px solid var(--line)}
.page-head .meta a:hover{color:var(--ink)}
.page-lede{margin:1.25rem 0 0;max-width:56ch;color:var(--taupe);font-size:var(--step-1);line-height:1.55}
.seeall{color:var(--taupe)}
.seeall:hover{color:var(--ink)}

.prose{padding-block:0 clamp(4rem,9vw,7rem);max-width:none}
/* two-column editorial: label left, body right. Keeps a readable measure
   without stranding one narrow column against an empty half-page. */
.prose-row{display:grid;gap:.5rem 3.5rem;margin:0 0 clamp(2.5rem,5vw,4rem);
  align-items:start;max-width:74rem}
.prose-row:last-child{margin-bottom:0}
@media (min-width:900px){
  .prose-row{grid-template-columns:15rem minmax(0,42rem)}
  .prose-row h2{position:sticky;top:6.5rem}
  /* intro statements read as a lead-in, not a label */
  .prose-row--wide{grid-template-columns:minmax(0,58rem);gap:.9rem}
  .prose-row--wide h2{position:static;font-size:var(--step-2);max-width:24ch}
}
.prose-body > *:last-child{margin-bottom:0}
/* long-form: one centred measure. padding-inline is already on .shell, so the
   centred column must not add its own or the text is inset twice and misaligns. */
.prose.narrow{max-width:40rem;margin-inline:auto;padding-inline:0}
@media (min-width:900px){
  .page-head.post-head{max-width:40rem;margin-inline:auto;padding-inline:0}
}
.prose h2{font-family:Fraunces,serif;font-variation-settings:"SOFT" 60,"WONK" 1;
  font-weight:400;font-size:var(--step-1);margin:0 0 .6rem;line-height:1.25;color:var(--ink);
  text-wrap:balance}

.prose p{margin:0 0 1.15rem;color:var(--taupe)}
/* body copy is uniform; the page lede is the only elevated paragraph */
.contact-grid p,.form-note p{font-size:var(--step-0);line-height:1.65}
.contact-grid p{color:var(--ink)}

/* project page */
.project-head .facts{display:grid;gap:1.25rem 2.5rem;margin:2.5rem 0 0;
  grid-template-columns:repeat(auto-fit,minmax(9rem,auto));border-top:var(--rule);padding-top:1.25rem}
.facts div{display:grid;gap:.2rem}
.facts dt{font-size:var(--step--1);text-transform:uppercase;letter-spacing:.18em;color:var(--taupe)}
.facts dd{margin:0;font-size:var(--step-0)}
.project{padding-block:clamp(2rem,5vw,3.5rem) clamp(3rem,7vw,5rem);
  display:grid;gap:clamp(1rem,2.5vw,2rem)}
.shot{margin:0;overflow:hidden;background:var(--paper-2);aspect-ratio:4/3}
.shot img{width:100%;height:100%;object-fit:cover;display:block}
/* the wide tiles that span the full column */

@media (min-width:900px){
  .project{grid-template-columns:repeat(2,1fr)}
  /* an odd gallery would leave the last tile alone in a half-width row:
     let it span instead, so it reads as a closing image, not a gap */
  .shot:last-child:nth-child(odd){grid-column:1/-1;aspect-ratio:21/9}
}
.pager{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  border-top:var(--rule);padding-block:1.25rem;margin-bottom:clamp(3rem,7vw,5rem)}

/* journal */
/* Explicit column counts, not auto-fit: with 6 posts auto-fit gave 4+2 at 1680px
   and 5+1 at 1920px. 6 divides evenly by 3, 2 and 1, so these never orphan a card. */
.post-grid{display:grid;gap:clamp(2rem,4vw,3.5rem);padding-bottom:clamp(4rem,9vw,7rem);
  grid-template-columns:1fr}
@media (min-width:640px){.post-grid{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1000px){.post-grid{grid-template-columns:repeat(3,1fr)}}
/* the homepage teaser runs 4 posts, so it stays 2x2 and matches the project grid */
@media (min-width:1000px){.post-grid--2{grid-template-columns:repeat(2,1fr)}}
.post-card h2,.post-card h3{margin:.15rem 0 0;font-family:Fraunces,serif;font-variation-settings:"SOFT" 60,"WONK" 1;
  font-weight:400;font-size:var(--step-1);line-height:1.2;max-width:24ch}
.post-fig{margin:0 0 .9rem;overflow:hidden;background:var(--paper-2);aspect-ratio:4/3}
.post-fig img{width:100%;height:100%;object-fit:cover;transition:transform 1s cubic-bezier(.16,1,.3,1)}
.post-card:hover .post-fig img{transform:scale(1.04)}
.post-hero{margin:0 auto clamp(2.5rem,5vw,3.5rem);overflow:hidden;max-width:54rem;padding-inline:var(--pad)}
/* 2026-09-21: article covers show in FULL, no forced crop. The lighting article's
   image carries labels at the left and right edges, which a 4:3 phone crop cut off. */
.post-hero img{width:100%;height:auto;display:block}
.post-title{font-size:var(--step-2);max-width:24ch}

/* contact */
.prose.contact-page{max-width:none}
.contact-grid{display:grid;gap:clamp(2rem,5vw,4rem);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,15rem),18rem));
  border-top:var(--rule);padding-top:2rem;max-width:62rem}
.contact-grid .meta{line-height:1.9}
.contact-grid h2{margin:0 0 .8rem;font-size:var(--step-0);text-transform:uppercase;
  letter-spacing:.18em;font-family:Inter,sans-serif;font-weight:500;color:var(--taupe)}
.contact-grid p{margin:0 0 .5rem;color:var(--ink)}
.form-note{margin-top:2.5rem;padding:1.15rem 1.4rem;background:var(--paper-2);max-width:46rem}
.form-note p{margin:0;color:var(--ink)}

footer{gap:1.5rem}
footer a{border-bottom:1px solid transparent}
footer a:hover{border-color:var(--line);color:var(--ink)}

/* ---------- mobile ---------- */
.wordmark{flex:0 0 auto}
@media (max-width:760px){
  .nav{flex-direction:column;align-items:flex-start;gap:.55rem;
       padding-block:.75rem;background:var(--paper)}
  .nav-links{gap:1.05rem;flex-wrap:wrap}
  .nav-links a{font-size:var(--step--1);letter-spacing:.12em}
  .wordmark img{width:76px}
  .hero{padding-top:clamp(7.5rem,20vh,9rem)}
  .page-head{padding-top:clamp(7.5rem,20vh,9rem)}
  .hero-foot{flex-direction:column;align-items:flex-start;gap:.75rem}
  .project-head .facts{grid-template-columns:repeat(2,1fr);gap:1rem}
  .pager{flex-direction:column;gap:.6rem}
  footer{flex-direction:column;gap:.5rem}
}
@media (max-width:420px){
  .nav-links{gap:.8rem}
  .nav-links a{font-size:var(--step--1);letter-spacing:.1em}
}

/* ---------- hero plate ---------- */
.hero-plate{position:relative}

/* ---------- full-screen scroll-scrubbed hero ---------- */
.hero-scroll{position:relative;height:520vh;margin-bottom:clamp(3rem,8vw,7rem)}
.hero-sticky{position:sticky;top:0;height:100svh;overflow:hidden;background:var(--ink)}
.hero-sticky .hero-still{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
}
.hero-veil{position:absolute;inset:0;pointer-events:none;
  background:
    /* keeps the nav legible whatever the frame is doing */
    linear-gradient(to bottom,rgba(12,9,8,.46) 0,rgba(12,9,8,.14) 120px,rgba(12,9,8,0) 200px),
    /* carries the headline over the bright frames */
    linear-gradient(to top,rgba(12,9,8,.60) 0,rgba(12,9,8,.30) 38%,rgba(12,9,8,0) 68%),
    linear-gradient(to right,rgba(12,9,8,.40) 0%,rgba(12,9,8,.12) 55%,rgba(12,9,8,0) 100%)}
.hero-copy{position:absolute;left:0;right:0;bottom:clamp(3.5rem,10vh,7rem);color:#FBFAF8}
.hero-copy .meta{color:rgba(251,250,248,.72)}
.hero-copy h1{margin:.5rem 0 0;font-size:var(--step-4);max-width:20ch;color:#FBFAF8;text-wrap:balance;
  text-shadow:0 1px 30px rgba(12,9,8,.35)}
.hero-copy h1 em{font-style:normal;color:#D8B487}
.hero-sub{margin:1.25rem 0 0;max-width:46ch;color:rgba(251,250,248,.88);font-size:var(--step-1);line-height:1.55;
  text-shadow:0 1px 20px rgba(12,9,8,.4)}
/* capability strip: a hairline row, no bullets or separators — the spacing does it */
.hero-caps{display:flex;flex-wrap:wrap;gap:.5rem 1.5rem;list-style:none;
  margin:1.4rem 0 0;padding:1.05rem 0 0;
  /* the rule is as wide as the items themselves — 46ch here would be measured
     against this row's 12px type, not the subline's, and would wrap the last item */
  width:fit-content;max-width:100%;
  border-top:1px solid rgba(251,250,248,.3);
  font-size:var(--step--1);text-transform:uppercase;letter-spacing:.14em;
  color:rgba(251,250,248,.86);line-height:1.5;
  text-shadow:0 1px 20px rgba(12,9,8,.45)}
@media (max-width:760px){
  /* Phones scrub a canvas frame sequence (see site.js) in a full-screen pinned pane.
     450vh since 2026-09-15, down from 600vh. MEASURED: 600vh gave 5.0 viewports of
     scrub travel (12 frames per half-viewport swipe); 450vh gives 3.5 viewports
     (17 frames per swipe). The reference dinuka compared against completes its hero
     in 3.3 viewports, so 450vh essentially MATCHES it rather than splitting the
     difference - a true midpoint would be ~530vh. Revert to 600vh for the old
     heavier feel; desktop is separate (520vh, line ~292). */
  .hero-scroll{height:450vh}
  .hero-sticky{position:sticky;top:0;height:100vh;height:100svh}
  .hero-veil{background:linear-gradient(to top,rgba(12,9,8,.72) 0%,rgba(12,9,8,.34) 55%,rgba(12,9,8,.12) 100%)}
}
@media (prefers-reduced-motion:reduce){
  .hero-scroll{height:auto}
  .hero-sticky{position:relative;height:min(88svh,44rem)}
  .hero-cue{display:none}
}

/* ---------- nav over the video hero ---------- */
.wordmark{position:relative;display:block;line-height:0}
.wordmark img{width:clamp(84px,9vw,116px);height:auto;display:block}
.mark-light{position:absolute;inset:0;opacity:0;transition:opacity .4s ease}
.nav--over{background:transparent;border-bottom-color:transparent;
  transition:background .45s ease,border-color .45s ease}
.nav--over .nav-links a{color:rgba(251,250,248,.86);text-shadow:0 1px 12px rgba(12,9,8,.5)}
.nav--over .nav-links a:hover{color:#FBFAF8}
.nav--over .mark-dark{opacity:0}
.nav--over .mark-light{opacity:1}
/* once past the hero it returns to the normal light bar */
.nav--over.is-solid{background:var(--paper);border-bottom-color:var(--line)}
.nav--over.is-solid .nav-links a{color:var(--taupe)}
.nav--over.is-solid .nav-links a:hover{color:var(--ink)}
.nav--over.is-solid .mark-dark{opacity:1}
.nav--over.is-solid .mark-light{opacity:0}

.btn{display:inline-block;text-align:center;background:var(--ink);color:var(--paper);
  padding:.95rem 1.5rem;font-size:var(--step--1);text-transform:uppercase;letter-spacing:.16em;
  transition:background .3s}
.btn:hover{background:var(--brass)}

/* lists inside journal posts */
.post-list{margin:0 0 1.15rem;padding:0 0 0 1.1rem;color:var(--taupe)}
.post-list li{margin:0 0 .5rem;line-height:1.65}
.post-list li::marker{color:var(--brass)}

/* ---------- enquiry form ---------- */
.enquiry{display:grid;gap:1.5rem;max-width:34rem;margin-top:2.5rem}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.field{display:grid;gap:.45rem}
.field-pair{display:grid;gap:1.5rem}
@media (min-width:560px){.field-pair{grid-template-columns:1fr 1fr}}
.enquiry label{font-size:var(--step--1);text-transform:uppercase;letter-spacing:.16em;color:var(--taupe)}
.enquiry .opt{text-transform:none;letter-spacing:0;color:var(--taupe)}
.enquiry input,.enquiry select,.enquiry textarea{
  font:inherit;font-size:var(--step-0);color:var(--ink);background:var(--paper);
  border:1px solid var(--line);padding:.7rem .85rem;width:100%;
  transition:border-color .25s}
.enquiry textarea{resize:vertical;min-height:7rem;line-height:1.6}
.enquiry input:hover,.enquiry select:hover,.enquiry textarea:hover{border-color:var(--taupe)}
.enquiry input:focus-visible,.enquiry select:focus-visible,.enquiry textarea:focus-visible{
  border-color:var(--ink);outline:2px solid var(--brass);outline-offset:2px}
.enquiry [aria-invalid="true"]{border-color:#9A3A2E}
.field-hint{margin:.1rem 0 0;font-size:var(--step--1);color:var(--taupe);line-height:1.55}
.field-error{margin:.1rem 0 0;font-size:var(--step--1);color:#8C3125;line-height:1.55}
.enquiry .btn{justify-self:start;border:0;cursor:pointer}
.enquiry .btn:disabled{opacity:.55;cursor:default}
.form-status{margin:0;font-size:var(--step-0);line-height:1.6;min-height:1.5em}
.form-status.is-ok{color:var(--ink)}
.form-status.is-error{color:#8C3125}

/* ---------- homepage sections ---------- */
.band{padding-block:clamp(4rem,9vw,7.5rem)}
.band--tint{background:var(--paper-2)}
.band + .band{border-top:var(--rule)}
.band--tint + .band,.band + .band--tint{border-top:0}

/* meet the team */
.team-grid,.founder-grid{display:grid;gap:clamp(2rem,5vw,4rem);align-items:start}
@media (min-width:900px){
  /* photo column deliberately narrow — the picture is a supporting note, not the subject */
  /* same proportions as the founder row below, so the two sections line up */
  /* heading + one sentence beside a square photo: centre it so the space around it balances */
  .team-grid{grid-template-columns:minmax(0,24rem) minmax(0,1fr);align-items:center}
  /* the message is long, so it gets the rest of the row instead of a fixed 36rem */
  .founder-grid{grid-template-columns:minmax(0,24rem) minmax(0,1fr)}
}
/* square: the new plate is portrait, so a landscape frame would crop the group */
.team-photo{margin:0;aspect-ratio:1/1;background:var(--paper);overflow:hidden}
.founder-photo{margin:0;aspect-ratio:3/4;background:var(--paper);overflow:hidden}
.team-photo img,.founder-photo img{width:100%;height:100%;object-fit:cover;display:block}
/* empty slots read as a considered placeholder, not a broken image */
.team-body p,.founder-note p{color:var(--taupe);margin:0 0 1.1rem;max-width:44ch}
.lead{font-family:Fraunces,serif;font-variation-settings:"SOFT" 60,"WONK" 1;
  font-weight:300;font-size:var(--step-2);line-height:1.25;color:var(--ink)!important;
  margin:0 0 1.2rem!important;max-width:22ch}

.founder-note{margin:0;border-left:2px solid var(--brass);padding-left:clamp(1.25rem,3vw,2rem)}
/* set the body in two columns on wide screens so it reads across rather than
   running down in one long ribbon */
.founder-body p{max-width:none}
@media (min-width:1080px){
  /* one column, full width of the message area — two columns could never end level,
     and the ragged bottom was worse than the extra measure */
  /* justified, but never break a word — the column is wide enough that justification
     spreads across many words per line, so the gaps stay small without hyphens */
  .founder-body,.team-body{text-align:justify;hyphens:none;-webkit-hyphens:none;
    overflow-wrap:normal;word-break:normal}
  .team-body p{max-width:none}
  .founder-body p{margin-bottom:.9rem}
  .founder-note .lead{max-width:30ch}
  /* motto and signature sit side by side under the columns so the row closes off */
  .founder-close{display:flex;align-items:baseline;justify-content:space-between;
    gap:2rem;flex-wrap:wrap;margin-top:1.8rem;
    border-top:1px solid var(--line);padding-top:1.4rem}
  .founder-close .founder-motto{margin:0!important}
  .founder-close .founder-sign{margin-top:0!important;text-align:right}
}
@media (min-width:1500px){.founder-note .lead{max-width:34ch}}
/* the closing line is the one people remember — set it, don't bury it in the body */
.founder-motto{margin:1.6rem 0 0!important;font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;font-weight:400;
  font-size:var(--step-1);line-height:1.35;color:var(--ink)!important;max-width:30ch!important}
.founder-note .founder-sign{display:block;margin-top:1.6rem;padding:0;border:0;gap:0;
  font-size:var(--step--1);text-transform:uppercase;letter-spacing:.16em;color:var(--ink)}
.founder-sign span{display:block;margin-top:.3rem;letter-spacing:.14em;color:var(--taupe)}

/* what we do */
.do-grid{display:grid;gap:clamp(1.75rem,4vw,3rem)}
@media (min-width:700px){.do-grid{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1100px){.do-grid{grid-template-columns:repeat(4,1fr)}}
.do-grid article{border-top:var(--rule);padding-top:1.1rem}
.do-grid h3{margin:0 0 .55rem;font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;font-weight:400;font-size:var(--step-1);line-height:1.25}
.do-grid p{margin:0;color:var(--taupe);line-height:1.65}

/* homepage contact */
#contact .contact-grid{border-top:0;padding-top:0}
#contact .contact-grid h3{margin:0 0 .8rem;font-size:var(--step-0);text-transform:uppercase;
  letter-spacing:.18em;font-family:Inter,sans-serif;font-weight:500;color:var(--taupe)}
#contact .contact-grid p{margin:0 0 .5rem;color:var(--ink)}
#contact .contact-cta{margin:clamp(2rem,4vw,3rem) 0 0}

/* ---------- Teddie, coming soon ---------- */
/* visually hidden but still focusable — the colour radios are driven by their
   labels, yet must stay reachable by keyboard and announced by screen readers. */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* the grid is a <fieldset> so the four colours form one named radio group */
.teddie-grid{display:grid;gap:clamp(2rem,5vw,4.5rem);align-items:center;
  border:0;padding:0;margin:0;min-width:0}
@media (min-width:900px){
  .teddie-grid{grid-template-columns:minmax(0,30rem) minmax(0,34rem);justify-content:start}
}
.teddie-shot{margin:0;background:var(--paper-2);overflow:hidden;
  position:relative;aspect-ratio:1/1}
/* all four renders stack in the same square box, so swapping colour never shifts layout */
.teddie-shot .tc-img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block;opacity:0;transition:opacity .45s ease}
#tc-sage:checked  ~ .teddie-shot .tc-sage,
#tc-dusty-blush:checked ~ .teddie-shot .tc-dusty-blush,
#tc-warm-grey:checked ~ .teddie-shot .tc-warm-grey,
#tc-light-beige:checked   ~ .teddie-shot .tc-light-beige{opacity:1}

/* the colour is the label — chips only, no type */
.swatches{margin:0 0 1.6rem}
.swatch-row{display:flex;flex-wrap:wrap;gap:.9rem}
.swatch{display:block;cursor:pointer;padding:5px}   /* padding keeps a 54px tap target */
.swatch-chip{display:block;width:44px;height:44px;  /* square, like the rest of the site */
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ink) 14%,transparent);transition:box-shadow .25s}
.swatch:hover .swatch-chip{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ink) 32%,transparent)}
/* selected: a square ring offset off the chip, matching the site's hairline language */
#tc-sage:checked  ~ .teddie-body .swatch-sage  .swatch-chip,
#tc-dusty-blush:checked ~ .teddie-body .swatch-dusty-blush .swatch-chip,
#tc-warm-grey:checked ~ .teddie-body .swatch-warm-grey .swatch-chip,
#tc-light-beige:checked   ~ .teddie-body .swatch-light-beige   .swatch-chip{
  box-shadow:inset 0 0 0 1px rgba(23,18,15,.2),0 0 0 1px var(--paper-2),0 0 0 3px var(--ink)}
/* keyboard focus has to show on the label, since the input itself is off-screen */
#tc-sage:focus-visible  ~ .teddie-body .swatch-sage,
#tc-dusty-blush:focus-visible ~ .teddie-body .swatch-dusty-blush,
#tc-warm-grey:focus-visible ~ .teddie-body .swatch-warm-grey,
#tc-light-beige:focus-visible   ~ .teddie-body .swatch-light-beige{outline:2px solid var(--brass);outline-offset:3px}
@media (prefers-reduced-motion:reduce){.teddie-shot .tc-img{transition:none}}
.teddie-flag{display:inline-block;margin:0 0 1rem;padding:.32rem .7rem;
  border:1px solid var(--brass);color:var(--brass)}
.teddie-name{margin:0 0 .6rem;font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;font-weight:300;
  font-size:var(--step-3);line-height:1}
.teddie-body p{color:var(--taupe);margin:0 0 1.1rem;max-width:42ch}
.teddie-note{color:var(--ink)!important}
.teddie-body .btn{margin-top:.6rem}

/* ---------- contact icons + map ---------- */
.clink{display:inline-flex;align-items:center;gap:.55rem}
.clink .ico{flex:0 0 auto;color:var(--taupe);transition:color .4s}
.clink:hover .ico{color:var(--brass)}

.map-block{margin:clamp(3rem,7vw,5rem) 0 0}
.map-label{margin:0 0 .35rem}
.map-addr{margin:0 0 .9rem;font-size:var(--step-0);color:var(--ink)}
/* square frame, hairline, matching the rest of the site */
.map-frame{position:relative;aspect-ratio:16/9;border:1px solid var(--line);
  background:var(--paper-2);overflow:hidden}
.map-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
@media (max-width:640px){.map-frame{aspect-ratio:4/3}}
.map-note{margin:.9rem 0 0}

/* ---------- touch targets ----------
   Nav, "see all" and footer links render 15-19px tall, which is fiddly on a phone.
   Pad the hit area vertically and pull the padding back with negative margin so
   the visual spacing stays exactly as designed. */
@media (max-width:760px) and (pointer:coarse),(max-width:760px){
  .nav-links a,.seeall,footer a{
    padding-block:.8rem;margin-block:-.8rem;
    display:inline-block}
  .nav-links{row-gap:0}
}

/* ---------- team roles ----------
   Six roles: 1 -> 2 -> 3 columns, so every row is always full. */
.team-roles{display:grid;grid-template-columns:1fr;
  gap:clamp(2rem,4vw,3rem) clamp(1.5rem,3vw,3rem);
  margin-top:clamp(3rem,6vw,4.5rem);padding-top:clamp(2rem,4vw,3rem);border-top:var(--rule)}
@media (min-width:640px){.team-roles{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1080px){.team-roles{grid-template-columns:repeat(4,1fr)}}
/* subgrid: each card spans three row tracks shared with its neighbours, so the
   role name, text and quote each start on the same line across the whole row,
   however long each person's text is */
.role{margin:0;display:grid;grid-row:span 4;grid-template-rows:subgrid;row-gap:0}
@supports not (grid-template-rows:subgrid){
  .role{display:flex;flex-direction:column}
  .role-quote{margin-top:auto!important}
}
.role-name{margin:0 0 .7rem;font-family:Inter,system-ui,sans-serif;font-size:var(--step--1);
  font-weight:500;text-transform:uppercase;letter-spacing:.14em;color:var(--taupe)}
/* short card text stays left-aligned: justifying a narrow card opens gaps between words */
.role-text{margin:0 0 1.1rem;color:var(--taupe);line-height:1.65;text-align:left}
.role-quote{margin:0;font-family:Fraunces,serif;font-variation-settings:"SOFT" 60,"WONK" 1;
  font-weight:400;font-size:var(--step-1);line-height:1.35;color:var(--ink)}

/* phone hero frame sequence: fades in over the poster once its first frame is drawn */
.hero-canvas{position:absolute;inset:0;width:100%;height:100%;display:block;
  opacity:0;transition:opacity .5s ease}
.hero-canvas.is-ready{opacity:1}

/* Lenis inertial scrolling: desktop only (site.js never starts it on phones) */
@media (min-width:761px){
  html.lenis, html.lenis body{height:auto}
  .lenis.lenis-smooth{scroll-behavior:auto!important}
  .lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}
}

/* ---------- founder: short note on home, full story on its own page ---------- */
@media (min-width:900px){
  /* the note is short now, so centre it against the portrait instead of hanging from the top */
  .founder-grid--short{align-items:center}
}
.founder-photo-link{display:block;overflow:hidden}
.founder-photo-link img{transition:transform 1.2s cubic-bezier(.2,.7,.2,1)}
.founder-photo-link:hover img,.founder-photo-link:focus-visible img{transform:scale(1.03)}
.founder-eyebrow{margin:0 0 1rem!important;color:var(--taupe)}
.founder-grid--short .founder-note .lead{max-width:30ch;font-size:var(--step-2);line-height:1.3;text-wrap:pretty}
.founder-grid--short .founder-close{margin-top:1.8rem}
.founder-more{margin:2rem 0 0!important}
.story-intro{padding-block:0 clamp(3.5rem,8vw,6rem)}
.story-intro .founder-note .lead{font-size:var(--step-2);max-width:32ch}
.story-close{text-align:center;display:flex;flex-direction:column;align-items:center}
.story-close .founder-motto{margin:0!important;font-size:var(--step-3);max-width:none!important}
.story-links{display:flex;gap:2rem;flex-wrap:wrap;justify-content:center;margin:2rem 0 0}
@media (prefers-reduced-motion:reduce){.founder-photo-link img{transition:none}}
/* founder story: never leave one word alone on a paragraph's last line */
.story .prose-body p,.story-close .founder-motto{text-wrap:pretty}

/* content-visibility:auto was tried here and REMOVED (2026-09-14): it made the
   document height swing by ~3700px on a phone while scrolling, because each
   section only gets its real height when it comes into range. Paint savings are
   not worth an unstable scroll on a page whose whole point is smooth scrolling. */

/* Hero scroll cue: same uppercase tracked label as the eyebrow, with a hairline
   that travels down on a loop. Square and flat, like the rest of the site.
   Fades out for good once the page has been scrolled (.is-gone). */
/* Scroll cue: an ORIGINAL hand-and-ripple icon, no wording (dinuka 2026-09-15,
   after a reference clip from another site - the idea, not their artwork).
   MEASURED: on phones the hero subline runs to within 20px of the right edge, so
   there is NO free side; the cue stays bottom-centre there and only moves to the
   side from 1100px up, where 547px is genuinely free. */
.hero-cue{position:absolute;left:50%;bottom:1.4rem;transform:translateX(-50%);
  display:flex;align-items:center;justify-content:center;
  color:rgba(251,250,248,.92);pointer-events:none;z-index:3;opacity:1;
  transition:opacity .6s ease;filter:drop-shadow(0 2px 14px rgba(12,9,8,.55))}
.hero-cue.is-gone{opacity:0}
/* Sized by the VISIBLE hand, not the canvas: his path occupies ~47% of the 240x280
   box (the rest is headroom for the +/-38 swipe), so a 40px canvas rendered a hand
   only ~19x14px - too small on a phone. 88x103 gives ~41x30px. */
.cue-hand{display:block;width:88px;height:103px}
@media (min-width:1100px){.cue-hand{width:80px;height:93px}}
/* dinuka's own animation, timing and keyframes exactly as he authored them.
   His asset carried its own prefers-reduced-motion block; dropped here because the
   page-level guard hides .hero-cue outright, which is stronger. */
.cue-swipe{animation:cue-swipe 2.4s infinite}
.cue-ring{transform-box:fill-box;transform-origin:center;animation:cue-touch 2.4s infinite}
/* The desktop side placement is withdrawn: the WhatsApp float now owns the
   bottom-right corner and the two boxes measurably overlapped at 1440x900. */
@keyframes cue-swipe{
  0%,8%{transform:translateY(38px);opacity:0}
  18%,28%{transform:translateY(38px);opacity:1}
  65%,77%{transform:translateY(-38px);opacity:1}
  90%,100%{transform:translateY(-38px);opacity:0}
}
@keyframes cue-touch{
  0%,12%{opacity:0;transform:scale(.45)}
  23%{opacity:1;transform:scale(.75)}
  42%{opacity:1;transform:scale(1,1.7)}
  66%,100%{opacity:0;transform:scale(1.1,1.9)}
}
@media (max-width:760px){.hero-cue{bottom:1rem}}

/* Re-assert the reduced-motion guard: the cue styles above are appended later in
   the file and would otherwise win at equal specificity over the earlier rule. */
@media (prefers-reduced-motion:reduce){
  .hero-cue{display:none!important}
}

/* team portraits: same 3:4 plate as Diana's, square corners, no crop in the browser */
.role-photo{margin:0 0 1rem;aspect-ratio:3/4;overflow:hidden;background:var(--paper-2)}
.role-photo img{width:100%;height:100%;object-fit:cover;display:block}
/* the two entries that are not people close the section instead of sitting in the grid */
.team-close{margin:clamp(2rem,4vw,3rem) 0 0;padding-top:clamp(1.5rem,3vw,2rem);
  border-top:var(--rule);font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;font-weight:400;
  font-size:var(--step-1);line-height:1.35;color:var(--ink)}
.team-close span{display:block;margin-top:.5rem;font-family:Inter,system-ui,sans-serif;
  font-size:var(--step-0);color:var(--taupe);line-height:1.65}

/* Role cards are links now (one page per person). Same restrained hover as .card;
   the global a{color:inherit} already handles colour, so only the affordance is new. */
.role{transition:opacity .4s}
.role .role-photo img{transition:transform 1.2s cubic-bezier(.16,1,.3,1),filter .6s;filter:saturate(.98)}
.role:hover .role-photo img,
.role:focus-visible .role-photo img{transform:scale(1.05);filter:saturate(1)}
.role:hover .role-name,
.role:focus-visible .role-name{color:var(--brass)}
.role-name{transition:color .3s}
@media (prefers-reduced-motion:reduce){
  .role .role-photo img,.role-name{transition:none}
  .role:hover .role-photo img,.role:focus-visible .role-photo img{transform:none}
}

/* Service cards carry a photograph of that stage of the work (2026-09-14).
   3/4 portrait matches .role-photo in the team row above, and the sources are
   all portrait, so a landscape crop would throw away most of each frame. */
.do-fig{margin:0 0 1.1rem;aspect-ratio:3/4;overflow:hidden;background:var(--paper-2)}
.do-fig img{width:100%;height:100%;object-fit:cover;display:block;filter:saturate(.98)}

/* The scroll cue collided with the Concept/Detail/Handover strip on phones
   (2026-09-15, dinuka: "scroll button and handover too close"). Measured in WebKit:
   they OVERLAPPED by 11px on iPhone SE and sat 1px apart on a 12 mini, because
   .hero-copy sits at 10vh while the cue is pinned 16px off the bottom and stands
   ~77px tall. The cue cannot move down, so the copy moves up: there is 269px+ of
   clearance to the nav on every phone size. Reserve the cue's height plus a
   comfortable gap. */
@media (max-width:760px){
  .hero-copy{bottom:calc(6.5rem + 4vh)}
}
/* Very short phones (SE in landscape, small Androids): the hero copy is tall enough
   that raising it further would crowd the nav, so the cue stands down instead. */
@media (max-width:760px) and (max-height:680px){
  .hero-copy{bottom:clamp(3.5rem,10vh,7rem)}
  .hero-cue{display:none}
}

/* Reveals fade and translate; the reference (brightbladegents) also scales its
   sections up as they enter. A small scale adds the same lift with no layout cost. */
.reveal{transform:translateY(18px) scale(.985)}
.reveal.in{transform:none}
.card.is-pending .card-fig{transform:translateY(18px) scale(.985)}
/* Re-assert the reduced-motion guard: it lives earlier in the file and would
   otherwise lose to the rules just above at equal specificity. */
@media (prefers-reduced-motion:reduce){
  .reveal{opacity:1;transform:none}
  .card.is-pending .card-fig{opacity:1;transform:none}
}

/* Team cards reworked 2026-09-15 (dinuka: smaller images, position + a short line,
   no per-member pages). The card is no longer a link, so the hover affordances that
   implied one are withdrawn. Three children now, not four, so the subgrid span drops. */
.role{grid-row:span 3}
.role-photo{max-width:12rem}
.role:hover .role-photo img,
.role:focus-visible .role-photo img{transform:none;filter:saturate(.98)}
.role:hover .role-name,
.role:focus-visible .role-name{color:var(--taupe)}
@supports not (grid-template-rows:subgrid){
  .role-text{margin-top:auto}
}

/* Team portraits: square and smaller, two-up on phones (2026-09-15, dinuka's
   reference is a sparse grid of small square headshots). The source frames are
   waist-up 3:4, so they were re-cropped square with a top bias rather than being
   squashed by aspect-ratio alone. */
/* Two-up on PHONES only. Unscoped this beat the earlier
   `@media (min-width:1080px){repeat(4,1fr)}` on source order and collapsed the
   desktop row to 2 columns, so the 4-column rule is re-asserted after it. */
@media (max-width:639px){.team-roles{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1080px){.team-roles{grid-template-columns:repeat(4,1fr)}}
.role-photo{aspect-ratio:1/1;max-width:9rem}
@media (min-width:1080px){.role-photo{max-width:10rem}}

/* Studio + Services rebuilt around pictures (2026-09-15, dinuka: "use them more
   pictures less text, now looks plain"). Sources are portrait, cropped 4:5, so
   these need their own grid rather than .shot (which is 4/3 landscape). */
.studio-page{padding-block:0 clamp(4rem,9vw,7rem)}
/* 8 tiles: 2 columns (4 even rows) or 4 columns (2 even rows). NOT 3 - that
   leaves 3+3+2 and strands a hole in the last row. Keep the count even. */
.gal-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(.6rem,1.6vw,1.1rem)}
@media (min-width:1100px){.gal-grid{grid-template-columns:repeat(4,1fr)}}
.gal-shot{margin:0;overflow:hidden;background:var(--paper-2);aspect-ratio:4/5}
.gal-shot img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform 1.2s cubic-bezier(.16,1,.3,1);filter:saturate(.98)}
.gal-shot:hover img{transform:scale(1.04)}
/* an odd last tile would sit alone: let it span so it closes the grid */
.gal-note{margin:clamp(2rem,4vw,3rem) 0 0;padding-top:clamp(1.5rem,3vw,2rem);
  border-top:var(--rule);font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;font-size:var(--step-1);
  line-height:1.35;color:var(--ink);max-width:34ch}
.gal-cta{display:flex;gap:2rem;flex-wrap:wrap;margin:clamp(1.5rem,3vw,2.25rem) 0 0}
/* the four service lines: a quiet row above the pictures, not a wall of prose */
.sv-list{display:grid;gap:clamp(1.5rem,3vw,2.5rem);margin:0 0 clamp(2.5rem,5vw,4rem)}
@media (min-width:700px){.sv-list{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1100px){.sv-list{grid-template-columns:repeat(4,1fr)}}
.sv-list div{border-top:var(--rule);padding-top:1.1rem}
.sv-list h2{margin:0 0 .55rem;font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;font-weight:400;font-size:var(--step-1);line-height:1.25}
.sv-list p{margin:0;color:var(--taupe);line-height:1.65}
@media (prefers-reduced-motion:reduce){
  .gal-shot img{transition:none}
  .gal-shot:hover img{transform:none}
}

/* Footer Instagram link (2026-09-15): dinuka wants ONE link per page but WITH the
   icon, so the icon lives on the footer link - the only one left. `.ico` styling is
   scoped to `.clink`, which this is not, so it needs its own alignment rule.
   Colour is inherited so it follows footer a / footer a:hover like its neighbours. */
.ig-link{display:inline-flex;align-items:center;gap:.4rem}
.ig-link .ico{flex:0 0 auto;width:14px;height:14px}

/* Floating WhatsApp button (2026-09-16, dinuka: "small icon - floating - for
   WhatsApp"), routed to the NEW PROJECTS number he chose. z-index 55 sits under
   the fixed nav (60). It owns the bottom-right corner, so the desktop scroll cue
   returns to bottom-centre - measured overlap was real, not theoretical. */
/* Smaller and quieter: dinuka asked for a SMALL icon, and #25D366 measures 1.90:1
   against --paper while the brand accent --brass is 5.10:1 - the raw green was the
   loudest thing on a restrained page. Ink-on-paper chip with a green glyph instead. */
/* dinuka supplied the official WhatsApp mark (2026-09-16), so the float IS the
   logo now - no paper chip, no border, or there would be a white ring around a
   green bubble. His PNG had 17% transparent padding; it is trimmed and squared in
   `site/img/brand/whatsapp-*.webp` (2x/3x for DPR-3 phones). Original kept at
   `_src/icon/whatsapp-original.png`. */
/* Middle of the right edge, not the bottom corner (dinuka 2026-09-16: "should be
   on middle right side. i feel it too low"). Vertical centring uses
   translateY(-50%), so the hover nudge must COMBINE with it - a bare
   translateY(-2px) would drop the button to the top, and the reduced-motion
   `transform:none` would do the same. Hover slides left instead of up, which
   reads better on an edge-anchored control. */
.wa-float{position:fixed;right:clamp(.9rem,2.5vw,1.4rem);top:50%;
  transform:translateY(-50%);
  z-index:55;display:block;width:48px;height:48px;line-height:0;
  filter:drop-shadow(0 4px 14px rgba(12,9,8,.22));
  transition:transform .35s cubic-bezier(.16,1,.3,1),filter .35s}
.wa-float img{width:100%;height:100%;display:block}
.wa-float:hover,.wa-float:focus-visible{transform:translateY(-50%) translateX(-3px);
  filter:drop-shadow(0 8px 20px rgba(12,9,8,.3))}
@media (max-width:760px){.wa-float{width:44px;height:44px}}
@media (prefers-reduced-motion:reduce){.wa-float{transition:none}
  .wa-float:hover,.wa-float:focus-visible{transform:translateY(-50%)}}

/* Journal teaser made compact (2026-09-16, dinuka: "Journal should be small").
   4 cards -> 4 across on desktop so the row is even (it was 2x2 with big 4:3
   images), smaller type, tighter gap, squarer thumbnails. /blog/ is unchanged. */
@media (min-width:1000px){.post-grid--2{grid-template-columns:repeat(4,1fr)}}
.post-grid--2{gap:clamp(1rem,2.5vw,1.75rem)}
.post-grid--2 .post-fig{aspect-ratio:1/1;margin-bottom:.7rem}
.post-grid--2 .post-card h3{font-size:var(--step-0);line-height:1.25;max-width:20ch}
.post-grid--2 .date{font-size:var(--step--1)}

/* Journal teaser on PHONES: the base .post-grid rule is 1fr, so the 4-card teaser
   ran 2101px tall - not "small". 2-up gives ~167px thumbs and ~514px total.
   /blog/ keeps the full-width single column. */
@media (max-width:639px){
  .post-grid--2{grid-template-columns:repeat(2,1fr);gap:1rem}
  .post-grid--2 .post-card h3{font-size:var(--step--1);line-height:1.3;max-width:none}
  .post-grid--2 .date{font-size:var(--step--1)}
}


/* Instagram moved out of the footer and next to the mobile numbers in the contact
   blocks (2026-09-16). It only appears on pages that HAVE a contact block - the
   homepage #contact and /contact-us/ - which dinuka accepted. */
.contact-grid .ig-link .ico,.prose .ig-link .ico{color:var(--taupe)}
.contact-grid .ig-link:hover .ico,.prose .ig-link:hover .ico{color:var(--brass)}

/* ============ DARK THEME (2026-09-16) ============================
   The site is ~187 var(--token) uses against 6 hardcoded hexes, so dark mode is
   mostly a second token block. The HERO is dark in BOTH themes, so every
   hero-scoped rgba() (veil, hero-copy, hero-caps, hero-cue, .nav--over) is left
   exactly as it is. Only page chrome flips. */
:root[data-theme="dark"]{
  --paper:#14110F;        /* warm near-black ground, not pure #000 */
  --paper-2:#1D1917;      /* raised surface */
  --ink:#F2EEE9;          /* type inverts to the old paper-2 */
  --taupe:#A99C8E;        /* secondary type, lifted for AA on the dark ground */
  --line:#332C27;         /* hairlines */
  --brass:#C79A62;        /* accent lifted: #86653F is too dark on a dark ground */
}
/* form errors need a lighter red on the dark ground */
:root[data-theme="dark"] .field-error,
:root[data-theme="dark"] .form-status.is-error{color:#E08A7B}
:root[data-theme="dark"] .enquiry [aria-invalid="true"]{border-color:#E08A7B}
/* the Google Maps embed is a light rectangle; soften it rather than leave it glaring */
:root[data-theme="dark"] .map-frame iframe{filter:invert(.92) hue-rotate(180deg) saturate(.8)}
/* photographs were toned for paper: take the edge off pure-white grounds */
:root[data-theme="dark"] .gal-shot img,
:root[data-theme="dark"] .post-fig img,
:root[data-theme="dark"] .card-fig img{filter:brightness(.92) saturate(.96)}

/* ---- the toggle itself ---- */
.theme-toggle{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;padding:0;margin-left:.9rem;border:1px solid var(--line);
  border-radius:50%;background:transparent;color:var(--taupe);cursor:pointer;
  transition:color .3s,border-color .3s,background .3s}
.theme-toggle:hover,.theme-toggle:focus-visible{color:var(--ink);border-color:var(--taupe)}
.theme-toggle .ico{display:block}
/* show one glyph at a time */
.theme-toggle .ico-moon{display:none}
:root[data-theme="dark"] .theme-toggle .ico-sun{display:none}
:root[data-theme="dark"] .theme-toggle .ico-moon{display:block}
/* over the dark hero the nav is transparent: match the link treatment there */
.nav--over .theme-toggle{color:rgba(251,250,248,.86);border-color:rgba(251,250,248,.3)}
.nav--over .theme-toggle:hover{color:#FBFAF8;border-color:rgba(251,250,248,.6)}
.nav--over.is-solid .theme-toggle{color:var(--taupe);border-color:var(--line)}
.nav--over.is-solid .theme-toggle:hover{color:var(--ink);border-color:var(--taupe)}
@media (max-width:760px){
  /* the nav stacks to a column on phones; keep the toggle on the wordmark row */
  .theme-toggle{position:absolute;top:.6rem;right:var(--pad);margin-left:0}
}
@media (prefers-reduced-motion:reduce){.theme-toggle{transition:none}}

/* ---- wordmark must follow the THEME, not just hero position (fixed 2026-09-16) ----
   The swap was driven only by .nav--over/.is-solid, i.e. "am I over the dark hero".
   In dark mode that left the BLACK logo (measured luminance 0/255) on a #14110F nav
   at 1.06:1 - invisible on all 18 pages. Only index.html even has .nav--over, so the
   other 17 never had a rule at all. In dark mode the WHITE mark is the default; the
   hero's transparent-nav behaviour is unchanged because the hero is dark either way. */
:root[data-theme="dark"] .mark-dark{opacity:0}
:root[data-theme="dark"] .mark-light{opacity:1}
:root[data-theme="dark"] .nav--over.is-solid .mark-dark{opacity:0}
:root[data-theme="dark"] .nav--over.is-solid .mark-light{opacity:1}


/* ===== LAYOUT PASS (2026-09-16) =========================================
   dinuka: "what we do images should be small, make it like 2 and 2 when you
   scroll", "projects should be small", "fix the layout font sizes to keep the
   flow, small text then big, then small". */

/* --- What we do: 2x2 on phones, smaller squarer images --- */
.do-grid{grid-template-columns:repeat(2,1fr);gap:clamp(1rem,3vw,1.75rem) clamp(.8rem,2.5vw,1.5rem)}
@media (min-width:1100px){.do-grid{grid-template-columns:repeat(4,1fr)}}
.do-fig{aspect-ratio:1/1;margin-bottom:.8rem}
.do-grid article{padding-top:.85rem}
@media (max-width:699px){
  .do-grid h3{font-size:var(--step-0)}
  .do-grid p{font-size:var(--step--1);line-height:1.55}
}

/* --- Projects: two-up on phones so a card is a glance, not a screenful --- */
@media (max-width:759px){
  .grid{grid-template-columns:repeat(2,1fr);gap:1rem .8rem}
  .grid .card-fig{aspect-ratio:1/1}
  .card-body{margin-top:.7rem;padding-top:.55rem;gap:.4rem}
  .card-body h2,.card-body h3{font-size:var(--step-0);line-height:1.25}
  .card-idx,.card-loc{font-size:calc(var(--step--1) * .92)}
  .card-loc{top:.5rem;left:.5rem;padding:.22rem .45rem}
  .card-new{top:.5rem;right:.5rem}
}

/* --- Type rhythm: a section title must outrank a card title ---------------
   Both were var(--step-1), so headings and cards read as one flat size and the
   page had no cadence. Section heads move up to step-2; card titles sit at
   step-0 on phones. Small label -> big section title -> small card text. */
.section-head h2{font-size:var(--step-2);line-height:1.15}
@media (max-width:760px){
  .section-head{align-items:flex-end}
  .section-head h2{font-size:clamp(1.35rem,1.05rem + 1.5vw,1.8rem)}
  .seeall{font-size:calc(var(--step--1) * .95)}
}

/* --- Services page: image + words as one unit, small images, 2-up on phones --- */
.sv-list{grid-template-columns:repeat(2,1fr);gap:clamp(1.2rem,3vw,2rem) clamp(.8rem,2.5vw,1.5rem)}
@media (min-width:1100px){.sv-list{grid-template-columns:repeat(4,1fr)}}
.sv-card{margin:0;border-top:var(--rule);padding-top:.85rem}
.sv-fig{margin:0 0 .8rem;aspect-ratio:1/1;overflow:hidden;background:var(--paper-2)}
.sv-fig img{width:100%;height:100%;object-fit:cover;display:block;filter:saturate(.98)}
.sv-card h2{margin:0 0 .45rem;font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;font-weight:400;
  font-size:var(--step-1);line-height:1.2}
.sv-card p{margin:0;color:var(--taupe);line-height:1.6}
@media (max-width:699px){
  .sv-card h2{font-size:var(--step-0)}
  .sv-card p{font-size:var(--step--1);line-height:1.55}
}

/* ===== HERO: the scrub walkthrough is BACK (2026-09-16) ==================
   dinuka supplied new footage and asked for "the same setting we used before
   with scroll hand animation". The type-on-paper hero is retired; .hero-sticky,
   .hero-veil, .hero-canvas, .hero-still and the whole .hero-cue set were never
   deleted, so this is wiring rather than rebuilding.
   NEW SET: 110 frames each, phone 750px portrait (4.5MB) / desktop 1280px
   (3.4MB) - sharper than the old 600px set Diana rejected on quality, and the
   spine-first loader in site.js is what keeps the heavier payload usable. */
/* The phone fold fix carries over: the hero must own the first screen so the
   team photo cannot appear above it (dinuka, earlier today). */
@media (max-width:760px){
  .hero-sticky{min-height:100svh}
}


/* Hover zoom (2026-09-16, dinuka: "3D live effect ... what i mean is zoom in
   when you keep the curser there"). Same easing as the project cards already use.
   Pointer-only: a phone has no hover, and :hover on touch sticks after a tap. */
@media (hover:hover) and (pointer:fine){
  .do-fig img,.sv-fig img,.teddie-shot .tc-img{
    transition:transform 1.1s cubic-bezier(.16,1,.3,1)}
  .do-grid article:hover .do-fig img,
  .sv-card:hover .sv-fig img,
  .teddie-shot:hover .tc-img{transform:scale(1.06)}
}
@media (prefers-reduced-motion:reduce){
  .do-fig img,.sv-fig img,.teddie-shot .tc-img{transition:none}
  .do-grid article:hover .do-fig img,
  .sv-card:hover .sv-fig img,
  .teddie-shot:hover .tc-img{transform:none}
}

/* About section on the homepage (2026-09-16) - replaces the removed Studio page.
   Text only, deliberately short, matching the prose measure used elsewhere. */
.about-block{max-width:46ch}
.about-block .lead{margin:0 0 .9rem;font-family:Fraunces,serif;
  font-variation-settings:"SOFT" 60,"WONK" 1;font-weight:400;
  font-size:var(--step-1);line-height:1.3;color:var(--ink)}
.about-block p{margin:0 0 .8rem;color:var(--taupe);line-height:1.65}
.about-block .about-note{margin:1.1rem 0 0;padding-top:.9rem;border-top:var(--rule);color:var(--ink)}

/* Service cards play a short muted loop instead of a still (2026-09-16).
   preload="none" + the poster keeps them off the critical path. */
.do-fig video,.sv-fig video{width:100%;height:100%;object-fit:cover;display:block;filter:saturate(.98)}
@media (hover:hover) and (pointer:fine){
  .do-fig video,.sv-fig video{transition:transform 1.1s cubic-bezier(.16,1,.3,1)}
  .do-grid article:hover .do-fig video,
  .sv-card:hover .sv-fig video{transform:scale(1.06)}
}
@media (prefers-reduced-motion:reduce){
  .do-fig video,.sv-fig video{transition:none}
  .do-grid article:hover .do-fig video,
  .sv-card:hover .sv-fig video{transform:none}
}

/* About page (2026-09-16): its own tab again, short, no images, with CTAs.
   The homepage #about section is gone - it interrupted team -> founder. */
.about-page{padding-block:0 clamp(4rem,9vw,7rem)}
.about-page .about-block{max-width:52ch}
.about-page .about-block p{margin:0 0 1rem;color:var(--taupe);line-height:1.7}
.about-facts{display:grid;gap:clamp(1.2rem,3vw,2rem) clamp(1rem,3vw,2.5rem);
  margin:clamp(2.5rem,5vw,3.5rem) 0 0;padding-top:clamp(1.5rem,3vw,2rem);border-top:var(--rule);
  grid-template-columns:repeat(2,1fr)}
@media (min-width:900px){.about-facts{grid-template-columns:repeat(4,1fr)}}
.about-facts div{display:grid;gap:.3rem}
.about-facts dt{font-size:var(--step--1);text-transform:uppercase;letter-spacing:.18em;color:var(--taupe)}
.about-facts dd{margin:0;font-size:var(--step-0);color:var(--ink);line-height:1.4}
.about-cta{display:flex;align-items:center;gap:clamp(1rem,3vw,2rem);flex-wrap:wrap;
  margin:clamp(2.5rem,5vw,3.5rem) 0 0}

/* Tap targets on phones (2026-09-16, dinuka: "focus more on mobile view").
   Measured: .clink (emails, numbers, @intrio.ae, "See the work", "Start a project",
   the project pagers) rendered 32px tall, and the breadcrumb links 15px. Both are
   under the 44px both platforms ask for. The existing touch-target rule covered
   .nav-links a / .seeall / footer a only. Padding is pulled back with negative
   margin so the visual spacing is unchanged. */
@media (max-width:760px){
  .clink,.pager a,.page-head .meta a,.story-links a,.about-cta .clink,.map-note a{
    padding-block:.7rem;margin-block:-.7rem;display:inline-flex;align-items:center}
  .contact-grid p{margin-bottom:.75rem}
  .pager{gap:.75rem}
}

/* Last two mobile nits (2026-09-16): the nav links padded to 41px, 3px under the
   44px minimum; and the uppercase micro-labels (category, location, date,
   breadcrumb) rendered 10.6-10.9px, which is small on a phone even for caps. */
@media (max-width:760px){
  .nav-links a{padding-block:.8rem;margin-block:-.8rem}
  .card-idx,.card-loc,.date,.page-head .meta,.card-new{font-size:.72rem}
}

/* 375px phones (SE, 12/13 mini): with About added the five nav links wrapped
   "Contact" onto a second line. Tighten spacing only below 390px. */
@media (max-width:389px){
  .nav-links{gap:.62rem}
  .nav-links a{letter-spacing:.07em}
}

/* Journal posts on phones (2026-09-16): `.prose.narrow` zeroes its side padding,
   which is right once 40rem is narrower than the screen, but on a phone the text
   ran flush to the screen edge. Restore the gutter until the column fits. */
@media (max-width:760px){
  .prose.narrow{padding-inline:var(--pad)}
}

/* Phone hero video scrub (experiment 2026-09-16): same slot as the canvas */
video.hero-video{object-fit:cover;pointer-events:none}

/* Desktop hero end still (2026-09-16): same framing as the last frame, faded in by site.js */
.hero-end{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  opacity:0;pointer-events:none;will-change:opacity}

/* Static hero (2026-09-16): one screen, one still image; the scrub is parked.
   Two classes so it beats the 520vh / 450vh scrub heights at any breakpoint. */
.hero-scroll.hero-static{height:100vh;height:100svh}
@media (prefers-reduced-motion:reduce){ .hero-scroll.hero-static{height:auto} }

/* 360 concept tour (/services/, 2026-09-17) */
.tour{margin-block:clamp(3.5rem,8vw,6rem) 0}
.tour .section-head{margin-bottom:1.1rem}
.tour-stage{position:relative;aspect-ratio:16/9;overflow:hidden;background:#14110F;color:#FBFAF8}
.tour-poster,.tour-view{position:absolute;inset:0;width:100%;height:100%}
.tour-poster{object-fit:cover;display:block;transition:opacity .6s ease}
.tour-view{opacity:0;transition:opacity .6s ease}
.tour-stage.is-ready .tour-view{opacity:1}
.tour-stage.is-ready.is-inline .tour-poster{opacity:0}
.tour-stage .pnlm-load-box,.tour-stage .pnlm-panorama-info,.tour-stage .pnlm-about-msg{display:none!important}
.tour-stage .pnlm-container{background:#14110F;font-family:inherit}
.tour-open{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:.75rem;
  padding:.55rem 1.2rem .55rem .55rem;border:1px solid rgba(251,250,248,.55);border-radius:999px;
  background:rgba(20,17,15,.55);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  color:#FBFAF8;font:inherit;font-size:var(--step--1);letter-spacing:.14em;text-transform:uppercase;cursor:pointer;min-height:48px}
.tour-open-ring{display:grid;place-items:center;width:2.6rem;height:2.6rem;border-radius:50%;
  border:1px solid rgba(251,250,248,.7);font-size:.68rem;letter-spacing:.04em}
.tour-stage.is-inline .tour-open{display:none}
.tour-bar{position:absolute;left:50%;bottom:clamp(.7rem,2vw,1.2rem);transform:translateX(-50%);display:flex;gap:.4rem;
  opacity:0;pointer-events:none;transition:opacity .4s ease}
.tour-stage.is-ready .tour-bar{opacity:1;pointer-events:auto}
.tour-bar button{width:40px;height:40px;border-radius:50%;border:1px solid rgba(251,250,248,.35);
  background:rgba(20,17,15,.62);color:#FBFAF8;font:inherit;font-size:1rem;line-height:1;cursor:pointer;
  display:grid;place-items:center;touch-action:manipulation}
.tour-bar button:hover{background:rgba(20,17,15,.85)}
.tour-bar button:focus-visible,.tour-open:focus-visible{outline:2px solid var(--brass);outline-offset:3px}
.tour-close{display:none!important}
.tour-note{margin:.9rem 0 0;color:var(--taupe);font-size:var(--step--1);line-height:1.6;max-width:60ch}
.tour-stage.is-loading .tour-open-ring{animation:tourpulse 1.2s ease-in-out infinite}
@keyframes tourpulse{50%{opacity:.35}}
.tour-stage.is-failed .tour-open{display:none}

/* touch devices: poster + button; the room opens full screen */
@media (max-width:760px){ .tour-stage{aspect-ratio:4/5} }
.tour-stage:not(.is-inline) .tour-bar{bottom:max(1rem,env(safe-area-inset-bottom))}
.tour-stage.is-open{position:fixed;inset:0;z-index:80;aspect-ratio:auto;height:100vh;height:100dvh}
.tour-stage.is-open .tour-open{display:none}
.tour-stage.is-open .tour-close{display:grid!important}
.tour-stage.is-open .tour-poster{opacity:0}
.tour-stage:not(.is-inline):not(.is-open) .tour-bar,
.tour-stage:not(.is-inline):not(.is-open) .tour-view{opacity:0;pointer-events:none}
.tour-open-page .wa-float{visibility:hidden}
@media (prefers-reduced-motion:reduce){
  .tour-poster,.tour-view,.tour-bar{transition:none}
  .tour-stage.is-loading .tour-open-ring{animation:none}
}
/* pannellum's own .pnlm-container rules load later: keep the view absolute and the controls above it */
.tour-stage .tour-view{position:absolute;inset:0;width:100%;height:100%;z-index:1}
.tour-stage .tour-bar,.tour-stage .tour-open{z-index:3}
.tour-open span:last-child{white-space:nowrap}

/* Autoplay loop hero (2026-09-17): plain looping video over the poster, no scroll link */
.hero-sticky .hero-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}
@media (prefers-reduced-motion:reduce){ .hero-sticky .hero-bg{display:none} }

/* Services: the trades list (2026-09-18). Text only, even count, 2 columns on phones
   and 4 from 1000px - never 3, which would strand a hole in an 8-item grid. */
.scope{margin-block:clamp(2.5rem,6vw,4.5rem) 0}
.scope .section-head{margin-bottom:1.1rem}
.scope-list{list-style:none;margin:0;padding:0;display:grid;gap:0 clamp(1rem,3vw,2.5rem);
  grid-template-columns:repeat(2,1fr)}
/* phones: one column, and keep the right edge clear of the floating WhatsApp button,
   which sits mid-screen right and would otherwise cover a service name */
@media (max-width:639px){.scope-list{grid-template-columns:1fr;padding-right:3.4rem}}
@media (min-width:1000px){.scope-list{grid-template-columns:repeat(4,1fr)}}
.scope-list li{display:flex;gap:.6rem;align-items:baseline;border-top:var(--rule);
  padding-block:.85rem;color:var(--ink);line-height:1.4}
.sc-idx{color:var(--brass);font-size:.72rem;letter-spacing:.1em;flex:0 0 auto}

/* Journal articles: subheadings and comparison tables (2026-09-21 lighting article) */
.prose h3{font-family:Inter,sans-serif;font-size:var(--step-0);font-weight:500;letter-spacing:.01em;
  margin:1.6rem 0 .5rem;color:var(--ink)}
.table-wrap{overflow-x:auto;margin:0 0 1.3rem}
.post-table{border-collapse:collapse;width:100%;font-size:var(--step--1);line-height:1.5}
.post-table th{text-align:left;font-weight:500;color:var(--ink);letter-spacing:.06em;text-transform:uppercase;
  font-size:.72rem;padding:.55rem .8rem .55rem 0;border-bottom:1px solid var(--line)}
.post-table td{padding:.7rem .8rem .7rem 0;border-bottom:1px solid var(--line);color:var(--taupe);vertical-align:top}
.post-table tr td:first-child{color:var(--ink);white-space:nowrap}
.prose a.clink{color:var(--brass);text-decoration:underline;text-underline-offset:.18em}
