/* Artwork layout is viewport-agnostic and lives with the section rules in global.css.
   This import remains as a stable component boundary for future art-only refinements. */
/* Hero intro (set piece A), hero-owned styles.
   The logo and arrow are inline rig SVGs (they were an img and a picture), and
   the intro swaps the foreground picture for its inline rig while it plays.
   These rules give the SVGs exactly the boxes the images had; the section
   layout itself is unchanged in global.css. */
.hero-foreground > svg { display: block; width: 100%; height: 100%; overflow: visible; }
.hero-logo-desktop svg,
.hero-invitation-arrow svg { display: block; width: 100%; height: auto; overflow: visible; }

/* Full-bleed wrappers: .hero-stage takes the impact shake, the .hero-cam layers
   the camera dolly (sky at a shallower depth). At rest they change nothing. */
.hero-stage, .hero-cam { position: absolute; inset: 0; }
/* The camera moves whole planes, so only .hero clips. */
.hero-art-sky { overflow: visible; }
.hero-intro-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* The glyph float runs on each glyph's path, so the intro can transform the
   glyph group without fighting a CSS animation (and the handoff never pops).
   The group carries no translate/rotate either: GSAP would fold them into an
   inline transform that hides the intro's (motion.css). */
.motion-ready .hero [data-rig='letter'] { animation: none; translate: none !important; rotate: none !important; }
.motion-ready .hero [data-rig='letter'] > * { transform-box: fill-box; transform-origin: center; translate: 0 var(--float-y) !important; rotate: var(--float-r) !important; animation: letter-float var(--float-duration,4s) ease-in-out var(--float-delay,0s) infinite alternate; }

/* The crab starts walking during its shake-off, before section activity (and
   so the hero's other CSS loops) begins. */
.motion-ready .hero:not(.is-motion-active) .hero-crab.is-walking * { animation-play-state: running !important; }

/* The ambient sea (hero-sea.ts) animates the hero's water marks itself, with
   SVG attributes (crisp on the GPU), so their CSS shimmer stays off here. */
.motion-ready .hero .water-mark { animation: none; }

/* The crab's "Don't touch me!" bubble (hero-crab-bubble.ts): built on demand
   inside the crab button, placed and shown by script, decorative. */
.hero-crab .crab-bubble { position: absolute; z-index: 1; display: block; visibility: hidden; pointer-events: none; }
.hero-crab .crab-bubble svg { position: static; width: 100%; height: 100%; }

/* Intro gate (see src/motion/pieces/hero-intro-gate.ts). The inline script adds
   .hero-intro-pending before first paint only when the intro will play; the
   piece removes it once frame 0 is rendered. Until then the hero shows the
   intro's opening frame: the purple void. No-JS and reduced motion never get
   the class, so they always see the static rest frame. */
html.hero-intro-pending .hero { background: var(--purple); }
html.hero-intro-pending .hero > :not(h1, script, .sr-only) { visibility: hidden; }
/* Manifesto motion states. Choreography: src/motion/pieces/manifesto.ts,
   storyboard: docs/v2-motion/manifesto.md.
   #about[data-manifesto]: "armed" (waiting to be seen), "play" (the timeline
   owns every pose), "rest" (finished; plain CSS, identical to the static page).
   No attribute (no-JS, reduced motion) is the authored composition. */

/* The vertical journey (client direction, 2026-10-09): the arrow points down
   to Jack. Same artwork, stroke weight and colour, turned so its head points
   straight down: it sweeps in from the page edge, loops and dives. Overrides
   global.css's sideways rotate(-90deg) / rotate(-96.91deg) and lifts the
   head clear of the section's bottom edge. */
.manifesto .manifesto-arrow { bottom: 4%; transform: rotate(-117deg); }
@media (max-width:1100px) and (orientation:portrait) {
  .manifesto .manifesto-arrow { bottom: 1.5%; transform: rotate(-117deg); }
}
/* Room for the arrow under the copy where the copy is as wide as the screen: the
   turned arrow's box is about 2.45 times its width tall, so the copy keeps that much
   (plus a margin) clear above the section's foot instead of running under the arrow. */
@media (max-width:599px) and (orientation:portrait) {
  section.manifesto.section-screen { padding-bottom: max(12dvh, calc(min(18vw,4.413rem) * 2.45 + 2dvh + .75rem)); }
}
@media (orientation:landscape) and (max-height:500px) {
  .manifesto .manifesto-arrow { width: min(clamp(5rem,8.86vw,8rem),13dvh); }
  section.manifesto.section-screen { padding-bottom: calc(13dvh * 2.45 + 4dvh + 1.25rem); }
}

/* The underline (global.css) is hidden while armed. */
.motion-ready .manifesto[data-manifesto="armed"] .manifesto-copy strong span { background-size: 0 0; }
/* While it draws: a flat cream cover (the section's own colour) sits over the
   right-hand part of the stroke and shrinks to nothing (--pen-cover 1 → 0). */
.motion-ready .manifesto[data-manifesto="play"] .manifesto-copy strong span:not([data-drawn]) {
  background:
    linear-gradient(var(--cream), var(--cream)) right bottom / calc(var(--pen-cover, 1) * 100%) .24em no-repeat,
    url('/images/derived/manifesto-underline.svg') left bottom / 100% .24em no-repeat;
}

/* Armed: the title and copy wait unseen (motion.css hides the arrow under
   .motion-ready); the timeline then owns every pose until rest. */
.motion-ready .manifesto[data-manifesto="armed"] :is(.manifesto-title > *, .manifesto-copy > :not(.sr-only)) { opacity: 0; }
.motion-ready .manifesto[data-manifesto="rest"] .manifesto-arrow :is(.draw-shaft, .draw-head) { stroke-dashoffset: 0; opacity: 1; }

/* The "status quo*" asterisk's twinkle: a twin glyph laid exactly over the
   original, on a cream patch that hides it while the twin spins. Wrapping the
   real character in an element would break its kerning and shift the line. */
.manifesto-star { position: absolute; display: block; overflow: visible; background: var(--cream); pointer-events: none; opacity: 0; }
.manifesto-star i { display: block; font-style: normal; text-align: left; white-space: pre; transform-origin: 50% 36%; }

/* Masked copy lines (manifesto.ts maskLines(), only while the reveal runs). */
.manifesto-line { display: block; }
.manifesto-line-mask { display: block; overflow: clip; }

/* Impact ticks for the verdict, drawn in the lettering's purple. */
.manifesto-fx { position: absolute; inset: 0; pointer-events: none; }
.manifesto-fx svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.manifesto-fx line { fill: none; stroke: var(--purple); stroke-width: 5; stroke-linecap: round; stroke-dasharray: 1 2; stroke-dashoffset: 1; opacity: 0; }
/* "Jack of all trades / Master of all": a full-screen panel between the
   manifesto and the services. Moved verbatim from the services panel rules;
   the computed composition is unchanged. */
.jack { position: relative; width: 100%; block-size: var(--screen-block); min-block-size: 30rem; overflow: hidden; background: var(--purple); color: var(--white); }
.jack > .section-stage { position: relative; top: var(--nav-height); width: 100%; height: var(--stage-height); }
.jack .service-intro-art { position: absolute; width: min(92%,calc(var(--stage-height) * 1.6)); left: 50%; top: 50%; transform: translate(-50%,-50%); }
.jack .service-intro-art svg { display: block; width: 100%; height: auto; }
.jack .intro-grain { position: absolute; inset: 0; pointer-events: none; }
.jack .intro-grain i { position: absolute; left: var(--grain-x); top: var(--grain-y); width: var(--grain-size); height: var(--grain-size); background: var(--deep-ink); opacity: .4; border-radius: 35% 60% 40% 25%; }
.motion-ready .jack.is-motion-active .intro-grain i { animation: grain-flicker 5.7s steps(1,end) var(--grain-delay) infinite; }
@keyframes grain-flicker { 0%,32%,83% { opacity: 0; } 15%,64% { opacity: .38; } 46%,95% { opacity: .18; } }
@media (max-width:1100px) and (orientation:portrait) {
  .jack .service-intro-art { width: 100%; }
}
@media (min-width:1101px), (min-width:600px) and (orientation:landscape) {
  .jack .service-intro-art.art-desktop { inset: 0; width: 100%; height: 100%; transform: none; display: grid; place-items: center; }
  .jack .service-intro-art.art-desktop svg { width: min(68vw, calc(var(--stage-height) * 1.25)); max-height: calc(var(--stage-height) - 3rem); }
}
@media (orientation:landscape) and (max-height:600px) {
  .jack { --screen-block: 100dvh; min-block-size: max(var(--screen-block), 25rem); }
  .jack > .section-stage { height: max(var(--stage-height), calc(25rem - var(--nav-height))); }
}
/*
 * The staged services scene (set piece C, src/motion/pieces/services.ts). The piece adds
 * .is-staged to #services: the four panels stack in one stage, pinned (sticky) over a run of
 * free scrolling (services-director.ts). No-JS and reduced motion never get the class and keep
 * the readable column of final compositions.
 */

/* The run. Jack's panel holds for its first stretch: the panel grows by the dwell and its stage
   sticks inside it (overflow: clip, unlike hidden, leaves sticky working; the stage keeps its
   place under the nav). The services section is laid over Jack's panel (it starts where Jack
   starts), as tall as the run plus one screen, and its stage sticks to the top of the viewport
   all the way. Over Jack's panel the section is clear; below it, the same purple. In-page links
   to #services land mid-Branding (scroll-margin-top, honoured by core/scroll.ts). */
.jack.is-svc-dwell { block-size: var(--svc-jack-block); min-block-size: 0; padding-top: var(--nav-height); overflow: clip; }
.jack.is-svc-dwell > .section-stage { position: sticky; }
.services.is-staged {
  margin-top: calc(-1 * var(--svc-overlap, 0px));
  block-size: var(--svc-block, auto);
  background: linear-gradient(to bottom, transparent var(--svc-overlap, 0px), var(--purple) var(--svc-overlap, 0px));
  scroll-margin-top: calc(-1 * var(--svc-anchor, 0px));
}
.services.is-staged .services-viewport { position: sticky; top: 0; }

.services.is-staged .services-track { position: relative; isolation: isolate; overflow: hidden; background: var(--purple); }
.services.is-staged .services-track > .service-panel { grid-area: 1 / 1; background: transparent; }
/* Until the entry has drawn the ground the stage is clear (Jack's panel shows through it) and
   takes no pointer. */
.services.is-staged.is-svc-clear .services-track { background: transparent; }
.services.is-staged.is-svc-clear .services-viewport { pointer-events: none; }
/* The stage keeps its own compositing layer: transitions only repaint what moves in it. */
.services.is-staged .services-track { will-change: transform; }

/* Until the shot is built, the stage shows the resting panel nearest to the scroll position. */
.services.is-staged:not(.is-built) .services-track > .service-panel:not(.is-svc-current) { visibility: hidden; }
/* Lifting reads every panel's art: one synchronous slice, never painted. */
.services.is-staged.is-lifting .services-track > .service-panel { visibility: visible !important; }

/* Built: one shared horizon replaces each panel's own sky. */
.services.is-built .service-panel .service-background { display: none; }
.services .svc-horizon, .services .svc-actors { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.services .svc-horizon { z-index: 0; }
.services .svc-horizon svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.services .svc-actors { z-index: 2; overflow: hidden; }

/* Lifted clones never run the art's CSS loops (their hand-offs must stay exact), and
   while staged the piece runs these loops itself, parked at rest (services-ambient.ts). */
.services .svc-actors *,
.services.is-staged :is(.steam-wisp, [data-rig='bottle'], [data-rig='cloud'], .water-mark) { animation: none !important; }

/* The progress marker: the four scenes as hand-drawn rings, the current one filled. Only with
   the staged scene (the column needs none), and only once the stage has drawn its ground: it
   comes and goes with the stage. A row at the bottom centre, where no scene has art or text
   (landscape: it moves left to keep clear of the text column, --svc-mark-shift from
   src/scripts/services-text.ts). Each mark is a button, 44px on touch screens; its name shows
   on hover and focus. */
.services .svc-marker { display: none; }
.services.is-staged .svc-marker {
  --svc-mark: 2.25rem;
  display: block; position: absolute; z-index: 5;
  left: calc(50% + var(--svc-mark-shift, 0px)); bottom: calc(max(6px, 1.2vh) + env(safe-area-inset-bottom, 0px)); translate: -50% 0;
  transition: opacity .3s ease, visibility 0s linear 0s;
}
@media (pointer: coarse) { .services.is-staged .svc-marker { --svc-mark: 2.75rem; } }
.services.is-staged.is-svc-clear .svc-marker:not(:focus-within) { opacity: 0; visibility: hidden; transition: opacity .2s ease, visibility 0s linear .2s; }
.services .svc-marker ol { display: flex; margin: 0; padding: 0; list-style: none; }
.services .svc-mark {
  position: relative; display: grid; place-items: center;
  inline-size: var(--svc-mark); block-size: var(--svc-mark); padding: 0; border: 0; border-radius: 50%;
  background: none; color: var(--cream); cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.services .svc-mark svg { display: block; inline-size: 1.125rem; block-size: 1.125rem; overflow: visible; transition: transform .35s cubic-bezier(.34, 1.56, .64, 1); }
.services .svc-mark path { fill: var(--purple); stroke: currentColor; stroke-width: 2.2px; transition: fill .2s ease; }
.services .svc-mark:hover path { fill: var(--electric-purple); }
.services .svc-mark[aria-current] svg { transform: scale(1.35); }
.services .svc-mark[aria-current] path { fill: var(--hot-pink); }
.services .svc-mark-name {
  position: absolute; left: 50%; bottom: calc(100% - 2px);
  padding: .35em .75em; border-radius: 999px; background: var(--deep-ink); color: var(--cream);
  font-size: .875rem; font-weight: 600; line-height: 1.2; white-space: nowrap;
  opacity: 0; pointer-events: none; translate: -50% 4px; transition: opacity .2s ease, translate .2s ease;
}
.services .svc-mark:is(:hover, :focus-visible) .svc-mark-name { opacity: 1; translate: -50% 0; }
/* Phones: as close to the bottom edge as is comfortable, to leave the copy room. */
@media (max-width: 599px) and (orientation: portrait) {
  .services.is-staged .svc-marker { bottom: calc(max(4px, .8dvh) + env(safe-area-inset-bottom, 0px)); }
}
/* Portrait tablets: the art reaches the bottom centre; the bottom-right corner is clear. */
@media (min-width: 600px) and (max-width: 1100px) and (orientation: portrait) {
  .services.is-staged .svc-marker { left: auto; right: max(6px, 1vw, calc(var(--svc-safe-r) + 6px)); translate: none; }
  .services .svc-marker li:nth-child(n + 3) .svc-mark-name { left: auto; right: 0; translate: 0 4px; }
  .services .svc-marker li:nth-child(n + 3) .svc-mark:is(:hover, :focus-visible) .svc-mark-name { translate: 0 0; }
}
/* A phone too short to leave it room under every scene's copy (services-text.ts). */
.services.is-staged[data-svc-mark='cramped'] .svc-marker { display: none; }
/* Phones on their side: that composition has no room for it (the page scrolls as ever). */
@media (orientation: landscape) and (max-height: 500px) {
  .services.is-staged .svc-marker { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .services .svc-mark svg:where(:root:not([data-motion="on"]), :root:not([data-motion="on"]) *), .services .svc-mark-name:where(:root:not([data-motion="on"]), :root:not([data-motion="on"]) *) { transition: none; }
}
.services .svc-mark svg:where([data-motion="off"], [data-motion="off"] *), .services .svc-mark-name:where([data-motion="off"], [data-motion="off"] *) { transition: none; }

/* One static viewport (services-scrub.ts). The stage is the small viewport (a phone's
   toolbars shown), so it never resizes as they come and go: the scene is composed for what is
   always visible, and below it the section's own purple continues the ground. */
.services.is-staged { --screen-block: 100svh; --stage-height: calc(100svh - var(--nav-height)); --stage-unit: calc(var(--stage-height) / 100); }
/* One text zone for every scene (src/scripts/services-text.ts zone mode; the art is placed
   around it, src/motion/pieces/services-compose.ts). Portrait phones: the title a comfortable gap
   under the nav, the copy at the bottom above the marker; the art fills the room between. */
/* Portrait tablets: their band of title and copy, a comfortable gap under the nav. */
@media (min-width: 600px) and (max-width: 1100px) and (orientation: portrait) {
  .services.is-staged .service-panel { --svc-title-y: max(28px, calc(var(--stage-unit) * 4.6)); }
}
@media (max-width: 599px) and (orientation: portrait) {
  .services.is-staged .service-panel {
    /* the site's one phone gutter (global.css): the copy takes a line less, the art the room */
    --col-x: max(var(--gutter-mobile), calc(max(var(--svc-safe-l), var(--svc-safe-r)) + 16px));
    --copy-y: var(--svc-copy-y, calc(var(--stage-unit) * 72.5));
    --svc-title-y: calc(var(--nav-height) + max(18px, 2.8svh));
  }
}
/* Work: a staggered vertical gallery (the vertical journey; no horizontal
   scrolling). Three columns on desktop with the middle column hung lower,
   centred between the outer two, so the downward arrow falls into the gap
   above it; two columns on mobile with the right one lowered. Cards keep their
   portrait ratio and rounded corners. Without JS, or with reduced motion, this
   is the whole composition. */
.work {
  container-type: inline-size;
  --work-gap: clamp(1rem, 4vw, 3.6rem);
  /* Card width is capped where it always was (22.5rem), so the photos keep
     their sharpness; wide screens centre the gallery and its heading. */
  --work-grid-w: min(100cqw - 2 * var(--section-gutter), 3 * 22.5rem + 2 * var(--work-gap));
  --work-col-w: calc((var(--work-grid-w) - 2 * var(--work-gap)) / 3);
  --work-tile-h: calc(var(--work-col-w) * 595 / 396);
  --work-top: clamp(2rem, 8dvh, 5rem);
  /* The middle column holds two cards (rows 3/2/3) and hangs centred. */
  --work-drop-2: calc(var(--work-tile-h) * .58 + var(--work-gap) / 2);
  --work-drop-3: calc(var(--work-tile-h) * .16);
  --work-arrow-w: clamp(4rem, 8.6vw, 7.75rem);
}
.work .work-heading { width: var(--work-grid-w); margin-inline: auto; }
.work .work-heading picture { pointer-events: none; }
.work .work-heading picture img { width: 100%; height: auto; }
/* The pen rig fills the same box as the image while it draws. */
.work .work-heading picture svg { display: block; width: 100%; height: auto; overflow: visible; }

.work .work-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--work-gap);
  width: var(--work-grid-w); margin: var(--work-top) auto 0; padding: 0 0 var(--work-drop-3); list-style: none;
}
/* Column drops are relative offsets: layout-neutral, and a property the motion
   never touches (GSAP folds a CSS translate into its own transform). */
.work .work-item { position: relative; min-width: 0; container-type: inline-size; }
.work .work-item:nth-child(3n + 2) { top: var(--work-drop-2); }
.work .work-item:nth-child(3n) { top: var(--work-drop-3); }
.work .work-item:nth-child(8) { grid-column: 3; top: var(--work-drop-3); }

.work .work-tile { position: relative; aspect-ratio: 396 / 595; overflow: hidden; border-radius: clamp(.75rem, 9cqi, 2rem); background: #ddd; }
.work .work-tile picture { display: block; width: 100%; height: 100%; }
.work .work-tile img { width: 100%; height: 100%; object-fit: cover; transition: transform 350ms ease, filter 250ms ease; }
@media (hover: hover) { .work .work-tile:hover img { transform: scale(1.025); filter: saturate(1.06); } }
/* While the piece drives hover (lift, tilt, zoom), the photo's transform is its own. */
.work .work-grid.is-live .work-tile img { transition: filter 250ms ease; }
.work .work-grid.is-live .work-tile:hover img { transform: none; }

/* Desktop: the arrow points straight down into the gap above the middle column. */
@media (min-width: 1101px), (orientation: landscape) {
  .work .work-heading picture {
    top: calc(100% + var(--work-top) + var(--work-drop-2) / 2 - var(--work-arrow-w) * .356);
    left: calc(50% - var(--work-arrow-w) / 2); width: var(--work-arrow-w); transform: rotate(-135deg);
  }
}
@media (max-width: 1100px) and (orientation: portrait) {
  .work {
    --work-gap: clamp(.875rem, 3.6vw, 1.75rem);
    --work-col-w: calc((var(--work-grid-w) - var(--work-gap)) / 2);
    --work-top: 9dvh;
    --work-drop-2: calc(var(--work-tile-h) * .42);
  }
  .work .work-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); padding-bottom: var(--work-drop-2); }
  .work .work-item:nth-child(n) { grid-column: auto; top: 0; }
  .work .work-item:nth-child(2n) { top: var(--work-drop-2); }
}

/* Linked cards (a published case study): the only cards that look clickable.
   Unlinked cards are unchanged.
   - A mouse (fine, hovering pointer) sees nothing at rest, so no artwork is
     covered: the purple arrow badge pops in at the bottom right when the card
     is hovered or keyboard-focused, then opens into "View case study".
   - Everywhere else (touch screens, which cannot hover) a small arrow chip sits
     at the top right, clear of the posters' own calls to action along the
     bottom. The whole card is the tap target; the chip is only a cue. */
.work .work-tile--link { display: block; color: inherit; text-decoration: none; }
.work .work-tile-cue {
  --cue: clamp(1.75rem, 11cqi, 2.25rem); --icon: 1rem; --cue-inset: clamp(.5rem, 4.5cqi, .9rem);
  position: absolute; z-index: 1; top: var(--cue-inset); right: var(--cue-inset); pointer-events: none;
  display: inline-flex; align-items: center; justify-content: center; min-width: var(--cue); height: var(--cue); padding: 0 calc((var(--cue) - var(--icon)) / 2);
  border-radius: 999px; background: var(--purple); color: var(--cream); font-size: .875rem; font-weight: 700; line-height: 1;
  box-shadow: 0 0 0 2px var(--cream);
}
.work .work-tile-cue svg { flex: none; width: var(--icon); height: var(--icon); fill: none; stroke: currentColor; stroke-width: 2.25; stroke-linecap: round; stroke-linejoin: round; }
.work .work-tile-cue-label { max-width: 0; overflow: hidden; white-space: nowrap; }
.work .work-tile--link:active img { filter: brightness(.94); }

@media (hover: hover) and (pointer: fine) {
  .work .work-tile-cue {
    --cue: clamp(2.25rem, 14cqi, 3rem); --icon: 1.2rem; --cue-inset: clamp(.6rem, 5cqi, 1.1rem);
    top: auto; bottom: var(--cue-inset); box-shadow: none;
    opacity: 0; transform: translate3d(0, .6rem, 0) scale(.55); transform-origin: 100% 100%;
    /* Away: quick and quiet. */
    transition: opacity 160ms ease-in, transform 200ms ease-in;
  }
  .work .work-tile-cue-label { transition: max-width 220ms ease-in, margin 220ms ease-in; }
  /* Towards: the card lifts first, the badge pops (a little overshoot, like the
     site's other cartoon beats), then it opens. */
  .work .work-tile--link:is(:hover, :focus-visible) .work-tile-cue {
    opacity: 1; transform: none;
    transition: opacity 140ms ease-out 50ms, transform 380ms cubic-bezier(.2, .9, .25, 1.4) 50ms;
  }
  .work .work-tile--link:is(:hover, :focus-visible) .work-tile-cue-label {
    max-width: 10rem; margin-right: .45rem;
    transition: max-width 420ms cubic-bezier(.2, .8, .2, 1) 150ms, margin 420ms cubic-bezier(.2, .8, .2, 1) 150ms;
  }
}
/* Reduced motion (and the Motion switch off): the badge is simply there, open, the instant the card is hovered or focused. */
@media (prefers-reduced-motion: reduce) {
  .work .work-tile-cue:where(:root:not([data-motion="on"]), :root:not([data-motion="on"]) *), .work .work-tile-cue-label:where(:root:not([data-motion="on"]), :root:not([data-motion="on"]) *), .work .work-tile--link:is(:hover, :focus-visible) .work-tile-cue:where(:root:not([data-motion="on"]), :root:not([data-motion="on"]) *), .work .work-tile--link:is(:hover, :focus-visible) .work-tile-cue-label:where(:root:not([data-motion="on"]), :root:not([data-motion="on"]) *) { transition: none !important; }
}
.work .work-tile-cue:where([data-motion="off"], [data-motion="off"] *), .work .work-tile-cue-label:where([data-motion="off"], [data-motion="off"] *), .work .work-tile--link:is(:hover, :focus-visible) .work-tile-cue:where([data-motion="off"], [data-motion="off"] *), .work .work-tile--link:is(:hover, :focus-visible) .work-tile-cue-label:where([data-motion="off"], [data-motion="off"] *) { transition: none !important; }
/* Clients: the logos sit still and read down the page (the vertical journey;
   no marquees). Desktop is the asymmetric field from global.css; mobile is a
   two-column stack with the right column hung half a row lower. */
.clients .clients-heading svg { display: block; width: 100%; height: auto; overflow: visible; }
.clients .client-field { margin: 0; padding: 0; list-style: none; }
/* The <picture> only switches the file; the logo stays the slot's grid item.
   A definite cell lets each logo's max-height: 100% hold it inside its slot. */
.clients .client-slot { grid-template: minmax(0,1fr) / minmax(0,1fr); }
.clients .client-slot picture { display: contents; }
@media (min-width:1101px), (min-width:700px) and (orientation:landscape) {
  .clients .clients-heading { top: max(calc(var(--nav-height) + 2.5rem),14%); left: 11%; }
  /* The pen arrow's head points straight down at the field below. */
  .clients .clients-heading picture { top: .15rem; left: calc(100% + 2.5rem); width: clamp(3.5rem,5vw,5.5rem); transform: rotate(132deg) scaleX(-1); }
}
/* Short landscape (phones): the stage already starts below the nav, so the heading
   sits just inside the stage's top rather than a further nav height down, which
   ran its second line into the logo field. */
@media (min-width:700px) and (orientation:landscape) and (max-height:500px) {
  .clients .clients-heading { top: max(1.25rem,6%); }
}
@media (max-width:1100px) and (orientation:portrait) {
  /* In flow, so a short phone grows the section instead of clipping a logo. */
  /* The stage sits a nav-height down (relative offset), so the section adds
     that much below it rather than clipping the stage's foot. */
  .clients.section-screen { block-size: auto; min-block-size: var(--screen-block); padding-bottom: var(--nav-height); }
  .clients > .section-stage { height: auto; min-height: var(--stage-height); padding: calc(var(--stage-unit) * 8) 0 max(1.5rem, calc(var(--stage-unit) * 4)); }
  .clients .clients-heading { position: relative; top: auto; left: auto; margin-left: 13.2%; }
  /* Under the heading, pointing down into the stack. */
  .clients .clients-heading picture { transform: rotate(132deg) scaleX(-1); }
  .clients .client-field {
    --row: clamp(6.5rem, 13.5dvh, 9rem);
    position: relative; top: auto; left: auto; width: 73.6%; height: auto; margin: clamp(6.5rem, 18vw, 8.5rem) 0 0 13.2%;
    grid-template-columns: repeat(2,minmax(0,1fr)); grid-template-rows: none; grid-auto-rows: var(--row);
    column-gap: 6vw; row-gap: 3.5dvh; padding-bottom: calc(var(--row) / 2);
  }
  /* A relative offset (half a row): the float animates transform, not this. */
  .clients .client-slot { position: relative; }
  .clients .client-slot:nth-child(2n) { top: 50%; }
  /* Optical boxes (as the mobile rows had them): wide wordmarks versus
     compact illustrated marks. */
  .clients .client-slot { --logo-size: clamp(5.5rem,12dvh,8rem); }
  .clients .client-slot .client-logo { width: 100%; height: 100%; object-fit: contain; }
  .clients .client-1 .client-logo { max-width: calc(var(--logo-size) * .98); max-height: var(--logo-size); }
  .clients .client-2 .client-logo { max-width: calc(var(--logo-size) * 1.05); max-height: calc(var(--logo-size) * 1.08); }
  .clients .client-3 .client-logo { max-width: calc(var(--logo-size) * 1.05); max-height: var(--logo-size); }
  .clients .client-4 .client-logo { max-width: calc(var(--logo-size) * 1.4); max-height: calc(var(--logo-size) * .65); }
  .clients .client-5 .client-logo { max-width: calc(var(--logo-size) * 1.4); max-height: calc(var(--logo-size) * .65); }
  .clients .client-6 .client-logo { max-width: calc(var(--logo-size) * 1.35); max-height: calc(var(--logo-size) * .72); }
}
/* Portrait tablets: the same staggered stack, sized for the screen. */
@media (min-width:600px) and (max-width:1100px) and (orientation:portrait) {
  .clients .clients-heading { margin-left: 14%; }
  .clients .client-field { --row: clamp(8rem,14dvh,13rem); width: 72%; margin-left: 14%; column-gap: 8vw; }
  .clients .client-slot { --logo-size: clamp(8rem,12.5dvh,12rem); }
}
/* Phones: the heading and the logo field sit on the one gutter (global.css). */
@media (max-width:599px) and (orientation:portrait) {
  .clients .clients-heading { margin-left: var(--gutter-mobile); }
  .clients .client-field { width: calc(100% - 2 * var(--gutter-mobile)); margin-left: var(--gutter-mobile); }
}
/* Large screens: the logo field keeps its 16:9 composition centred (global.css --box-*). */
@media (min-width:1921px) {
  .clients .clients-heading { left: calc(var(--box-x) + var(--box-w) * .11); }
  .clients .client-field { left: calc(var(--box-x) + var(--box-w) * .0826); width: calc(var(--box-w) * .8348); column-gap: calc(min(100vw, var(--screen-block) * 16 / 9) * .072); }
}
