/* ============================================================
   Maal — v17
   Designed by hand in Affinity, built section by section from
   the artboards. Hand-rolled; no framework, no build step.
   ABC Areal (Dinamo, free fonts licence), served from fonts/, for the
   sections that carry words (Switzer via Fontshare until 2026-10-10,
   Newsbag Sans until 2026-10-17).

   Artboard 01 · Landing (1461×1026 at 1x, 2026-09-12)
     ground        white (was black; swapped 2026-09-12)
     label         white box 202×71.5 at y 28, centred; the word
                   inside with ~20px sides and ~11.5px top/bottom
     plate         the Sforza study, cut out; the photograph's
                   ground kept at 21.6% white behind it (a faint
                   dark rectangle on black); box 465.5×516.5,
                   its centre at 51.7% of the viewport height
     copy slots    four, reserved, words to come (black on white):
                   above  x 495–957  y 197–265   3 lines, centred
                   below  x 495–957  y 814–883
                   left   x 200–479  y 446–514   centred on the plate
                   right  x 982–1260 y 446–514
                   ~19px cap height, ~25px line pitch
   ============================================================ */

/* ABC Areal, three cuts, Latin subset. Semibold (600) is set in Bold.
   Dinamo's web licence covers one domain (maal.au) and allows self-hosting
   and subsetting; the files must not go in a public repository. */
@font-face{font-family:"ABC Areal";src:url("fonts/ABCAreal-Regular.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"ABC Areal";src:url("fonts/ABCAreal-Medium.woff2") format("woff2");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:"ABC Areal";src:url("fonts/ABCAreal-Bold.woff2") format("woff2");font-weight:600 700;font-style:normal;font-display:swap}

:root{
  /* light scheme, chosen 2026-09-12 (the black ground is one token swap away:
     --bg #000, --fg #fff, and the plate's ground rgba(255,255,255,.216)) */
  --bg:#FFFFFF;
  --fg:#000000;
  --paper:#FFFFFF;                 /* the label — same as the ground, so it disappears into it */
  --ground:transparent;            /* the plate's 21.6% photographic ground is invisible on white */

  --sans:"ABC Areal",-apple-system,BlinkMacSystemFont,"Helvetica Neue",Inter,system-ui,sans-serif;
  --ease:cubic-bezier(.16,1,.3,1);

  /* landing geometry, as fractions of the 1461×1026 artboard so it
     scales with the viewport rather than with a fixed pixel grid */
  --label-top:2.73svh;             /* 28 / 1026 */
  --label-w:clamp(120px,13.82vw,240px); /* 202 / 1461 */
  --plate-h:50.3svh;               /* 516.5 / 1026 */
  --plate-centre:51.7svh;          /* (273 + 516.5/2) / 1026 */
  --plate-ratio:2674 / 2971;       /* the Met photograph */
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;background:var(--bg)}
body{
  margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:clip;
}
h1,h2,h3,p,ul,ol,figure,figcaption{margin:0}
ul,ol{padding:0;list-style:none}
main:focus{outline:none}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%;height:auto}

.skip{
  position:absolute;left:1rem;top:-100%;z-index:10;
  padding:.5rem .75rem;background:var(--fg);color:var(--bg);font-size:.875rem;
}
.skip:focus{top:1rem}

/* ---- 00 · Nav — fixed, the two corners only; the centre column belongs to
   the drawn word (2026-09-17). No bar, no ground: the links sit on the void
   at the footer index's scale, so the page gains a route without gaining a
   slab. Held back until the word has finished drawing itself; interior pages,
   which never run the intro, show it at once. ------------------------- */

.nav{
  position:fixed;z-index:8;left:0;right:0;
  top:calc(var(--label-top) + var(--label-w) * .137);   /* the block word's centre: half the label's .275 height (2026-09-26; was .178 for the traced word) */
  transform:translateY(-50%);
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  padding:0 clamp(1.25rem,5vw,5rem);
  pointer-events:none;                                  /* the void stays clickable */
  font-size:.75rem;font-weight:500;letter-spacing:.04em;text-transform:uppercase;
  opacity:0;transition:opacity .7s var(--ease);
}
.intro-done .nav,.case .nav{opacity:1}
.nav a{pointer-events:auto;color:var(--fg);transition:color .25s var(--ease)}
/* over a dark section the type turns to the footer's cream; the underline
   rides on currentColor, so it follows without a second rule */
.nav--light a{color:#F9F5EC}
.nav--light .nav__home img{filter:invert(1)}

/* The nav carried no ground of its own (fixed, transparent, black type), so
   from the first screen on it printed over body text and over the full-bleed
   case artwork, where black on the Omari plates is simply unreadable
   (fixed 2026-09-20). Past the hero it takes the page's own ground and becomes
   a bar; and it steps out of the way while you read, gone on the way down,
   back on the way up, which keeps the void rather than parking a rule across
   every screen. The landing is untouched: at the top there is still no bar. */
.nav{--nav-hide:0}
.nav.is-bar{
  top:0;transform:translateY(calc(var(--nav-hide) * -102%));
  padding-top:clamp(.9rem,1.7vw,1.15rem);padding-bottom:clamp(.9rem,1.7vw,1.15rem);
  background:var(--bg);box-shadow:0 1px 0 rgba(0,0,0,.09);
  transition:transform .34s var(--ease),opacity .7s var(--ease);
}
/* it has a ground now, so the dark-section rule stands down */
.nav.is-bar a{color:var(--fg)}
.nav.is-bar .nav__home img{filter:none}
@media (prefers-reduced-motion:reduce){
  .nav.is-bar{--nav-hide:0;transition:none}
}
/* The link wipe, shared by the nav and the footer index (2026-09-17).
   The rule draws itself, the way the word does: in from the left on enter,
   out to the right on leave, so it reads as one stroke passing through rather
   than a box switching on. The origin flips at rest, which is invisible at
   full width. Each context sets its own padding, so the line keeps the gap
   it already had; only the travel is shared. */
.nav__set a,.nav__mail{position:relative;padding:.25em 0}   /* symmetric, so the gap under the word does not lift the text off the label's centre */
.nav__set a::after,.nav__mail::after,
.close__list a::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:currentColor;
  transform:scaleX(0);transform-origin:right;
  transition:transform .24s var(--ease);
}
.nav__set a:hover::after,.nav__set a:focus-visible::after,
.nav__mail:hover::after,.nav__mail:focus-visible::after,
.close__list a:hover::after,.close__list a:focus-visible::after{
  transform:scaleX(1);transform-origin:left;
}
.nav__set a:focus-visible,.nav__mail:focus-visible{outline:none}
/* the wordmark is an image, not a word: it dims, it does not get underlined */
.nav__home{transition:opacity .24s var(--ease)}
.nav__home:hover,.nav__home:focus-visible{opacity:.55;outline:none}
.nav__set{grid-column:1;display:flex;align-items:center;gap:clamp(.9rem,2vw,2rem)}
/* One nav on every page (2026-09-25): links left, the mark in the centre, the address
   right. The mark once led the left group on case pages because a centred fixed mark
   printed over the prose (2026-09-17); the nav has had a ground past the top of the page
   since 2026-09-20, so the centre is safe again. On the home page the landing's label is
   the word, so the nav's own mark waits for the bar and arrives with it. */
.nav__home{grid-column:2;width:clamp(56px,5vw,76px)}
.nav__home--bar{opacity:0;visibility:hidden;transition:opacity .34s var(--ease),visibility 0s linear .34s}
.nav.is-bar .nav__home--bar{opacity:1;visibility:visible;transition:opacity .34s var(--ease),visibility 0s}
.nav.is-bar .nav__home--bar:hover,.nav.is-bar .nav__home--bar:focus-visible{opacity:.55}
.nav__home img{width:100%;height:auto;display:block;transition:filter .25s var(--ease)}
/* Peek (2026-09-25, MW 4 on the canvas): Work and Services show what is behind them.
   Pointing at either drops its list underneath, one line after another; keyboard focus
   does the same. Touch has no hover, so there a tap simply goes where it always went.
   The list carries the nav's own ground, so it reads over the bar, the void and a dark
   section alike, and it stays hidden (not just transparent) while closed so it never
   catches a click. */
.nav__peek{position:relative;display:flex;align-items:center;pointer-events:auto}   /* the nav itself lets the void through; the peek and its list must not */
.nav__list{pointer-events:auto}
.nav__list{
  position:absolute;left:-.75rem;top:100%;z-index:1;margin:0;padding:.55rem .75rem .7rem;width:max-content;   /* only as wide as its longest line, so its ground never clips the landing copy */
  list-style:none;background:var(--bg);
  text-transform:none;letter-spacing:0;font-size:.8125rem;font-weight:400;line-height:1.25;
  /* the whole list fades, ground and all, and fast on the way out: a list still clearing
     must not sit over the one opening next door (Work's list is wide enough to run under
     Services', 2026-09-25) */
  opacity:0;visibility:hidden;transition:opacity .14s var(--ease),visibility 0s linear .14s;
}
.nav--light:not(.is-bar) .nav__list{background:#000}
.nav__list li{opacity:0;transform:translateY(-4px);transition:opacity .14s var(--ease),transform .14s var(--ease)}
.nav__list a{display:inline-block;padding:.2em 0;opacity:.6;transition:opacity .2s var(--ease)}
.nav__list a:hover,.nav__list a:focus-visible{opacity:1}
/* Nav 1 (2026-10-03, from the "Maal Buttons — 100 Ideas" canvas): a crop of the project
   unfolds beside its name in the Work list. The slot is 0 wide at rest, so the list keeps
   its width and its ground; it opens to 24px on the site's ease. Touch has no hover, so
   there the crop is simply present. 48×60 webp sources in img/nav, 0.3–1.5 KB each. */
.nav__list a{display:inline-flex;align-items:center}
.nav__thumb{width:0;height:30px;object-fit:cover;margin-right:0;transition:width .36s var(--ease),margin-right .36s var(--ease)}
@media (hover:hover){.nav__list a:hover .nav__thumb{width:24px;margin-right:.625rem}}
@media (hover:none){.nav__thumb{width:24px;margin-right:.625rem}}
.nav__list a:focus-visible .nav__thumb{width:24px;margin-right:.625rem}
@media (prefers-reduced-motion:reduce){.nav__thumb{transition:none}}
@media (hover:hover){
  .nav__peek:hover .nav__list{z-index:2;opacity:1;visibility:visible;transition:opacity .2s var(--ease),visibility 0s}
  .nav__peek:hover .nav__list li{opacity:1;transform:none;transition-duration:.3s;transition-delay:calc(var(--i,0) * 35ms)}
}
.nav__peek:has(:focus-visible) .nav__list{z-index:2;opacity:1;visibility:visible;transition:opacity .2s var(--ease),visibility 0s}
.nav__peek:has(:focus-visible) .nav__list li{opacity:1;transform:none}
.nav__list li:nth-child(2){--i:1}.nav__list li:nth-child(3){--i:2}.nav__list li:nth-child(4){--i:3}.nav__list li:nth-child(5){--i:4}
@media (prefers-reduced-motion:reduce){.nav__list,.nav__list li{transition:none}}
.nav__mail{grid-column:3;justify-self:end;text-transform:none;letter-spacing:.01em}

@media (prefers-reduced-motion:reduce){
  .nav__set a::after,.nav__mail::after,.nav__home,
  .close__list a::after,
  .nav a,.nav__home img{transition:none}
}

/* ---- 01 · Landing ------------------------------------------ */

.land{
  position:relative;
  min-height:100svh;
  overflow:hidden;
}

.label{
  position:absolute;left:50%;top:var(--label-top);transform:translateX(-50%);
  width:var(--label-w);
  background:var(--paper);
  /* 202 × 71.5 → sides 20/202 = 9.9%, top/bottom 11.5/202 = 5.7% of the
     label's own width (percent padding would resolve against the page) */
  padding:calc(var(--label-w) * .057) calc(var(--label-w) * .099);
}
.label__word{width:100%;height:auto;display:block;overflow:visible}
.label:focus-visible{outline:2px solid var(--fg);outline-offset:4px}
/* The word, painted (2026-09-25, from the button studies canvas, MW 6). On hover a
   colour plate fills the drawn letters and only the letters: a circle opens where the
   pointer enters the label and closes toward where it leaves, sized in main.js to reach
   the farthest corner so every entry takes the same time. The plate settles from a slight
   zoom as it opens. A different plate on each load (nav.js); no plate until the draw is done. No
   outline: tried for the pale flower sheet, dropped at Kristian's call the same day. */
.label__paint{display:none;pointer-events:none}
.intro-done .label__paint,.case .label__paint{display:inline}
.label__img{transform-box:fill-box;transform-origin:center;transform:scale(1.12);transition:transform 1.2s var(--ease)}
.label__iris{transform-box:fill-box;transform-origin:center;transform:scale(0);transition:transform .48s var(--ease)}
@media (hover:hover){
  .label:hover .label__iris{transform:scale(1);transition-duration:.72s}
  .label:hover .label__img{transform:scale(1)}
}
.label:focus-visible .label__iris{transform:scale(1)}
.label:focus-visible .label__img{transform:scale(1)}
@media (prefers-reduced-motion:reduce){.label__iris,.label__img{transition:none}}

.plate{
  position:absolute;left:50%;top:var(--plate-centre);transform:translate(-50%,-50%);
  height:var(--plate-h);
  aspect-ratio:var(--plate-ratio);
  max-width:84vw;
  background:var(--ground);
}
.plate picture,.plate__img{width:100%;height:100%}
.plate__img{transition:transform .6s var(--ease);will-change:transform}   /* the cursor drift */
.plate__img{object-fit:contain}

/* The one line, above the plate and as wide as it (2026-10-08: the side lines
   removed, the bottom slot was already empty). ~20px at 25px pitch, centred. */
.say{
  position:absolute;
  font-size:clamp(.95rem,1.37vw,1.5rem);   /* 20 / 1461 */
  line-height:1.25;font-weight:500;letter-spacing:-.01em;
  text-align:center;text-wrap:balance;color:var(--fg);
}
.say--above{left:50%;top:19.2svh;transform:translateX(-50%);width:31.7vw}           /* y 197, x 495–957 */

/* ---- Reveal: Apple's blur-in. Out of focus and a little low until the
   element enters the viewport, then it sharpens and settles. ------------ */
.js [data-reveal]{
  opacity:0;filter:blur(14px);transform:translateY(18px) scale(.985);
  transition:opacity .9s var(--ease),filter .9s var(--ease),transform .9s var(--ease);
  transition-delay:var(--d,0ms);
}
.js [data-reveal].is-in{opacity:1;filter:none;transform:none}   /* none, not blur(0): a filtered layer at opacity 0 can ghost in Safari */
@media (prefers-reduced-motion:reduce){.js [data-reveal]{opacity:1;filter:none;transform:none;transition:none}}

/* ---- Work: the hover gallery. One tile active → the rest fade out, that
   project's extra images appear in the surrounding cells, its name takes
   the line's cell. (Studio Freight's home, read from its DOM.) ---------- */
.work__extra{
  grid-column:var(--c);grid-row:var(--r);
  display:block;overflow:hidden;pointer-events:none;
  opacity:0;transform:translateY(10px);visibility:hidden;
  transition:opacity .45s var(--ease),transform .45s var(--ease),visibility 0s linear .45s;
}
.work__extra picture{display:block;width:100%;height:100%}   /* extras that ship WebP (the Mahal sketch plate, 2026-09-15) */
.work__extra img{width:100%;height:100%;object-fit:cover;display:block}
/* Tile captions (2026-09-21). On a pointer device the headline swaps to the
   project's name on hover, so the tiles need no label. On a phone that hover
   never happens and .work__name is hidden, which left six unattributed images:
   the work was on the page and no one could tell whose it was. */
.work__cap{display:none}
/* Design plates, not photographs (2026-09-20). A specimen sheet cropped to the
   tile's ratio loses its own edges, so these sit contained on the plate's own
   ground and letterbox instead of clipping. Each span sets --plate-bg. */
.work__extra--plate img{object-fit:contain;background:var(--plate-bg,#F2F2F2)}
.work__name{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:0 8%;opacity:0;transition:opacity .35s var(--ease);pointer-events:none;font-weight:500}
.work__name b{display:block;font-weight:500}
.work__logo{display:block;height:74%;width:auto;max-width:min(64%,440px);object-fit:contain;color:var(--fg);overflow:visible}
.work__logo--draw path{stroke:currentColor;stroke-linejoin:round;stroke-width:0;vector-effect:non-scaling-stroke}
/* Freya's mark is handwriting, so its box is nearly square — the F's ascender and the
   y's descender own most of the height. At the shared 74% the word itself read small
   (ink 129 wide against GML's 169, Mahal's 279), so it gets more height instead. */
.work__name[data-for="freya"] .work__logo{height:92%}
/* Omari's wordmark (2026-09-26, Kristian): the profile tile, in its own colours: the
   stacked OM/ARI in bubble pink on paper. The one mark here not in --fg, by decision. */
.work__name[data-for="omari"] .work__logo{height:74%}
/* the GML ident (from Kristian's "GML Logo Animation.html"): a canvas key over SVG type, 5:3 */
.ident{position:relative;display:block;height:74%;aspect-ratio:5 / 3;color:var(--fg)}
.ident__key,.ident__type{position:absolute;inset:0;width:100%;height:100%}
.ident__type{fill:currentColor;overflow:visible}   /* a definite height: a % max-height on an image in a grid cell collapsed to 0 */
/* the Mahal ident (from 222.svg via 222-animation.html, "draw + sweep", 2026-09-14): one inline SVG, the pennant's ratio */
.ident--mahal{height:auto;width:min(58%,420px);aspect-ratio:1765 / 609}
.ident--mahal svg{display:block;width:100%;height:100%;overflow:visible}
.ident__fill{fill:currentColor}
.ident__trace{fill:none;stroke:currentColor;stroke-width:1.25;stroke-linejoin:round;vector-effect:non-scaling-stroke}
.ident--mahal image{pointer-events:none}   /* the match-cut frames; opacity is driven by mahal-ident.js */
.work__default{transition:opacity .35s var(--ease)}
/* active state */
.work__grid.is-active .work__tile:not(.is-hot){opacity:0;filter:none;pointer-events:none;visibility:hidden;transition:opacity .45s var(--ease),visibility 0s linear .45s}   /* no blur here: a blurred layer at opacity 0 still ghosts in Safari */
.work__grid.is-active .work__tile.is-hot{z-index:2}
.work__grid.is-active .work__default{opacity:0}
.work__grid.is-active .work__name.is-hot{opacity:1;transition-delay:.12s}
.work__grid.is-active .work__extra.is-hot{opacity:1;transform:none;visibility:visible;transition:opacity .5s var(--ease),transform .5s var(--ease),visibility 0s;transition-delay:calc(90ms + var(--j) * 90ms),calc(90ms + var(--j) * 90ms),0s}
.work__tile{transition:opacity .45s var(--ease),filter .45s var(--ease),transform .9s var(--ease)}
.work__line{font-size:clamp(1.125rem,1.7vw,1.625rem);line-height:1.15}

/* ---- 02 · Work (placeholder) ------------------------------- */

.work{
  --gut:12px;
  --cols:5;--rows:5;                    /* larger, closer: 278×191 tiles at 1461×1026, a ring around the line (2026-09-12) */
  height:100svh;padding:var(--gut);
}
.work__grid{
  display:grid;height:100%;
  grid-template-columns:repeat(var(--cols),1fr);
  grid-template-rows:repeat(var(--rows),1fr);
  gap:var(--gut);
}
.work__tile,.work__line{grid-column:var(--c);grid-row:var(--r)}
.work__tile{
  display:block;background:#E9E9E9;overflow:hidden;
  --d:calc(var(--i,0) * 55ms);   /* the reveal's stagger */
}
.work__tile picture,.work__tile img{display:block;width:100%;height:100%}
.work__tile img{object-fit:cover;transition:transform .6s var(--ease)}
.work__tile:hover img,.work__tile:focus-visible img{transform:scale(1.03)}
.work__tile:focus-visible{outline:2px solid var(--fg);outline-offset:2px}
.work__line{
  grid-column:var(--c) / span 3;
  position:relative;
  align-self:stretch;display:grid;place-content:center;   /* fill the cell so a logo can be sized to it */
  font-size:clamp(1.6rem,2.94vw,3rem);   /* Studio Freight's 43px at 1461 */
  font-weight:500;letter-spacing:-.02em;line-height:1.1;
  text-align:center;
}
/* the stagger: each tile gets its index once, in source order */
.work__tile:nth-child(2){--i:1}.work__tile:nth-child(3){--i:2}.work__tile:nth-child(4){--i:3}.work__tile:nth-child(5){--i:4}
.work__tile:nth-child(6){--i:5}.work__tile:nth-child(7){--i:6}.work__tile:nth-child(8){--i:7}.work__tile:nth-child(9){--i:8}
.work__tile:nth-child(10){--i:9}.work__tile:nth-child(11){--i:10}.work__tile:nth-child(12){--i:11}.work__tile:nth-child(13){--i:12}
.work__tile:nth-child(14){--i:13}.work__tile:nth-child(15){--i:14}.work__tile:nth-child(16){--i:15}.work__tile:nth-child(17){--i:16}
.work__tile:nth-child(18){--i:17}.work__tile:nth-child(19){--i:18}.work__tile:nth-child(20){--i:19}.work__tile:nth-child(21){--i:20}
.work__tile:nth-child(22){--i:21}.work__tile:nth-child(23){--i:22}.work__tile:nth-child(24){--i:23}.work__tile:nth-child(25){--i:24}
.work__tile:nth-child(26){--i:25}

/* ---- 03 · Studio (the statement, as a circle) ---------------- */

.studio{
  min-height:100svh;display:grid;place-items:center;padding:var(--gut,12px);
}
.disc{
  --d:min(26rem,86vw);           /* diameter; the 30 words fill ~90% of the disc at 32px */
  width:var(--d);height:var(--d);
  font-size:clamp(1.5rem,2.2vw,2rem);line-height:1.3;font-weight:500;letter-spacing:-.015em;
  overflow:hidden;
}
.disc__cut{
  float:left;width:50%;height:100%;
  /* an explicit radius: with no size a radial-gradient's percentages run to
     the farthest corner, which carved a 362px disc inside a 512px box */
  --r:calc(var(--d) / 2);
  shape-outside:radial-gradient(circle var(--r) at 100% 50%, transparent 99%, #000 100%);
  shape-image-threshold:.5;
}
.disc__cut--r{
  float:right;
  shape-outside:radial-gradient(circle var(--r) at 0% 50%, transparent 99%, #000 100%);
}
.disc__text{
  text-align:center;
  cursor:crosshair;              /* centred, not justified: the chords shape the block without rivers */
  hyphens:auto;-webkit-hyphens:auto;
  hyphenate-limit-chars:10 5 4;   /* no "stu-dio" */
  padding-top:.7em;               /* the first line starts where the chord holds three words */
}
/* each word is unbreakable, each letter a fixed-width box so a swapped
   glyph never reflows the line; the letters move, the line does not */
.disc__w{display:inline-block;white-space:nowrap}
.disc__c{display:inline-block;text-align:center;transition:transform .35s var(--ease),color .35s var(--ease)}
/* While the cursor is in the disc the script drives every frame, so the transition
   is off and the letters track the pointer exactly. On leave, is-live goes and the
   transition above carries them home and fades the colour back to black. */
.disc__text.is-live .disc__c{transition:none;will-change:transform,color}

/* ------------------------------------------------------------------------
   Services — the roll call (2026-09-29). The three capabilities stacked at the
   title's size; the typeface's own full stop bounces in over them like the
   loader's ball, then hops to whichever line is read (main.js § 6). The register
   it replaces is parked at _parked/v17-index-services-register-2026-09-29.html.
   ------------------------------------------------------------------------ */
.services{max-width:1680px;margin:0 auto;padding:128px 5vw 112px;display:flex;flex-direction:column;align-items:center;gap:72px;text-align:center;scroll-margin-top:0}
.services__title{font-size:20px;line-height:1.2;letter-spacing:-.025em;font-weight:500}
.services__names{position:relative;font-size:clamp(52px,6.1vw,88px);line-height:1;letter-spacing:-.055em;font-weight:500}
.services__name{display:block;margin:0 auto;padding:0;border:0;background:none;font:inherit;letter-spacing:inherit;color:#000;cursor:pointer;
  transform-origin:50% 80%;transition:color .3s var(--ease);scroll-margin-top:30vh}
.services__name.is-dim{color:#9B9C96}
.services__name:focus-visible{outline:2px solid #000;outline-offset:6px}
/* every line keeps its full stop's width, so the three centre alike; the one
   that shows is the ball. Without script, Expression's ends the stack.
   The full stop is round, as in the word (2026-10-05): a dot a fifth of the
   letter height (Areal's cap is .716em), sat on the baseline and centred where
   the typeface's square stop would be, with the same margins as before, so the lines still centre alike. */
.services__stop,.services__ballq{display:inline-block;width:.143em;height:.143em;margin:0 -.005em 0 .05em;border-radius:50%;background:currentColor}
.services__stop{opacity:0}
.services:not(.is-live) .services__name:nth-child(3) .services__stop{opacity:1}
.services__ball{position:absolute;left:0;top:0;opacity:0;pointer-events:none}
.services:not(.is-live) .services__ball{display:none}
.services.is-set .services__ball{opacity:1}
.services__bally{display:inline-block}
.services__ballq{margin:0;transform-origin:50% 100%}   /* the ball is placed at the dot itself, not its advance */

.services__reading{width:min(460px,100%);min-height:380px;display:flex;flex-direction:column;align-items:center}
.services__rest p,.services__sub{font-size:14px;line-height:1.45;color:#6F6F6F}
.services__tap{display:none}
@media(hover:none){.services__tap{display:inline}}
.services__cap{display:flex;flex-direction:column;align-items:center;gap:20px;width:100%}
.services__cap[hidden],.services__rest[hidden]{display:none}
.services.is-live .services__h{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.services__h{font-size:20px;line-height:1.2;letter-spacing:-.025em;font-weight:500}
.services__desc{font-size:16px;line-height:1.45}
.services__list{font-size:19px;line-height:1.32;letter-spacing:-.03em;color:#9B9C96}
.services__all{width:min(280px,100%);font-size:13px}
.services__all summary{display:flex;align-items:center;justify-content:center;gap:14px;min-height:44px;cursor:pointer;list-style:none;border-top:1px solid #dedede}
.services__all summary::-webkit-details-marker{display:none}
.services__toggle{position:relative;width:10px;height:10px;flex-shrink:0}
.services__toggle:before,.services__toggle:after{content:"";position:absolute;background:currentColor}
.services__toggle:before{width:10px;height:1px;top:4px;left:0}
.services__toggle:after{height:10px;width:1px;left:4px;top:0}
.services__all[open] .services__toggle:after{display:none}
.services__all ul{padding:10px 0 6px;line-height:1.5;color:#555}
.services__work{display:inline-flex;align-items:center;gap:10px;min-height:44px;margin-top:-12px;font-size:12px}
.services__contact{font-size:14px;border-bottom:1px solid #000;padding-bottom:2px}
.services__work:hover,.services__contact:hover{opacity:.6}
.services a:focus-visible,.services summary:focus-visible{outline:2px solid #000;outline-offset:5px}
/* without script: all three read in full, one after another */
.services:not(.is-live) .services__reading{gap:64px;min-height:0}
.services:not(.is-live) .services__rest{display:none}
@media(max-width:600px){.services{padding:104px 24px 64px;gap:40px}.services__reading{min-height:440px}}

/* ---- 05 · Close — build, then flood (2026-09-27) ------------------------ */
/* Chosen on the footer canvas over thirty-odd directions. White now, like the
   rest of the page (the black slab went: dark slabs shout). The word rises out
   of its own baseline, the painting runs out of the full stop and floods the
   close, and the close's own layout comes back in white on the painting: no
   boxes, the same positions, inverted. The geometry lives in main.js § 8, which
   measures .close__home (the word's slot, laid out here) and draws into the SVG. */

.close{
  --pad-x:clamp(1.25rem,5.5vw,5rem);
  --word-x:clamp(1.25rem,3.33vw,3rem);
  --word-b:clamp(3.5rem,8svh,5rem);
  --info:1;
  position:relative;min-height:84svh;overflow:hidden;   /* was 100svh; a little shorter by decision, 2026-09-27 */
  background:var(--bg);color:var(--fg);border-top:1px solid #E4E4E4;
}
.close a{color:inherit;transition:color .3s var(--ease),border-color .3s var(--ease)}
.close__info{
  position:relative;z-index:2;opacity:var(--info);
  display:grid;grid-template-columns:repeat(12,minmax(0,1fr));column-gap:24px;align-items:start;
  padding:72px var(--pad-x) 0;
}
.close__contact{grid-column:1 / 6;display:flex;flex-direction:column;gap:.5rem;line-height:1.45}
.close__mail{
  align-self:flex-start;font-size:clamp(1.25rem,2vw,1.875rem);font-weight:500;letter-spacing:-.02em;
  border-bottom:1px solid currentColor;padding-bottom:.06em;
}
.close__mail:hover,.close__mail:focus-visible{border-bottom-color:transparent;outline:none}
.close__meta{font-size:.875rem;color:#6F6F6F}
.close__index{grid-column:7 / 10;font-size:.875rem;line-height:1.5}
.close__list{list-style:none;margin:0;padding:0}
.close__list a{position:relative;display:inline-block;padding-bottom:.02em}
.close__list a:focus-visible{outline:none}
.close__time{grid-column:10 / 13;text-align:right;font-size:.875rem;line-height:1.5;font-variant-numeric:tabular-nums}
.close__time time{display:block;min-width:5.5ch}

/* the drawing: ink letters, the painting inside them, the flood, the white word */
.close__art{position:absolute;inset:0;z-index:1;width:100%;height:100%;display:none;pointer-events:none}
.close.is-live .close__art{display:block}
.close__glyph{fill:#000}
.close__veil{fill:#000;opacity:0}
.close__white{fill:#fff;opacity:0}

/* the word's slot: without script it shows the word itself; with it, the SVG draws here */
.close__home{
  position:absolute;z-index:2;left:var(--word-x);right:var(--word-x);bottom:var(--word-b);
  display:block;aspect-ratio:1772 / 355;
}
.close__word{width:100%;height:auto;display:block}
.close.is-live .close__word{visibility:hidden}
.close__home:focus-visible{outline:1px solid currentColor;outline-offset:6px}

.close__legal{position:absolute;z-index:2;bottom:2rem;margin:0;font-size:.75rem;line-height:1.45}
.close__legal{right:var(--pad-x);color:#6F6F6F;opacity:var(--info)}

/* after the flood: the same layout, white on the painting */
.close.is-flooded{color:#fff}
.close.is-flooded .close__meta{color:rgba(255,255,255,.8)}
.close.is-flooded .close__legal{color:rgba(255,255,255,.85)}

@media (max-width:720px){
  .close{--word-x:20px;--word-b:56px}
  .close__info{display:flex;flex-direction:column;gap:1.75rem;padding:48px 20px 0}
  .close__mail{font-size:1.5rem}
  .close__meta{font-size:.8125rem}
  .close__index{font-size:1rem}
  .close__list a{display:flex;align-items:center;min-height:44px;border-top:1px solid rgba(0,0,0,.14)}
  .close__list li:last-child a{border-bottom:1px solid rgba(0,0,0,.14)}
  .close.is-flooded .close__list a{border-color:rgba(255,255,255,.35)}
  .close__list a::after{display:none}
  .close__time{text-align:left;font-size:.8125rem;color:#6F6F6F}
  .close.is-flooded .close__time{color:rgba(255,255,255,.8)}
  .close__time time{display:inline}
  .close__legal{left:20px;right:auto;bottom:24px;font-size:.6875rem}
}

/* ---- Case study pages (work/*.html), stubs ------------------------- */
/* GML: the ident is the hero — a cropped square of the leather in the column, the key turning on a loop, the name closing behind it. */
.case__ident{position:relative;margin:0 0 2.5rem;aspect-ratio:1 / 1;display:grid;place-items:center;background:#0f3d23 url(img/work/gml-leather.jpg) center/cover no-repeat;color:#e8e2d2;overflow:hidden}
.case__ident .ident{width:62%;height:auto;aspect-ratio:5 / 3;color:#e8e2d2}
/* Mahal: the same square, on the tiles' grey, the pennant drawing itself on a loop */
.case__ident--mahal{background:#E9E9E9;color:var(--fg)}
.case__ident--mahal .ident{width:70%;aspect-ratio:1765 / 609;color:var(--fg)}
.case{background:var(--bg)}
.case__main{max-width:52rem;margin:0 auto;padding:clamp(7rem,18vh,11rem) 1.5rem 6rem}
/* every page carries the home page's label (2026-09-25): absolute at the top, as on the
   landing, so it scrolls away and the nav's mark arrives with the bar. The column starts
   clear of it whatever the label's size. */
.label--page{z-index:1}
.label--page ~ .case__main{padding-top:max(clamp(7rem,18vh,11rem), calc(var(--label-top) + var(--label-w) * .275 + 3.5rem))}
.case__kicker{font-size:.8125rem;letter-spacing:.04em;text-transform:uppercase;color:#6F6F6F;margin-bottom:1rem}
.case__title{font-size:clamp(2rem,5vw,4rem);font-weight:500;letter-spacing:-.03em;line-height:1;margin-bottom:.75rem}
.case__line{font-size:clamp(1.125rem,1.6vw,1.375rem);color:#6F6F6F;margin-bottom:2.5rem}
.case__hero{margin-bottom:2.5rem}.case__hero img{width:100%;height:auto;display:block}
/* The close of a case study (2026-09-21): one ask, then the next case. */
.case__close{margin:3.25rem 0 0;padding-top:1.5rem;border-top:1px solid #E4E4E4}
.case__ask{font-size:1.0625rem;line-height:1.45;letter-spacing:-.01em;margin-bottom:.875rem}
.case__ask a{text-decoration:underline;text-underline-offset:3px}
.case__close .case__next{font-size:.8125rem;color:#6F6F6F}
.case__close .case__next a{color:var(--fg)}
.case__sep{padding:0 .5rem;color:#B9B9B9}
.case__fig{margin:0 0 2.5rem}.case__fig img,.case__fig video{width:100%;height:auto;display:block}
.case__fig video{aspect-ratio:16/9;background:#EDEDED}
/* two plates side by side, one caption under both (Maal case, 2026-09-26); a stack on phones */
.case__pair{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.case__pair picture{display:block;min-width:0}
.case__pair figcaption{grid-column:1 / -1;margin-top:.1rem}
@media (max-width:560px){.case__pair{grid-template-columns:minmax(0,1fr)}}
/* a white plate on a white page needs an edge to stay an object (as .card__cell did in v16) */
.case__edge img,.case__edge video{box-shadow:0 0 0 1px rgba(0,0,0,.07)}
.case__hero figcaption,.case__fig figcaption{font-size:.8125rem;line-height:1.5;color:#6F6F6F;max-width:44em;margin-top:.75rem}
.case__body{font-size:1.0625rem;line-height:1.5;max-width:36em;margin-bottom:2rem}
/* the written case studies need a section mark and a closing route line (2026-09-17);
   both borrow the kicker's register so the page keeps one small-type scale */
.case__h2{font-size:.8125rem;font-weight:500;letter-spacing:.04em;text-transform:uppercase;color:#6F6F6F;margin:3rem 0 .9rem}
.case__body + .case__body{margin-top:-1rem}
.case__route{font-size:.9375rem;line-height:1.55;color:#6F6F6F;max-width:36em;border-top:1px solid #E4E4E4;padding-top:1.25rem;margin:3.5rem 0 0}
.case__status{font-size:.9375rem;line-height:1.55;color:#6F6F6F;max-width:36em;margin:2.5rem 0 0}
.case__next{margin-top:2.25rem}
.case__next a{border-bottom:1px solid currentColor}

/* The run-on (2026-10-05, case-more.js § 3): below the close, one screen of the next case's
   opening, laid out exactly as that page opens, so reaching the end is arriving there. The
   only cue is a line along the foot of the screen that fills as the next page rises (a
   label there sat on the incoming page's text on phones); it fades before the swap. The
   page opts in to the cross-document transition here and nav.js skips it unless the
   run-on started the navigation. */
.runon{position:relative;height:100vh;overflow:hidden;cursor:pointer}
.runon .case__main{padding-bottom:0}
.runon__cue{
  position:fixed;left:0;right:0;bottom:0;z-index:5;height:2px;margin:0;
  background:var(--fg);transform-origin:0 50%;transform:scaleX(var(--p,0));
  opacity:0;transition:opacity .3s var(--ease);pointer-events:none;
}
.runon__cue.is-on{opacity:1}
@view-transition{navigation:auto}
::view-transition-old(root),::view-transition-new(root){animation-duration:.4s}
@media (prefers-reduced-motion:reduce){::view-transition-old(root),::view-transition-new(root){animation:none}}

/* Phones: the artboard is a laptop. Keep the order and the label size,
   let the plate take the width instead of the height. */
@media (max-width:720px){
  :root{--label-w:clamp(112px,34vw,160px)}
  /* everything goes into the flow: label, the line, plate */
  .land{display:flex;flex-direction:column;align-items:center;gap:2rem;padding:calc(var(--label-top) + 12vw) 6vw 4rem}
  .label{position:static;transform:none}
  .say{position:static;transform:none;width:min(100%,32ch);font-size:1.125rem}
  .say--above{order:1}.plate{order:2}
  .plate{position:static;transform:none;height:auto;width:80vw;max-width:none}
  /* the work grid: three columns, auto rows, the explicit cells released */
  .work{height:auto}
  .work__grid{grid-template-columns:repeat(2,1fr);grid-template-rows:none;grid-auto-rows:1fr}
  .work__tile{grid-column:auto;grid-row:auto;aspect-ratio:1.56}
  .work__extra,.work__name{display:none}
  /* so the caption carries the name instead */
  .work__tile{position:relative}
  .work__cap{
    display:block;margin-top:.5rem;
    font-size:.8125rem;line-height:1.3;letter-spacing:-.01em;color:var(--fg);
  }
  .work__grid.is-active .work__tile:not(.is-hot){opacity:1;filter:none;pointer-events:auto}
  .work__line{grid-column:1 / -1;grid-row:auto;padding:2rem 0}
  /* the label is in the flow here, so the nav pins to the top edge instead */
  .nav{top:1rem;transform:none;font-size:.6875rem;padding:0 1.25rem}
  .nav__home{width:52px}
  /* the landing puts its label in the flow; the pages keep theirs absolute, centred, at the
     height the landing's sits (nav on the top edge, the label below it) */
  .label.label--page{position:absolute;left:50%;transform:translateX(-50%);top:calc(var(--label-top) + 12vw)}
  .label--page ~ .case__main{padding-top:calc(var(--label-top) + 12vw + var(--label-w) * .275 + 3rem)}
}
/* On a phone the three links are wider than half the bar, so a page-centred mark would sit
   on STUDIO: the mark centres in the space between the links and the address instead. */
@media (max-width:560px){
  .nav{grid-template-columns:auto minmax(0,1fr) auto}
  .nav__home{justify-self:center;width:46px}
  .nav__set{gap:.8rem}
}
@media (max-width:360px){
  .nav{padding:0 .9rem;column-gap:.5rem}
  .nav__set{gap:.6rem}
  .nav__home{width:40px}
}
/* Very short, wide windows: don't let the plate crowd the label. */
@media (max-height:520px){
  :root{--plate-h:44svh;--plate-centre:54svh}
}

/* Maal: the header wordmark, static (the assembly animation was removed 2026-09-15). */
.work__mark{display:block;width:min(24%,200px);height:auto}   /* ~200×60: the GML wordmark's scale (228×54), not the ident box — the word is solid, the others carry air */
.case__ident--maal{background:#e9e9e9}
.case__mark{display:block;width:46%;height:auto}   /* ≈360×108 in the 784 square, the GML case wordmark's height (113) */

/* Plain documents (privacy, and anything else that is only prose):
   the case shell, plus the subheads and lists the case pages never needed. */
.legal h2{font-size:1.125rem;font-weight:500;letter-spacing:-.01em;margin:2.5rem 0 .75rem}
.legal p{font-size:1.0625rem;line-height:1.5;max-width:36em;margin-bottom:1rem}
.legal ul{font-size:1.0625rem;line-height:1.5;max-width:36em;margin:0 0 1rem 1.1em}
.legal li{margin-bottom:.35rem}
.legal a{border-bottom:1px solid currentColor}
.legal__updated{font-size:.8125rem;color:#6F6F6F;margin-bottom:2.5rem}

/* ── The journey ──────────────────────────────────────────────
   A tiered node tree: each level is a band across the page and
   the flow descends through them. Columns hold to one route all
   the way down, so a node's parent is the one above it. Level
   names sit in a left gutter, out of the connectors' way, and
   each column's connector starts under its own last card and
   stretches to the band's foot, so every arrowhead lands on the
   same line however uneven the columns are. Drawn in the
   strategy plate's register, connectors made of borders so the
   whole thing survives reflow. It breaks out of the text column
   because a diagram needs more width than prose. */
.jrn{
  --ink:#F9F5EC; --mute:rgba(249,245,236,.74); --faint:rgba(249,245,236,.5);
  --link:rgba(249,245,236,.5);
  --glass:rgba(255,255,255,.10); --glass-up:rgba(255,255,255,.14); --glass-soft:rgba(255,255,255,.05);
  --edge:rgba(249,245,236,.26); --edge-soft:rgba(249,245,236,.15);
  --cols:3; --gap:1.25rem; --labelw:8.5rem; --lgap:1.5rem;
  position:relative;border-radius:20px;overflow:hidden;
  width:min(78rem,calc(100vw - 3rem));margin-left:50%;transform:translateX(-50%);
  margin-bottom:3.5rem;padding:2.5rem 2rem 2.25rem;
  /* Maal ink, not GML's green (2026-09-20). Five case studies carry a journey
     map now, so the instrument is the studio's rather than one client's. */
  background:#1B1B1B;color:var(--ink)
}
.jrn>*:not(.jrn__ground){position:relative;z-index:1}
.jrn__ground{position:absolute;inset:0;z-index:0}
.jrn__ground img{width:100%;height:100%;object-fit:cover;filter:blur(44px) saturate(1.05);transform:scale(1.18)}
.jrn__ground::after{content:"";position:absolute;inset:0;background:radial-gradient(120% 100% at 50% 45%,rgba(0,0,0,0) 40%,rgba(0,0,0,.42) 100%),rgba(6,8,7,.58)}
.jrn__label{font-size:.75rem;letter-spacing:.12em;text-transform:uppercase;color:var(--mute);margin:0 0 1.75rem}

/* a level: its name in the gutter, its nodes in the band */
.jrn__row{display:grid;grid-template-columns:var(--labelw) 1fr;column-gap:var(--lgap);align-items:stretch}
.jrn__level{font-size:.6875rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);margin:.25rem 0 0;line-height:1.5}
.jrn__band{display:grid;grid-template-columns:repeat(var(--cols),1fr);gap:var(--gap)}
.jrn__col{display:flex;flex-direction:column;gap:.625rem;min-width:0}

/* the connector: starts under a column's last card, ends on the band's foot */
.jrn__drop{flex:1 0 2rem;position:relative;min-height:2rem}
.jrn__drop::before{content:"";position:absolute;left:50%;top:.375rem;bottom:7px;border-left:1px solid var(--link)}
.jrn__drop::after{content:"";position:absolute;left:50%;bottom:0;transform:translateX(-50%);width:0;height:0;border-top:7px solid var(--link);border-left:4.5px solid transparent;border-right:4.5px solid transparent}
/* the fan off the problem: a riser, a crossbar, then a drop per column */
.jrn__fan{position:relative;height:3rem;display:grid;grid-template-columns:repeat(var(--cols),1fr);gap:var(--gap);margin-top:.25rem}
.jrn__fan::after{content:"";position:absolute;left:50%;top:0;height:1.25rem;border-left:1px solid var(--link)}
.jrn__fan::before{content:"";position:absolute;top:1.25rem;
  left:calc((100% - (var(--cols) - 1) * var(--gap)) / (var(--cols) * 2));
  right:calc((100% - (var(--cols) - 1) * var(--gap)) / (var(--cols) * 2));
  border-top:1px solid var(--link)}
.jrn__fan>i{position:relative}
.jrn__fan>i::before{content:"";position:absolute;left:50%;top:1.25rem;bottom:7px;border-left:1px solid var(--link)}
.jrn__fan>i::after{content:"";position:absolute;left:50%;bottom:0;transform:translateX(-50%);width:0;height:0;border-top:7px solid var(--link);border-left:4.5px solid transparent;border-right:4.5px solid transparent}

/* the nodes */
.jrn__node{border:1px solid var(--edge);border-radius:12px;background:var(--glass);padding:.75rem .9375rem .8125rem}
.jrn__name{font-size:.9375rem;font-weight:500;line-height:1.3;letter-spacing:-.005em;margin:0}
.jrn__desc{font-size:.8125rem;line-height:1.45;color:var(--mute);margin:.1875rem 0 0}
.jrn__node--problem{background:var(--glass-up);padding:1.125rem 1.25rem 1.1875rem;max-width:38rem;margin:0 auto}
.jrn__node--problem .jrn__name{font-size:clamp(1.25rem,2.4vw,1.75rem);letter-spacing:-.02em;line-height:1.2}
.jrn__node--problem .jrn__desc{font-size:.875rem;margin-top:.5rem}
.jrn__node--route{background:var(--glass-up)}
.jrn__node--route .jrn__name{font-size:1.0625rem}
.jrn__n{color:var(--faint);font-size:.75rem;font-weight:400;letter-spacing:.08em;margin-right:.625rem;vertical-align:.1em}
.jrn__node--answer{border-color:rgba(249,245,236,.5);background:rgba(255,255,255,.15)}
.jrn__node--answer .jrn__name{font-size:1rem}
.jrn__node--soft{background:var(--glass-soft);border-color:var(--edge-soft);border-style:dashed}
.jrn__node--soft .jrn__name{color:var(--mute)}
.jrn__ahead{display:flex;align-items:center;gap:.75rem;margin:0 0 .3125rem}
.jrn__alabel{font-size:.625rem;letter-spacing:.11em;text-transform:uppercase;color:var(--mute)}
.jrn__bars{display:flex;gap:3px;margin-left:auto;flex:none}
.jrn__bars i{display:block;width:3px;height:10px;background:rgba(249,245,236,.22)}
.jrn__bars i.on{background:var(--ink)}
/* which route a node belongs to — the column says it, until the columns collapse */
.jrn__via{display:none;font-size:.625rem;letter-spacing:.11em;text-transform:uppercase;color:var(--faint);margin:0 0 .25rem}
/* the closing band: what the map settles */
.jrn__rule{border:0;border-top:1px solid rgba(249,245,236,.16);margin:2.25rem 0 1.75rem}
.jrn__node--approach{background:var(--glass-up);border-color:rgba(249,245,236,.4);display:flex;flex-direction:column;height:100%}
.jrn__anum{font-size:1.75rem;font-weight:500;line-height:1;letter-spacing:-.02em;color:rgba(249,245,236,.4);margin:0 0 .5rem}
.jrn__node--approach .jrn__name{font-size:1.0625rem;margin-bottom:.4375rem}
/* reserve two lines so the rule sits at the same height in every card,
   whether the move it follows from wraps or not */
.jrn__from{font-size:.625rem;line-height:1.5;letter-spacing:.11em;text-transform:uppercase;color:var(--faint);margin:0 0 .625rem;padding-bottom:.5rem;min-height:2.375rem;border-bottom:1px solid rgba(249,245,236,.14)}
.jrn__from b{font-weight:400;color:var(--mute)}
.jrn__foot{font-size:.75rem;line-height:1.5;color:var(--faint);max-width:44em;margin:2rem 0 0}

@media (max-width:1000px){.jrn{--gap:.875rem;--labelw:6.5rem;--lgap:1rem;padding:2rem 1.5rem 1.75rem}.jrn__desc{font-size:.78125rem}}
@media (max-width:720px){
  .jrn{--cols:1;width:auto;margin-left:0;transform:none;padding:1.75rem 1.125rem 1.5rem;border-radius:16px}
  .jrn__row{grid-template-columns:1fr;row-gap:.5rem}
  .jrn__level{margin:1rem 0 0}
  .jrn__fan{height:1.75rem;margin-top:0}
  .jrn__fan::before{display:none}
  .jrn__fan::after{height:100%}
  .jrn__fan>i::before{top:0}
  .jrn__drop{flex:0 0 1.5rem;min-height:1.5rem}
  /* one column, so the fan is a single drop, and only the band's last
     connector survives — the others would sit between sibling routes
     and read as flow from one to the next, which is not what they mean */
  .jrn__fan>i:not(:first-child){display:none}
  .jrn__col:not(:last-child) .jrn__drop{display:none}
  .jrn__node--problem{max-width:none}
  .jrn__via{display:block}
  .jrn__col,.jrn__band{gap:.5rem}
}

/* ---- Case studies: the outcomes register (2026-09-17). Every case page closes
   on what the client has at the end, one line per thing delivered, so the last
   thing read is the work rather than a caveat about what hasn't happened yet.
   Small elements, rules for structure, the detail set quiet to the right. ---- */
.case__deliver{list-style:none;margin:0 0 2rem;padding:0;max-width:36em;border-top:1px solid #E4E4E4}
.case__deliver li{display:grid;grid-template-columns:minmax(7rem,11rem) 1fr;gap:.2rem 2rem;
  align-items:baseline;font-size:1.0625rem;line-height:1.5;padding:.85rem 0;border-bottom:1px solid #E4E4E4}
.case__deliver b{font-weight:500}
.case__deliver span{font-size:.9375rem;color:#6F6F6F}
@media (max-width:540px){.case__deliver li{grid-template-columns:1fr;gap:.15rem}}

/* ---- The loader (2026-09-26) -------------------------------------------
   The block word centred on the ground; a ball bounces in from the left, stamps
   each A's counter open and lands as the full stop (the roll call motion study).
   Then main.js fades it and the page arrives: nav down from the top, the rest up
   from below. `translate` rather than `transform`, so none of the elements' own
   centring transforms are touched. */
.loader{display:none}
.intro-active .loader{display:grid;place-items:center;position:fixed;inset:0;z-index:100;background:var(--bg)}
.loader.is-out{display:grid;place-items:center;position:fixed;inset:0;z-index:100;background:var(--bg);opacity:0;pointer-events:none;transition:opacity .45s cubic-bezier(.4,0,.2,1)}
/* the scrollbar's room (--sbw, measured in index.html's head) is kept while the
   loader holds the page still, so where scrollbars always show, neither the word
   nor the page slides left as the scrollbar returns (2026-10-05) */
.intro-active{overflow:hidden;padding-right:var(--sbw,0px)}
.intro-active body{overflow:hidden}
.intro-active .loader{right:var(--sbw,0px)}
.loader__word{width:clamp(200px,30vw,420px);height:auto;overflow:visible;fill:var(--fg)}
.loader__hole{fill:var(--bg)}
.loader__hole,.loader__ball,.loader__a1,.loader__a2{transform-box:fill-box}
.loader__hole{transform-origin:50% 50%;transform:scale(0)}
.loader__ball,.loader__a1,.loader__a2{transform-origin:50% 100%}
.loader__bx{transform:translateX(-700px);animation:ldBx 2s both}
.loader__by{transform:translateY(-900px);animation:ldBy 2s both}
.loader__ball{animation:ldSquash 2s both}
.loader__c1{animation:ldPop1 2s both}
.loader__c2{animation:ldPop2 2s both}
.loader__a1{animation:ldDip1 2s both}
.loader__a2{animation:ldDip2 2s both}
@keyframes ldBx{0%{transform:translateX(-700px);animation-timing-function:linear}30%{transform:translateX(602.362px);animation-timing-function:linear}50%{transform:translateX(1027.559px);animation-timing-function:linear}75%,100%{transform:translateX(1736.22px)}}
@keyframes ldBy{0%{transform:translateY(-900px);animation-timing-function:cubic-bezier(.55,0,.9,.4)}30%{transform:translateY(-35.433px);animation-timing-function:cubic-bezier(.2,.6,.4,1)}40%{transform:translateY(-380px);animation-timing-function:cubic-bezier(.55,0,.9,.4)}50%{transform:translateY(-35.433px);animation-timing-function:cubic-bezier(.2,.6,.4,1)}62%{transform:translateY(-440px);animation-timing-function:cubic-bezier(.55,0,.9,.4)}75%{transform:translateY(318.898px);animation-timing-function:cubic-bezier(.2,.6,.4,1)}84%{transform:translateY(250px);animation-timing-function:cubic-bezier(.55,0,.9,.4)}92%,100%{transform:translateY(318.898px)}}
@keyframes ldSquash{0%,28%{transform:scale(1)}30%{transform:scale(1.3,.72)}33%,48%{transform:scale(1)}50%{transform:scale(1.3,.72)}53%,73%{transform:scale(1)}75%{transform:scale(1.3,.72)}79%,100%{transform:scale(1)}}
@keyframes ldPop1{0%,30%{transform:scale(0);animation-timing-function:cubic-bezier(.16,1,.3,1)}36%{transform:scale(1.3)}42%,100%{transform:scale(1)}}
@keyframes ldPop2{0%,50%{transform:scale(0);animation-timing-function:cubic-bezier(.16,1,.3,1)}56%{transform:scale(1.3)}62%,100%{transform:scale(1)}}
@keyframes ldDip1{0%,29%{transform:scaleY(1)}32%{transform:scaleY(.92)}38%,100%{transform:scaleY(1)}}
@keyframes ldDip2{0%,49%{transform:scaleY(1)}52%{transform:scaleY(.92)}58%,100%{transform:scaleY(1)}}

/* the page arrives */
.intro-active .nav,.intro-active .land,.intro-active main{opacity:0}
@keyframes ldDrop{from{translate:0 -180%;opacity:0}to{translate:0 0;opacity:1}}
@keyframes ldRise{from{translate:0 56px;opacity:0}to{translate:0 0;opacity:1}}
.intro-rise .nav{animation:ldDrop .9s var(--ease) .3s both}
.intro-rise .label{animation:ldRise 1.1s var(--ease) .25s both}
.intro-rise .say--above{animation:ldRise 1.1s var(--ease) .34s both}
.intro-rise .plate{animation:ldRise 1.2s var(--ease) .4s both}
.intro-rise main{animation:ldRise 1.2s var(--ease) .56s both}

/* the roll call on the work grid (2026-09-26): the Maal tile's name replays the loader's
   motion each time it goes hot; at rest it is the finished word */
.work__roll{overflow:visible;fill:currentColor;color:var(--fg)}
.roll__hole{fill:var(--bg)}
.roll__hole,.roll__ball,.roll__a1,.roll__a2{transform-box:fill-box}
.roll__hole{transform-origin:50% 50%}
.roll__ball,.roll__a1,.roll__a2{transform-origin:50% 100%}
.roll__bx{transform:translateX(1736.22px)}
.roll__by{transform:translateY(318.898px)}
.work__name.is-hot .roll__bx{animation:ldBx 1.7s both}
.work__name.is-hot .roll__by{animation:ldBy 1.7s both}
.work__name.is-hot .roll__ball{animation:ldSquash 1.7s both}
.work__name.is-hot .roll__c1{animation:ldPop1 1.7s both}
.work__name.is-hot .roll__c2{animation:ldPop2 1.7s both}
.work__name.is-hot .roll__a1{animation:ldDip1 1.7s both}
.work__name.is-hot .roll__a2{animation:ldDip2 1.7s both}
@media (prefers-reduced-motion:reduce){.work__roll *{animation:none !important}}
/* Omari: Levels (2026-09-26). The tile's condensed capitals rise from their baselines
   like meter bars catching a beat, OM first, then ARI, each overshooting and settling. */
.levels__bar{transform-box:fill-box;transform-origin:50% 100%}
.levels__ground{transform-box:fill-box;transform-origin:50% 50%}
.work__name.is-hot .levels__ground{animation:lvGround .45s cubic-bezier(.2,.7,.2,1) both}
.work__name.is-hot .levels__bar{animation:lvBar .95s cubic-bezier(.2,.7,.2,1) both;animation-delay:calc(var(--d) + 120ms)}
@keyframes lvGround{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:none}}
@keyframes lvBar{0%{transform:scaleY(0)}42%{transform:scaleY(1.08)}62%{transform:scaleY(.95)}80%{transform:scaleY(1.02)}100%{transform:none}}
@media (prefers-reduced-motion:reduce){.levels *{animation:none !important}}

/* ── Case studies, mostly visual (2026-09-28) ─────────────────────────────────────────
   After Mouthwash Studio's project pages: a Client / Year / Services row under the title,
   then three chapters (what they are, what makes them different, what we did), each one
   line with a "Read more" pill. The full text opens in a white sheet over a blurred page.
   Pictures carry the rest, with one-line captions. */
.case__meta{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem;border-top:1px solid #E4E4E4;padding-top:.75rem;margin:0 0 2.5rem;font-size:.8125rem;line-height:1.4}
.case__meta dt{color:#6F6F6F;margin-bottom:.125rem}
.case__meta dd{margin:0}
/* Case studies v2 (2026-10-03): a summary row (Client / Change / We did), then two chapters,
   The ask and What we did, each with a short paragraph on the page and the fuller account
   in its sheet; the journey map cut to the problem and where the effort goes; the pictures
   after What we did. Spec: Website/v17-case-study-structure.md. */
.case__meta--sum{grid-template-columns:minmax(0,1fr) minmax(0,2fr) minmax(0,1fr)}
.chap__text{font-size:clamp(1rem,1.25vw,1.125rem);line-height:1.55;max-width:32em;margin:-.25rem auto 1.75rem;text-wrap:pretty}
.jrn--short .jrn__via{display:block}   /* with the routes row gone, each column names its route */
.chap{text-align:center;padding:clamp(4.5rem,14vh,8rem) 0 clamp(3.5rem,10vh,6rem)}
.chap__label{font-size:.75rem;letter-spacing:.04em;text-transform:uppercase;color:#6F6F6F;margin:0 0 1.125rem}
.chap__label span{margin-right:.625rem;color:#B9B9B9}
.chap__head{font-size:clamp(1.5rem,3.4vw,2.625rem);font-weight:500;letter-spacing:-.03em;line-height:1.1;max-width:22em;margin:0 auto 1.75rem;text-wrap:balance}
.chap__more{display:inline-flex;align-items:center;gap:.625rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--fg);background:#E9E9E9;border:0;border-radius:999px;padding:.5rem .875rem .5rem 1rem;cursor:pointer;transition:background .24s var(--ease)}
.chap__more:hover{background:#DCDCDC}
.chap__more:focus-visible,.more__x:focus-visible{outline:2px solid var(--fg);outline-offset:2px}
.chap__plus{position:relative;width:10px;height:10px}
.chap__plus::before,.chap__plus::after{content:"";position:absolute;left:0;top:4.5px;width:10px;height:1px;background:currentColor}
.chap__plus::after{transform:rotate(90deg)}
.more[open]{position:fixed;inset:0;width:100%;height:100%;max-width:none;max-height:none;margin:0;padding:16px;border:0;background:transparent;display:grid;place-items:center;overflow:hidden}
.more::backdrop{background:rgba(245,245,245,.55);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);animation:moreFade .45s var(--ease) both}
.more.is-closing::backdrop{animation:moreOut .45s var(--ease) both}
.more__sheet{position:relative;width:min(34rem,100%);max-height:calc(100svh - 6rem);overflow:auto;overscroll-behavior:contain;background:#fff;color:var(--fg);border-radius:20px;box-shadow:0 0 0 1px rgba(0,0,0,.06),0 24px 60px rgba(0,0,0,.12);padding:1.75rem 1.75rem 2rem;text-align:left}
.more[open] .more__sheet{animation:moreIn .9s var(--ease) both}
.more[open] .more__sheet>*{animation:moreIn .9s var(--ease) both;animation-delay:calc(var(--i,0) * 55ms + 110ms)}
.more[open] .more__sheet>.more__x{animation:none}   /* the control arrives with the sheet, not on the lines' stagger */
.more.is-closing .more__sheet{animation:moreOut .45s var(--ease) both}   /* forwards on the site's curve: most of the fade in the first third, as every other exit on the site; a reversed curve held the sheet at full strength, then dropped it */
.more.is-closing .more__sheet>*{animation:none}
@keyframes moreIn{from{opacity:0;filter:blur(14px);transform:translateY(18px) scale(.985)}to{opacity:1;filter:none;transform:none}}
@keyframes moreFade{from{opacity:0}to{opacity:1}}
@keyframes moreOut{from{opacity:1}to{opacity:0}}
.more__x{position:sticky;top:0;float:right;margin:-.5rem -.5rem 0 1rem;width:2.25rem;height:2.25rem;border-radius:50%;border:0;background:#E9E9E9;cursor:pointer}
.more__x::before,.more__x::after{content:"";position:absolute;left:50%;top:50%;width:12px;height:1px;background:var(--fg);transform:translate(-50%,-50%) rotate(45deg)}
.more__x::after{transform:translate(-50%,-50%) rotate(-45deg)}
.more__label{font-size:.75rem;color:#6F6F6F;margin:0 0 .5rem}
.more__title{font-size:1.125rem;font-weight:500;letter-spacing:-.015em;line-height:1.25;margin:0 0 1.5rem;max-width:26em;text-wrap:balance}
.more__plate{display:block;clear:both;width:100%;height:auto;aspect-ratio:900 / 272;object-fit:cover;margin:0 0 1.5rem}   /* a painting opens each sheet, as an image opens Mouthwash's */
.more__sheet p:not(.more__label){font-size:.9375rem;line-height:1.55;margin:0 0 1rem}
html:has(.more[open]){overflow:hidden}
/* Without script the sheets print inline under their line. */
html:not(.js) .chap__more,html:not(.js) .more__x{display:none}
html:not(.js) .more{display:block;position:static;border:0;padding:0;margin:0 auto;background:none;max-width:36em}
html:not(.js) .more__sheet{box-shadow:none;padding:0;width:auto;max-height:none}
html:not(.js) .more__label,html:not(.js) .more__title{display:none}
/* Bento (2026-09-28), narrowed after Mouthwash Studio and Studio Dumbar: 60rem wide, rows of a
   fixed shape (66/33, 33/66, halves, thirds, whole) 10px apart, square tiles on the tile grey.
   Screenshots and films (.b--inset) sit whole on the grey with a margin, so nothing is cropped;
   plates (.b--bleed) fill their tile; the mark sits centred. Each row's height comes from
   --row (its width over its height), so the tiles in it always line up. */
.bento{width:min(60rem,calc(100vw - 3rem));margin:0 0 0 50%;transform:translateX(-50%);display:grid;gap:10px}
.bento__row{display:grid;grid-template-columns:var(--cols);gap:10px;aspect-ratio:var(--row)}
.b{position:relative;margin:0;background:#E9E9E9;overflow:hidden;min-width:0;--d:calc(var(--i,0) * 55ms);--inset:clamp(14px,3vw,34px)}
.b picture{display:contents}
.b img,.b video{position:absolute;display:block;transition:transform .6s var(--ease)}
.b--inset img,.b--inset video{inset:var(--inset);width:calc(100% - var(--inset) * 2);height:calc(100% - var(--inset) * 2);object-fit:contain}
.b--bleed img,.b--bleed video{inset:0;width:100%;height:100%;object-fit:cover}
.b--mark{display:grid;place-items:center}
.b__word{display:block;width:72%;height:auto}
.b--mark>img{position:static;width:56%;height:auto}   /* a client's mark as an image (Freya) */
.b--mark:hover>img,.b:hover video[controls]{transform:none}   /* a mark and a film with controls hold still */
.b--close::after{content:"";position:absolute;inset:0;background:rgba(0,0,0,.4)}   /* the close's veil: white type over 40% black, no boxes */
.b__word--white{position:absolute;left:50%;top:50%;width:52%;transform:translate(-50%,-50%);color:#fff;z-index:1}
.b--edge::after{content:"";position:absolute;inset:0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.07);pointer-events:none}   /* the colours plate: its grey field is the tile grey, so it bleeds and takes a hairline */
.b:hover img,.b:hover video{transform:scale(1.03)}
.b video{background:transparent}
.bento__cap{font-size:.8125rem;line-height:1.5;color:#6F6F6F;max-width:40em;margin:.375rem 0 0}   /* inside the grid, so it starts on the tiles' edge */
.case__main--visual .jrn{width:min(60rem,calc(100vw - 3rem));margin-bottom:10px}
@media (max-width:700px){
  .bento{width:auto;margin-left:0;transform:none}
  .bento__row{grid-template-columns:minmax(0,1fr);aspect-ratio:auto}
  .b{aspect-ratio:var(--ar);--inset:12px}
}
@media (max-width:560px){.case__meta{grid-template-columns:1fr 1fr}.case__meta div:last-child{grid-column:1 / -1}.case__meta--sum div:last-child{grid-column:auto}.case__meta--sum div:nth-child(2){grid-column:1 / -1;order:3}.more__sheet{padding:1.375rem 1.25rem 1.5rem;max-height:calc(100svh - 3rem)}}
@media (prefers-reduced-motion:reduce){.more[open] .more__sheet,.more[open] .more__sheet>*,.more::backdrop,.more.is-closing .more__sheet{animation:none}.chap__more,.b img,.b video{transition:none}.b:hover img,.b:hover video{transform:none}}
