/* Aura Chu — redesign concept. Mobile-first; breakpoints 640 / 900 / 1200. */

:root {
  /* One size for every section's lead paragraph (Hero, Definition, How We Work, Projects, About Me,
     Contact), a step smaller on phones. From tablets up the Hero's is larger (see .intro__lede). */
  --lead-size: 1.05rem;
  --maroon: #3F0910;   /* backgrounds and fills (About you, buttons) */
  --maroon-deep: #2C050B; /* contact + footer: a shade darker, so they feel set behind the page */
  --ink: #5E1823;      /* text: a lighter maroon, so it reads as maroon rather than near-black */
  --maroon-2: #57101A;
  /* Text is maroon or white only. Secondary tones are solid maroons, not transparent ones, which
     blend into the cream and read as grey-brown. */
  --ink-70: #7A3540;
  --ink-50: #9A5A63;
  --rule: rgb(63 9 16 / 0.14);
  /* One light, warm off-white for every light background (no pure white anywhere). */
  --paper: #F7F2EB;
  --wall: #ECE7E0; /* the plain wall at the top of the About Me photo, where About You ends */
  --paper-2: #EDE5DB;
  --charcoal: #141214;
  --cream: #F5F5F7;

  /* Serif for headlines and titles; a quiet sans for everything read as body text or UI.
     Swap either family here and the whole site follows. */
  --serif: "Cormorant Garamond", Georgia, serif;
  --sans: "Inter", system-ui, sans-serif;
  --body-weight: 300; /* reading text; UI labels, nav and buttons stay at 500 */
  --logo: var(--serif);
  --display: var(--serif);
  --text: var(--sans);
  --ui: var(--sans);

  --pad: 1.25rem;
  --header-h: 3.5rem;
  --story-bar-h: 3.75rem;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  /* 1% of the screen height. Every height here is sized from it, not from svh directly: on touch
     screens app.js pins it to pixels measured on load, so a phone's address bar sliding in or out
     (Firefox resizes even svh as its bottom bar moves) never resizes anything. */
  --vh: 1svh;
  /* The same with the address bar hidden (the tallest the screen gets), pinned the same way. */
  --lvh: 1lvh;
}
@media (min-width: 900px) { :root { --pad: 3rem; --header-h: 4rem; } }

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
/* Native smooth scrolling is the fallback; Lenis (app.js) takes over and needs it off. */
html.lenis { scroll-behavior: auto; }
html {
  scroll-behavior: smooth;
  scroll-padding-top: var(--header-h);
  scrollbar-color: rgb(63 9 16 / 0.45) transparent;
}
html:has(dialog[open]:modal) { overflow: hidden; }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font: var(--body-weight) 1rem/1.65 var(--text); -webkit-font-smoothing: antialiased;
}
img, video { display: block; max-width: 100%; }
h1, h2, h3, p, figure, dl, dd { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
::selection { background: var(--maroon); color: var(--paper); }
/* Dark sections reverse the highlight; maroon-on-maroon selection would be invisible. */
:is(.work, .contact, .footer, .viewer) ::selection { background: var(--cream); color: var(--ink); }
:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.icon { width: 1em; height: 1em; flex: 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: -3rem; left: 1rem; z-index: 99; padding: 0.6rem 1rem;
  background: var(--maroon); color: var(--paper); font: 500 0.8rem var(--ui); text-decoration: none;
}
.skip-link:focus { top: 1rem; }

.eyebrow, .label {
  font: 500 0.85rem/1.4 var(--ui); color: var(--ink-50);
}

.btn {
  display: inline-flex; align-items: center; gap: 0.6rem; padding: 0.95rem 1.4rem;
  border: 1px solid var(--maroon); border-radius: 0; cursor: pointer; text-decoration: none;
  font: 500 0.95rem var(--ui); letter-spacing: 0;
  transition: background-color 0.25s, color 0.25s, border-color 0.25s;
}
.btn .icon { transition: translate 0.25s var(--ease); }
.btn:hover .icon { translate: 0.25rem 0; }
.btn--solid { background: var(--maroon); color: var(--paper); }
.btn--solid:hover { background: var(--charcoal); border-color: var(--charcoal); }
.btn--line { color: var(--ink); background: transparent; }
.btn--line:hover { background: var(--maroon); color: var(--paper); }
.btn--line-light { color: var(--cream); border-color: rgb(245 245 247 / 0.7); background: transparent; }
.btn--line-light:hover { background: var(--cream); border-color: var(--cream); color: var(--ink); }
.btn--light { background: var(--paper); color: var(--ink); border-color: var(--paper); }
.btn--light:hover { background: transparent; color: var(--paper); }
.btn:disabled { opacity: 0.6; cursor: progress; }

.round-btn {
  display: inline-grid; place-items: center; width: 2.5rem; height: 2.5rem; flex: none;
  border: 1px solid var(--rule); border-radius: 50%; background: transparent; cursor: pointer;
  transition: background-color 0.2s, color 0.2s, border-color 0.2s;
}
.round-btn:hover { background: var(--maroon); border-color: var(--ink); color: var(--paper); }
.round-btn--light { border-color: rgb(245 245 247 / 0.3); color: var(--cream); }
.round-btn--light:hover { background: var(--cream); color: var(--charcoal); border-color: var(--cream); }

.link-btn {
  padding: 0; border: 0; background: none; cursor: pointer;
  text-decoration: underline; text-decoration-color: rgb(245 245 247 / 0.4); text-underline-offset: 0.2em;
}
.link-btn:hover { text-decoration-color: currentColor; }

/* ---------- Header ----------
   Over the hero. --p (0 → 1, set by app.js) runs from the top of the page until the hero has
   scrolled out of view, fading the bar from transparent to translucent white.
   Sticky at the top of .page (the header and <main>), so once the page's bottom edge reaches it, the
   page carries it up and away as Contact is uncovered. The browser does this in step with the scroll;
   moving it from a script lagged behind on phones. <main> is pulled up under it, so it takes no room.
   (The pull is on <main>, not a negative margin on the header: that would shrink the header's own
   box, which is what sticky keeps inside .page, and leave it stranded over Contact.) */
.page > main { margin-top: calc(-1 * var(--header-h)); }
.header {
  --p: 0;
  position: sticky; top: 0; z-index: 30; height: var(--header-h);
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding: 0 var(--pad);
  background: rgb(247 242 235 / calc(var(--p) * 0.62));
  -webkit-backdrop-filter: blur(calc(var(--p) * 16px)); backdrop-filter: blur(calc(var(--p) * 16px));
  border-bottom: 1px solid rgb(63 9 16 / calc(var(--p) * 0.12));
}
/* Over the maroon About you section the translucent bar would tint mauve, so it turns near-opaque there. */
.header.is-over-dark { background: rgb(247 242 235 / 0.97); transition: background-color 0.3s; }
.wordmark { font: 500 1.4rem/1 var(--logo); letter-spacing: -0.01em; color: inherit; text-decoration: none; }
.header__wordmark { grid-column: 2; font-size: 1.9rem; white-space: nowrap; }
.header__nav { display: flex; gap: 1rem; }
.header__nav--end { grid-column: 3; justify-self: end; }
.header__nav:not(.header__nav--end) { grid-column: 1; grid-row: 1; }
.header__nav a {
  font: 500 0.8rem var(--ui); text-transform: uppercase; letter-spacing: 0.19em; white-space: nowrap;
  color: var(--ink); text-decoration: none; padding: 0.4rem 0; border-bottom: 1px solid transparent;
  transition: border-color 0.2s;
}
.header__nav a:hover, .header__nav a[aria-current="true"] { border-bottom-color: var(--ink); }
/* Menu button (phones): two lines in a 44px tap target; they cross into an X while the menu is open. */
.menu-btn {
  --gap: 7px;
  display: none; grid-column: 3; justify-self: end; place-content: center; gap: var(--gap);
  width: 44px; height: 44px; margin-right: -9px; padding: 0; border: 0; background: none; cursor: pointer; color: var(--ink);
  transition: color 0.3s;
}
.menu-btn span { display: block; width: 26px; height: 1.6px; border-radius: 1px; background: currentColor; transition: translate 0.35s var(--ease), rotate 0.35s var(--ease); }
.menu-btn[aria-expanded="true"] span:first-child { translate: 0 calc((var(--gap) + 1.6px) / 2); rotate: 45deg; }
.menu-btn[aria-expanded="true"] span:last-child { translate: 0 calc((var(--gap) + 1.6px) / -2); rotate: -45deg; }
/* While the menu is open the header sits clear over it: no bar, cream wordmark and X. */
html.menu-open { overflow: hidden; }
/* The bar takes on the menu's maroon as the menu fades in (and back as it fades out), so the menu
   seems to fade in over everything and the page never shows through the bar meanwhile. */
html.menu-open .header { background: var(--maroon-deep); border-bottom-color: transparent; }
html:is(.menu-open, .menu-closing) .header { transition: background-color 0.3s ease, border-color 0.3s ease; }
html.menu-open .header__wordmark, html.menu-open .menu-btn { color: var(--cream); }
.header__wordmark { transition: color 0.3s; }

/* Phone menu: the dark maroon, fading in under the header. Links in the middle, separated by hairlines;
   the email and language switch at the foot. */
.menu {
  position: fixed; z-index: 25; /* under the header (30) */
  background: var(--maroon-deep); color: var(--cream);
  opacity: 0; transition: opacity 0.3s ease;
}
.menu[open] { display: flex; flex-direction: column; justify-content: space-between; padding: calc(var(--header-h) + 1rem) 2rem 2rem; }
.menu.is-open { opacity: 1; }
/* Opening moves focus to the menu itself (so Tab starts at its first link), without a visible ring. */
.menu:focus { outline: none; }
/* As it opens, the links fade in one after another, top to bottom, then the foot. Closing fades the
   whole menu at once. */
.menu :is(.menu__links a, .menu__foot) {
  opacity: 0; translate: 0 0.6rem;
  transition: opacity 0.3s ease, translate 0s 0.3s; /* closing: fade with the menu, then reset the drift */
}
.menu.is-open :is(.menu__links a, .menu__foot) {
  opacity: 1; translate: 0 0;
  transition: opacity 0.5s ease var(--delay, 0s), translate 0.6s var(--ease) var(--delay, 0s), color 0.2s;
}
.menu__links a:nth-child(1) { --delay: 0.08s; }
.menu__links a:nth-child(2) { --delay: 0.16s; }
.menu__links a:nth-child(3) { --delay: 0.24s; }
.menu__foot { --delay: 0.34s; }
.menu__links { display: grid; margin-block: auto; }
.menu__links a {
  padding: 1.15rem 0; border-top: 1px solid rgb(255 255 255 / 0.1);
  font: 400 2rem/1.15 var(--display); letter-spacing: 0;
  color: var(--cream); text-decoration: none; transition: color 0.2s;
}
.menu__links a:last-child { border-bottom: 1px solid rgb(255 255 255 / 0.1); }
.menu__links a:hover { color: rgb(245 245 247 / 0.6); }
.menu__foot { display: flex; justify-content: space-between; align-items: center; gap: 1rem; }
.menu__email {
  padding: 0.75rem 0; font: 500 0.72rem/1.3 var(--ui); text-transform: uppercase; letter-spacing: 0.14em;
  color: rgb(245 245 247 / 0.7); text-decoration: none;
}
.menu .lang-toggle { --w: 3.4em; font-size: 0.78rem; }
.menu .lang-toggle span { padding: 1em 0 0.95em 0.12em; } /* about 44px tall */
/* On the maroon: a faint light track, a pale thumb, and dark lettering on the thumb. */
.menu .lang-toggle { background: rgb(245 245 247 / 0.1); color: var(--cream); }
.menu .lang-toggle::before { background: rgb(245 245 247 / 0.92); box-shadow: none; }
.menu .lang-toggle span { transition: opacity 0.35s, color 0.35s; }
.menu .lang-toggle span.is-current { color: var(--maroon-deep); }
@media (prefers-reduced-motion: reduce) { .menu, .menu-btn span, .menu.is-open :is(.menu__links a, .menu__foot) { transition: none; } }

/* EN / FR switch: a faint tinted track with a pale thumb that slides behind the current language.
   Kept light so it sits quietly beside the links. */
.lang-toggle {
  --w: 3em; /* each half */
  position: relative; display: inline-grid; grid-auto-flow: column; grid-auto-columns: var(--w);
  align-self: center; padding: 2px; border: 0; border-radius: 999px; background: rgb(94 24 35 / 0.07);
  cursor: pointer; font: 500 0.8rem/1 var(--ui); letter-spacing: 0.14em; color: var(--ink); /* the nav links' size */
}
.lang-toggle::before {
  content: ""; position: absolute; top: 2px; bottom: 2px; left: 2px; width: var(--w); border-radius: 999px;
  background: rgb(255 255 255 / 0.85); box-shadow: 0 1px 2px rgb(44 5 11 / 0.12);
  transition: translate 0.35s var(--ease);
}
.lang-toggle[data-current="fr"]::before { translate: 100% 0; }
.lang-toggle span {
  position: relative; padding: 0.62em 0 0.57em 0.12em; /* the extra left pad balances the letter-spacing */
  text-align: center; opacity: 0.5; transition: opacity 0.35s;
}
.lang-toggle span.is-current, .lang-toggle:hover span { opacity: 1; }
.lang-toggle:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .lang-toggle::before, .lang-toggle span { transition: none; } }
/* Phones: no room for two links + wordmark + one link in a row, so the left pair stacks. */
@media (max-width: 639px) {
  /* A slightly smaller bar on phones, to leave more of the screen to the page. */
  :root { --header-h: 3.1rem; }
  .header__wordmark { font-size: 1.5rem; }
  .menu-btn { --gap: 6px; }
  .menu-btn span { width: 22px; }
  .header__nav:not(.header__nav--end) { flex-direction: column; gap: 0.15rem; }
  /* The links move into the menu; the bar keeps the wordmark and the menu button. */
  .header__nav { display: none; }
  .menu-btn { display: grid; }
}
@media (min-width: 900px) { .header__nav { gap: 2.25rem; } }

/* ---------- Intro: full-bleed portrait, statement set over its darker lower half ---------- */
.intro {
  position: relative; isolation: isolate; min-height: calc(100 * var(--vh));
  display: flex; align-items: flex-end; color: var(--cream);
}
.intro__bg {
  position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 0%;
}
.intro::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top, rgb(20 18 20 / 0.78) 0%, rgb(20 18 20 / 0.45) 35%, rgb(20 18 20 / 0) 65%);
}
.intro__text { padding: 0 var(--pad) 3rem; max-width: 52rem; }

.intro__title {
  font: 400 clamp(2.4rem, 8.5vw, 5.2rem)/1.03 var(--display); letter-spacing: -0.015em;
  text-wrap: balance;
}
.intro__title em { font-style: normal; }
.intro__lede { margin-top: 1.25rem; font-size: var(--lead-size); line-height: 1.55; color: rgb(245 245 247 / 0.88); }
/* Two balanced lines; the width is in em so it grows with the larger size from tablets up. */
.intro__lede { max-width: 39em; text-wrap: balance; }
/* From tablets up the Hero's paragraph is a step larger than the other sections' (phones keep them equal). */
@media (min-width: 640px) { .intro__lede { font-size: 1.12rem; } }
.intro__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }
/* A small arrow at the foot of the hero: a quiet cue that there's more below. */
.intro__down {
  display: inline-grid; place-items: center; width: 2.5rem; height: 4rem; margin: 0.6rem 0 0 -0.5rem;
  color: var(--cream); font-size: 2.6rem; opacity: 0.9; transition: opacity 0.2s;
  animation: down-drift 2.8s ease-in-out infinite;
}
.intro__down .icon { width: 0.6em; height: 1em; }
.intro__down:hover { opacity: 1; }
@keyframes down-drift { 0%, 100% { translate: 0 0; } 50% { translate: 0 0.3rem; } }

@media (min-width: 900px) {
  .intro__text { padding: 0 var(--pad) 4.5rem; }
  .intro__title { font-size: clamp(3.2rem, 5vw, 5.4rem); }
  .intro__lede { font-size: 1.2rem; }
}

/* ---------- Definition: what brand therapy is, and what it isn't ---------- */
.definition { padding: 5rem var(--pad); }
.definition h2 { font: 400 clamp(2.2rem, 4.6vw, 3.3rem)/1.05 var(--display); letter-spacing: -0.01em; }
.definition__lead { margin-top: 1.25rem; max-width: 36rem; font-size: var(--lead-size); line-height: 1.7; color: var(--ink-70); text-wrap: pretty; }
/* What we look at: four questions in two columns, each on its own ruled line. */
.definition__looks { list-style: none; margin: 2.25rem 0 0; padding: 0; display: grid; border-top: 1px solid var(--rule); }
.definition__looks li { padding: 1rem 0; border-bottom: 1px solid var(--rule); font: italic 400 1.35rem/1.35 var(--display); color: var(--ink); }
/* Desktop: the definition on the left, the questions down the right. */
@media (min-width: 900px) {
  .definition { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); column-gap: clamp(3rem, 7vw, 8rem); align-items: center; padding: 7.5rem var(--pad); }
  .definition__looks { margin-top: 0; }
  .definition__looks li { padding: 1.2rem 0; font-size: 1.5rem; }
}

/* ---------- Process: a timeline whose line draws itself in ---------- */
.process { padding: 4.5rem var(--pad) 5rem; background: var(--paper-2); }
.process h2 { font: 400 clamp(2.2rem, 4.6vw, 3.3rem)/1.05 var(--display); letter-spacing: -0.01em; }
.process__sub { margin-top: 0.9rem; max-width: 36rem; font-size: var(--lead-size); line-height: 1.6; color: var(--ink-70); }
.timeline { --draw: 1.6s; position: relative; list-style: none; margin: 3rem 0 0; padding: 0 0 0 2rem; display: grid; gap: 2.25rem; }
/* The line: down the left on phones, across the top on wider screens. It grows from its start. */
.timeline::before {
  content: ""; position: absolute; left: 0.3rem; top: 0.96rem; bottom: var(--tail, 0.5rem); width: 1px; background: var(--ink-50); /* --tail: stops at the last dot (app.js) */
  transform: scaleY(0); transform-origin: top; transition: transform var(--draw) cubic-bezier(0.65, 0, 0.35, 1);
}
.timeline.is-drawn::before { transform: scaleY(1); }
.timeline__step { position: relative; opacity: 0; translate: 0 0.5rem; transition: opacity 0.6s ease, translate 0.6s var(--ease); }
/* A small dot on the line for each step, level with the middle of its title. */
.timeline__step::before {
  content: ""; position: absolute; left: calc(-2rem + 0.3rem - 3.5px); top: calc(0.96rem - 4px); width: 8px; height: 8px; border-radius: 50%;
  background: var(--paper-2); border: 1px solid var(--ink);
}
.timeline.is-drawn .timeline__step { opacity: 1; translate: 0 0; }
/* Each step appears as the line reaches it. */
.timeline.is-drawn .timeline__step:nth-child(1) { transition-delay: 0.1s; }
.timeline.is-drawn .timeline__step:nth-child(2) { transition-delay: calc(var(--draw) * 0.33); }
.timeline.is-drawn .timeline__step:nth-child(3) { transition-delay: calc(var(--draw) * 0.62); }
.timeline.is-drawn .timeline__step:nth-child(4) { transition-delay: calc(var(--draw) * 0.9); }
.timeline__step h3 { font: 400 1.6rem/1.2 var(--display); }
.timeline__step p { margin-top: 0.5rem; max-width: 22rem; font-size: 1rem; line-height: 1.6; color: var(--ink-70); }
@media (min-width: 900px) {
  .process { padding: 7rem var(--pad); text-align: center; }
  .process__sub { margin-inline: auto; }
  .timeline { --gap: clamp(1.5rem, 3vw, 3rem); grid-template-columns: repeat(4, 1fr); gap: var(--gap); margin-top: 4rem; padding: 2.5rem 0 0; }
  /* Each step is centred in its column, so the line runs from the first dot to the last with equal
     space either side: a complete path, centred on the page. */
  .timeline { --half: calc((100% - 3 * var(--gap)) / 8); text-align: center; }
  .timeline::before { left: var(--half); right: var(--half); top: 0; bottom: auto; width: auto; height: 1px; transform: scaleX(0); transform-origin: left; }
  .timeline.is-drawn::before { transform: scaleX(1); }
  .timeline__step::before { left: calc(50% - 4px); top: calc(-2.5rem - 3.5px); }
  .timeline__step p { margin-inline: auto; }
  .timeline__step h3 { font-size: clamp(1.6rem, 2.1vw, 1.9rem); }
}
@media (prefers-reduced-motion: reduce) { .timeline::before, .timeline__step { transition: none; } }

/* ---------- About you: a pinned index of situations beside the Categories ---------- */
/* The Contact maroon at the top, easing lighter and slightly cooler toward the bottom as you scroll. */
/* One flat colour at a time that shifts as you scroll through, from the Contact maroon at the top to
   the wall colour at the top of the About Me photo. app.js sets --m (0 → 1, how far toward it) and switches
   the text to maroon (.is-light) once that reads better than cream. */
.work {
  --m: 0;
  color: var(--cream);
  background: color-mix(in oklab, var(--maroon-deep), var(--wall) calc(var(--m) * 100%));
}
.usecase__title, .usecase__body, .usecase__you, .usecase__you span { transition: color 0.4s; }
.work.is-light .usecase__title, .work.is-light .usecase__you { color: var(--ink); }
.work.is-light .usecase__you span { color: var(--ink-50); }
.work.is-light .usecase__body { color: var(--ink-70); }
/* While the colour passes quickly through the mid-tones, every line shows at full strength. */
.work.is-mid .usecase__body, .work.is-mid .usecase__you span { color: var(--cream); }
.work.is-mid.is-light .usecase__body, .work.is-mid.is-light .usecase__you span { color: var(--ink); }
.index { display: none; }
@media (min-width: 1100px) {
  /* The bottom padding lives on the section, not the last Category, so the grid area (and with it the
     sticky index) ends exactly at the last Project card's bottom edge. */
  .work { display: grid; grid-template-columns: minmax(18.5rem, 3.4fr) 8fr; column-gap: clamp(2rem, 4vw, 4rem); padding: 0 0 6.5rem var(--pad); }
  .previews .usecase:last-child { padding-bottom: 0; }
  .index {
    /* Pins below the fixed header, so "You are…" then sits the same distance (6.5rem) below the
       header as it does below the top of the section. */
    display: block; position: sticky; top: var(--header-h); align-self: start;
    padding: 6.5rem 0 0;
  }
  .index__lead { font: 400 1.6rem/1.2 var(--display); color: rgb(245 245 247 / 0.62); transition: color 0.4s; }
  .work.is-light .index__lead { color: var(--ink-70); }
  .work.is-light .index__list a { color: var(--ink-70); border-left-color: var(--rule); }
  .work.is-light .index__list a:hover { color: var(--ink); }
  .work.is-light .index__list a[aria-current="true"] { color: var(--ink); border-left-color: var(--ink); }
  .work.is-mid .index__lead, .work.is-mid .index__list a { color: var(--cream); }
  .work.is-mid.is-light .index__lead, .work.is-mid.is-light .index__list a { color: var(--ink); }
  .index__list { list-style: none; margin: 1.25rem 0 0; padding: 0; display: grid; gap: 0.9rem; }
  .index__list a {
    display: block; padding-left: 1rem; border-left: 1px solid rgb(245 245 247 / 0.18);
    font: 400 1.5rem/1.3 var(--display); color: rgb(245 245 247 / 0.62); text-decoration: none;
    transition: color 0.3s, border-color 0.3s;
  }
  .index__list a:hover { color: rgb(245 245 247 / 0.85); }
  .index__list a[aria-current="true"] { color: var(--cream); border-left-color: var(--cream); }
  .previews { min-width: 0; }
  .previews .usecase { padding-left: 0; }
  .usecase__you { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
/* The situation phrase heading each Category where there's no index (phones, tablets). */
.usecase__you { grid-column: 1 / -1; font: 400 1.25rem/1.3 var(--display); color: var(--cream); }
.usecase__you span { display: block; font-size: 0.95rem; color: rgb(245 245 247 / 0.62); }

/* Each Category: the situation on top, a Project card from it underneath. */
.usecase { display: grid; gap: 2.5rem; padding: 4.5rem var(--pad); }
.usecase__title { max-width: 34rem; font: 400 clamp(2rem, 4.2vw, 3.1rem)/1.1 var(--display); text-wrap: balance; color: var(--cream); }
.usecase__body { margin-top: 1.5rem; max-width: 32rem; font-size: var(--lead-size); line-height: 1.7; color: rgb(245 245 247 / 0.78); }
.sample { padding: 1.5rem; background: var(--paper); color: var(--ink); }
.sample .label {
  width: fit-content; margin: 1.25rem 0 0.75rem; padding: 0.3rem 0.65rem;
  border: 1px solid currentColor; border-radius: 0.3rem;
  text-transform: uppercase; letter-spacing: 0.14em; font-size: 0.72rem; line-height: 1.2;
}
.sample__media { display: block; width: 100%; padding: 0; border: 0; background: var(--paper-2); cursor: pointer; }
.sample__media { aspect-ratio: 3 / 2; overflow: hidden; }
.sample__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; transition: transform 0.9s var(--ease); }
.sample__media:hover img { transform: scale(1.008); }
.sample__title { margin-top: 0.35rem; font: 500 1.6rem/1.15 var(--display); }
.sample__dek { margin-top: 0.4rem; max-width: 21rem; color: var(--ink-70); }
.sample .btn { margin-top: 1.25rem; }
@media (min-width: 900px) {
  .usecase + .usecase { border-top: 1px solid rgb(245 245 247 / 0.14); transition: border-color 0.4s; }
  .work.is-light .usecase + .usecase { border-top-color: var(--rule); }
  .usecase { gap: 3rem; padding: 6.5rem var(--pad); }
  /* Copy steps in from the card's width: the body a little narrower than the card, the headline a
     little narrower again. */
  .usecase__title { max-width: 78%; }
  .usecase__body { max-width: 88%; }
  .usecase__title { text-wrap: wrap; }
  /* With the full width to itself, the card lies on its side: photo left, details right. */
  .sample { display: grid; grid-template-columns: 7fr 5fr; gap: clamp(1.5rem, 3vw, 3rem); align-items: center; padding: 1.25rem; }
  .sample .label { margin-top: 0; color: var(--cream); }
}

/* ---------- Work: one case, laid out like a magazine feature ---------- */

.case__body { display: grid; gap: 2.5rem; padding: 3rem var(--pad) 5rem; }
.case__aside { border-top: 1px solid var(--maroon); padding-top: 1.5rem; }
.case__title { font: 500 2.5rem/1.05 var(--display); letter-spacing: -0.01em; }
.case__dek { margin-top: 0.55rem; font: var(--body-weight) 1.02rem/1.55 var(--text); color: var(--ink-70); }
.facts { display: grid; gap: 1.6rem; margin-top: 1.75rem; padding-top: 1.75rem; border-top: 1px solid var(--rule); }
.facts dt { font: 500 0.8rem var(--ui); color: var(--ink-50); }
.facts dd { margin-top: 0.15rem; font-size: 0.95rem; line-height: 1.45; }
.facts a { color: inherit; display: flex; align-items: center; gap: 0.3rem; width: fit-content; text-underline-offset: 0.2em; text-decoration-color: var(--rule); }
.facts a + a { margin-top: 0.3rem; }
.facts a:hover { text-decoration-color: currentColor; }
.facts a .icon { font-size: 0.75rem; }

.case__story { max-width: 40rem; }
.case__story p { font-size: 1rem; line-height: 1.75; color: var(--ink-70); hyphens: auto; -webkit-hyphens: auto; }
.case__story p + p { margin-top: 1.1rem; }

.group { margin-top: 3.5rem; }
.group .label {
  display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem;
  font: 400 1.25rem/1.2 var(--display); text-transform: none; letter-spacing: 0; color: var(--ink);
}
.group .label::after { content: ""; flex: 1; height: 1px; background: var(--rule); }

/* Gallery rows (layout decided in app.js): each row is full width with its own aspect ratio; items
   share its height and split its width unevenly. */
.gallery { display: flex; flex-direction: column; gap: 0.6rem; }
/* overflow: hidden stops a video's built-in size from stretching the row past its aspect ratio. */
.gallery__row { display: flex; gap: 0.6rem; overflow: hidden; }
.gallery__row .media { height: 100%; min-width: 0; aspect-ratio: auto; }
.media {
  position: relative; display: block; width: 100%; aspect-ratio: var(--w) / var(--h);
  padding: 0; border: 0; overflow: hidden; background: var(--paper-2);
}
.media img, .media video { width: 100%; height: 100%; object-fit: cover; }
button.media { cursor: pointer; }
button.media img { transition: transform 0.9s var(--ease), opacity 0.4s; }
button.media:hover img { transform: scale(1.008); }

/* A photo still loading when it scrolls into view fades in over its placeholder (app.js). An animation,
   not a transition, so it doesn't replace the hover zoom's transition on the same image. */
img.is-arriving { opacity: 0; }
img.is-arrived { animation: img-arrive 0.7s ease-in-out; }
@keyframes img-arrive { from { opacity: 0; } }

/* In-place video: plays muted while on screen; tap for sound. */
.media--video { cursor: pointer; background: var(--paper-2) center / cover no-repeat; }
/* The poster (the button's background) shows until the video is really playing, then it fades in. */
.media--video video { opacity: 0; transition: opacity 0.3s; }
.media--video.is-playing video { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .media--video video { opacity: 1; } }
.media__play {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgb(20 18 20 / 0); transition: background-color 0.3s;
}
.media__play .icon {
  font-size: 3.75rem; color: rgb(255 255 255 / 0.88); filter: drop-shadow(0 2px 10px rgb(0 0 0 / 0.4));
  transition: color 0.3s, transform 0.3s var(--ease);
}
.media--video:hover .media__play { background: rgb(20 18 20 / 0.15); }
.media--video:hover .media__play .icon { color: rgb(255 255 255 / 0.95); transform: scale(1.1); }
.case__lead { display: block; width: 100%; margin-bottom: 2.5rem; }

/* Previous / next Project: two halves of one bar (stacked on phones, next first). */
.case__nav {
  display: grid; margin-top: 4rem; border-top: 1px solid var(--maroon); border-bottom: 1px solid var(--rule);
}
.case__step {
  display: flex; align-items: center; gap: 1.5rem; padding: 1.75rem 0;
  border: 0; background: none; width: 100%; cursor: pointer; color: inherit; text-align: left;
}
.case__step small { display: block; font: 500 0.72rem var(--ui); text-transform: uppercase; letter-spacing: 0.14em; color: var(--ink-50); }
.case__step span { display: block; margin-top: 0.4rem; font: 400 clamp(1.25rem, 2.4vw, 1.6rem)/1.2 var(--display); }
.case__step small + span { margin-top: 0.4rem; }
.case__step > span { flex: 1; margin-top: 0; }
.case__step .icon { flex: none; font-size: 1.6rem; transition: translate 0.3s var(--ease); }
.case__step--prev .icon { rotate: 180deg; }
.case__step--next:hover .icon { translate: 0.4rem 0; }
.case__step--prev:hover .icon { translate: -0.4rem 0; }
.case__step--next { order: -1; }
.case__step--prev { border-top: 1px solid var(--rule); }
@media (min-width: 700px) {
  .case__nav { grid-template-columns: 1fr 1fr; }
  .case__step--next { order: 0; justify-content: flex-end; text-align: right; padding-left: 2rem; }
  .case__step--prev { border-top: 0; border-right: 1px solid var(--rule); padding-right: 2rem; }
}

@media (min-width: 900px) {
  .case__body { grid-template-columns: 4fr 8fr; gap: 4.5rem; padding: 4.5rem var(--pad) 7rem; }
  /* The project card stays put while the story and media scroll past it. */
  /* Pinned exactly where it starts (the bar plus the body's top padding), so it never shifts. */
  .case__aside { position: sticky; top: calc(var(--story-bar-h) + 4.5rem); align-self: start; }
  .case__title { font-size: 3rem; }
  .gallery, .gallery__row { gap: 0.9rem; }
}


/* ---------- Dropdown (dropdown.js): a site-styled list over a hidden native <select> ---------- */
.dd { position: relative; display: inline-block; max-width: 100%; vertical-align: baseline; }
.dd__button { display: inline-block; max-width: 100%; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: inherit; }
.dd__list {
  position: absolute; top: calc(100% + 0.5rem); left: 0; z-index: 40;
  min-width: max(100%, 14rem); max-width: min(26rem, calc(100vw - 2rem)); max-height: min(22rem, calc(60 * var(--vh))); overflow-y: auto;
  margin: 0; padding: 0.35rem; list-style: none;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--rule); box-shadow: 0 18px 40px -12px rgb(20 18 20 / 0.35);
  font: 400 1rem/1.35 var(--text); font-style: normal; letter-spacing: 0; text-transform: none;
  animation: dd-in 0.14s ease-out;
}
.dd__list.is-up { top: auto; bottom: calc(100% + 0.5rem); }
.dd__list:focus { outline: none; }
.dd__list li {
  position: relative; padding: 0.55rem 0.85rem 0.55rem 1.75rem; cursor: pointer; white-space: nowrap;
}
.dd__list li.is-active { background: var(--paper-2); }
/* Current choice: a small maroon mark, like a ribbon bookmark. */
.dd__list li[aria-selected="true"]::before {
  content: ""; position: absolute; left: 0.75rem; top: 50%; width: 0.4rem; height: 0.4rem;
  border-radius: 50%; background: var(--maroon); translate: 0 -50%;
}
@keyframes dd-in { from { opacity: 0; translate: 0 -0.25rem; } }

/* ---------- About: edge-to-edge photo; text sits on the open wall to the right of Aura ---------- */
.about { position: relative; isolation: isolate; background: var(--wall); }
/* The photo fades in from the colour About You ends on, so one section blends into the next. */
/* Not selectable: dragging a text selection past the copy would otherwise select (and tint) the photo. */
.about__bg {
  -webkit-user-select: none; user-select: none;
  display: block; aspect-ratio: 4 / 5; max-height: calc(75 * var(--vh)); width: 100%; overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 clamp(5rem, calc(16 * var(--vh)), 9rem));
  mask-image: linear-gradient(to bottom, transparent, #000 clamp(5rem, calc(16 * var(--vh)), 9rem));
}
.about__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 8%; }
.about__text { padding: 3rem var(--pad) 4.5rem; max-width: 40rem; }
.about h2 { font: italic 400 clamp(2.1rem, 5.5vw, 2.9rem)/1.18 var(--display); letter-spacing: -0.005em; text-wrap: balance; }
.about__text > p { margin-top: 1.25rem; font-size: var(--lead-size); line-height: 1.75; }
.about__text > h2 + p { margin-top: 2rem; }
.about__text > p + p { margin-top: 0.9rem; }
.about__more { margin-top: 1.75rem; }
/* Phones: the portrait shown at its own shape (3:4), so none of it is cropped. */
@media (max-width: 639px) { .about__bg { aspect-ratio: 1350 / 1800; max-height: none; } }
/* From tablets up the wide photo is never cropped top or bottom, so her feet stay in frame. Its fade
   is a share of its own height, so it always ends above her head. Positions and sizes below are in
   vw: the photo spans the full width, so its height is a fixed share of the width and everything on
   it scales together. In the photo, Aura and the chair end at about 40% of the width, and the floor
   starts at about 76% of the height. */
@media (min-width: 640px) and (max-width: 1199px) {
  .about__bg {
    --fade: linear-gradient(to bottom, transparent 0, rgb(0 0 0 / 0.3) 2%, rgb(0 0 0 / 0.7) 5%, rgb(0 0 0 / 0.93) 8%, #000 10%);
    -webkit-mask-image: var(--fade); mask-image: var(--fade);
  }
}
/* Small tablets: the wide photo shown whole, only the heading on the wall beside her, and the rest of
   the copy below. The heading is centred in the open wall (right of the chair, above the floor). */
@media (min-width: 640px) and (max-width: 899px) {
  .about { display: grid; grid-template-columns: 100%; }
  .about__bg, .about__text > * { grid-column: 1; }
  .about__bg { grid-row: 1; aspect-ratio: 2400 / 1579; max-height: none; }
  .about__text { display: contents; }
  /* Raised above the photo, whose fade mask paints it on a layer of its own. */
  .about h2 {
    position: relative; z-index: 1; grid-row: 1; align-self: start;
    /* Measured: the lines run 43.5vw wide, so a 48vw start leaves 8vw on either side of the open
       wall (40vw–100vw). 18vw down sits it a touch above the wall's middle, level with her face. */
    width: 44vw; margin: 18vw 0 0 48vw; font-size: 4.3vw;
  }
  .about__text > p, .about__more { justify-self: start; max-width: 40rem; margin-inline: var(--pad); }
  .about__text > h2 + p { margin-top: 2.5rem; }
  .about__more { margin-bottom: 4.5rem; }
}
/* Large tablets and desktop: all the copy on the wall beside Aura. The section is never shorter
   than the photo's own shape (nor than most of the screen), so the photo can only lose its sides,
   never her head or feet. The floor is always the bottom 24%, so a row of that height keeps the copy
   centred on the wall. Column 2 starts about where the chair ends. */
@media (min-width: 900px) {
  .about {
    display: grid; grid-template-columns: 2fr 3fr; grid-template-rows: 76fr 24fr;
    min-height: max(calc(100vw * 1579 / 2400), calc(90 * var(--vh)), 44rem);
  }
  .about__bg { position: absolute; inset: 0; z-index: -1; aspect-ratio: auto; max-height: none; }
  .about__bg img { object-position: 25% 50%; }
  .about__text { grid-column: 2; grid-row: 1; align-self: center; justify-self: center; padding: 2rem 0; }
}
@media (min-width: 900px) and (max-width: 1199px) {
  .about { min-height: calc(100vw * 1579 / 2400); }
  .about__bg img { object-position: 15% 50%; }
  .about__text { max-width: 34rem; padding-inline: 2.5rem; }
  .about h2 { font-size: 3.4vw; }
  .about__text > p { line-height: 1.7; }
  .about__text > h2 + p { margin-top: 1.5rem; }
}
@media (min-width: 1200px) {
  .about__text { max-width: 36rem; }
  .about h2 { font-size: clamp(2.3rem, 2.95vw, 3.25rem); }
}

/* ---------- Contact ---------- */
.contact {
  display: grid; gap: 3rem; padding: 4.5rem var(--pad);
  background: var(--maroon-deep); color: var(--cream);
  --soft: rgb(245 245 247 / 0.72);
  --faint: rgb(245 245 247 / 0.35);
}
.contact:focus { outline: none; } /* focused only from a script, when arriving from About Me on a phone */
.contact h2 { font: 400 clamp(2.6rem, 6vw, 4.2rem)/1.02 var(--display); letter-spacing: -0.01em; }
.contact__intro > p { margin-top: 1.25rem; max-width: 26rem; font-size: var(--lead-size); line-height: 1.6; color: var(--soft); }

/* Standard form: a label above every field, underlined inputs, generous spacing. */
/* Spacing follows screen height so the whole panel fits one laptop screen (needed for the pinned reveal). */
.form { display: grid; gap: clamp(1.3rem, calc(3 * var(--vh)), 2rem); }
.form__row { display: grid; gap: clamp(1.3rem, calc(3 * var(--vh)), 2rem); }
.field { display: block; }
.field > span {
  display: block; margin-bottom: 0.45rem;
  font: 500 0.72rem var(--ui); text-transform: uppercase; letter-spacing: 0.14em; color: var(--soft);
}
.field > span em { font-style: normal; text-transform: none; letter-spacing: 0.02em; }
.field :is(input, select, textarea, .dd__button) {
  display: block; width: 100%; padding: 0.55rem 0; border: 0; border-bottom: 1px solid var(--faint); border-radius: 0;
  background: transparent; color: var(--cream); font: var(--body-weight) 1.05rem/1.45 var(--text);
  transition: border-color 0.2s;
}
.field :is(input, select, textarea, .dd__button):hover { border-bottom-color: rgb(245 245 247 / 0.6); }
.field :is(input, select, textarea, .dd__button):focus { outline: none; border-bottom-color: var(--cream); }
.field :is(input, textarea):focus-visible, .field .dd__button:focus-visible { box-shadow: 0 1px 0 0 var(--cream); }
.field [aria-invalid="true"] { border-bottom-color: #F2A9A9; }
/* The label row also holds the field's inline error (right-aligned), so showing it never moves the form. */
.field > .field__head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
/* The clear (×) button inside a typed field. */
.field__box { position: relative; display: block; }
.field__box > :is(input, textarea) { padding-right: 2.25rem; }
.field__clear {
  position: absolute; right: -0.4rem; top: 50%; translate: 0 -50%; display: grid; place-items: center;
  width: 2.25rem; height: 2.25rem; padding: 0; border: 0; border-radius: 50%; background: none; cursor: pointer;
  color: rgb(245 245 247 / 0.55); font-size: 1rem; transition: color 0.2s;
}
.field__clear:hover, .field__clear:focus-visible { color: var(--cream); }
.field__box--area .field__clear { top: 0.35rem; right: 0.15rem; translate: none; }
.field__error { white-space: nowrap; font: 500 0.72rem var(--ui); text-transform: none; letter-spacing: 0.02em; color: #F2A9A9; }
.field :is(select, .dd__button) {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 1.5rem; text-align: left;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 9l6 6 6-6' fill='none' stroke='%23F5F5F7' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right center / 0.9rem;
}
.field select option { color: var(--ink); }
.field .dd { display: block; }
/* The open message is the main field: a framed box so it reads as "write here". */
.field--message textarea {
  min-height: clamp(6.5rem, calc(15 * var(--vh)), 9rem); padding: 0.85rem 1rem; resize: vertical;
  border: 1px solid var(--faint); background: rgb(245 245 247 / 0.04);
}
.field--message textarea:focus { border-color: var(--cream); }

.form__error { font: 500 0.85rem var(--ui); color: var(--cream); }
.form__send { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.75rem; margin-top: 0.85rem; }
.form__alt { font: var(--body-weight) 1rem var(--text); color: var(--soft); }
.form__alt a { color: var(--cream); text-underline-offset: 0.2em; text-decoration-color: var(--faint); }
.form__alt a:hover { text-decoration-color: currentColor; }
.form__alt .link-btn:hover { color: var(--cream); }

.sent:focus { outline: none; }
.sent__title { font: 400 2.6rem/1.1 var(--display); }
.sent__next { margin-top: 0.85rem; font-size: 1.15rem; line-height: 1.6; color: var(--soft); max-width: 34rem; }

@media (min-width: 640px) {
  .form__row { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 900px) {
  .contact { grid-template-columns: 5fr 7fr; column-gap: clamp(5rem, 9vw, 9rem); padding: clamp(2.5rem, calc(6 * var(--vh)), 7rem) var(--pad); }
}

/* ---------- Finale: contact + footer revealed from behind the page ----------
   <main> is lifted above (z-index 1, solid background, soft shadow along its bottom edge). The finale
   is sticky at the bottom of the viewport underneath it, so as <main> scrolls away the finale is
   uncovered in place, without moving. Only used on wider screens, when the finale fits on one screen
   (app.js); on phones it scrolls in like any other section, so a phone's address bar sliding in and
   out never moves it. */
main {
  position: relative; z-index: 1; background: var(--paper);
  /* --shadow (set by app.js) fades the shadow as the page's edge leaves the top of the screen. */
  box-shadow: 0 40px 70px -30px rgb(20 18 20 / calc(0.55 * var(--shadow, 1)));
}
.finale { position: relative; z-index: 0; background: var(--maroon-deep); }
.finale.is-reveal { position: sticky; bottom: 0; overflow: clip; }
.finale.is-reveal .finale__inner { min-height: calc(100 * var(--vh)); display: flex; flex-direction: column; }
.finale.is-reveal .contact { flex: 1; align-content: center; }

/* ---------- Footer ---------- */
/* Signature on the left, Back to top on the right: words and a small arrow on desktop, just a larger
   up arrow on phones. */
.footer {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; padding: 2rem var(--pad);
  background: var(--maroon-deep); color: rgb(245 245 247 / 0.6); font: 400 0.85rem var(--ui);
}
.footer__sign { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 2rem; }
.footer__short { display: none; }
.footer__end { display: flex; align-items: center; gap: 1.5rem; flex: none; }
.footer__top { flex: none; white-space: nowrap; transition: color 0.2s; }
/* The footer's language switch: on the dark maroon, hidden until the header has slid away. */
.footer__lang { background: rgb(245 245 247 / 0.1); color: var(--cream); opacity: 0; visibility: hidden; transition: opacity 0.4s ease, visibility 0s 0.4s; }
.footer__lang::before { background: rgb(245 245 247 / 0.92); box-shadow: none; }
.footer__lang span { transition: opacity 0.35s, color 0.35s; }
.footer__lang span.is-current { color: var(--maroon-deep); }
.footer__lang.is-shown { opacity: 1; visibility: visible; transition: opacity 0.4s ease; }
/* Switching language: the text fades out and back in around the change. */
/* Text only, so photos and backgrounds stay put. */
:is(main :is(h1, h2, h3, p, li:not(.timeline__step), .btn, .label, .index__list, .you-bar), .contact, .footer__sign, .footer__top, .header__nav a,
  #story-body :is(h2, h3, p, dl, .case__nav), #story-situation, .about-story__body, #about-story .story__situation, .menu__links, .menu__email) { transition: opacity 0.22s ease; }
html.lang-fading :is(main :is(h1, h2, h3, p, li:not(.timeline__step), .btn, .label, .index__list, .you-bar), .contact, .footer__sign, .footer__top, .header__nav a,
  #story-body :is(h2, h3, p, dl, .case__nav), #story-situation, .about-story__body, #about-story .story__situation, .menu__links, .menu__email) { opacity: 0; }
.footer__top .icon { display: none; }
.footer .wordmark { color: var(--cream); }
.footer a { color: inherit; text-decoration: none; }
/* Desktop: "tagline · © 2026" on one line. */
.footer a:hover { color: var(--cream); }

/* ---------- Full story panel: a full-screen page that rises gently into view ---------- */
/* Closing only fades it: the drift back down waits until it's invisible, ready for the next opening. */
.story[open] { display: block; }
.story {
  overflow-y: auto; overscroll-behavior: contain; background: var(--paper); color: var(--ink);
  opacity: 0; translate: 0 2.5rem; transition: opacity 0.35s ease, translate 0s 0.35s;
}
.story.is-open { opacity: 1; translate: 0 0; transition: opacity 0.35s ease, translate 0.45s var(--ease); }
/* Opening a panel focuses the panel itself, so its close button doesn't start out ringed; Tab still
   reaches the close button first, and Esc closes as before. */
.story:focus { outline: none; }
.story::backdrop { background: rgb(20 18 20 / 0.35); opacity: 0; transition: opacity 0.35s ease; }
/* The dimming fades with the panel; otherwise it snaps on before the panel appears and lingers after it leaves. */
.story.is-open::backdrop { opacity: 1; }
/* Fades out and back in when stepping to another Project inside the panel. */
.story__body { transition: opacity 0.28s ease; }
.story__body.is-fading { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .story__body { transition: none; } }
.story__bar {
  position: sticky; top: 0; z-index: 5; height: var(--story-bar-h);
  display: flex; align-items: center; justify-content: space-between; padding: 0 var(--pad);
  background: rgb(247 242 235 / 0.9); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--rule);
}
.story__situation { font: 500 0.72rem var(--ui); text-transform: uppercase; letter-spacing: 0.14em; color: var(--ink-50); }

/* ---------- About Me, in full: four chapters beside a pinned, crossfading photo ---------- */
.about-story__photos { display: none; }
.about-story__body { max-width: 40rem; margin: 0 auto; padding: 3rem var(--pad) 5rem; }
.about-story__chapter { margin-top: 4rem; }
.about-story__inline { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; margin-bottom: 1.75rem; background: var(--paper-2); }
.about-story__label { margin: 0 0 0.9rem; font: 400 1.7rem/1.2 var(--display); color: var(--ink); }
.about-story__chapter > p:not(.about-story__label) { font-size: 1rem; line-height: 1.8; color: var(--ink-70); }
.about-story__chapter > p:not(.about-story__label) + p { margin-top: 1.1rem; }
.about-story__link { margin-top: 1.4rem; }
.about-story__link a {
  display: inline-flex; align-items: baseline; gap: 0.45rem; color: var(--ink);
  text-decoration: none; border-bottom: 1px solid var(--rule); padding-bottom: 0.2rem; transition: border-color 0.2s;
}
.about-story__link a:hover { border-bottom-color: currentColor; }
.about-story__url { color: var(--ink-50); }
.about-story__link .icon { font-size: 0.8rem; align-self: center; }
.about-story__cta { margin-top: 2.25rem; }
/* The thin arrow that fades in under the chapter in view once scrolling pauses (app.js). */
/* Clickable: glides to the next chapter. Only takes clicks while it's showing. */
.about-story__hint {
  align-self: flex-start; display: grid; place-items: center; width: 2.5rem; height: 3.5rem; margin: 1.5rem 0 0 -0.7rem; padding: 0;
  border: 0; background: none; cursor: pointer; font-size: 2.6rem; color: var(--ink); opacity: 0; pointer-events: none; transition: opacity 0.6s ease;
  /* The drift runs all the time, hidden or not: stopping it as the arrow faded out made it jump, and
     changed how the browser drew it, nudging it sideways mid-fade. Only the opacity changes now. */
  animation: down-drift 2.8s ease-in-out infinite; will-change: opacity, translate;
}
.about-story__hint .icon { width: 0.6em; height: 1em; }
.about-story__hint.is-shown { opacity: 0.55; pointer-events: auto; }
.about-story__hint.is-shown:hover { opacity: 0.9; }
.about-story__cta, .about-story__link { align-self: flex-start; }
@media (min-width: 900px) {
  /* The photo stays pinned on the left while the chapters scroll on the right; it crossfades to each
     chapter's photo as that chapter reaches the middle of the screen. */
  .about-story__layout { display: grid; grid-template-columns: 5fr 6fr; }
  .about-story__photos {
    grid-column: 1; grid-row: 1; display: block; position: sticky; top: var(--story-bar-h); align-self: start;
    height: calc(100 * var(--vh) - var(--story-bar-h)); overflow: hidden; background: var(--paper-2);
  }
  .about-story__photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 0.9s ease; }
  .about-story__photo.is-on { opacity: 1; }
  .about-story__inline { display: none; }
  /* One chapter per screen, vertically centred. */
  .about-story__body { grid-column: 2; grid-row: 1; margin: 0; padding: 0 clamp(2.5rem, 5vw, 5rem); }
  .about-story__body > * { max-width: 40rem; }
  /* Text fades with distance from the middle of the screen (--focus, 1 → 0, set by app.js). */
  /* Not the arrow: it keeps its own hidden-until-pause opacity. */
  .about-story__chapter > :not(.about-story__inline, .about-story__hint) { opacity: calc(0.3 + 0.7 * var(--focus, 1)); }
  .about-story__chapter {
    position: relative; display: flex; flex-direction: column; justify-content: center;
    min-height: calc(100 * var(--vh) - var(--story-bar-h)); margin-top: 0; padding: 5rem 0;
  }
  /* Its own column on the right, pinned to the middle of the screen while the chapters scroll. */
}
@media (prefers-reduced-motion: reduce) { .about-story__photo { transition: none; } .about-story__hint { animation: none; } }
/* Leaving for Contact: the whole panel slides up off the screen, uncovering the form behind it. */
.about-story.is-leaving { translate: 0 -100%; transition: translate 0.75s cubic-bezier(0.65, 0, 0.35, 1); }
.about-story.is-leaving::backdrop { opacity: 0; transition-duration: 0.3s; }
@media (prefers-reduced-motion: reduce) { .about-story.is-leaving { transition: none; } }

/* ---------- Photo viewer ---------- */
dialog { padding: 0; border: 0; margin: 0; width: 100%; height: 100%; max-width: none; max-height: none; inset: 0; }
.viewer[open] { display: grid; grid-template-rows: auto 1fr auto; }
.viewer {
  background: var(--charcoal); color: var(--cream);
  opacity: 0; transition: opacity 0.25s;
}
.viewer.is-open { opacity: 1; }
.viewer::backdrop { background: transparent; }
.viewer__bar { display: flex; justify-content: space-between; align-items: center; padding: 1rem var(--pad); }
.viewer__count { font: 500 0.85rem var(--ui); color: rgb(245 245 247 / 0.6); font-variant-numeric: tabular-nums; }
.viewer__stage { position: relative; display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 1rem; padding: 0 var(--pad); min-height: 0; touch-action: pan-y pinch-zoom; }
.viewer__stage img {
  grid-column: 2; justify-self: center; max-width: 100%; max-height: 100%; min-height: 0;
  object-fit: contain; user-select: none; -webkit-user-drag: none; transition: opacity 0.2s;
}
.viewer__stage img.is-loading { opacity: 0; }
.player { grid-column: 2; justify-self: center; position: relative; max-width: 100%; max-height: 100%; min-height: 0; display: flex; background: #000; }
.player video { max-width: 100%; max-height: calc(100 * var(--vh) - 11rem); width: auto; height: auto; cursor: pointer; }
.player__controls {
  position: absolute; inset: auto 0 0; padding: 2.5rem 1rem 0.75rem;
  background: linear-gradient(to top, rgb(20 18 20 / 0.8), transparent); transition: opacity 0.3s;
}
.player.is-idle .player__controls { opacity: 0; pointer-events: none; }
.player.is-idle, .player.is-idle video { cursor: none; }
.player__scrub { padding: 0.5rem 0; cursor: pointer; touch-action: none; }
.player__track { position: relative; height: 2px; background: rgb(245 245 247 / 0.3); transition: height 0.15s; }
.player__scrub:is(:hover, :focus-visible, .is-scrubbing) .player__track { height: 4px; }
.player__fill { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--cream); }
.player__row { display: flex; align-items: center; gap: 1rem; margin-top: 0.25rem; }
.player__btn { display: grid; place-items: center; width: 2rem; height: 2rem; margin: 0 -0.25rem; padding: 0; border: 0; background: none; color: var(--cream); cursor: pointer; font-size: 0.95rem; }
.player__btn:last-child { margin-left: auto; }
.player__time { font: 500 0.75rem var(--ui); font-variant-numeric: tabular-nums; color: rgb(245 245 247 / 0.8); }
.viewer__step { display: none; }
@media (min-width: 640px) { .viewer__step { display: inline-grid; } }
.viewer__thumbs {
  display: flex; gap: 0.4rem; padding: 1rem var(--pad) 1.25rem; overflow-x: auto; scrollbar-width: none;
  justify-content: safe center;
}
.viewer__thumbs button { flex: none; height: 3.75rem; padding: 0; border: 0; background: none; opacity: 0.4; cursor: pointer; transition: opacity 0.2s; }
.viewer__thumbs button[aria-current="true"], .viewer__thumbs button:hover { opacity: 1; }
.viewer__thumbs button[aria-current="true"] { outline: 1px solid var(--cream); outline-offset: 2px; }
.viewer__thumbs img { height: 100%; width: auto; }
.viewer__thumbs button.is-video { position: relative; }
.viewer__thumbs button.is-video::after { content: "▶"; position: absolute; inset: 0; display: grid; place-items: center; color: rgb(255 255 255 / 0.85); font-size: 0.8rem; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ---------- Experiment: the Project photo fills the whole card, details laid over it ---------- */
.sample { position: relative; display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-start; padding: 0; overflow: hidden; aspect-ratio: 4 / 5; color: var(--cream); background: var(--maroon-deep); }
.sample__media { position: absolute; inset: 0; aspect-ratio: auto; }
/* A soft shade from the bottom keeps the text readable over any photo. */
.sample__media::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to top, rgb(28 4 8 / 0.9) 0%, rgb(28 4 8 / 0.7) 40%, rgb(28 4 8 / 0) 72%); pointer-events: none; }
.sample__info { position: relative; padding: 1.5rem; pointer-events: none; }
.sample__info .btn { pointer-events: auto; }
.sample .label { margin-top: 0; color: var(--cream); }
.sample__dek { color: rgb(245 245 247 / 0.82); }
.sample .btn--line { color: var(--cream); border-color: rgb(245 245 247 / 0.7); }
.sample .btn--line:hover { background: var(--cream); border-color: var(--cream); color: var(--ink); }
@media (min-width: 900px) {
  .sample { display: flex; align-items: flex-start; aspect-ratio: 16 / 9; padding: 0; }
  .sample__info { max-width: 34rem; padding: clamp(2rem, 3.5vw, 3rem); }
  .sample__media::after { background: linear-gradient(to top right, rgb(28 4 8 / 0.85) 0%, rgb(28 4 8 / 0.4) 40%, rgb(28 4 8 / 0) 70%); }
}

/* ---------- Phones and tablets (no Category index) ---------- */
@media (max-width: 1099px) {
  /* One "You are…" line pinned under the header, on the section's own (scroll-shifting) colour. */
  .you-bar {
    position: sticky; top: var(--header-h); z-index: 5;
    --bar-bg: color-mix(in oklab, var(--maroon-deep), var(--wall) calc(var(--m) * 100%));
    padding: 0.85rem var(--pad) 0.9rem; background: var(--bar-bg);
    border-bottom: 1px solid rgb(245 245 247 / 0.12);
  }
  .work.is-light .you-bar { border-bottom-color: var(--rule); }
  .you-bar__lead { display: block; font: 400 1.2rem/1.3 var(--display); color: rgb(245 245 247 / 0.62); transition: color 0.4s; }
  .you-bar__text { display: block; min-height: 1.3em; font: 400 1.6rem/1.25 var(--display); color: var(--cream); transition: opacity 0.22s ease, color 0.4s; }
  .you-bar__text.is-fading { opacity: 0; }
  .work.is-light .you-bar__lead { color: var(--ink-70); }
  .work.is-light .you-bar__text { color: var(--ink); }
  .work.is-mid .you-bar__lead { color: var(--cream); }
  .work.is-mid.is-light .you-bar__lead { color: var(--ink); }
  /* The bar names each Category, so its own heading is kept for screen readers only. */
  .usecase__you { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .usecase { padding-top: 3rem; }
}
@media (min-width: 1100px) { .you-bar { display: none; } }

/* ---------- Phones ---------- */
@media (max-width: 639px) {
  /* Body text a step smaller on a small screen, and buttons a touch smaller (still about 44px tall). */
  .btn { gap: 0.5rem; padding: 0.8rem 1.2rem; font-size: 0.88rem; }
  body { font-size: 0.92rem; }
  :root { --lead-size: 0.94rem; }
  .case__story p, .about-story__chapter > p:not(.about-story__label) { font-size: 0.92rem; }
  /* About Me panel: the first photo close under the bar. */
  .about-story__body { padding-top: 1.25rem; }
  .about-story__chapter:first-child { margin-top: 0; }
  .case__dek { font-size: 0.92rem; }
  .about__bg {
    --fade: linear-gradient(to bottom, transparent 0, rgb(0 0 0 / 0.3) 0.9rem, rgb(0 0 0 / 0.7) 2.1rem, rgb(0 0 0 / 0.93) 3.2rem, #000 4rem);
    -webkit-mask-image: var(--fade); mask-image: var(--fade);
  }
  .footer__sign { flex-direction: column; gap: 0.6rem; }
  /* Phones: one short line instead of the wordmark, tagline and year, and Back to top as just a larger
     up arrow. */
  .footer__sign > :not(.footer__short), .footer__top-label { display: none; }
  .footer__short { display: block; }
  /* No language switch in the footer on phones (the header's menu has one): with it there, pulling
     the page past its end would flash it into view. */
  .footer__lang { display: none; }
  /* Contact and footer together fill the screen (the tall one, with the address bar hidden), Contact
     centred in the space above the footer. */
  .finale__inner { min-height: calc(100 * var(--lvh)); display: flex; flex-direction: column; }
  .finale__inner .contact { flex: 1; align-content: center; }
  .footer__top { display: grid; place-items: center; width: 48px; height: 48px; margin-right: -12px; font-size: 2.1rem; }
  .footer__top .icon { display: block; rotate: 180deg; }
  /* A calm, short Contact on phones: the reply line without the cities, and the form without Timeline
     and "What's this about?" (both optional; their "Not sure yet" is still sent). */
  .contact__where, .form__row--pair { display: none; }
  .contact { gap: 2.25rem; padding: 3.5rem var(--pad) 2.5rem; }
  .contact h2 { font-size: 2.25rem; }
  .contact__intro > p { margin-top: 0.75rem; line-height: 1.5; }
  .form, .form__row { gap: 1.4rem; }
  .field > span { margin-bottom: 0.35rem; }
  .field :is(input, select, textarea, .dd__button) { padding: 0.45rem 0; font-size: 1rem; }
  .field--message textarea { min-height: 4.75rem; padding: 0.7rem 0.85rem; }
  .form__send { margin-top: 0.6rem; }
  .footer { padding: 1rem var(--pad) 1.25rem; }
}
