:root {
  --serif: "Times New Roman", Times, serif;
  --display: Palatino, "Palatino Linotype", "Book Antiqua", "URW Palladio L", serif;
  --gutter: 80px; /* left and right page margin */
  --rail: 376px; /* left rail width */
  --grid-gap: 24px; /* 12-column grid inside the page margins */
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { background: #fff; }
body {
  font-family: var(--serif);
  font-size: 20px;
  line-height: normal;
  color: #000;
  background: transparent;
  min-height: 100vh;
  position: relative;
}
a { color: inherit; text-decoration: none; }
/* Keyboard focus: a clear ring on links and buttons; programmatic focus targets (sections) stay quiet */
a:focus-visible, button:focus-visible { outline: 2px solid #000; outline-offset: 4px; border-radius: 2px; }
[tabindex="-1"]:focus { outline: none; }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.skip-link { position: fixed; top: 12px; left: 12px; z-index: 100; padding: 10px 16px; background: #fff; color: #000; border: 2px solid #000; border-radius: 4px; transform: translateY(-200%); }
.skip-link:focus { transform: none; }
.motion-toggle { left: 190px; font: inherit; cursor: pointer; }
@media (hover: hover) and (pointer: fine) { .about-loop { cursor: none; } }
em { font-style: italic; }

/* Shared page frame */
.page {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 100vh;
  padding: 150px var(--gutter) 50px;
}
.cols { display: flex; justify-content: space-between; align-items: flex-start; }
.side { position: sticky; top: 50px; align-self: flex-start; display: flex; flex-direction: column; gap: 100px; width: 376px; flex: none; }
.intro { display: flex; flex-direction: column; gap: 20px; }
.name { font: 400 32px var(--display); }
.desc { font-size: 15px; }
.note { font-size: 15px; }
.nav { display: flex; flex-direction: column; gap: 10px; font-size: 16px; }
.nav a:hover { text-decoration: underline; text-decoration-thickness: from-font; text-underline-position: from-font; }
.nav .current { font-style: italic; text-decoration: underline; text-decoration-thickness: from-font; text-underline-position: from-font; }
.main, .work { width: 1102px; flex: 0 1 1102px; min-width: 0; }
.foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  font: 400 14px var(--display);
  color: #555;
  margin-top: 100px;
}
.foot em { font-family: var(--display); }
.foot a:hover { text-decoration: underline; }

/* Home / work */
.work { position: relative; width: 100%; aspect-ratio: 1102 / 1760; }
.work .w { position: absolute; margin: 0; outline: none; transition: opacity .5s ease, filter .5s ease; }
.work .w img, .work .w1 video, .work .w2 video, .work .w3 video, .work .w4 video { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover;
  box-shadow: -60px 60px 70px rgba(67, 98, 124, .2); }
.work .w2 img, .work .w2 video { object-position: top; }
/* Card 1 stacks a still (loads first) under the animation, which fades in only while it plays (script.js) */
/* The still carries the shadow; the video sits over it, so its own shadow would double up while it plays */
.work .w video { box-shadow: none !important; }
.work .w1 .play, .work .w2 .play, .work .w3 .play, .work .w4 .play { opacity: 0; visibility: hidden; }
.work .w1.playing .play, .work .w2.playing .play, .work .w3.playing .play, .work .w4.playing .play { opacity: 1; visibility: visible; }
.work figcaption { position: absolute; top: 0; left: calc(100% + 48px); width: min(280px, 24vw); display: flex; flex-direction: column; gap: 8px;
  font-size: 18px; opacity: 0; filter: blur(8px); transform: translateY(8px); pointer-events: none;
  transition: opacity .5s ease, filter .5s ease, transform .5s ease; }
.work .w2 figcaption, .work .w4 figcaption { left: auto; right: calc(100% + 48px); text-align: right; }
.work figcaption strong { font-weight: 400; font-size: 24px; }
.work figcaption span { font-style: normal; }
.work figcaption small { font-size: 15px; color: #555; }
/* Hover or focus one image: the others blur back and its caption comes forward */
.work .w:focus-visible { outline: 2px solid #000; outline-offset: 8px; }
.work:has(.w:focus-visible) .w:not(:focus-visible) { opacity: .35; filter: blur(10px); }
/* Mouse hover only counts once the pointer has moved (script.js sets .hover-live), so a frame that lands under a resting cursor doesn't react */
.hover-live .work:has(.w:hover) .w:not(:hover) { opacity: .35; filter: blur(10px); }
/* The Optimly caption is long and the image sits mid-column, so it opens below the image */
.work .w3 figcaption { left: auto; right: calc(100% + 48px); text-align: right; }  /* opens to the card's left */
.hover-live .w:hover figcaption, .w:focus-visible figcaption { opacity: 1; filter: none; transform: none; }
.w1 { left: 21.960%; top: 0.000%; width: 21.779%; height: 30.398%; }
.w2 { left: 42.105%; top: 31.818%; width: 57.895%; height: 23.352%; }
/* Toshi Chen mockup: big enough to read (2932:1458 recording) */
.w3 { left: 11.978%; top: 57.386%; width: 57.985%; height: 18.068%; }
.w4 { left: 50.000%; top: 81.250%; width: 43.285%; height: 16.932%; }
/* Desktop: one frame at a time down the right column, the next peeking in below. Sizes are 15% up on the old collage. */
@media (min-width: 901px) {
  /* Even 150px between frames (script.js eases a frame to the centre when you stop close to it). */
  .work { aspect-ratio: auto; display: flex; flex-direction: column; container-type: inline-size; gap: 150px; padding-bottom: 20vh; }
  .work .w { position: relative; left: auto; top: auto; height: auto; }
  .work .w1 { --h: calc(39.1cqw * 535 / 240); width: 39.1%; aspect-ratio: 240 / 535; margin-left: 30.45%; }
  .work .w1 figcaption { left: auto; right: calc(100% + 48px); text-align: right; }  /* centred card: caption opens to its left, like the right-hand cards */
  .work .w2 { --h: calc(92cqw * 411 / 638); width: 92%; aspect-ratio: 638 / 411; margin-left: 8%; }
  .work .w3 { --h: calc(86cqw * 318 / 639); width: 86%; aspect-ratio: 639 / 318; margin-left: 0; }
  .work .w4 { --h: calc(80cqw * 298 / 477); width: 80%; aspect-ratio: 477 / 298; margin-left: 12%; }
  /* The handover is a one-off: script.js flips --out / --in and these play it on a timer. The old text
     leaves first, then the studio intro and the work section come in. */
  .hero video, .p-home .rail-a h1, .rail-a .phonetic, .rail-a .definition { transition: opacity .6s ease .45s, filter .6s ease .45s; }
  .studio, .rail-b, .fade-sec { transition: opacity .6s ease, filter .6s ease; }
  /* Going down the old text leaves first; coming back up the intro leaves first, so the two never overlap. */
  .handed-over .hero video, .handed-over .p-home .rail-a h1, .handed-over .rail-a .phonetic, .handed-over .rail-a .definition { transition-delay: 0s; }
  .handed-over .studio, .handed-over .rail-b, .handed-over .fade-sec { transition-delay: .45s; transition-duration: .8s; }
  .p-home .rail-a h1 { opacity: calc(1 - var(--out, 0)); filter: blur(calc(var(--out, 0) * 14px)); }  /* the title leaves with the definition */
  .p-home.rail-on .rail-a a { pointer-events: none; }
  /* The rail is click-through so it never blocks the page, so its text needs to opt back in to be selectable:
     the lockup while it is showing, the studio intro once it has taken over. */
  html:not(.handed-over) .rail-a > * { pointer-events: auto; }
  .handed-over .rail-b > :not(.nav) { pointer-events: auto; }
  .rail-a .studio { display: none; }
  /* Even 150px between work, About and Services */
  .work { padding-bottom: 0; }
  .p-home .sec { padding-top: 150px; }
  .p-home .sec-about { min-height: 0; }
  /* Services matches the About column: 500px, on the left edge of the right section */
  .p-home .sec-services { align-items: flex-start; }
  .p-home .sec-services .copy, .p-home .sec-services .services { max-width: 500px; }
  /* Last screen: Services + footer fill exactly one viewport at the end of the page, so no About shows above it */
  .p-home .sec-services { min-height: calc(100vh - var(--foot-h, 72px) - 50px); }
  /* Services starts level with the rail title; the margin keeps the 150px gap above it */
  .p-home .sec-services { padding-top: 65px; margin-top: 85px; }
  /* Fixed measure so the description breaks after "Seattle" */
  .rail-b .desc { width: 336px; }
  /* Hovering a frame also grows it 8% with a gentle ease */
  .work .w { transition: opacity .5s ease, filter .5s ease, transform .7s cubic-bezier(.22, .61, .36, 1); }
  .hover-live .work .w:hover, .work .w:focus-visible { transform: scale(1.08); z-index: 2; }
  /* The card grows 8% on hover; the caption shrinks back by the same factor so its text stays 18px, like About and Services */
  .work figcaption { transform-origin: 0 0; font-size: 18px; }
  .work .w1 figcaption, .work .w2 figcaption, .work .w3 figcaption, .work .w4 figcaption { transform-origin: 100% 0; }
  .hover-live .work .w:hover figcaption, .work .w:focus-visible figcaption { transform: scale(.926); }
  /* Hovering a frame also pushes the left rail back, like the other frames */
  .rail { transition: opacity .5s ease, filter .5s ease; }
  body:has(.work .w:focus-visible) .rail { opacity: .35; filter: blur(10px); }
  .hover-live body:has(.work .w:hover) .rail { opacity: .35; filter: blur(10px); }
}

/* About / Services sections (stacked below the work on the one long page) */
.sec { min-height: 100vh; padding-top: 150px; display: flex; flex-direction: column; align-items: center; gap: 50px; }
.sec .copy { width: 100%; }
.sec-about .copy { align-self: flex-start; max-width: 500px; font-size: 18px; } /* narrow measure, on the left edge of the right section */
.sec-services .copy { width: 100%; }
/* Last screen: Services plus the footer fill exactly one viewport, footer on the bottom edge. */
.sec-services { min-height: calc(100vh - 72px); }
.p-home .foot { margin-top: 0; }
.sec-about .copy p + p { margin-top: 1lh; }
.sec-about .copy p, .rail-a .definition, .work figcaption { text-wrap: pretty; }  /* no single short word left alone on the last line */
.about-loop { display: block; width: 100%; aspect-ratio: 3 / 1; object-fit: contain; object-position: center; flex: none;
  /* The dandelion sits ~79% across the clip: shift it onto the paragraph's centre, then
     scale up about the stem's base so it grows upward; margin-top reserves that room. */
  transform-origin: 79% 100%; transform: translateX(calc(250px - 79%)) scale(1.6); margin-top: 20%; }
.copy a { text-decoration: underline; text-decoration-thickness: from-font; text-decoration-skip-ink: none; text-underline-position: from-font; }
.sec-services { font-size: 18px; }  /* same body size as About */
.services { list-style: none; display: flex; flex-direction: column; gap: 56px; width: 100%; }
.services li { display: flex; align-items: flex-start; gap: 24px; }
.services li > span { flex: 0 0 50%; }
.services em { flex: 1; text-align: left; font-size: 14px; line-height: 1.7; color: #555; }  /* same as the note under the intro */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Smaller screens: collapse to a single column */
@media (max-width: 1677px) {
  .main, .work { width: auto; flex: 1; }
}
@media (max-width: 900px) {
  :root { --gutter: 24px; }
  .page { padding-top: 48px; }
  .cols { flex-direction: column; gap: 60px; }
  .side { width: 100%; gap: 48px; }
  .main { width: 100%; min-height: 0 !important; }
  .sec, .sec-services { min-height: 0; padding-top: 100px; }
  .p-home .foot { margin-top: 80px; }
  .work figcaption, .work .w2 figcaption, .work .w4 figcaption { top: 100%; left: 0; right: auto; width: 240px; margin-top: 16px; text-align: left; }
  .foot { flex-direction: column; align-items: flex-start; font-size: 14px; }
  .landing > * { width: 100%; }
}

/* Home: landing and work in one scroll. The rail starts as the definition,
   then hands over to the studio intro as you scroll (see script.js). */
.p-home .page { padding-top: 0; }
/* Right rail: columns 7-12 of the 12-column grid, i.e. half the content width minus half a gap. */
.p-home .stage { margin-left: auto; width: calc((100% - var(--grid-gap)) / 2); }
.p-home .work { width: 100%; }
.hero { position: relative; height: 100vh; margin: 0 calc(-1 * var(--gutter)); }
.hero video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; object-position: center bottom; background: #fff;
  /* Blown up about the bottom-right corner: only the empty top/left of the frame is trimmed. */
  transform-origin: 100% 100%; transform: scale(1.35);
  opacity: calc(1 - var(--out, 0)); filter: blur(calc(var(--out, 0) * 14px)); will-change: opacity, filter; }
.p-home .work { margin-top: 150px; }
.rail { position: fixed; top: 0; bottom: 0; left: var(--gutter); width: var(--rail); z-index: 2; pointer-events: none; }
.rail a { pointer-events: auto; }
.rail-a, .rail-b { position: absolute; left: 0; width: 100%; will-change: opacity, filter; }
/* Landing: the lockup sits vertically centred and simply blurs/fades out as the studio intro blurs in */
.rail-a { top: calc((100vh - var(--lh, 220px)) / 2); width: 384px; display: flex; flex-direction: column; gap: 20px; }
/* Opening beat: lines blur in once, then scroll takes over (see script.js) */
body.intro-wait .rail-a > * { opacity: 0 !important; filter: blur(14px) !important; }
.intro-play .rail-a > * { animation: intro-in 1.2s ease backwards; }
.intro-play .rail-a > :nth-child(2) { animation-delay: .35s; }
.intro-play .rail-a > :nth-child(3) { animation-delay: .7s; }
@keyframes intro-in { from { opacity: 0; filter: blur(14px); } }
/* "Verisimilitude" shrinks in place to the title size while " Studio" blurs in next to it,
   in step with the intro text blurring in (--in); the definition lines blur out first (--out). */
.rail-a h1 { font: 400 44px var(--display); white-space: nowrap; }
.rail-a h1 a { display: inline-block; }
.studio { display: inline-block; white-space: pre; opacity: var(--in, 0); filter: blur(calc((1 - var(--in, 0)) * 14px)); }
.rail-a .phonetic, .rail-a .definition { opacity: calc(1 - var(--out, 0)); filter: blur(calc(var(--out, 0) * 14px)); }
.rail-a .phonetic { font-style: italic; font-size: 24px; }
.rail-a .definition { font-size: 24px; margin-top: 20px; }
.rail-b { top: calc(var(--gutter) - 14px); position: absolute; opacity: var(--in, 0); filter: blur(calc((1 - var(--in, 0)) * 14px)); }
.rail-b .nav a { pointer-events: none; }
.p-home.rail-on .rail-b .nav a { pointer-events: auto; }
/* Larger screens: the full-height opening, filling the hero. It is 16:9 with the scene on the right and
   the left kept empty for the text and the drifting seeds, so a narrower window trims the left. */
.hero .hero-full { display: block; object-fit: cover; object-position: 100% 50%; transform: none; }
.hero .hero-phone { display: none; }
@media (prefers-reduced-motion: reduce) { .hero video { display: none; } }
/* Phones: the hero is one screen, text at the top, the animation in the middle and a
   "Scroll down" cue at the bottom; the studio intro follows below it. The rail and page
   wrappers dissolve (display: contents) so their children can be ordered in one column. */
.scroll-cue, .wash, .c-mob, .m-br { display: none; }
.topbar { display: none; }
@keyframes cue-nudge { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(7px); } }
@media (max-width: 900px) {
  .hero .hero-full { display: none; }
  .hero .hero-phone { display: block; }
  body.p-home { display: flex; flex-direction: column; }
  .rail, .page { display: contents; }
  /* Closing the gap: the hero is one screen tall at first, then its empty lower part shrinks away as you
     scroll (--hero-p eases from 0 to 1 over a screen of scrolling in script.js), so the Design studio block rises to meet the text lockup
     faster than the page scrolls. overflow-anchor is off so the browser doesn't undo the shift. */
  body.p-home { overflow-anchor: none; }
  .hero { order: 1; height: var(--hero-h); height: calc(var(--hero-h) - var(--hero-p, 0) * (var(--hero-h) - var(--hero-min))); margin: 0; overflow: hidden; }
  /* One group, centred vertically above the scroll cue: the visible animation, a 20px gap, then the
     text lockup. The phone clip is 1080x2160 and fills the hero from the top (the green runs the full height); its scene
     occupies the top --art-h (92.6vw), so the lockup sits right beneath it.
     --lh is the lockup's height (script.js keeps
     it current); --group-top is where the art starts. */
  /* Any screen height: the art + lockup group sits centred in the space above the scroll cue (--cue-h reserves the cue and a
     breathing gap), and the hero grows past one screen when the group plus cue would not fit, so they never overlap. */
  :root { --lh: 116px; --art-h: 92.593vw; --cue-h: 112px;
    --group-h: calc(var(--art-h) + 20px + var(--lh));
    --hero-h: max(100svh, calc(var(--group-h) + var(--cue-h)));
    --group-top: 0px;  /* the clip starts flush with the top of the screen (its opening frames are full-height green) */
    --hero-min: calc(var(--art-h) * .7); }  /* where the hero stops shrinking: the faded art is mostly gone by then, so the Studio statement rises close under the top bar */
  .hero video { inset: 0; width: 100%; height: 100%;
    object-fit: cover; object-position: 50% 0; transform: translateY(var(--group-top)); }
  .hero video { opacity: calc((1 - var(--out, 0)) * var(--vo, 1)); filter: blur(calc(var(--out, 0) * 14px + var(--vb, 0px))); }  /* plus its own near-the-top fade (--vo, --vb) */
  .rail-a { position: absolute; z-index: 3; top: calc(var(--group-top) + var(--art-h) + 20px); left: var(--gutter); right: var(--gutter); width: auto; gap: 4px; }
  .rail-a h1 { font-size: 34px; }
  .rail-a .phonetic, .rail-a .definition { font-size: 20px; margin-top: 0; }
  .rail-a .studio { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  /* Once the intro has played, each lockup line blurs and fades by its own height on the screen (--lo and
     --lb are set per line in script.js as the line nears the top). */
  body:not(.intro-play):not(.intro-wait) .rail-a > * { opacity: var(--lo, 1) !important; filter: blur(var(--lb, 0px)) !important; }
  /* Watercolour wash behind the scroll cue: pale yellow-green into stem green into dandelion blue-grey,
     drawn from the animation's palette. It sits faint at the bottom and, as you scroll, stretches
     upward like a brush stroke whose tip is drawn up past the "Design studio" block and ends with that section
     (--wash-s is the stretch, --wash its 0..1 strength, --wash-o the fade; all set in script.js). */
  .wash { display: block; position: fixed; z-index: 2; left: 50%; bottom: -4svh; width: 30vw; height: 20svh; margin-left: -15vw;
    border-radius: 50% 50% 46% 46% / 62% 62% 38% 38%; pointer-events: none;
    /* heaviest at the bottom edge and thinning toward the top, so the eye is pulled down the page */
    background: linear-gradient(to top, rgba(86, 114, 132, .95) 0%, rgba(118, 152, 118, .8) 28%, rgba(190, 208, 150, .5) 60%, rgba(226, 232, 190, .38) 100%);
    filter: blur(22px); opacity: calc(.78 * var(--wash-o, 1) + var(--wash, 0) * .08);
    transform-origin: 50% 100%; transform: scaleY(var(--wash-s, 1)); will-change: transform, opacity; }
  body.intro-wait .wash { opacity: 0; }
  .intro-play .wash { animation: intro-in 1.4s ease .9s backwards; }
  @media (prefers-reduced-motion: reduce) { .wash { transform: none; } }
  .scroll-cue { display: flex; flex-direction: column; align-items: center; gap: 6px; position: absolute; z-index: 4; left: 0; right: 0; bottom: calc(28px + env(safe-area-inset-bottom, 0px));
    font-style: italic; font-size: 18px; color: #000; pointer-events: none; opacity: var(--cue-o, 1); }
  body.intro-wait .scroll-cue { opacity: 0; }
  .scroll-cue span:last-child { display: inline-block; animation: cue-nudge 1.8s ease-in-out infinite; }
  @media (prefers-reduced-motion: reduce) { .scroll-cue span:last-child { animation: none; } }
  .intro-play .scroll-cue { animation: intro-in 1.2s ease .9s backwards; }
  .rail-b { order: 2; position: static; width: auto; margin: 24px var(--gutter) 96px;
    opacity: 1 !important; transform: none !important; filter: none !important; }
  /* Studio intro: no repeated title; the description is the centred hero statement */
  .rail-b { text-align: center; align-self: stretch; }  /* full width, so the centred text sits in the middle of the screen; 24px above, and 96px below before the first work card */
  .rail-b .name { display: none; }
  .rail-b .intro { align-items: center; gap: 24px; }
  .rail-b .desc { font: 400 26px/1.25 var(--display); text-wrap: pretty; }  /* centred, natural line lengths */
  .rail-b .note { max-width: none; text-wrap: balance; font-size: 16px; }  /* same size as the example descriptions */
  .rail-b .nav { display: none; }            /* the top bar carries About and Services */
  .rail-b .nav a { pointer-events: auto; }
  .p-home .stage { order: 3; margin: 0 var(--gutter); width: auto; }
  .p-home .foot { order: 4; margin: 0 var(--gutter) 24px; }
  .p-home .work { margin-top: 0; }
  /* Top bar: slides in once you scroll past the hero, title top left, section links right */
  .topbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; position: fixed; z-index: 10; top: 0; left: 0; right: 0;
    padding: calc(12px + env(safe-area-inset-top, 0px)) var(--gutter) 12px; background: rgba(255, 255, 255, .88);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); border-bottom: 1px solid rgba(0, 0, 0, .08);
    transform: translateY(-100%); opacity: 0; pointer-events: none; visibility: hidden; transition: transform .45s cubic-bezier(.2, .7, .3, 1), opacity .35s ease, visibility 0s .45s; }  /* hidden from keyboard and screen readers until it slides in */
  .topbar-on .topbar { transform: none; opacity: 1; pointer-events: auto; visibility: visible; transition-delay: 0s; }
  .topbar-title { font: 400 20px var(--display); white-space: nowrap; }
  .topbar-nav { display: flex; gap: 14px; font-size: 16px; white-space: nowrap; }
  .m-br { display: inline; }  /* the hero text lockup breaks into four set lines on phones */
  .m-hide { display: none; }  /* top bar: "Verisimilitude" and "Studio" only, so the bar fits one line */
  .topbar-nav a { padding: 8px 0; }
  .topbar-nav .current { font-style: italic; text-decoration: underline; text-decoration-thickness: from-font; text-underline-position: from-font; }
  .sec, .work { scroll-margin-top: 56px; }
}

/* Dandelion seeds (see script.js) float over the whole page */
.seeds { position: absolute; inset: 0; z-index: 5; overflow: hidden; pointer-events: none; opacity: var(--out, 0); }
.seeds span { position: absolute; display: block; line-height: 0; padding: 8px; margin: -8px; pointer-events: none; }
.seeds-on .seeds span { pointer-events: auto; }
.seeds i { display: block; transition: transform 1.4s cubic-bezier(.2, .7, .3, 1), opacity 1.4s ease; }
.seeds .blown i { transform: translate(180px, -120px) rotate(260deg); opacity: 0; }

/* Scroll-driven blur and fade between sections (see script.js) */
.fade-sec { opacity: var(--v, 1); filter: blur(calc((1 - var(--v, 1)) * 14px)); will-change: opacity, filter; }

/* Held during the opening beat so nothing scrolls until the definition appears */
html { scrollbar-gutter: stable; }
html.scroll-lock, html.scroll-lock body { overflow: hidden; }

/* Phones and small tablets: the work is a vertical carousel of rounded product-shot cards on a light
   gradient. The mobile product sits in a thin phone outline, the web products in a hairline window, both
   cropped off the card edge; the peach illustration is a plain corner crop. A round arrow button at
   each card's top right blurs the shot and reveals the description, and turns into a close button.
   Cards ease in and out of scale and opacity as they pass the middle of the screen (script.js sets
   --s, --o and --pan). */
@property --arrive { syntax: "<number>"; inherits: false; initial-value: 1; }
.work-toggle { display: none; }
@media (max-width: 900px) {
  .work { aspect-ratio: auto; display: flex; flex-direction: column; gap: 112px; }
  /* Each example is its frame with the description underneath (a grid: frame on top, caption below). All four
     are plain square frames. */
  .work .w { position: relative; left: auto; top: auto; width: 100%; height: auto; display: grid; grid-template-columns: 100%;
    transform: scale(var(--s, 1)); opacity: calc(var(--o, 1) * var(--arrive, 1)); translate: 0 calc((1 - var(--arrive, 1)) * 56px);
    filter: blur(var(--bl, 0px)); transition: none; }
  .work .w img, .work .w1 video, .work .w2 video, .work .w3 video, .work .w4 video { grid-area: 1 / 1; position: static; display: block; max-width: none; width: 100%; height: auto;
    object-fit: cover; object-position: top; border-radius: 0; box-shadow: 0 20px 44px rgba(20, 30, 50, .2); transition: filter .5s ease, scale .6s ease; }
  .work .w1 img, .work .w1 video { width: min(72%, 300px); justify-self: center; aspect-ratio: 412 / 917; border: 0; border-radius: 0; box-shadow: 0 20px 44px rgba(20, 30, 50, .2); }
  .work .w2 img, .work .w2 video { aspect-ratio: 1910 / 1230; }
  .work .w3 img, .work .w3 video { aspect-ratio: 2932 / 1458; }
  .work .w4 img, .work .w4 video { aspect-ratio: 2000 / 1250; }
  /* Arrival: as the work section scrolls in, each card slides up into place from 56px below while it
     fades in, one after another from the top card down (--d is its stagger delay). script.js adds
     .reveal-ready to <html> once it is watching, and .revealed to each card in turn. Without script
     the cards just show. */
  .reveal-ready .work .w:not(.revealed) { --arrive: 0; }
  .reveal-ready .work .w.revealed { --arrive: 1; transition: --arrive 1s cubic-bezier(.2, .7, .3, 1) var(--d, 0s); }
  .work figcaption, .work .w1 figcaption, .work .w2 figcaption, .work .w3 figcaption, .work .w4 figcaption {
    grid-area: 2 / 1; position: static; width: auto; justify-self: stretch; margin: 0; padding: 36px 0 0; display: flex; flex-direction: column; gap: 6px;
    font-size: 16px; text-align: center; opacity: 1; filter: none; transform: none; pointer-events: auto; transition: none; }
  .work figcaption strong { font-size: 18px; }
  .work figcaption span { font-style: italic; color: #555; }  /* the description takes the Services list style: italic, soft grey */
  .sec-about .copy, .sec-services { font-size: 16px; }  /* phone body text */
  .work-toggle { display: none !important; }  /* descriptions sit under each frame, no button */
  .work-toggle svg { grid-area: 1 / 1; width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
    transition: opacity .3s ease, transform .4s cubic-bezier(.2, .7, .3, 1); }
  .work-toggle .ic-close { opacity: 0; transform: rotate(-90deg); }
  .work .w.open .ic-arrow { opacity: 0; transform: rotate(90deg); }
  .work .w.open .ic-close { opacity: 1; transform: none; }
  .work:has(.w:focus-visible) .w:not(:focus-visible) { opacity: calc(var(--o, 1) * var(--arrive, 1)); filter: blur(var(--bl, 0px)); }
  @media (prefers-reduced-motion: reduce) { .work .w, .work .w img, .work figcaption, .work-toggle svg { transition: none; } .work .w img { translate: none; } .reveal-ready .work .w:not(.revealed) { --arrive: 1; } }
  /* Comfortable tap targets for the text links */
  .nav { gap: 0; }
  .nav a { display: block; padding: 10px 0; }
  .foot a { display: inline-block; padding: 10px 0; }
  /* About dandelion, blown up: instead of scaling the whole 3:1 clip (which wasted space above it), crop
     it to a taller box and slide the clip so the bulb sits in the middle */
  .sec-about .copy { align-self: center; }  /* wider phones and small tablets: the 500px text column sits in the middle under the centred dandelion */
  /* The top of this frame is empty until the seeds fly into it, so it tucks up under the last example (margin % is of the column
     width, so the overlap scales with the screen) instead of leaving a tall blank gap. It is decorative and click-through. */
  .about-loop { aspect-ratio: 1 / 1; object-fit: cover; object-position: 93.6% 50%; transform: none; margin-top: -12%; mix-blend-mode: multiply; pointer-events: none; }  /* bulb centred, about 3x the clip */
  /* Services/contact is its own full-height screen: the section fills the viewport above the footer
     (script.js sets --foot-h), its content centred with generous space around it, and the footer
     sitting on the bottom edge. */
  .sec-services { min-height: calc(100vh - var(--foot-h, 180px)); min-height: calc(100svh - var(--foot-h, 180px));
    justify-content: flex-start; padding: 215px 0 0; margin-top: 0; }  /* contact lockup near the top; the services centre in the space below it */
  .services em { line-height: 2.2; }  /* a clear gap between each listed service */
  /* The same soft green oblong as behind the hero cue, now behind the contact lockup */
  .sec-services { position: relative; }
  .sec-services::before { content: ""; position: absolute; z-index: -1; left: 50%; top: 163px; width: 72vw; height: 190px; margin-left: -36vw;
    border-radius: 50% 50% 46% 46% / 62% 62% 38% 38%; pointer-events: none;
    background: linear-gradient(to top, rgba(128, 154, 170, .5) 0%, rgba(158, 188, 156, .42) 30%, rgba(208, 222, 178, .3) 62%, rgba(234, 240, 208, .16) 100%);
    filter: blur(28px); opacity: .7; }  /* softened: pale enough that black text stays well above 4.5:1 (see the contrast check in the notes) */
  .sec-services { gap: 0; }
  .sec-services .services { margin-block: auto; padding-block: 24px; }  /* centred between the contact lockup and the footer */
  /* Contact: the email is the big line, as wide as the column allows on one line (script.js sizes it),
     with the sentence below it */
  .c-desk { display: none; }
  .c-mob { display: block; margin-top: 14px; text-align: center; }
  .copy .big-email { display: block; white-space: nowrap; font-family: var(--display); line-height: 1.1; letter-spacing: -.01em;
    text-decoration-thickness: 1px; text-underline-offset: .12em; }  /* the email is sized up to fill the column, so a fixed hairline (from-font would scale with it) */
  /* Staggered blur-in for About and Services (script.js adds .stagger-ready, then .in piece by piece) */
  .stagger-ready .stagger:not(.in) { opacity: 0; filter: blur(14px); translate: 0 16px; }
  .stagger-ready .stagger.in { opacity: 1; filter: none; translate: none;
    transition: opacity 1s ease var(--d, 0s), filter 1s ease var(--d, 0s), translate 1s cubic-bezier(.2, .7, .3, 1) var(--d, 0s); }
  @media (prefers-reduced-motion: reduce) { .stagger-ready .stagger:not(.in) { opacity: 1; filter: none; translate: none; } }
}

@media (prefers-reduced-motion: reduce) {
  .hero video, .p-home .rail-a h1, .rail-a .phonetic, .rail-a .definition, .studio, .rail-b, .fade-sec, .rail, .work .w, .topbar { transition: none !important; }
}
