/* ═══════════════════════════════════════════════════════════════════════════
   Mizan Architect — editorial site stylesheet
   Structure follows kononenkogroup.com; palette, type and content are Mizan.
   Authoring unit: 1rem = 1px in the 1920 design.
   ═════════════════════════════════════════════════════════════════════════ */

@font-face{font-family:'Aventa';font-weight:400;font-style:normal;font-display:swap;src:url(fonts/2fb3fa9cd4d9.woff2) format('woff2')}
@font-face{font-family:'Aventa';font-weight:500;font-style:normal;font-display:swap;src:url(fonts/9f2d05e729a5.woff2) format('woff2')}
@font-face{font-family:'Aventa';font-weight:600;font-style:normal;font-display:swap;src:url(fonts/19dc5be3b5e7.woff2) format('woff2')}
@font-face{font-family:'Hedvig Letters Serif';font-weight:400;font-style:normal;font-display:swap;src:url(fonts/hedvig-latin.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Hedvig Letters Serif';font-weight:400;font-style:normal;font-display:swap;src:url(fonts/hedvig-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+2C60-2C7F,U+A720-A7FF}

/* Floored at .9px so body copy never drops below 14.4px — the reference site
   has no floor and renders 8.3px body text at a 1000px viewport (measured). */
html{font-size:max(.9px, calc(100vw / 1920));-webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;box-sizing:border-box}
@media(max-width:767.98px){html{font-size:calc(100vw / 375)}}
*,*::before,*::after{box-sizing:inherit;margin:0;padding:0}

:root{
  --bg:#FFFFFF; --text:#0c231d; --muted:#4d6b62; --border:#E7E7E4;
  --deep:#00382F; --accent:#B8EBAC;
  --ease:cubic-bezier(.17,.84,.44,1);
  --pad:30rem; --gut:20rem;
}

body{font-family:'Aventa',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  font-size:16rem;line-height:1.2;letter-spacing:-.02em;color:var(--text);
  background:var(--bg);overflow-x:hidden}
img{display:block;max-width:100%;height:auto}
a{color:inherit;text-decoration:none}
h1,h2,h3,h4{font-weight:400;letter-spacing:-.03em}
button{font:inherit;color:inherit}
.serif{font-family:'Hedvig Letters Serif',Georgia,serif}
.ctr{padding:0 var(--pad);width:100%}
.grd{display:grid;grid-template-columns:repeat(15,1fr);gap:var(--gut);width:100%}
.label{font-size:16rem;color:var(--muted)}
/* screen-reader-only: for pages whose visual design carries no heading */
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}
.eyebrow{display:flex;align-items:center;gap:12rem;font-size:16rem;color:var(--muted);
  margin-bottom:40rem}
.eyebrow::before{content:'';width:40rem;height:2px;background:currentColor;flex-shrink:0}

/* ── render save deterrents ────────────────────────────────────────────────
   Right-click, drag-to-desktop and the iOS long-press sheet are refused on
   images. Be clear about the ceiling: a screenshot, the network tab or a
   direct asset URL still work - nothing a browser can do prevents that. This
   only removes the one-click routes. */
img{-webkit-user-drag:none;-webkit-touch-callout:none}
.mimg,.sh,.gi,.it,.pf,.tcard-img,.thumb{-webkit-user-select:none;user-select:none}

/* ── reveals ─────────────────────────────────────────────────────────────── */
/* The clip box needs a little more than the line box or the mask cuts the
   glyphs themselves - at .big's 1.02 line-height the tops and the commas were
   being shaved off (studio 2026-09-02). Padding opens the box, the negative
   margin hands the space back to the layout, and the reveal offset grows by
   the same amount so the line still starts fully out of sight. */
.lnw{display:block;overflow:hidden;padding-block:.22em;margin-block:-.22em}
.ln{display:block;transform:translateY(calc(101% + .24em))}
.in .ln{transform:translateY(0)}
.fade{opacity:0;transform:translateY(20rem);transition:opacity .8s var(--ease),transform .8s var(--ease)}
.in.fade,.in .fade{opacity:1;transform:none}
.in .fade:nth-child(2){transition-delay:.06s}
.in .fade:nth-child(3){transition-delay:.12s}
.in .fade:nth-child(4){transition-delay:.18s}
.mimg{position:relative;overflow:hidden;background:#e9e9e6;clip-path:inset(0 0 100% 0);
  transition:clip-path 1.2s var(--ease)}
.mimg.in{clip-path:inset(0 0 0 0)}
.mimg img{width:100%;transform:scale(1.06);transition:transform 1.6s var(--ease)}
.mimg.in img{transform:scale(1)}

/* ── chrome: progress bar + blend-mode nav ───────────────────────────────── */
.prog{position:fixed;top:0;left:0;width:100%;height:4px;background:var(--text);
  transform:scaleX(0);transform-origin:left;z-index:10000;will-change:transform}
.nav{position:fixed;top:0;left:0;width:100%;padding:20rem 0;color:#fff;
  mix-blend-mode:difference;pointer-events:none;z-index:9999}
.nav a{pointer-events:auto}
/* No dimming over imagery: an earlier .over-img rule ghosted the bar to .22
   whenever an image or video sat under it, and on the index hero (a bright
   full-bleed video) that made the menu unreadable - the studio flagged it.
   The difference blend above is the legibility mechanism; the ONE state that
   hides the bar is browsing renders one by one, below. */
.nav{transition:opacity .45s var(--ease),transform .5s var(--ease)}
/* browsing renders one by one (.rview, z-index 15) sits BELOW the nav
   (9999) by design elsewhere on the site, so without this the wordmark and
   the links would float on top of a fullscreen render. No hover brings it
   back - the render owns the screen until it closes. */
.nav.hide,.nav.hide a{pointer-events:none}
.nav.hide{opacity:0}
/* Scrolling down tucks the bar up out of the frame, scrolling back up slides
   it down again (studio 2026-09-02: over a hero title the fixed bar was in
   the way). Transform, not opacity, so it reads as the bar leaving rather
   than dissolving - and so it never fights .hide above. */
.nav.tuck{transform:translateY(-100%)}
.nav.tuck a{pointer-events:none}
.nav .row{display:flex;justify-content:space-between;align-items:flex-start;gap:20rem}
/* links and picker travel together, hard right */
.nav .row > ul:not(.lang){margin-left:auto}
.nav ul{display:flex;gap:.4em;list-style:none;font-size:16rem;flex-wrap:wrap;
  justify-content:flex-end}
.nav ul a{position:relative}
.nav ul a::after{content:'';position:absolute;left:0;bottom:-.15em;width:100%;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:left;
  transition:transform .4s var(--ease)}
.nav ul a:hover::after,.nav ul a[aria-current]::after{transform:scaleX(1)}
/* The language picker. Same row as the links, set apart by a rule rather
   than by size, so it reads as a control and not as a fifth page. The
   current language is a span, so it takes the muted colour and no underline
   - there is nothing to click. */
.nav .lang{display:flex;gap:.5em;list-style:none;font-size:14rem;
  align-items:center;margin-left:1.1em;padding-left:1.1em;
  border-left:1px solid currentColor;align-self:flex-start;
  line-height:1.15}
.nav .lang a{position:relative;pointer-events:auto}
.nav .lang a::after{content:'';position:absolute;left:0;bottom:-.15em;
  width:100%;height:1px;background:currentColor;transform:scaleX(0);
  transform-origin:left;transition:transform .4s var(--ease)}
.nav .lang a:hover::after{transform:scaleX(1)}
.nav .lang [aria-current]{opacity:.55}

/* ── hero ────────────────────────────────────────────────────────────────── */
.hero{position:relative;height:100vh;display:flex;align-items:flex-end;
  overflow:hidden;color:#fff}
.hero-bg{position:absolute;inset:0}
.hero-bg img{width:100%;height:100%;object-fit:cover}
.hero-bg::after{content:'';position:absolute;inset:0;
  background:linear-gradient(to top,rgba(0,56,47,.42),rgba(0,56,47,0) 55%)}
.hero-foot{position:relative;z-index:2;width:100%;display:flex;
  justify-content:space-between;align-items:flex-end;gap:40rem;padding:38rem var(--pad)}
.hero h1{font-size:80rem;line-height:.8;max-width:900rem}

/* odometer digit columns */
.d{display:block;height:1em;line-height:1;overflow:visible clip;
  margin-top:-.15em;margin-bottom:-.15em;text-align:center}
.dcol{display:block;transform:translateY(0);transition:transform 1.8s var(--ease)}
.dcol span{display:block}
.dghost{position:absolute;visibility:hidden;white-space:pre}

/* ── generic section rhythm ──────────────────────────────────────────────── */
.sec{padding-block:95rem}
.sec-head{margin-bottom:60rem}
.sec-head h2{font-size:64rem;line-height:1.05}
.sec-head p{font-size:19rem;color:var(--muted);margin-top:20rem;max-width:640rem}

/* ── lead paragraph ──────────────────────────────────────────────────────── */
.lead{font-size:26rem;line-height:1.15;letter-spacing:-.03em}
/* the project description under the lead, same right-hand slot: body size and
   a reading measure, so a paragraph reads as text and not as a display slab */
.lead-sub{font-size:15rem;line-height:1.55;color:var(--muted);max-width:620rem;
  margin-top:18rem}
/* CTA: words as inline blocks so cta.js can move them; the M sits in a slot
   whose width the timeline opens. Static (no-JS / reduced-motion) state is the
   finished composition. */
.lead-wrap{grid-column:9/-1}

/* ── info / facts rows ───────────────────────────────────────────────────── */
/* --c/--r pin each cell to its own slot, so a hidden cell leaves its column
   empty and the rest stay put. Custom properties rather than grid-column and
   grid-row outright, so the phone rule below can hand the row back to auto
   flow without !important to beat an inline style. */
.facts-row > *{grid-column:var(--c,auto);grid-row:var(--r,auto)}
/* --fc is the number of cells build.py actually emitted: a project can switch
   a fact off, and five columns for three cells left a visible hole. */
/* The left half of a project's info section: the fact row, and under it the
   area figures. One block, so the figures sit directly beneath the facts
   rather than being pushed down the grid by the description beside them.
   --fc is set HERE now, so both children inherit the same track count. */
.info-l{grid-column:1/9}
/* --fc is capped at 5, so a project carrying Client and Team as well wraps
   onto a second line instead of squeezing seven cells into the eight columns
   this block gets. row-gap is what makes that second line readable. */
.facts-row{display:grid;grid-template-columns:repeat(var(--fc,5),1fr);
  gap:var(--gut);row-gap:30rem}
/* Three tracks, not the fact row's five. The two rows shared --fc so their
   columns lined up, but html's font-size is floored at .9px below a 1728
   viewport while the grid stays a share of the width - so under that width
   the type grows against its track and "Total Building Area" wrapped to two
   lines (studio 2026-09-02). Three tracks give every label room to stay on
   one line at any width, and the block still starts on the fact row's own
   left edge, and a track floor of 150rem: the longest label measures ~135rem
   wide at this size, so the floor always clears it and a width that cannot
   fit three of them drops the third to a second row instead of wrapping
   the words. */
.areas{display:grid;grid-template-columns:repeat(auto-fit,minmax(150rem,1fr));
  gap:26rem var(--gut);margin-top:46rem}
.areas .acell{min-width:0}
/* Aventa, not the serif (studio 2026-09-02) - figure and unit both, so the
   areas read as data in the page's own voice, not as display numerals. The
   serif class is simply not emitted on .av any more. */
/* the same size as the fact value above it, not a display figure: 19rem, no
   display tracking, the same 10rem step off its own label (studio
   2026-09-02) - the two rows are one block and should read as one */
.areas .av{font-size:19rem;margin-top:10rem;
  display:flex;align-items:baseline;gap:.2em;white-space:nowrap}
/* the unit rides with the figure, smaller, as it does on the hero */
.areas .au{font-size:.72em}

/* The areas sit behind a disclosure. <details>/<summary>, not a scripted
   toggle: the platform already does the click, the keyboard and the
   accessibility tree, and it works with no JS at all. */
/* One disclosure for the whole row. It spans the grid and repeats the page's
   own fifteen tracks, so its cells land exactly under the fact row and the
   statement above them: figures left, the rest of the description right. The
   summary sits at the right end of the left block, under the last fact cell. */
.more{grid-column:1/-1;display:grid;grid-template-columns:repeat(15,1fr);
  gap:22rem var(--gut)}
.more > summary{grid-column:9/-1;grid-row:1;justify-self:start;
  display:inline-block;font-size:14rem;color:var(--muted);
  cursor:pointer;list-style:none;-webkit-user-select:none;user-select:none;
  border-bottom:1px solid var(--border);padding-bottom:2rem;
  transition:color .3s var(--ease),border-color .3s var(--ease)}
.more > summary::-webkit-details-marker{display:none}
.more > summary::marker{content:''}
.more > summary:hover{color:var(--text);border-color:var(--text)}
.more > summary:focus-visible{outline:2px solid var(--deep);outline-offset:3px}
/* both labels are in the DOM and one is hidden, so the accessible name
   changes with the state instead of being faked in CSS content */
.more .m-b{display:none}
/* opened, the button drops under the text it revealed. Closed there is no
   row 1 content, so it sits tight under the statement as before. */
.more[open] > summary{grid-row:2}
.more[open] .m-a{display:none}
.more[open] .m-b{display:inline}
/* Chrome wraps a details' content in ::details-content, so the two cells are
   children of THAT box, not grid items of .more - the placement further down
   is inert there and this box has to carry it instead. Engines without the
   pseudo-element ignore this rule and use that placement, where the cells
   really are .more's own grid items. Both paths give the same result.

   The box exists whether the details is open or not, and at row 1 spanning
   every column it sat right on top of the summary and ate the click -
   elementsFromPoint returned the details before the summary, so pressing
   More did nothing (measured on the live page 2026-09-02). Hence the second
   rule: closed, the box is inert and the click reaches the button. The grid
   itself stays unconditional - the box needs display:grid at all times or
   the content collapses into one narrow column. */
.more::details-content{grid-column:1/-1;grid-row:1}
.more:not([open])::details-content{pointer-events:none}
/* .more-in is the real box: the two columns live on it, and site.js runs its
   height for the open and close. ::details-content is a pseudo element - it
   cannot be measured or given an inline height - so it only carries the
   placement and hands the width down to this wrapper. */
.more-in{display:grid;grid-template-columns:repeat(15,1fr);gap:var(--gut)}
.more-in > .areas{grid-column:1/9;margin-top:0}
.more-in > .more-r{grid-column:9/-1}
.more-in > .more-r .lead-sub{margin-top:0}
.more-in > .more-r .lead-sub + .lead-sub{margin-top:18rem}
/* the Awards cell's value: contest logo + Winner line */
.awv{display:flex;flex-direction:column;align-items:flex-start;gap:8rem;
  margin-top:4rem}
.awv img,.awv .alogo{height:30rem;width:auto;max-width:96rem;object-fit:contain;
  color:var(--deep)}
.facts-row .v{font-size:19rem;margin-top:10rem}


/* ── team — 4-col staggered grid, geometry measured off the reference ────── */
/* About group shot: full container width, box reserved so the masked reveal
   has nothing to shift. The ratio matches the source, so cover crops nothing. */
.abt-group{aspect-ratio:1/1}
.abt-group img{height:100%;object-fit:cover}

.tgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:30rem 20rem;align-items:start}
.tgrid > :nth-child(4n+2){margin-top:25rem}
.tgrid > :nth-child(4n+3){margin-top:53rem}
.tgrid > :nth-child(4n){margin-top:15rem}
.tcard .ph{overflow:hidden;background:#e9e9e6;aspect-ratio:5/7}
.tcard .ph img{width:100%;height:100%;object-fit:cover;
  transition:transform 1.109s var(--ease)}
.tcard:hover .ph img{transform:scale(1.03)}
.tcard .row{display:flex;justify-content:space-between;align-items:baseline;
  gap:20rem;margin-top:16rem}
.tcard .nm{font-size:16rem;letter-spacing:-.022em}
.tcard .rl{font-size:16rem;color:var(--muted)}
/* The team band carries the brand green, as the footer does. --muted is a dark
   grey-green and would sink into --deep, so the role takes --accent (9.5:1 on
   this ground); the image tint goes dark too, or every card flashes light grey
   while its photograph loads. */
.tsec{background:var(--deep);color:#fff}
.tsec .tcard .rl{color:var(--accent)}
.tsec .tcard .ph{background:#0b2b24}

/* ── contact ─────────────────────────────────────────────────────────────── */
.cmap{grid-column:1/-1;margin-top:60rem;border:2px solid var(--border);aspect-ratio:21/9;
  background:#e9e9e6;display:flex;align-items:center;justify-content:center;
  color:var(--muted);font-size:16rem}

/* ── gallery: three layouts, one visible ─────────────────────────────────── */
.gal{position:relative;overflow:hidden;width:100%}
/* Inactive views must be hidden outright: hiding only their images left the
   List view (text rows) painting on top of whichever view was active. */
.view{position:absolute;top:0;left:0;width:100%;padding:0 var(--pad);
  pointer-events:none;visibility:hidden;opacity:0;
  /* visibility flips only after the fade, so the outgoing layout crossfades
     under the incoming one instead of vanishing on the first frame */
  transition:opacity .35s var(--ease),visibility 0s linear .35s}
.view.on{position:relative;pointer-events:auto;visibility:visible;opacity:1;
  transition:opacity .35s var(--ease),visibility 0s}

/* switching layouts: items of the newly active view rise in one after
   another - same easing family as the reference's measured 1109ms morph */
.view.on .pcard,.view.on .lrow,.view.on .it{
  animation:view-in .9s var(--ease) backwards;
  animation-delay:calc(var(--i,0) * 45ms)}
@keyframes view-in{
  from{opacity:0;transform:translateY(34rem)}
  to{opacity:1;transform:none}
}
/* view-in is a LOAD-ONLY entrance. .switched is set on the first layout
   change and never cleared - keying this off the transient .morphing class
   meant the rise-in restarted the moment a morph finished, blanking the
   whole grid to opacity 0 and fading it back in a second time. */
.gal.switched .view.on .pcard,.gal.switched .view.on .lrow,.gal.switched .view.on .it{
  animation:none}

/* the flying clones: fixed layer above the page, below the nav */
/* absolute (not fixed) and sized to the full document, not the viewport - a
   fixed+clipped layer only shows whatever is inside the current scroll
   window, so anything below the fold never appeared to move. Coordinates
   below are document-absolute (top+scrollY), matching this layer exactly. */
.morph-layer{position:absolute;top:0;left:0;width:100%;height:100%;
  z-index:800;pointer-events:none;overflow:visible}
.morph-fly{position:absolute;object-fit:cover;max-width:none;
  will-change:top,left,width,height;
  /* one coordinated layout transformation: no fade, no bounce - the images
     travel, shrink and overlap, then settle. Matches MORPH_MS in site.js. */
  transition:top .86s cubic-bezier(.76,0,.24,1),left .86s cubic-bezier(.76,0,.24,1),
    width .86s cubic-bezier(.76,0,.24,1),height .86s cubic-bezier(.76,0,.24,1)}
.view img{width:100%;opacity:0;transition:opacity .6s var(--ease)}
.view.on img{opacity:1}
.detail{display:flex;flex-direction:column;gap:120rem;
  padding-block:180rem 120rem}   /* reference: 180rem then 120rem */

.view .it img{cursor:pointer}
.masonry{display:flex;align-items:flex-start;gap:var(--gut);padding-block:120rem}
.masonry .mcol{display:flex;flex:1;flex-direction:column;gap:var(--gut);min-width:0}
.slider{display:flex;align-items:center;height:calc(74svh + 240rem);padding-block:120rem}
.slider .swin{height:100%;width:100%;overflow:hidden}
.slider .strack{display:flex;gap:var(--gut);height:100%;width:max-content;cursor:grab;
  will-change:transform;touch-action:pan-y;
  transition:transform .5s var(--ease)}   /* reference: frame change .5s */
.slider .strack.drag{cursor:grabbing;transition:none}
.slider .strack.drag img{pointer-events:none}
.slider .it{flex:none;height:100%}
.slider .it img{height:100%;width:auto;max-width:none;object-fit:cover}
.viewbar{position:fixed;bottom:12rem;left:0;width:100%;display:flex;justify-content:center;
  z-index:900;pointer-events:none;  /* above the morph layer's flying clones */transform:translateY(calc(100% + 15rem));
  transition:transform .6s var(--ease)}
.viewbar.on{transform:translateY(0)}
.pill{display:flex;gap:20rem;padding:10rem 14rem;border-radius:6rem;
  background:var(--border);pointer-events:auto}
.vb{appearance:none;border:0;background:none;font-size:14rem;display:flex;align-items:center;
  gap:5rem;cursor:pointer;opacity:.4;transition:opacity .3s var(--ease)}
.vb svg{width:16rem;flex-shrink:0}
.vb.on{opacity:1;pointer-events:none}

/* a reserved video slot among the renders: same box, a play mark, inert */
.it.vid{aspect-ratio:16/10;background:#e9e9e6;display:grid;place-items:center;
  color:var(--muted)}
.it.vid svg{width:56rem;height:56rem}
/* with a file in, the tile is the player and fills the box the same way a
   render does - the inline aspect-ratio build.py writes still sets the shape */
.it.vid video{width:100%;height:100%;object-fit:cover;display:block}
.slider .it.vid{aspect-ratio:auto}
.slider .it.vid video{height:100%;width:auto;max-width:none}

/* ── more work: 4 projects in a row, .pcard reused from index/Work ────────── */
/* Off the page's pure white (--bg), the same warm off-white the project brief
   paper already uses - so this band reads as its own surface between the
   gallery above and the green footer below, not more of the same flat white. */
/* overflow-x:clip: the .stk fan thumbnails behind each card are rotated, and
   a rotated box reaches past its own edges - on the rightmost card that put
   18px past the viewport and the whole page scrolled sideways (measured). */
.around-sec{background:#F4F2ED;padding-block:120rem;overflow-x:clip}
.around{display:grid;grid-template-columns:repeat(4,1fr);gap:40rem}
.around .pcard .row{margin-top:14rem}
.around .pcard .nm{font-size:19rem;letter-spacing:-.02em}
.around .pcard .ar{font-size:14rem}

/* ── footer ──────────────────────────────────────────────────────────────── */
footer{border-top:2px solid var(--border)}

/* ── mobile: one breakpoint, as in the reference ─────────────────────────── */
@media(max-width:767.98px){
  :root{--pad:15rem;--gut:15rem}
  .grd{grid-template-columns:1fr;gap:40rem}
  .nav ul{font-size:14rem}
  .nav .lang{font-size:12rem;margin-left:.7em;padding-left:.7em;gap:.4em}
  .hero-foot{flex-direction:column;align-items:flex-start;gap:40rem;padding:20rem var(--pad)}
  .hero h1{font-size:40rem;max-width:none}
  .sec{padding-block:40rem}
  .sec-head{margin-bottom:30rem}
  .sec-head h2{font-size:34rem}
  .sec-head p{font-size:16rem}
  .info-l,.lead,.lead-wrap{grid-column:1}
  .areas{grid-template-columns:1fr;gap:26rem;margin-top:34rem}
  /* one column, in reading order: the desktop placement would leave the
     description in a track that does not exist here */
  .more{grid-template-columns:1fr;margin-top:0}
  .more > summary{grid-column:1;grid-row:auto;justify-self:start}
  .more-in{grid-template-columns:1fr;gap:26rem}
  .more-in > .areas,.more-in > .more-r{grid-column:1}
  .more-in > .areas{margin-top:0}
  .lead{font-size:26rem}
  .lead-sub{font-size:16rem}
  .facts-row{grid-template-columns:1fr 1fr;gap:24rem}
  /* two columns, filled in order: the desktop slots would leave holes and
     push cells past the end of a two-track row */
  .facts-row > *{grid-column:auto;grid-row:auto}
  .detail,.masonry{padding-block:40rem;gap:15rem}
  .masonry{display:grid;grid-template-columns:1fr}
  .masonry .mcol{display:contents}
  .slider{height:calc(60svh + 80rem);padding-block:40rem}
  .viewbar{display:none}
  .pill{gap:14rem}
  .vb{font-size:13rem}
  .around-sec{padding-block:70rem}
  /* One column, not two (studio 2026-09-02). Two 162rem cards left the
     name 88rem to work in, so every project of more than two words broke
     to three lines beside its area, and a long one pushed the figure to
     the card's edge. At full width the pair sits on one line and the
     thumbnail is worth looking at. */
  .around{grid-template-columns:1fr;gap:34rem}
  .around .pcard .row{align-items:baseline;gap:16rem}
}

@media(prefers-reduced-motion:reduce){
  .ln,.fade,.mimg,.mimg img,.dcol,.tcard .ph img{
    transition:none!important}
  .ln{transform:none}
  .fade{opacity:1;transform:none}
  .mimg{clip-path:none}
  .mimg img{transform:none}
}


/* ═══════════════════════════════════════════════════════════════════════════
   1:1 parity block — geometry measured off the reference (2026-08-18)
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── preloader: white sheet, content bottom-left, slides away ────────────── */
.pre{position:fixed;inset:0;width:100%;height:100vh;background:var(--bg);color:var(--text);
  z-index:9999;transform:translateY(0);
  transition:transform 1s var(--ease),visibility 0s linear 1s}
.pre.gone{transform:translateY(-100%);pointer-events:none;visibility:hidden}

/* contact page only: the same lift-away curtain, in the brand green rather
   than the default cream - inspired by specia1ne.com's opening panel */
.pre.pre-brand{background:var(--deep);color:#fff}
.pre.pre-brand .pl{color:rgba(255,255,255,.7)}

.pre .in-b{display:flex;align-items:flex-end;height:100%;width:100%;padding:38rem var(--pad);
  justify-content:space-between}
.pre .pn{font-size:175rem;line-height:.8;letter-spacing:-.03em}
.pre .pl{font-size:16rem;color:var(--muted);max-width:300rem;line-height:1.4}
@media(max-width:767.98px){
  .pre .in-b{padding:20rem var(--pad)}
  .pre .pn{font-size:90rem}
}

/* ── fullscreen menu overlay ─────────────────────────────────────────────── */

/* ── project page: sticky thumbnail rail in the last grid column ──────────
   In flow, not fixed - a fixed rail floated over the meta row and every
   section it passed. One grid column wide, as in the reference.            */
.pgal{position:relative;overflow:hidden}
.pgal .gwrap{position:relative;overflow:hidden}

/* Fixed at the left edge, as on the reference. The only departure: the
   reference draws its thumbs through WebGL, which leaves them blank until the
   gallery is on screen; ours are real images, so the rail is faded in on the
   same cue instead. */
.rail{position:fixed;left:var(--pad);top:50%;transform:translateY(-50%);
  display:flex;align-items:center;max-height:80vh;z-index:20;
  pointer-events:none;opacity:0;transition:opacity .3s var(--ease)}
.rail.on{opacity:1;pointer-events:auto}
.rail .strip{display:flex;flex-direction:column;gap:10rem;max-height:80vh;
  overflow:hidden auto;overscroll-behavior:contain;scrollbar-width:none}
.rail .strip::-webkit-scrollbar{display:none}
.rail .th{width:70rem;flex:0 0 auto;border:2px solid transparent;
  cursor:pointer;background:none;padding:0;transition:border-color .3s}
.rail .th.on{border-color:var(--border)}
.rail .th img{width:100%;display:block}
@media(max-width:767.98px){
  .rail{left:50%;bottom:15rem;top:auto;transform:translate(-50%);
    max-height:none;max-width:calc(100vw - 30rem)}
  .rail .strip{flex-direction:row;max-height:none;max-width:100%;
    overflow:auto hidden}
  .rail .th{width:44rem}
}

/* Lenis: it moves the page itself, so the html element must not clip */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto!important}


/* ── offices ─────────────────────────────────────────────────────────────── */
.offices{display:grid;grid-template-columns:repeat(4,1fr);gap:40rem var(--gut);
  border-top:2px solid var(--border);padding-top:40rem}
.offices .off .c{font-size:19rem;margin-top:12rem}
.offices .off .c a:hover{opacity:.6}
.offices .off .s{font-size:16rem;color:var(--muted);margin-top:6rem;line-height:1.45}

/* ── placeholder marking: add ?ph to any URL to outline every open slot ──── */
html.show-ph [data-ph]{outline:1px dashed #c46b00;background:rgba(255,196,0,.14);
  color:#8a4b00;border-radius:2px}

@media(max-width:767.98px){
  .offices{grid-template-columns:1fr;gap:24rem}
}


/* ── stage 1 hero: full-bleed media + studio wordmark ────────────────────── */
.hero-bg video{width:100%;height:100%;object-fit:cover;display:block}
.hero-open .hero-bg::after{background:linear-gradient(to top,
  rgba(0,56,47,.45),rgba(0,56,47,0) 60%)}


/* ═══════════════════════════════════════════════════════════════════════════
   Client layout (from the design screens) with the reference's motion system
   ═══════════════════════════════════════════════════════════════════════════ */

.mzlogo{display:block;height:auto;fill:currentColor}
.mzlogo.mz-nav{width:200rem}
.mzlogo.mz-hero{width:300rem}
.mzlogo.mz-word{width:100%}
.nav .nmark{color:#fff}
.nmark-gap{display:block}

/* hero: wordmark bottom-left over the media */
.hero-logo{color:#fff}

/* centred claim */
.claim{padding-block:150rem 90rem;text-align:center}
/* The headline's ink drifts like water: a green gradient clipped to the
   glyphs, washing back and forth. It lives on the split-reveal line spans,
   not the h1 - the reveal transforms those children, and a transformed child
   breaks background-clip:text on its parent (the text painted blank). The
   un-split h1 (no JS) simply keeps its solid var(--deep). */
/* A .70 line box is shorter than the glyphs it carries, and the reveal mask
   clips. Two moves, and no flex column: that turned every word into its own
   flex row and the line splitter produced three lines instead of two.
   1. the mask clips with a bleed allowance, so ascenders and descenders
      survive without negative margins that would collapse between siblings;
   2. the line pays for its own paint box - background-clip:text only has
      background to clip inside the element box, which is why the headline
      went invisible at this line-height. overflow:clip on the mask is a BFC,
      so this margin does not collapse outward. */
/* flow-root because overflow:clip - unlike hidden - does NOT establish a
   block formatting context, so without it the line's negative margins escape
   the mask and the rows sit 15px apart too far (measured). */
.claim h1 .lnw,.grad .lnw{overflow:clip;overflow-clip-margin:.22em;display:flow-root}
.claim h1 .ln,.grad .ln{padding-block:.17em;margin-block:-.17em}
.claim h1 .ln,.grad .ln{background:linear-gradient(100deg,var(--deep) 10%,#17705A 32%,#5FB392 50%,#17705A 68%,var(--deep) 90%);
  background-size:230% 100%;-webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;animation:tide 8s ease-in-out infinite}
@keyframes tide{50%{background-position:100% 0}}

/* ── About: the headline sits on the group photograph ─────────────────────
   The photo's top quarter measures L~48 (mean of 44-53, no figures in it), so
   the type goes there and carries a light gradient - the dark --deep ramp the
   homepage uses would disappear into it. A short scrim guarantees the contrast
   whatever photograph replaces this one. */
.abt-hero{position:relative;width:100%}
.abt-hero::after{content:'';position:absolute;inset:0 0 auto;height:42%;
  background:linear-gradient(180deg,rgba(0,0,0,.42),rgba(0,0,0,0));
  pointer-events:none;z-index:1}
/* Mirror of the scrim above, for the studio's statement standing on the floor
   of the photograph: measured, that floor averages 125/255, which is only
   4.2:1 against white - too thin for body copy. The scrim takes it past 7:1
   without darkening the group itself. */
.abt-hero::before{content:'';position:absolute;inset:auto 0 0;height:52%;
  background:linear-gradient(0deg,rgba(0,0,0,.62),rgba(0,0,0,0));
  pointer-events:none;z-index:1}
.abt-say{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding-bottom:70rem;color:#fff}
.abt-say .abt-lead{grid-column:1/9;font-size:44rem;line-height:1.14;
  letter-spacing:-.01em;font-style:italic}
.abt-say .abt-note{grid-column:10/-1;display:grid;gap:16rem;align-self:end}
.abt-say .abt-note p{font-size:14rem;line-height:1.55;color:rgba(255,255,255,.86)}
.abt-over{position:absolute;top:0;left:0;right:0;z-index:2;padding-top:155rem}
.abt-over h1{font-size:118rem;line-height:1.0;max-width:980rem}
/* background-image, NOT the background shorthand: the shorthand also resets
   background-clip, which would undo the :text clipping set above and paint the
   line as a solid gradient bar (it did). */
/* white-based: the tide reads as a sheen moving through white, not as green */
.grad-light .ln{background-image:linear-gradient(100deg,#FFFFFF 10%,#D9EFE6 32%,
    #FFFFFF 50%,#CFE9DE 68%,#FFFFFF 90%);background-size:230% 100%}

/* "team", written across the group photograph at the drawn angle */
.abt-team{position:absolute;left:50%;top:55%;z-index:2;pointer-events:none;
  transform:translate(-50%,-50%) rotate(-6deg);
  font-style:italic;font-size:220rem;line-height:1;letter-spacing:-.01em;
  color:rgba(255,255,255,.92)}
.claim h1{font-size:96rem;line-height:.92;letter-spacing:-.03em;color:var(--deep);
  max-width:1000rem;margin-inline:auto}   /* forces the design's two-line break */
.claim p{font-size:14rem;line-height:1.5;color:var(--muted);max-width:520rem;
  margin:28rem auto 0}

/* full-bleed showcase render */
.showcase{width:100%}
.showcase .mimg{width:100%}
.showcase .mimg img{width:100%;height:auto;object-fit:contain}

/* Founded / Founder / Services + justified paragraph */
.meta{border:0;padding-block:60rem}
.meta .mrow{grid-column:1/8;display:grid;grid-template-columns:120rem 1fr;gap:20rem;
  padding-block:6rem;font-size:14rem}
.meta .mrow .v{color:var(--text);font-size:40rem;line-height:1.05;
  letter-spacing:-.03em;margin-top:12rem}
.meta .mtext{grid-column:9/-1;grid-row:1/4;font-size:35rem;line-height:1.10;
  letter-spacing:-.03em;font-family:'Hedvig Letters Serif',Georgia,serif;
  color:var(--text)}

/* section heads on these pages sit in brand green */
.sec-head h2,.big{color:var(--deep)}
.big{font-size:80rem;line-height:1.02;letter-spacing:-.03em}

/* two-column staggered project cards */
.pgrid{display:grid;grid-template-columns:1fr 1fr;gap:70rem 80rem;align-items:start}
.pgrid > .stag{margin-top:180rem}
.pcard{position:relative}

/* two extra thumbnails fan out behind the main render on arrival, then
   settle flat and fade once .mimg reveals (same [data-reveal] trigger the
   main image already uses) - a nod to the reference's stacked-photos load */
.stk{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  pointer-events:none;transform:translate(7%,5%) rotate(var(--r,6deg));
  transition:transform 1s var(--ease),opacity .5s var(--ease) .35s}
.pcard:has(.mimg.in) .stk{transform:none;opacity:0}
@media(prefers-reduced-motion:reduce){.stk{display:none}}

.pcard .mimg{width:100%;aspect-ratio:16/10}
.pcard .mimg img{width:100%;height:100%;object-fit:cover}
.pcard .row{display:flex;justify-content:space-between;gap:20rem;margin-top:18rem;
  font-size:19rem;color:var(--deep);letter-spacing:-.022em}
.pcard .row .ar{flex-shrink:0}
/* Always readable as a control: brand green with its underline standing, not
   a hover secret (studio direction 2026-08-28). Hover just lifts it. */
.seeall{display:block;width:max-content;margin:90rem auto 0;font-size:21rem;
  font-weight:600;color:var(--deep);transition:opacity .3s var(--ease)}
.seeall::after{content:'';display:block;height:2px;margin-top:4rem;
  background:currentColor}
.seeall:hover{opacity:.6}

/* list view: name on the left, the project's renders on the right. Both sit on
   the page grid - one column is 105rem, which is exactly one thumbnail. */
.lrows{display:grid;row-gap:56rem}
.lrow{display:grid;grid-template-columns:repeat(15,1fr);gap:var(--gut);
  align-items:start}
.lrow .nm{grid-column:1/8;font-size:34rem;line-height:1.05;letter-spacing:-.03em;
  color:var(--deep);transition:opacity .4s var(--ease)}
.lrow .shots{grid-column:10/-1;display:grid;grid-template-columns:repeat(6,1fr);
  gap:var(--gut)}
.lrow .sh{display:block;aspect-ratio:16/9;overflow:hidden;background:#e9e9e6}
.lrow .sh img{width:100%;height:100%;object-fit:cover;display:block;
  transition:opacity .4s var(--ease),transform .6s var(--ease)}
.lrow:hover .nm{opacity:.45}
.lrow:hover .sh img{transform:scale(1.06)}

/* ── work filter: a draggable scrubber ──────────────────────────────────── */
/* Its own easing token: the site's --ease is a soft decelerate, this
   instrument wants the same weighted curve the view morph uses. */
.pfilter{--pf-ease:cubic-bezier(.76,0,.24,1);
  --pf-pale:#C8D6D0;                       /* pale gray-green: the untravelled rail */
  padding:0 var(--pad);color:var(--deep)}

/* the one control that is visible by default */
.pf-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:10rem 26rem;
  padding-bottom:18rem;border-bottom:1px solid var(--border)}
.pf-toggle{appearance:none;background:none;border:0;padding:0;cursor:pointer;
  font:inherit;color:var(--deep);display:flex;align-items:center;gap:9rem;
  font-size:13rem;letter-spacing:.07em;text-transform:uppercase}
.pf-n{font-size:12rem;letter-spacing:.04em;color:var(--muted);
  font-variant-numeric:tabular-nums}
.pf-n:empty{display:none}

/* the plus turns into a close cross: one glyph, rotated, never swapped */
.pf-x{position:relative;width:11rem;height:11rem;flex-shrink:0;
  transition:transform .8s var(--pf-ease)}
.pf-x i{position:absolute;inset:50% 0 auto;height:1px;background:currentColor}
.pf-x i:last-child{inset:0 auto 0 50%;width:1px;height:100%}
.pfilter.open .pf-x{transform:rotate(135deg)}
.pfilter.open .pf-word{visibility:hidden}
.pf-word{position:relative}
.pf-word::after{content:attr(data-close);position:absolute;left:0;top:0;
  visibility:hidden}
.pfilter.open .pf-word::after{visibility:visible}

/* selected filters, alongside the control while the panel is shut */
.pf-chips{display:flex;flex-wrap:wrap;gap:8rem 16rem}
.pfilter.open .pf-chips{display:none}
.pf-chip{appearance:none;background:none;border:0;padding:0;cursor:pointer;
  font:inherit;font-size:13rem;letter-spacing:.07em;text-transform:uppercase;
  color:var(--deep);display:flex;align-items:center;gap:6rem;
  transition:opacity .3s var(--ease)}
.pf-chip:hover{opacity:.55}
.pf-chip span{font-size:14rem;line-height:1}

/* 0fr -> 1fr is the one height transition that resolves to a true auto
   height, so the portfolio below is pushed down by the real panel size */
.pf-panel{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .8s var(--pf-ease)}
.pfilter.open .pf-panel{grid-template-rows:1fr}
/* visibility keeps the controls out of the tab order while shut, and waits
   for the collapse to finish before it hides them */
.pf-inner{overflow:hidden;min-height:0;visibility:hidden;
  transition:visibility 0s linear .8s}
.pfilter.open .pf-inner{visibility:visible;transition-delay:0s}

/* mode row: a sliding rule, no tabs, no pills */
.pf-modes{position:relative;display:flex;gap:34rem;padding:26rem 0 0}
.pf-mode{appearance:none;background:none;border:0;padding:0 0 10rem;cursor:pointer;
  font:inherit;font-size:13rem;letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);transition:color .4s var(--ease)}
.pf-mode.on{color:var(--deep)}
.pf-ink{position:absolute;left:0;bottom:0;height:1px;background:var(--deep);
  width:var(--ink-w,0);transform:translateX(var(--ink-x,0));
  transition:transform .5s var(--pf-ease),width .5s var(--pf-ease)}
.pf-modes::after{content:'';position:absolute;left:0;right:0;bottom:0;height:1px;
  background:var(--border)}

.pf-scrub{padding:38rem 0 6rem}

/* the category labels sit above their own snap points; inert by design - the
   thumb is the only control, so this can never read as a list of links */
.pf-sets{position:relative;height:20rem;pointer-events:none}
.pf-set{position:absolute;inset:0;opacity:0;visibility:hidden}
.pf-set.on{opacity:1;visibility:visible}
/* The horizontal offset rides in --sx rather than an inline transform: JS owns
   `left` only, so the active label's scale and the mode-change slide can
   compose with it instead of an inline style silently winning. */
.pf-cat{position:absolute;top:0;white-space:nowrap;cursor:pointer;
  font-size:13rem;letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);opacity:.55;
  transform:translateX(var(--sx,-50%));
  transition:color .4s var(--ease),opacity .5s var(--pf-ease),
             transform .5s var(--pf-ease)}
.pf-cat.on{color:var(--deep);opacity:1;
  transform:translateX(var(--sx,-50%)) scale(1.06)}
/* mode change: the old set drops away, the new one is parked below and
   released a frame later so it rises into place */
.pf-set.leave .pf-cat,.pf-set.enter .pf-cat{opacity:0;
  transform:translateX(var(--sx,-50%)) translateY(12rem) scale(.98)}
.pf-set.leave .pf-cat{transition-duration:.26s}
@keyframes pf-rise{from{opacity:0;transform:translateY(12rem) scale(.98)}}

/* the rail itself: one architectural hairline */
.pf-rail{position:relative;height:34rem;margin-top:16rem;cursor:pointer;
  touch-action:none;-webkit-user-select:none;user-select:none}
.pf-rail:focus-visible{outline:1px solid var(--deep);outline-offset:6rem}
.pf-track,.pf-fill{position:absolute;top:50%;height:1px;margin-top:-.5px}
.pf-track{left:0;right:0;background:var(--pf-pale)}
.pf-fill{left:0;width:var(--fill,0);background:var(--deep);
  transition:width .42s var(--pf-ease)}
.pf-thumb{position:absolute;top:50%;left:0;width:20rem;height:20rem;
  margin-top:-10rem;transform:translateX(var(--tx,0));
  transition:transform .42s var(--pf-ease)}
.pf-thumb i{display:block;width:100%;height:100%;border-radius:50%;
  background:var(--deep);
  transition:transform .3s var(--pf-ease)}
.pf-rail.drag .pf-thumb,.pf-rail.drag .pf-fill{transition:none}
.pf-rail.drag .pf-thumb i{transform:scale(1.18)}
/* the settle: a single measured pulse, no bounce */
.pf-thumb.pop i{animation:pf-pop .4s var(--pf-ease)}
@keyframes pf-pop{0%{transform:scale(1)}45%{transform:scale(1.15)}100%{transform:scale(1)}}

.pf-foot{display:flex;align-items:baseline;gap:26rem;flex-wrap:wrap;
  padding:30rem 0 34rem}
.pf-clear{appearance:none;background:none;border:0;padding:0;cursor:pointer;
  font:inherit;font-size:13rem;letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);transition:color .3s var(--ease)}
.pf-clear:hover{color:var(--deep)}
.pf-none{font-size:14rem;color:var(--muted)}

/* ── filtered-out projects ─────────────────────────────────────────────── */
/* A leaver is lifted out of the flow at the exact box it occupied, so the
   survivors can reflow underneath it while it fades - that is what makes the
   FLIP read as one movement instead of a collapse followed by a shuffle. */
/* the curve is written out here, not taken from --pf-ease: that token lives on
   .pfilter, and these cards are its siblings, not its descendants - the var
   would resolve to nothing and void the whole declaration */
.pcard.pf-out,.lrow.pf-out{position:absolute;margin:0!important;pointer-events:none;
  opacity:0;transform:scale(.96);
  transition:opacity .45s cubic-bezier(.76,0,.24,1),
             transform .45s cubic-bezier(.76,0,.24,1)}
.pgrid,.lrows{position:relative}
.pcard.pf-in,.lrow.pf-in{animation:pf-rise .7s cubic-bezier(.76,0,.24,1) backwards}
.pcard.off,.lrow.off{display:none}
/* the gallery board is a fixed pack - nothing moves, so the same curve is
   spent on the fade instead of on a reflow that cannot happen */
.gi{transition:opacity .7s cubic-bezier(.76,0,.24,1)}
.gi.off{opacity:.12;pointer-events:none}

@media(max-width:767.98px){
  .pf-scrub{padding-top:30rem}
  .pf-modes{gap:22rem}
  .pf-cat{font-size:12rem}
  .pf-sets{height:16rem}
  /* six labels cannot share 375px without colliding, so the rail carries only
     the one it is on and that caption travels with the thumb */
  .pf-cat{opacity:0}
  .pf-cat.on{opacity:1}
}

/* everything above degrades to an instant, correct state */
@media(prefers-reduced-motion:reduce){
  .pf-panel,.pf-x,.pf-ink,.pf-fill,.pf-thumb,.pf-thumb i,.pf-cat,.gi{transition:none}
  .pf-thumb.pop i,.pcard.pf-in,.lrow.pf-in{animation:none}
  .pcard.pf-out,.lrow.pf-out{display:none}
  /* the menu wipe and hover zooms sat outside every reduce block until now */
  .ovl,.ovl li a,.gi img,.lrow .sh img,.pre{transition:none}
}

/* work page: the three views share the switcher mechanism */
.work-gal{padding-block:150rem 60rem}
.work-gal .view{padding:0 var(--pad)}
.work-gal .gallery{display:block;padding:0}
/* In the gallery view the board runs straight into the green footer - its
   clip edge IS the footer edge, so renders surface from behind the green
   instead of being cut off above a white gap. Desktop only: on mobile the
   board is a normal grid and keeps the section spacing. */
@media(min-width:768px){
  /* the board fills the viewport and the footer is not in the picture - the
     green edge below the board was the footer showing through */
  .work-gal:has(.view.gallery.on){padding-block:0}
  .work-gal:has(.view.gallery.on) ~ .ftr{display:none}
  /* the collapsed FILTERS+ row is the last 31px keeping the board off the top
     of the viewport - float it over the board instead of letting it push */
  .work-gal:has(.view.gallery.on) .pfilter{position:absolute;top:0;left:0;right:0;
    z-index:5}
  /* floating over the board, the filter row's rule ran right across the
     renders as a stray hairline - measured, 1px #E7E7E4 at the top edge */
  .work-gal:has(.view.gallery.on) .pf-head{border-bottom:0}
  /* ...and open, it had no ground at all: categories, rail and CLOSE all
     landed straight on the renders and could not be read. Paint it only while
     open - a permanent white bar across the top of the board would cost more
     than it saves. */
  .work-gal:has(.view.gallery.on) .pfilter{
    transition:background .45s var(--pf-ease),box-shadow .45s var(--pf-ease)}
  .work-gal:has(.view.gallery.on) .pfilter.open{background:var(--bg);
    padding-bottom:30rem;box-shadow:0 20rem 46rem rgba(12,35,29,.16)}
  /* collapsed it is two words over whatever render is beneath them, so they
     get their own small plate rather than a full-width one */
  .work-gal:has(.view.gallery.on) .pfilter:not(.open) .pf-toggle,
  .work-gal:has(.view.gallery.on) .pfilter:not(.open) .pf-chips{
    background:var(--bg);padding:8rem 13rem;border-radius:3rem}
  .work-gal:has(.view.gallery.on) .pf-head{padding-top:12rem}
}

/* stats column (lives inside .proc, which sets its own colour and column) */
/* Reference geometry: the number is 5.87vw at line-height .70, the label
   3.96vw in the serif at .90, and the label sits UNDER the number rather than
   beside it. The label is held at 60rem, not the reference's 76rem, because
   this column is 6 of 15 grid columns wide - at 76rem every label wraps to
   three lines. Widen the column if the full size is wanted. */
.stat{display:flex;flex-direction:column;align-items:flex-start;gap:6rem}
/* The vw caps are a floor guard, not a design change: they are inert at every
   width the band was designed for. Below 1728 the fluid rem floors at .9px, so
   this type stops shrinking while its column keeps narrowing with the viewport
   - and at 768 the longest Russian label ("Завершённые", 347px) then runs past
   the 269px column and pushes the document 22px wider than the screen, i.e. a
   horizontal scrollbar on the home page. Measured, and it predates the current
   copy: the labels this band carried before were 344px by the same measure.
   min() picks the rem value down to ~1000px and the vw value below that; the
   ratio between the two sizes is held (113/60 = 10.1/5.4) so the pair still
   reads as one. The phone block below overrides both anyway. */
.stat .n{font-size:min(113rem, 10.1vw);line-height:.70;letter-spacing:-.03em;display:block}
.stat .n .lnw{padding-top:.20em;margin-top:-.20em}
.stat .l{font-size:min(60rem, 5.4vw);line-height:.90;letter-spacing:-.03em;text-align:left}
/* The reference's long duration, read off its own transitions: 1.109s with the
   same cubic-bezier(.17,.84,.44,1) our --ease already is. Scoped to the stats
   so the rest of the site keeps its shorter .85s. */
.stat .ln{transition-duration:1.109s}

/* footer: giant wordmark */
.ftr{padding-block:120rem 30rem;min-height:100svh;
  display:flex;align-items:flex-end}
.ftr > .ctr{width:100%}
.ftr.green{background:var(--deep);color:#fff}
/* Nav and socials sit left so the brief sheet has the whole right half to
   open into; the sheet itself stays right (margin-inline-start:auto). */
.ftr .fnav{display:flex;gap:30rem;font-size:16rem;justify-content:flex-start;
  padding-bottom:26rem}
.ftr .fnav a:hover{opacity:.6}
.ftr .fword{width:100%}
/* the wordmark carries the brand green; on the dark footer it stays light */
.ftr:not(.green) .fword{color:var(--deep)}
.ftr .socials{justify-content:flex-start;padding:0 0 30rem}
.ftr .fbot{display:flex;justify-content:space-between;gap:20rem;font-size:14rem;
  opacity:.7;padding-top:30rem;transition:margin-top .7s var(--ease)}
/* No override needed here any more. .fword's transform (scaling it down while
   open) doesn't reflow - its LAYOUT bottom, which is what positions .fbot, is
   the same line whether the wordmark is full size or shrunk. And since the
   sheet's own `top` is now computed (in site.js) to land its bottom on that
   exact line, .fbot simply sits below both of them at its normal padding, the
   same as when the sheet is closed. A -17rem pull-up used to live here from
   when the sheet's bottom didn't reach that line; now that it does, the same
   rule pulled the row up INTO the sheet and the shrunk wordmark instead of
   past them (measured: the copyright line landed inside the wordmark's own
   box, and the phone number inside the open sheet's corner). */

@media(max-width:767.98px){
  .mzlogo.mz-nav{width:120rem}
  .mzlogo.mz-hero{width:180rem}
  .claim{padding-block:70rem 50rem}
  .claim h1{font-size:44rem;line-height:.76}
  .meta .mtext{font-size:24rem}
  .claim p{font-size:14rem}
  .meta{padding-block:40rem}
  .meta .mrow,.meta .mtext{grid-column:1;grid-row:auto}
  .meta .mrow{grid-template-columns:90rem 1fr}
  .meta .mrow .v{font-size:26rem}
  .big{font-size:38rem}
  /* clear the fixed bar: 20rem padding + the wordmark + 20rem is a 64rem
     bar at this width, and 34rem put the h1 30rem underneath it (measured
     on the phone, studio 2026-09-02). 90rem leaves the title a gap of its
     own rather than just missing the bar. */
  .abt-over{padding-top:90rem}
  .pgrid{grid-template-columns:1fr;gap:40rem}
  .pgrid > :nth-child(even){margin-top:0}
  .tgrid{grid-template-columns:1fr 1fr;gap:60rem 30rem}
  .tgrid > :nth-child(4n+2),.tgrid > :nth-child(4n+3),.tgrid > :nth-child(4n){margin-top:0}
  .pcard .row{font-size:16rem}
  .seeall{margin-top:40rem;font-size:16rem}
  .lrows{row-gap:34rem}
  .lrow{grid-template-columns:1fr;gap:12rem}
  .lrow .nm{grid-column:1/-1;font-size:24rem}
  .lrow .shots{grid-column:1/-1;grid-template-columns:repeat(3,1fr);gap:8rem}
  .work-gal{padding-block:80rem 40rem}
  .stat .n{font-size:72rem}
  .stat .l{font-size:34rem}
  .proc{overflow-clip-margin:240rem}
  .ftr{padding-block:60rem 20rem}
  .brief{position:static;margin:0 0 70rem auto}
  /* on mobile the sheet is back in the flow and pushes its own room, so the
     wordmark has nothing to get out of the way of */
  .ftr .fword{margin-top:0}
  .brief.open ~ .fword{transform:none}
  .abt-over h1{font-size:44rem}
  .abt-team{font-size:84rem}
  /* a 375-wide square leaves no floor to stand on: the statement drops out of
     the photograph and back into the page, in the page's own ink */
  .abt-hero::before{display:none}
  /* keep .ctr's side padding - a bare 'padding:40rem 0 0' zeroed it and
     ran the statement edge to edge */
  .abt-say{position:static;padding:40rem var(--pad) 0;color:var(--deep)}
  .abt-say .abt-lead{grid-column:1/-1;font-size:26rem}
  .abt-say .abt-note{grid-column:1/-1;margin-top:24rem}
  .abt-say .abt-note p{color:var(--muted)}
  .cmap{grid-column:1}
  .ftr .fnav{justify-content:flex-start;gap:18rem;padding-bottom:30rem}
  .ftr .fbot{flex-direction:column;gap:6rem}
}

/* Gallery = every render of every project on one board you drag around, as on
   the reference. build.py packs the positions (seeded and overlap-free); this
   is the window onto that board plus the drag-to-pan surface. */
.gwin{position:relative;overflow:hidden;height:100svh;cursor:grab;
  touch-action:none;-webkit-user-select:none;user-select:none}
.gwin.drag{cursor:grabbing}
.gboard{position:absolute;top:0;left:0;will-change:transform}
/* a render must be a drag handle for the board, not a draggable link - without
   this, pressing on an image starts the browser's own link/image drag and the
   pan never begins (dragging only worked from the white gaps) */
.gi{position:absolute;display:block;line-height:0;overflow:hidden;
  -webkit-user-drag:none}
.gi img{-webkit-user-drag:none}
/* the pack sizes every item, so the image fills its slot and a late-decoding
   render can never resize its neighbours */
.gi img{width:100%;height:100%;max-width:none;display:block;object-fit:cover;
  transition:transform .9s var(--ease)}
.gwin:not(.drag) .gi:hover{z-index:2}
.gwin:not(.drag) .gi:hover img{transform:scale(1.04)}
.gwin.drag .gi img{pointer-events:none}

/* Mobile: the board is packed on a 2900-unit desktop canvas, and on mobile
   1rem is 100vw/375 - dragging around it would be unusable, and the window's
   touch-action:none would swallow page scrolling. Two columns in normal flow
   instead: still every render. Must come AFTER the rules above, not in an
   earlier media block, or source order hands the win back to them.
   !important because build.py writes each position inline. */
@media(max-width:767.98px){
  .gwin{height:auto;overflow:visible;cursor:default;touch-action:auto}
  .gboard{position:static;display:grid;grid-template-columns:1fr 1fr;gap:14rem;
    width:auto!important;height:auto!important;transform:none!important}
  .gi{position:static!important;width:auto!important;height:auto!important}
  .gi img{height:auto}
}


/* ── text reveal, timed off the reference (0.85s, 0.09s stagger) ─────────── */
.ln{transition:transform .85s var(--ease)}
[data-split] .ln{transform:translateY(101%)}
[data-split].in .ln{transform:translateY(0)}
[data-split] .w{font-style:normal}
@media(prefers-reduced-motion:reduce){
  [data-split] .ln{transform:none!important;transition:none!important}
}


/* ── awards: compact row list (reference density, our logos) ─────────────── */
.alogos{display:grid;grid-template-columns:1fr 1fr;column-gap:80rem;
  border-top:1px solid var(--border)}

/* hover fills the row from the left and inverts its contents, as on the
   reference's spotlight list; the marker at the right end appears with it */
.alogos .alog{position:relative;isolation:isolate;overflow:hidden;
  display:flex;align-items:center;gap:20rem;padding-block:16rem;
  padding-inline:14rem;margin-inline:-14rem;
  border-bottom:1px solid var(--border)}
.alogos .alog::before{content:'';position:absolute;inset:0;z-index:-1;
  background:var(--deep);transform:scaleX(0);transform-origin:left;
  transition:transform .85s var(--ease)}
.alogos .alog:hover::before{transform:scaleX(1)}
.alogos .alog:hover .nm{color:#fff}
.alogos .alog:hover .abody img{filter:brightness(0) invert(1);opacity:1}
.alogos .alog:hover .go{opacity:1;color:var(--accent);
  transition:opacity .4s var(--ease) .3s}
.alogos .abody{display:flex;align-items:center;gap:20rem;flex:1;min-width:0}
.alogos .abody img{height:28rem;width:auto;max-width:110rem;object-fit:contain;
  object-position:left;flex-shrink:0;filter:grayscale(1);opacity:.55;
  transition:filter .6s var(--ease),opacity .6s var(--ease)}
.alogos .abody .alogo{height:34rem;width:auto;max-width:110rem;flex-shrink:0;
  color:var(--text);opacity:.7;
  transition:color .5s var(--ease),opacity .5s var(--ease)}
.alogos .alog:hover .abody .alogo{color:#fff;opacity:1}
/* the winning projects' thumbs, riding at the row's right end */
.awins{display:flex;gap:8rem;flex-shrink:0}
.awin{display:block;width:64rem;height:42rem;overflow:hidden;border-radius:3rem}
.awin img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .6s var(--ease)}
.awin:hover img{transform:scale(1.08)}
/* reserved slot while the studio's award->project mapping is pending */
span.awin{border:1px dashed var(--border)}
.alogos .alog .nm{font-size:16rem;letter-spacing:-.022em;flex:1;color:var(--text);
  transition:color .5s var(--ease)}
.alogos .alog .go{font-size:14rem;color:var(--muted);opacity:0;
  transition:opacity .3s var(--ease)}
@media(max-width:767.98px){
  .alogos{grid-template-columns:1fr;column-gap:0}
  .alogos .alog{gap:14rem;padding-block:12rem}
  .alogos .abody img{height:22rem;max-width:80rem}
  .awin{width:52rem;height:34rem}
  .alogos .alog .go{opacity:1}
}


@media(prefers-reduced-motion:reduce){
  .claim h1 .ln{animation:none}
  .view.on .pcard,.view.on .lrow,.view.on .it{animation:none}
}


/* ── process panel: white ground, animating scatter left, figures right ──── */
/* The burst flies OVER the page: no clip, and the panel outranks the footer's
   positioned children (the brief sheet is z 3), so frames sweep across the
   divider, the wordmark and the sheet on their way out. The dead scroll space
   translated boxes would add below the footer is handled in site.js - a frame
   that has fully faded is display:none, so it stops counting into scrollable
   overflow. */
/* No runway padding. The 640rem bottom that used to buy the burst its scroll
   was a screen of white between the last stat and the footer - the flight is
   timed now, so the panel only needs its own breathing room. */
.proc{background:var(--bg);color:var(--text);padding-block:120rem;
  position:relative;z-index:6;
  /* The frames are absolutely positioned and translated a viewport outward, so
     their boxes reach ~800px below this panel. overflow:clip does NOT make that
     free: measured, the clip-margin region still counts towards the document's
     scrollable overflow, and a 1200px margin left 207px of dead white below the
     footer. The margin is therefore held UNDER the footer's own height: the
     contribution is min(frame reach, margin), so while that stays below the
     footer it adds nothing to the page - and the document height stops
     depending on the frames at all, which is what made the burst flicker.
     The frames still paint the whole way down across the wordmark. */
  overflow:clip;overflow-clip-margin:460rem}
.proc .grd{align-items:center}

.proc-stage{grid-column:1/9;position:relative;height:660rem;
  pointer-events:none;                    /* inert: nothing here is clickable */
  -webkit-user-select:none;user-select:none}

/* Always on screen, always moving - the reference redraws every frame with a
   dozen-plus planes rather than fading single pictures in and out. Each frame
   gets its own vector and period so nothing pulses in unison. */
.proc-stage .pf{position:absolute;left:var(--x);top:var(--y);width:var(--w);height:auto;
  animation:drift var(--t,18s) ease-in-out infinite alternate;
  animation-delay:var(--d,0s);will-change:transform;-webkit-user-drag:none}
/* --sx/--sy/--sr are written by the scatter driver on scroll; the drift and the
   burst therefore compose into a single transform instead of fighting over it */
@keyframes drift{
  from{transform:translate3d(var(--sx,0px),var(--sy,0px),0)
       rotate(var(--sr,0deg)) scale(var(--s0,1))}
  to{transform:translate3d(calc(var(--dx,0px) + var(--sx,0px)),
       calc(var(--dy,0px) + var(--sy,0px)),0)
       rotate(var(--sr,0deg)) scale(var(--s1,1))}
}

.proc .statcol{grid-column:10/-1;display:flex;flex-direction:column;gap:70rem;
  align-items:flex-start}
.proc .stat{color:var(--text)}

@media(max-width:767.98px){
  .proc{padding-block:60rem}
  .proc-stage{grid-column:1;height:420rem}
  .proc .statcol{grid-column:1;align-items:flex-start;gap:30rem}
}
@media(prefers-reduced-motion:reduce){
  .proc-stage .pf{animation:none}
}


/* ── contact: the four-frame storyboard (cta.js drives both stages) ────────
   Stage A: one giant line sliding left under a pin; waiting words at 31% ink
   (both numbers measured off the client's frames). Stage B: the three-line
   sentence with inline chips, the M and the pill; the veil is the takeover. */
/* the reference's sticky-wrap: 400vh tall, the stage rides inside it - so
   the circle the pill gathers into stays mid-screen to the very end */
.ctaA{position:relative;height:400svh}
/* Opaque and above what follows, so the pin is a curtain: while it is stuck
   AND while it un-sticks and scrolls away (still full-viewport, still on top),
   the offices section sitting flush right after it in the document is hidden
   underneath rather than showing through mid-animation. It is revealed the
   instant the pin finishes scrolling past - which is how the reference hands
   over to its next section too. */
.ctaA-pin{position:sticky;top:0;height:100svh;display:grid;align-content:center;
  overflow:hidden;background:var(--bg);z-index:2}
/* z3, ABOVE the pin's curtain (z2): everything after the hero rides up over
   it (the pull-up + shared background live with the other .ctaA ~ rules
   further down; this ID-specific rule would out-rank them, so the z-index
   here must agree with theirs). */
.ctaA + #offices{position:relative;z-index:3}
.ca-desc{position:absolute;bottom:9svh;left:var(--pad);max-width:460rem;
  font-size:15rem;line-height:1.5;color:var(--muted)}
.ctaA-track{display:flex;align-items:center;gap:.22em;white-space:nowrap;
  padding-left:var(--pad);width:max-content;font-weight:700;
  font-size:150rem;line-height:1;letter-spacing:-.03em;color:#0c231d}
.caw.dim{color:rgba(12,35,29,.31)}
.ca-pill{display:inline-flex;align-items:center;justify-content:flex-end;
  width:28vw;height:9vw;border-radius:4.5vw;background:#F5F5F5;
  padding-right:1.4vw;flex-shrink:0;overflow:hidden;color:#00382F}
.ca-star{display:block}
.ca-star svg{width:5.6vw;height:5.6vw;display:block;
  animation:ca-spin 10s linear infinite}  /* one turn per 10s - measured */
@keyframes ca-spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.ca-star svg{animation:none}}

/* ── contact: the three-question sheet (see contact_wizard in build.py) ───── */
.cw-open{appearance:none;border:1px solid var(--deep);background:none;cursor:pointer;
  color:var(--deep);font-size:17rem;letter-spacing:-.01em;border-radius:100rem;
  padding:16rem 34rem;margin-top:34rem;
  transition:background .35s var(--ease),color .35s var(--ease)}
.cw-open:hover{background:var(--deep);color:#fff}

.cw{position:fixed;inset:0;z-index:120;display:grid;grid-template-columns:1fr 1fr;
  background:var(--bg);opacity:0;pointer-events:none;
  clip-path:inset(0 0 100% 0);
  transition:opacity .5s var(--ease),clip-path .7s var(--ease)}
.cw.open{opacity:1;pointer-events:auto;clip-path:inset(0 0 0 0)}

/* the studio's own render, one per step, cross-faded */
.cw-plate{position:relative;overflow:hidden;background:var(--deep)}
.cw-plate img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .8s var(--ease)}
.cw-plate img.on{opacity:1}

.cw-x{position:absolute;top:34rem;right:var(--pad);z-index:2;appearance:none;border:0;
  background:none;cursor:pointer;color:var(--deep);font-size:14rem;
  letter-spacing:.14em;text-transform:uppercase}
.cw-x:hover{opacity:.6}

.cw-form{position:relative;display:flex;flex-direction:column;justify-content:center;
  padding:0 80rem;min-width:0}
.cw-dots{position:absolute;top:40rem;left:80rem;display:flex;gap:8rem;list-style:none}
.cw-dots li{width:26rem;height:2rem;background:var(--border)}
.cw-dots li.on{background:var(--deep)}

.cw-step{border:0;padding:0;margin:0;display:none}
.cw-step.on{display:block}
.cw-q{font-size:46rem;line-height:1.1;letter-spacing:-.03em;color:var(--deep);
  max-width:600rem;padding:0;margin-bottom:44rem}

.cw-opts{display:flex;flex-direction:column;gap:12rem;align-items:flex-start}
.cw-opt{position:relative;cursor:pointer}
.cw-opt input{position:absolute;opacity:0;width:0;height:0}
.cw-opt span{display:block;border:1px solid var(--border);border-radius:100rem;
  padding:14rem 32rem;font-size:19rem;color:var(--deep);
  transition:background .3s var(--ease),color .3s var(--ease),border-color .3s var(--ease)}
.cw-opt:hover span{border-color:var(--deep)}
.cw-opt input:checked + span{background:var(--deep);color:#fff;border-color:var(--deep)}
.cw-opt input:focus-visible + span{outline:2px solid var(--deep);outline-offset:3px}

.cw-fields{display:flex;flex-direction:column;gap:22rem;max-width:560rem}
.cw-fields input,.cw-fields textarea{width:100%;background:none;border:0;
  border-bottom:1px solid var(--border);padding:12rem 0;font:inherit;font-size:20rem;
  color:var(--deep);resize:none}
.cw-fields input::placeholder,.cw-fields textarea::placeholder{color:var(--muted)}
.cw-fields input:focus,.cw-fields textarea:focus{outline:0;border-bottom-color:var(--deep)}

.cw-foot{display:flex;align-items:center;gap:22rem;margin-top:40rem;flex-wrap:wrap}
.cw-back{appearance:none;border:0;background:none;cursor:pointer;color:var(--muted);
  font-size:15rem;margin-top:36rem}
.cw-back:hover{color:var(--deep)}
.cw-foot .cw-back{margin-top:0}
.cw-send{appearance:none;border:0;cursor:pointer;background:var(--deep);color:#fff;
  font-size:17rem;border-radius:100rem;padding:16rem 40rem}
.cw-send:hover{background:#17705A}
.cw-note{font-size:14rem;color:var(--muted)}
.cw-note.err{color:#a4361f}

@media(max-width:767.98px){
  .cw{grid-template-columns:1fr;grid-template-rows:200rem 1fr}
  .cw-form{padding:0 22rem}
  .cw-dots{left:22rem;top:20rem}
  .cw-q{font-size:28rem;margin-bottom:28rem}
  .cw-opt span{font-size:16rem;padding:12rem 24rem}
  .cw-fields input,.cw-fields textarea{font-size:16rem}
}
@media(prefers-reduced-motion:reduce){
  .cw{transition:opacity .2s linear}
  .cw-plate img{transition:none}
}

/* ── contact: two direct lines instead of the placeholder grid ───────────── */
/* ── contact map ─────────────────────────────────────────────────────────── */
/* The hero line is centred in a 100svh pin inside a 400svh wrapper, so once
   the pin releases its lower half scrolls past empty - about 50svh of nothing.
   The sentence section that used to follow absorbed that with the same
   pull-up; with it gone the offices take over the job. Scoped to the sibling
   of .ctaA so only the Contact page is affected. */
/* Offices + map ride up OVER the pinned hero, scroll-synced, starting right
   after the pill has flipped to deep green (the flip begins at 55% of the
   scrub = 165svh of the 300svh range; -120svh puts this section's top at the
   viewport bottom at 180svh). Everything after the hero sits at z-index 3
   with its own ground, one layer above the pin's curtain (z2), so the page
   slides across the hero instead of waiting behind it. */
.ctaA + #offices{margin-top:-120svh}
.ctaA ~ section,.ctaA ~ footer{position:relative;z-index:3;background:var(--bg)}
#offices{padding-block:50rem 24rem}
/* padding-top, not the map's own margin-top: .map-sec has no top padding of
   its own, so .cmap's 60rem top margin collapsed OUT through it - the section
   box started 54px lower and that 54px strip painted no background at all,
   which let the pinned hero line show straight through between the offices
   and the map (measured: offices ended 3807, map-sec began 3861). Owning the
   gap as padding keeps the section's own ground under it. */
.map-sec{padding:60rem var(--pad)}
.map-sec .cmap{margin-top:0}
/* absolutely filling the 21/9 frame: a fixed iframe height left the frame's
   gray ground showing above and below the map (studio flagged it). The frame
   itself must be the containing block, or inset:0 resolves against .map-sec
   and the iframe overflows the border by the section's own padding. */
.cmap{position:relative}
.cmap iframe{position:absolute;inset:0;width:100%;height:100%;border:0;
  display:block;background:#e9e9e6}

/* ── social channels in the footer ───────────────────────────────────────── */
.socials{display:flex;gap:14rem}
.socials .soc{width:44rem;height:44rem;border-radius:50%;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
  border:1px solid currentColor;color:inherit;opacity:.55;
  transition:opacity .35s var(--ease),background .35s var(--ease),color .35s var(--ease)}
.socials a.soc:hover{opacity:1;background:currentColor}
.socials a.soc:hover svg{color:var(--bg)}
.ftr.green .socials a.soc:hover svg{color:var(--deep)}
.socials .soc svg{width:18rem;height:18rem;display:block}
.socials span.soc{cursor:not-allowed}
@media(max-width:767.98px){
  .socials{gap:10rem}
  .socials .soc{width:36rem;height:36rem}
  .socials .soc svg{width:15rem;height:15rem}
}


/* ── project brief sheet, laid over the right of the footer wordmark ─────── */
/* two states: a small card showing only its heading, and the open sheet */
/* The sheet sits just under the footer nav row and opens DOWNWARD. It used to
   hang low over the wordmark and grow upward, which pushed the top of the form
   behind the previous section (measured: 272rem above the footer, and the top
   rows stopped being clickable). Opening down keeps the whole form on screen;
   .ftr reserves the room for it below. */
/* Out of the footer's flow entirely: the sheet opens into reserved space
   (the .fword margin below) and the wordmark cannot move. Anchored top-right,
   level with the nav row, which now lives on the left. */
.ftr .ctr{position:relative}
/* Only a breath below the closed card - NOT room for the open sheet. Reserving
   the open height left 503px of measured dead space in the closed footer. The
   sheet is fully opaque with its own shadow, so when it opens it simply lies
   over the wordmark; the wordmark still never moves, which was the point. */
.ftr .fword{margin-top:60rem;transform-origin:0 100%;
  transition:transform .7s var(--ease)}
/* The sheet opens over the wordmark, so the wordmark steps aside: it scales
   down from its own bottom-left corner and comes to rest clear of the sheet's
   left edge (the sheet is 58% wide, anchored right). Transform only - the
   footer's height never changes, so nothing else in the page moves. */
/* one silent frame for the open driver's measuring pass - without it the
   wordmark's scale below picks the probe up as a flicker */
.ftr.no-anim,.ftr.no-anim *{transition:none!important}
.brief.open ~ .fword{transform:scale(.24)}
.brief{position:absolute;top:0;right:var(--pad);margin:0;width:15%;z-index:3;
  background:#F4F2ED;color:#2a2a26;padding:20rem 18rem 18rem;
  box-shadow:0 18rem 40rem rgba(12,35,29,.14);
  font-size:12rem;line-height:1.35;overflow:hidden;max-height:120rem;
  /* `top` is written inline by the open driver so the open sheet's bottom
     lands on the wordmark's bottom line; it eases with the rest rather than
     jumping. On mobile .brief is position:static, so the inline value is
     simply ignored there. */
  transition:width .6s var(--ease),max-height .7s var(--ease),
             top .7s var(--ease),
             padding .6s var(--ease),box-shadow .6s var(--ease)}
.brief.open{width:58%;max-height:760rem;padding:26rem 28rem 24rem;
  box-shadow:0 30rem 60rem rgba(12,35,29,.18);
  /* sideways, not downward: two columns of fields, head and foot full-width */
  display:grid;grid-template-columns:1fr 1fr;column-gap:48rem;align-content:start}
.brief.open .b-head,.brief.open .b-foot{grid-column:1/-1}
/* the sheet clips its own overflow for the collapse, so the paperclip has to
   sit inside the panel instead of hanging over its top edge */
.brief .clip{position:absolute;left:auto;right:56rem;top:7rem;width:11rem;
  height:auto;color:#9b9b95}
/* the heading doubles as the control */
.brief .b-head{display:grid;grid-template-columns:34rem 1fr auto;align-items:start;
  gap:10rem;margin-bottom:26rem;width:100%;background:none;border:0;padding:0;
  cursor:pointer;text-align:left;color:inherit;font:inherit}
.brief .b-head h3{font-size:17rem;line-height:1.05;letter-spacing:-.02em;
  text-transform:uppercase}
.brief .b-no{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11rem;color:#8e8e88}
.brief .b-row{display:grid;grid-template-columns:34rem 1fr;gap:10rem;
  margin-bottom:16rem}
.brief .b-row label{display:block;font-size:12rem;margin-bottom:3rem;color:#5c5c56}
/* Three children, two columns: the field wrapped onto the second grid row and
   landed in the 34rem number column - 31px wide, so anything typed scrolled
   straight out of sight (measured). Label and field both belong in the
   content column, under the number. */
/* DIRECT children only. Without the >, `.brief .b-row label` also matched the
   six checkbox labels inside .b-checks and placed every one of them in column
   2 of .b-checks' own grid - which created an implicit second track and left
   column 1 as a ~111px empty gutter (measured on the phone; on the desktop it
   is why the two-column checkbox set rendered as one). */
.brief .b-row > label,
.brief .b-row > input,
.brief .b-row > textarea,
.brief .b-row > .b-checks{grid-column:2}
.brief input,.brief textarea{width:100%;background:none;border:0;
  border-bottom:1px solid #c9c7c0;color:inherit;font:inherit;font-size:12rem;
  padding:4rem 0;outline:none;resize:none}
.brief input:focus,.brief textarea:focus{border-bottom-color:#2a2a26}
.brief .b-checks{display:grid;grid-template-columns:1fr 1fr;gap:6rem 10rem;
  margin-top:3rem}
/* label.ck, not .ck: .brief .b-row label above also matches these labels and
   is more specific, which is why only the font-size was being ignored. */
.brief label.ck{display:flex;align-items:center;gap:9rem;font-size:14rem;cursor:pointer;
  padding:3rem 0;-webkit-user-select:none;user-select:none}
.brief .ck:hover .box{border-color:var(--deep)}
.brief .ck input{position:absolute;opacity:0;width:0;height:0}
.brief .ck .box{width:16rem;height:16rem;background:#b9b7b0;flex-shrink:0;
  position:relative;border:1px solid transparent;
  transition:background .25s var(--ease)}
/* it did toggle before, it just did not look like it: a 10px square that only
   changed colour. Now it draws an actual tick. */
.brief .ck input:checked + .box{background:var(--deep)}
.brief .ck input:checked + .box::after{content:'';position:absolute;
  left:4rem;top:2rem;width:6rem;height:9rem;
  border:2rem solid #F4F2ED;border-top:0;border-left:0;
  transform:rotate(42deg)}
.brief .ck input:focus-visible + .box{outline:2px solid var(--deep);outline-offset:2px}
.brief .b-foot{display:flex;align-items:center;gap:12rem;margin-top:20rem;flex-wrap:wrap}
.brief .b-submit{background:#2a2a26;color:#F4F2ED;border:0;cursor:pointer;
  font:inherit;font-size:12rem;padding:10rem 20rem;
  transition:background .3s var(--ease)}
.brief .b-submit:hover{background:var(--deep)}
.brief .b-note{font-size:11rem;color:#8e8e88;flex:1;min-width:120rem}
.brief .b-note.err{color:#a3341f}

@media(max-width:767.98px){
  .brief{position:static;margin:40rem 0 0;padding:30rem 20rem 26rem;
    box-shadow:none;border:1px solid #ddd}
  .brief .clip{display:none}
  .brief .b-head{grid-template-columns:44rem 1fr auto;margin-bottom:30rem}
  .brief .b-row{grid-template-columns:44rem 1fr;margin-bottom:22rem}
  .brief .b-checks{grid-template-columns:1fr;gap:2rem}
  .brief .b-row label{font-size:14rem;margin-bottom:5rem}
  .brief input,.brief textarea{font-size:16rem;padding:8rem 0}
  .brief label.ck{font-size:16rem;gap:12rem;padding:8rem 0}
  .brief .ck .box{width:20rem;height:20rem}
  .brief .ck input:checked + .box::after{left:5rem;top:3rem;width:7rem;height:11rem}
  /* 44rem tall: the smallest target a finger can be asked to hit */
  .brief .b-submit{font-size:15rem;padding:14rem 26rem;min-height:44rem}
  .brief .b-note{font-size:12rem}
}

.brief .b-sign{position:relative;width:14rem;height:14rem;flex-shrink:0;
  align-self:center}
.brief .b-sign::before,.brief .b-sign::after{content:'';position:absolute;
  background:#2a2a26;transition:transform .5s var(--ease)}
.brief .b-sign::before{left:0;top:50%;width:100%;height:1.5rem;margin-top:-.75rem}
.brief .b-sign::after{top:0;left:50%;height:100%;width:1.5rem;margin-left:-.75rem}
.brief.open .b-sign::after{transform:scaleY(0)}
.brief:not(.open){cursor:pointer}
.brief:not(.open) .b-head{margin-bottom:0}
.brief:not(.open):hover{box-shadow:0 22rem 46rem rgba(12,35,29,.2)}
@media(max-width:767.98px){
  /* One column again: two 119px columns is no place for form fields. Full
     width, but NOT open - it arrived expanded because max-height:none was on
     .brief itself, so the toggle had nothing left to do (studio 2026-09-02).
     Collapsed it shows its own heading and opens on a tap, as on the desktop. */
  .brief,.brief.open{width:100%;display:block}
  .brief{max-height:132rem;overflow:hidden}
  .brief.open{max-height:none;overflow:visible}
}

/* Struck out for the phone by the studio 2026-09-02: the drifting collage
   with the stats column beside it (.proc), and the team portrait grid
   (.tsec). Both are wide compositions - the collage only reads as a drifting
   pile at desk width, and the portraits stack into a very long scroll. They
   stay on the desktop untouched. */
@media(max-width:767.98px){
  .proc,.tsec{display:none}

  /* Struck out for phones by the studio 2026-09-02: the project page's big
     serif statement, and the About page's "We offer..." block. More and the
     description under it stay - only the display line goes. */
  .lead{display:none}
  .abt-say{display:none}

  /* About is off the phone entirely (studio 2026-09-02): its link goes from
     the header nav and from the footer's link row. The page itself still
     builds - one file serves both formats - it just is not offered here.
     :has() so the whole <li> goes and the row's gap closes with it; hiding
     only the <a> would leave the gap behind. */
  .nav ul li:has(> a[href="about.html"]){display:none}
  .fnav a[href="about.html"]{display:none}

  /* The wrapper only ever holds .lead here, and that is hidden - but the
     empty row still charged the grid's 40rem gap on both sides of itself,
     which put More 102rem below the facts. Dropping the row and pulling
     .more up leaves about the 18rem it sits under the statement on a
     desktop. */
  .lead-wrap{display:none}
  .more{margin-top:-22rem}
}


/* ═══════════════════════════════════════════════════════════════════════════
   Project Brief - submit animation. Scoped to .brief-* only: a fixed overlay
   clone, so nothing else on the page can reflow while it runs.
   ═════════════════════════════════════════════════════════════════════════ */
.brief-submit-animation{position:fixed;inset:0;pointer-events:none;z-index:99999;
  perspective:1400px;perspective-origin:60% 40%}

.brief-paper{position:fixed;transform-style:preserve-3d;transform-origin:50% 75%;
  transition:transform 420ms cubic-bezier(.65,0,.35,1),opacity 300ms linear 140ms}

/* One REAL fold instead of three fake ones. The sheet is two halves: the
   bottom half stays put, the top half is a flap hinged on the centre crease
   that swings 180deg down over it - content on its front, plain paper on its
   back - exactly what folding a printed sheet looks like. */
.brief-bh{position:absolute;inset:0;background:#F4F2ED;
  clip-path:inset(50% 0 0 0);
  box-shadow:0 18px 40px rgba(12,35,29,.16)}
.brief-fh{position:absolute;left:0;top:0;width:100%;height:50%;
  transform-origin:50% 100%;transform-style:preserve-3d;
  transition:transform 560ms cubic-bezier(.6,0,.3,1)}
.brief-paper.folded .brief-fh{transform:rotateX(-180deg)}
.brief-fh > span{position:absolute;inset:0;backface-visibility:hidden;
  overflow:hidden}
.brief-fh .ff{background:#F4F2ED}
/* the sheet's blank back, with a soft sheen falling away from the crease */
.brief-fh .fb{transform:rotateX(180deg);
  background:linear-gradient(0deg,#EFEDE6 0,#F7F5F0 34%,#EDEBE3 100%)}
.brief-fh .fb::after{content:'';position:absolute;left:0;right:0;bottom:0;
  height:2px;background:rgba(12,35,29,.1)}   /* the crease line */
/* the flap dims slightly while it stands up, as paper against the light */
.brief-fh .ff::after{content:'';position:absolute;inset:0;background:#2a2a26;
  opacity:0;transition:opacity 280ms linear}
.brief-paper.folded .brief-fh .ff::after{opacity:.1}

/* 0-200ms: the sheet lifts off the interface */
.brief-paper.brief-lift{transform:translateZ(26px) scale(1.012)}

/* the folded packet collapses into the point the 3D plane hatches from */
.brief-paper.brief-away{transform:translateZ(6px) rotate(-14deg) scale(.1);
  opacity:0}

/* ── the plane itself: four paper facets in real 3D ────────────────────────
   Two wings with dihedral and two keel panels below, each lit differently -
   the silhouette and the shading change as it banks, which is what the flat
   clip-path dart could never do. Nose points LEFT (-x). */
.pplane{position:fixed;width:0;height:0;transform-style:preserve-3d;
  will-change:transform;opacity:0;
  transform:translate3d(0,0,0)}
.pplane.on{opacity:1;transition:opacity 200ms linear}
.pplane.brief-flying{transition:transform 640ms cubic-bezier(.33,0,.66,.5),
  opacity 200ms linear}
/* the trail: dots dropped along the flight path, each fading out on its own */
.brief-dot{position:fixed;width:5px;height:5px;border-radius:50%;
  background:var(--accent);pointer-events:none;
  animation:dotfade 1.5s ease-out forwards}
@keyframes dotfade{to{opacity:0;transform:scale(.15)}}
.pplane.brief-flying-2{transition:transform 660ms cubic-bezier(.4,.05,1,.6),
  opacity 240ms linear 300ms}

/* attitude + glide wobble live on the inner assembly, so they compose with
   the outer element's travel instead of fighting it for one transform */
.pp{position:absolute;left:0;top:0;width:0;height:0;transform-style:preserve-3d;
  transform:rotateX(62deg) rotateZ(4deg);
  animation:pp-glide 1.7s ease-in-out infinite}
@keyframes pp-glide{
  0%,100%{transform:rotateX(62deg) rotateZ(4deg) rotateY(-7deg)}
  50%{transform:rotateX(68deg) rotateZ(0deg) rotateY(8deg)}
}

/* facets: built nose-left in the XY plane, folded about the body axis (y=0).
   Wings fold back (away from the viewer), keels fold steeply forward. */
.pp i{position:absolute;left:-150px;top:0;width:150px;height:56px;
  transform-origin:50% 0;backface-visibility:visible}
.pp .pw{clip-path:polygon(0 0,100% 0,100% 88%)}
.pp .pw.l{transform:rotateX(44deg);
  background:linear-gradient(102deg,#FFFFFF 4%,#F3F0E8 50%,#E9E4D9 96%)}
.pp .pw.r{transform:rotateX(-44deg) scaleY(-1);
  background:linear-gradient(98deg,#E6E1D4 6%,#D5CFBF 55%,#C8C1AF 96%)}
.pp .pk{clip-path:polygon(0 0,100% 0,100% 62%);height:34px}
.pp .pk.l{transform:rotateX(80deg);
  background:linear-gradient(100deg,#D8D2C4 8%,#C9C2B1 92%)}
.pp .pk.r{transform:rotateX(-80deg) scaleY(-1);
  background:linear-gradient(100deg,#CFC8B8 8%,#BDB5A2 92%)}
/* The ground shadow is its own element at an offset, not a filter hugging the
   silhouette - the offset grows and the blob fades as the plane climbs, which
   is what sells the altitude. (Technique from aminosbh's MIT-licensed SDL
   flying-plane demo, translated to CSS; no assets copied.) */
.psh{position:absolute;left:-96px;top:64px;width:132px;height:34px;
  border-radius:50%;background:radial-gradient(closest-side,
    rgba(12,35,29,.32),rgba(12,35,29,0));
  filter:blur(5px);transform:skewX(-24deg);
  transition:transform 640ms cubic-bezier(.33,0,.66,.5),
             opacity 640ms linear,
             left 640ms cubic-bezier(.33,0,.66,.5),
             top 640ms cubic-bezier(.33,0,.66,.5)}
.pplane.brief-flying .psh{left:-40px;top:150px;opacity:.45;
  transform:skewX(-24deg) scale(.72)}
.pplane.brief-flying-2 .psh{left:20px;top:260px;opacity:0;
  transform:skewX(-24deg) scale(.45)}

/* the spine crease catches the light */
.pp .ps{position:absolute;left:-150px;top:-.5px;width:150px;height:1px;
  background:linear-gradient(90deg,rgba(255,255,255,.95),rgba(180,173,158,.6));
  transform:translateZ(.5px)}


/* ── project page: Design Plans ───────────────────────────────────────────
   Geometry copied from the reference: viewer 2/-2 at 800rem inside a 2px
   frame, 2px progress line hanging 2px outside it, rail in the last column
   sticky at 60rem, thumbs 105rem tall with a 132rem image cap.            */
.plans{margin-block:95rem;overflow-x:clip;text-align:center}
.plans .grd{position:relative}

/* 16:9, not a fixed height: every plan drawing is authored to that ratio, so
   the frame IS the drawing's box and nothing letterboxes (studio 2026-09-02).
   Column 1, not 2, so the frame's left edge sits on the same line as the
   gallery renders below it - .view pads by var(--pad), which is where the
   grid's first column starts. */
.plans .pview{grid-column:1/-2;position:relative;width:100%;aspect-ratio:16/9;
  border:2px solid var(--border)}
.plans .pframe{position:absolute;inset:0;overflow:hidden;
  display:flex;align-items:center;justify-content:center}
/* The reference draws its plans on a WebGL canvas, so there is no DOM image
   to read a transition off of - the earlier "both readable, slow overlap"
   note here came from watching the wrong element (an aria-only placeholder
   div with no pixels of its own) and was wrong. Corrected by sampling the
   canvas itself: on Next, drawImage() onto a hidden 2D canvas + getImageData
   every rAF, diffed against the settled frame. That gave a real curve - 75%
   resolved by 23ms, 80% by 276ms, 95% by 560ms, 99% by 863ms - a fast initial
   swap with a long decaying tail, not a slow linear cross-dissolve. A
   per-column luminance read (does a wipe front move across it?) ruled that
   out too: values didn't sweep across in one direction, they lagged
   specifically at the drawing's own left/right edges - consistent with the
   incoming plan also settling in from a slight scale (~3.5%) rather than
   snapping straight to size, which naturally takes longest right at its own
   boundary. So: a fast opacity swap plus a slower expo-out scale settle. */
.plans .pl{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  opacity:0;transform:scale(1.035);
  transition:opacity .18s linear,transform 1s cubic-bezier(.16,1,.3,1)}
.plans .pl.on{opacity:1;transform:scale(1)}
.plans span.pl{display:flex;align-items:center;justify-content:center;
  font-size:16rem;color:var(--muted)}

/* Optional per-plan overlay (studio reference, 2026-09-03): a title, a
   description in the brand's own mint highlight, an area badge over the
   drawing itself, and a category legend below it. A plan with no `desc`
   emits none of this - .phead/.plegend then hold no visible child, so the
   row they occupy collapses to nothing and the layout is exactly what it
   was before this existed. Explicit grid-row throughout: three stacked rows
   now share the column range .pview alone used to own. */
.plans .phead{grid-column:1/-2;grid-row:1;text-align:left}
.plans .pinfo{display:none;align-items:flex-start;gap:var(--gut);margin-bottom:30rem}
.plans .pinfo.on{display:flex}
.plans .pi-title{flex:0 0 auto;font-size:56rem;line-height:1.05;color:var(--deep);
  white-space:nowrap}
.plans .pi-desc{flex:1 1 auto;background:var(--accent);color:var(--deep);
  padding:26rem 30rem;font-size:18rem;line-height:1.4}
.plans .pview{grid-row:2}
.plans .pbadge{display:none;position:absolute;top:24rem;left:24rem;z-index:2;
  background:var(--deep);color:var(--accent);font-size:14rem;
  padding:10rem 18rem;border-radius:100px}
.plans .pbadge.on{display:block}
.plans .plegend{grid-column:8/-2;grid-row:3;display:none;flex-direction:column;
  gap:14rem;list-style:none;margin-top:24rem;text-align:left}
.plans .plegend.on{display:flex}
.plans .plegend li{display:flex;align-items:center;gap:10rem;font-size:15rem;color:var(--text)}
.plans .plegend svg{width:16rem;height:16rem;flex:0 0 auto;color:var(--deep)}

.plans .pbar{position:absolute;bottom:-2px;left:-2px;width:calc(100% + 4px);height:2px}
.plans .pfill{display:block;width:100%;height:100%;background:#d3d3d3;
  transform:scaleX(var(--p,0));transform-origin:left center;
  transition:transform .5s var(--ease)}

.plans .prail{grid-column:-2/-1;grid-row:1/4;position:sticky;top:60rem;height:max-content;
  display:flex;flex-direction:column;align-items:flex-start;gap:20rem;text-align:left}
.plans .plab{font-size:14rem;color:var(--muted)}
.plans .pthumbs{display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:15rem;width:100%}
.plans .pth{display:flex;align-items:center;justify-content:center;
  width:100%;height:105rem;padding:10rem;background:none;
  border:2px solid transparent;cursor:pointer;font:inherit;font-size:13rem;
  color:var(--muted);transition:border-color .3s ease,opacity .3s var(--ease)}
.plans .pth.on{border-color:var(--border);cursor:default}
.plans .pth img{width:100%;max-height:132rem;object-fit:contain}
.plans .pnav{display:flex;gap:15rem;justify-content:space-between;width:100%;
  font-size:14rem}
.plans .pnav .link{cursor:pointer;user-select:none}

@media(max-width:767.98px){
  .plans{margin-block:40rem}
  .plans .pinfo{flex-direction:column;gap:16rem}
  .plans .pi-title{white-space:normal;font-size:36rem}
  .plans .pi-desc{padding:20rem}
  .plans .plegend{grid-column:1/-1}
  .plans .pview{display:none}
  .plans .prail{position:static;grid-column:1/-1}
  .plans .pth{border:0;height:auto;padding:0;width:100%}
  .plans .pth img{max-height:none}
  .plans .pnav{display:none}
}


/* ── opened render ────────────────────────────────────────────────────────
   What the reference shows when a render is clicked: that render alone,
   centred at 93% of the viewport height, on the page background - no scrim,
   no scroll, no view change. It paints that in WebGL, so the timings here are
   its own image-transform values: transform 1.109s, fade .3s, shared easing.
   z-index sits under the rail (20) so the rail keeps navigating.          */
.rview{position:fixed;inset:0;z-index:15;background:var(--bg);
  opacity:0;pointer-events:none;transition:opacity .3s var(--ease)}
.rview.on{opacity:1;pointer-events:auto;cursor:zoom-out}
.rview img{position:absolute;left:0;top:0;transform-origin:top left;
  object-fit:cover;transition:opacity .3s var(--ease)}


/* ── 404 ─────────────────────────────────────────────────────────────────────────
   Built to gabrielbeaugonin.com/404. Its planes are a three.js scene; these
   are SVG darts on the drift keyframes the process panel already ships, each
   with its own depth (scale + blur + opacity), which reads the same and adds
   no dependency. Geometry is the reference's, converted from its rem
   (viewport/144) to ours (viewport/1920).                                  */
.nf{position:relative;min-height:100svh;overflow:hidden;background:var(--bg)}
.nf-sky{position:absolute;inset:0;pointer-events:none;z-index:0}
.p404{position:absolute;left:var(--x);top:var(--y);width:var(--w);
  color:var(--text);opacity:var(--o);filter:blur(var(--b));
  animation:nf-drift var(--t,40s) ease-in-out infinite alternate;
  animation-delay:var(--d,0s);will-change:transform}
.p404 svg{display:block;width:100%;height:auto;fill:currentColor}
@keyframes nf-drift{
  from{transform:translate3d(0,0,0) rotate(var(--r,0deg))}
  to{transform:translate3d(var(--dx,0),var(--dy,0),0)
     rotate(calc(var(--r,0deg) + 26deg))}}

/* left 25.7 of their rem = 17.8vw; the block is centred in the viewport */
.nf-copy{position:relative;z-index:1;left:17.8vw;width:max-content;
  min-height:100svh;display:flex;flex-direction:column;align-items:flex-start;
  justify-content:center;gap:66rem}
.nf-head{display:flex;flex-direction:column;gap:7rem}
.nf-copy h1{font-size:43rem;line-height:1;font-weight:400;color:var(--text)}
.nf-copy p{font-size:43rem;line-height:1;color:var(--muted)}
.nf-back{font-size:19rem;color:var(--muted);position:relative}
.nf-back::after{content:'';position:absolute;left:0;bottom:-.2em;width:100%;
  height:1px;background:currentColor;transform:scaleX(0);transform-origin:left;
  transition:transform .5s var(--ease)}
.nf-back:hover::after{transform:scaleX(1)}

@media(max-width:767.98px){
  .nf-copy{left:0;align-items:center;text-align:center;padding:0 var(--pad);
    gap:44rem;width:100%}
  .nf-copy h1,.nf-copy p{font-size:64rem}
  .nf-back{font-size:28rem}
}
@media(prefers-reduced-motion:reduce){.p404{animation:none}}


/* ── fullscreen render tally: "3 / 8", minimal, bottom centre ────────────── */
.rcount{position:absolute;left:50%;bottom:26rem;transform:translateX(-50%);
  font-size:13rem;letter-spacing:.08em;color:var(--muted);
  font-variant-numeric:tabular-nums;pointer-events:none}


/* ── mobile overrides for the contact hero ──────────────────────────────────
   AT THE END OF THE FILE on purpose: the hero's base rules sit late in the
   file (the Contact rebuild appended them), and a media query adds no
   specificity - an override higher up silently loses to them, which is
   exactly the bug this block replaces (the phone showed the full 150rem
   line: one word filled the screen). */
@media(max-width:767.98px){
  .ctaA{height:300svh}                 /* three screens of scrub is enough */
  .ctaA-track{font-size:56rem}
  .ca-desc{max-width:70vw;font-size:13rem;bottom:6svh}
  .ca-pill{width:40vw;height:13vw;border-radius:6.5vw;padding-right:2vw}
  .ca-star svg{width:8vw;height:8vw}
  /* the shorter hero needs a shorter pull-up: -120svh would float the
     offices in while the pill is still pale (flip starts at 55% = 110svh of
     the 200svh range; -60svh brings them in at 140svh, just as it lands) */
  .ctaA + #offices{margin-top:-60svh}
}
