@charset "utf-8";

/* ==========================================================================
   Ibraheem Hassan — portfolio, second edition

   Visual system: one black ground, everything else floats on it.

   The first edition (kept at /v1/) alternated dark "field" and pale "sheet"
   grounds and spoke in drafting marks. This one is a single black: the
   black of the portrait clip, so the opening has no edge. On it sit a few
   kinds of object, and only these:

     type      large, light, upper-case titles with tight tracking; small,
               quiet grey text for everything that is read
     pills     outlined capsules for disciplines, scope and tools
     buttons   a filled grey button for the main action, an outlined ring
               beside a label for the second one, round buttons for arrows
     cards     rounded dark panels with a round icon disc, for things that
               come in sets
     pictures  rounded, black and white until the pointer is on them

   There is no accent colour. Hierarchy is carried by size, weight and grey.

   Contents
     1. Font              9. About             17. Work index
     2. Tokens           10. Expertise         18. Project pages
     3. Reset            11. Practice          19. CV
     4. Type             12. Experience        20. 404
     5. Shared parts     13. Record            21. Lightbox
     6. Navigation       14. Contact           22. Motion
     7. Opening          15. Footer            23. Reduced motion, no-JS,
     8. Selected work    16. Pictures              RTL, print
   ========================================================================== */


/* 1. Font ================================================================= */

@font-face {
  font-family: "Archivo";
  src: url("../fonts/archivo-latin-var.woff2") format("woff2-variations");
  font-weight: 100 900; font-stretch: 62% 125%; font-style: normal; font-display: swap;
}


/* 2. Tokens =============================================================== */

:root {
  /* The black of the portrait clip's own background, measured off its
     frames. Every ground on the site is this. */
  --void: #050505;
  --surface: #111111;
  --surface-2: #181818;
  --surface-3: #262626;

  --line: rgba(255, 255, 255, 0.08);
  --line-2: rgba(255, 255, 255, 0.16);
  --line-3: rgba(255, 255, 255, 0.34);

  --text: #f1f1f1;
  --muted: #8d8d8d;
  --faint: #5e5e5e;
  --paper: #ebebeb;          /* the ground drawings sit on */

  --sans: "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --t-display: clamp(3rem, 8.5vw, 8rem);
  --t-section: clamp(2.3rem, 1.1rem + 4.3vw, 4.7rem);
  --t-title: clamp(1.3rem, 1rem + 1vw, 1.95rem);
  --t-card: clamp(1.02rem, 0.96rem + 0.3vw, 1.2rem);
  --t-lede: clamp(1.05rem, 0.95rem + 0.5vw, 1.35rem);
  --t-body: clamp(0.95rem, 0.92rem + 0.15vw, 1.02rem);
  --t-small: 0.86rem;
  --t-tiny: 0.75rem;

  --gutter: clamp(1.25rem, 5.5vw, 7rem);
  --gap: clamp(1rem, 2vw, 1.75rem);
  --maxw: 1320px;
  --rail-h: 4rem;
  --section: clamp(5rem, 11vw, 10rem);

  --r-card: 20px;
  --r-img: 16px;
  --r-btn: 10px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --fast: 180ms;
  --mid: 420ms;

  /* Motion (section 22). Arrivals ease out — a quick start and a long,
     gentle stop; departures ease in and are shorter. Nothing overshoots. */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in: cubic-bezier(0.55, 0, 1, 0.45);
  --d-press: 160ms;
  --d-hover: 320ms;
  --d-enter: 640ms;
  --d-title: 950ms;
  --d-settle: 1200ms;

  color-scheme: dark;
}


/* 3. Reset ================================================================ */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-block-start: calc(var(--rail-h) + 1.5rem);
}

body {
  margin: 0;
  background: var(--void);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--t-body);
  font-weight: 360;
  line-height: 1.6;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
[hidden] { display: none !important; }

button {
  font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer;
}

ul, ol { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
h1, h2, h3, h4 { font-weight: inherit; }

:where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 3px;
  border-radius: 4px;
}

::selection { background: var(--text); color: var(--void); }

.skip-link {
  position: fixed; inset-block-start: 0.75rem; inset-inline-start: 0.75rem; z-index: 200;
  padding: 0.6rem 1.1rem; border-radius: 999px;
  background: var(--text); color: var(--void); font-size: var(--t-small);
  transform: translateY(-180%); transition: transform var(--fast) var(--ease);
}
.skip-link:focus { transform: none; }

/* Icons: one family, 16-unit grid, single stroke, no fills. */
.ic {
  width: 1em; height: 1em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}


/* 4. Type ================================================================= */

.display {
  font-size: var(--t-display); font-weight: 300; font-stretch: 100%;
  line-height: 0.9; letter-spacing: -0.05em; text-transform: uppercase;
}
.section__title {
  font-size: var(--t-section); font-weight: 300; font-stretch: 100%;
  line-height: 0.98; letter-spacing: -0.045em; text-transform: uppercase;
  text-wrap: balance;
}
.label {
  font-size: var(--t-tiny); font-weight: 450; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted);
}
.muted { color: var(--muted); }


/* 5. Shared parts ========================================================= */

.wrap { width: min(100% - (var(--gutter) * 2), var(--maxw)); margin-inline: auto; }

.section { position: relative; padding-block: var(--section); }

.section__head {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 1.25rem; align-items: end;
  margin-block-end: clamp(2.5rem, 5vw, 4.5rem);
}
.section__head > .section__title, .section__lead { grid-column: 1 / span 8; }
.section__lead { display: grid; gap: clamp(0.9rem, 2vw, 1.4rem); align-content: end; }
.section__no { font-size: var(--t-tiny); letter-spacing: 0.14em; color: var(--faint); font-variant-numeric: tabular-nums; }
.section__aside {
  grid-column: 9 / -1; justify-self: end; max-width: 36ch;
  color: var(--muted); font-size: var(--t-small); line-height: 1.65; text-wrap: pretty;
}
.carousel__nav { display: flex; gap: 0.6rem; }
@media (max-width: 900px) {
  .section__head > .section__title, .section__lead, .section__aside { grid-column: 1 / -1; justify-self: start; }
}

/* A part inside a section (Expertise inside About, Record inside
   Experience): a ruled head, smaller than a section title. */
.subsection { margin-block-start: clamp(4.5rem, 9vw, 7.5rem); }
.subhead {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  margin-block-end: clamp(1.75rem, 3.5vw, 2.75rem);
  padding-block-start: clamp(1.25rem, 2.5vw, 2rem); border-block-start: 1px solid var(--line);
}
.subhead__title {
  font-size: clamp(1.5rem, 1rem + 1.9vw, 2.6rem); font-weight: 300;
  line-height: 1; letter-spacing: -0.04em; text-transform: uppercase;
}

/* Pills: outlined capsules. */
.pills { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.pill {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.42rem 1rem; border: 1px solid var(--line-3); border-radius: 999px;
  font-size: var(--t-small); line-height: 1.25; color: var(--text); white-space: nowrap;
}
.pills--sm .pill { padding: 0.3rem 0.75rem; font-size: var(--t-tiny); border-color: var(--line-2); color: var(--muted); }
.pill--tiny { padding: 0.12rem 0.55rem; font-size: 0.68rem; margin-inline-start: 0.5rem; border-color: var(--line-2); color: var(--muted); }
.pill--link {
  text-decoration: none; min-height: 40px;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), scale var(--d-press) var(--ease-out);
}
.pill--link:hover { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.6); }

/* The main action: a filled grey button. */
.btn {
  display: inline-flex; align-items: center; gap: 0.6rem; min-height: 44px;
  padding: 0.7rem 1.4rem; border-radius: var(--r-btn);
  background: var(--surface-3); border: 1px solid rgba(255, 255, 255, 0.07);
  color: var(--text); font-size: var(--t-small); font-weight: 460; text-decoration: none;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              scale var(--d-press) var(--ease-out);
}
.btn:hover { background: #333; border-color: rgba(255, 255, 255, 0.14); }
.btn--ghost { background: transparent; border-color: var(--line-2); }
.btn--ghost:hover { background: rgba(255, 255, 255, 0.06); }

/* The second action: a label beside an outlined ring. */
.iconlink {
  display: inline-flex; align-items: center; gap: 0.75rem; min-height: 44px;
  color: var(--text); font-size: var(--t-small); font-weight: 460; text-decoration: none;
}
.iconlink__ring {
  display: grid; place-items: center; width: 2.1rem; height: 2.1rem;
  border: 1px solid var(--line-3); border-radius: 50%;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease), border-color var(--fast) var(--ease),
              scale var(--d-press) var(--ease-out);
}
.iconlink:hover .iconlink__ring, .iconlink:focus-visible .iconlink__ring {
  background: var(--text); border-color: var(--text); color: var(--void);
}

/* A quiet link inside text blocks. */
.textlink {
  display: inline-flex; align-items: center; gap: 0.5rem;
  color: var(--text); font-size: var(--t-small); font-weight: 480; text-decoration: none;
  padding-block: 0.3rem; background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition: background-size var(--mid) var(--ease);
}
.textlink:hover, .textlink:focus-visible { background-size: 100% 1px; }
.textlink .ic { transition: transform var(--mid) var(--ease); }
.textlink:hover .ic { transform: translateX(0.2rem); }

/* Round buttons, for arrows. */
.roundbtn {
  display: grid; place-items: center; flex: none;
  width: 2.75rem; height: 2.75rem; border-radius: 50%;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--text);
  transition: background var(--fast) var(--ease), opacity var(--fast) var(--ease), scale var(--d-press) var(--ease-out);
}
.roundbtn:hover:not(:disabled) { background: var(--surface-3); }
.roundbtn:disabled { opacity: 0.3; cursor: default; }

/* Cards: rounded dark panels with a round icon disc. */
.card {
  position: relative; display: flex; flex-direction: column; align-items: center;
  gap: 0.85rem; text-align: center;
  padding: clamp(1.75rem, 3vw, 2.5rem) clamp(1.25rem, 2.5vw, 2rem) clamp(1.4rem, 2.5vw, 2rem);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, #171717, #0f0f0f);
  border: 1px solid rgba(255, 255, 255, 0.05);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
  min-height: 17rem;
}
.card__icon {
  display: grid; place-items: center; width: 3.1rem; height: 3.1rem; margin-block-end: 0.55rem;
  border-radius: 50%; background: var(--surface-3); border: 1px solid var(--line-2);
}
.card__icon .ic { width: 1.3rem; height: 1.3rem; }
.card__title { font-size: var(--t-card); font-weight: 440; letter-spacing: -0.01em; line-height: 1.25; }
.card__text { max-width: 30ch; color: var(--muted); font-size: var(--t-small); line-height: 1.65; text-wrap: pretty; }
.card__no { margin-block-start: auto; padding-block-start: 1rem; font-size: var(--t-tiny); letter-spacing: 0.1em; color: var(--faint); }

/* Panels: the same surface, for blocks of reading. */
.panel {
  border-radius: var(--r-card); background: var(--surface);
  border: 1px solid rgba(255, 255, 255, 0.05);
  padding: clamp(1.4rem, 2.5vw, 2rem);
}
.panel__title { margin-block-end: 0.75rem; font-size: var(--t-small); font-weight: 460; color: var(--muted); }

.list li { padding-block: 0.8rem; border-block-end: 1px solid var(--line); text-wrap: pretty; }
.list li:first-child { padding-block-start: 0; }
.list li:last-child { border-block-end: 0; padding-block-end: 0; }
.list b { display: block; font-weight: 480; }
.list span { display: block; margin-block-start: 0.2rem; color: var(--muted); font-size: var(--t-small); line-height: 1.55; }

.facts div {
  display: grid; grid-template-columns: minmax(6.5rem, 0.5fr) 1fr; gap: 0.3rem 1rem;
  padding-block: 0.75rem; border-block-end: 1px solid var(--line); font-size: var(--t-small);
}
.facts div:first-child { padding-block-start: 0; }
.facts div:last-child { border-block-end: 0; padding-block-end: 0; }
.facts dt { color: var(--muted); }
.facts dd { margin: 0; }

.duties { display: grid; gap: 0.5rem; }
.duties li {
  position: relative; padding-inline-start: 1.1rem;
  color: var(--muted); font-size: var(--t-small); line-height: 1.6; text-wrap: pretty;
}
.duties li::before {
  content: ""; position: absolute; inset-inline-start: 0; inset-block-start: 0.75em;
  width: 0.4rem; height: 1px; background: var(--faint);
}

.hairline {
  display: block; height: 1px; margin-block: clamp(1.5rem, 3vw, 2.25rem);
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.03));
}


/* 6. Navigation =========================================================== */

.nav {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 90;
  height: var(--rail-h);
  background: rgb(5 5 5 / 0.72);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-block-end: 1px solid var(--line);
}
.nav__inner {
  width: min(100% - (var(--gutter) * 2), var(--maxw)); height: 100%;
  margin-inline: auto; display: flex; align-items: center; gap: 2rem;
}
.nav__name {
  margin-inline-end: auto; font-size: 0.98rem; font-weight: 500;
  letter-spacing: -0.01em; text-decoration: none;
}
.nav__links { display: flex; align-items: center; gap: clamp(1rem, 2.4vw, 2.1rem); }
.nav__links a {
  font-size: var(--t-small); color: var(--muted); text-decoration: none;
  transition: color var(--fast) var(--ease);
}
.nav__links a:hover, .nav__links a[aria-current] { color: var(--text); }
.nav__links .nav__cta {
  color: var(--text); padding: 0.45rem 1.05rem;
  border: 1px solid var(--line-3); border-radius: 999px;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.nav__links .nav__cta:hover { background: var(--text); color: var(--void); }

.nav__toggle {
  display: none; align-items: center; gap: 0.6rem; min-height: 40px;
  padding: 0.4rem 1rem; border: 1px solid var(--line-3); border-radius: 999px;
  font-size: var(--t-small);
}
.nav__glyph { display: grid; gap: 5px; width: 16px; }
.nav__glyph i {
  display: block; height: 1px; background: currentColor;
  transition: transform var(--fast) var(--ease);
}
.nav__toggle[aria-expanded="true"] .nav__glyph i:nth-child(1) { transform: translateY(3px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__glyph i:nth-child(2) { transform: translateY(-3px) rotate(-45deg); }

.drawer {
  position: fixed; inset-block-start: var(--rail-h); inset-inline: 0; z-index: 89;
  display: none; padding: 1rem var(--gutter) 1.75rem;
  background: rgb(5 5 5 / 0.96); border-block-end: 1px solid var(--line);
  clip-path: inset(0 0 100% 0); transition: clip-path var(--mid) var(--ease);
}
.drawer[data-open] { clip-path: inset(0 0 0 0); }
.drawer a {
  display: block; padding-block: 0.8rem; border-block-end: 1px solid var(--line);
  font-size: 1.6rem; font-weight: 300; letter-spacing: -0.03em;
  text-transform: uppercase; text-decoration: none;
}
.drawer a:last-child { border-block-end: 0; }
.drawer__no {
  display: inline-block; width: 2.75rem; vertical-align: 0.35em;
  font-size: var(--t-tiny); letter-spacing: 0.1em; color: var(--faint);
}

@media (max-width: 860px) {
  .nav__links { display: none; }
  .nav__toggle { display: inline-flex; }
  .drawer { display: block; }
}


/* 7. Opening ============================================================== */

/* The first screen is his portrait: a clip in which only the light moves.
   Name, title and the actions are live text in the dark to its left, so
   they are there before any pixel of the picture arrives. The clip is
   driven by scroll: going down runs it forward, coming back up runs it in
   reverse. While it runs, the portrait holds and the text scrolls away;
   then the selected work comes up from below and the portrait lifts a few
   pixels and fades. The portrait layer is sticky; the page is not. Nothing
   is pinned and the page moves at exactly the speed the visitor scrolls.

   --edge is the left edge of every .wrap; the text stands on it.
   --figure-start is where the seated figure begins in the rendered frame,
   worked out from the clip's own geometry, which the generator writes onto
   .opening. The frame covers the screen with object-position 100%, so any
   crop comes off the empty left, and the text column stops short of it. */
.opening {
  container-type: inline-size;
  position: relative;
  background: var(--void);

  --edge: max(var(--gutter), (100cqw - var(--maxw)) / 2);
  --col-gap: clamp(1.5rem, 3vw, 3rem);
  --frame-w: max(100cqw, 100svh * var(--frame-ratio, 1.75));
  --figure-start: calc(100cqw - (1 - var(--figure-x0, 0.53)) * var(--frame-w));
}

/* The track spans the whole opening; the portrait sticks inside it, so it
   holds still while the hero and the selected work pass over it. */
.opening__track { position: absolute; inset: 0; pointer-events: none; }
.opening__media { position: sticky; inset-block-start: 0; height: 100svh; overflow: clip; }
.opening__portrait {
  position: absolute; inset: 0;
  opacity: calc(1 - var(--exit, 0));
  transform: translate3d(0, calc(var(--exit, 0) * -2.5svh), 0);
}

.hero__img,
.hero__video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 100% 30%;
}

/* The clip is a layer over the still, transparent until it has decoded the
   frame for the current scroll position. */
.hero__video { opacity: 0; transition: opacity 900ms cubic-bezier(0.4, 0, 0.2, 1); }
.hero__video.is-ready { opacity: 1; }

.hero__veil {
  position: absolute; inset: 0;
  background:
    linear-gradient(to right, rgb(5 5 5 / 0.6), rgb(5 5 5 / 0) 48%),
    linear-gradient(to top, var(--void), rgb(5 5 5 / 0) 26%);
}

/* The stretch of scroll the clip runs over. It only exists once site.js has
   the clip to run (data-scrub). */
.opening__run { height: 0; }
.opening[data-scrub] .opening__run { height: 70svh; }

.hero {
  position: relative; z-index: 1;
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  padding-block: calc(var(--rail-h) + 2.5rem) 5rem;
}

/* The text column runs from the site's edge to just short of the figure, and
   the name is sized to that column, so it can never reach the face. */
.hero__body {
  container-type: inline-size;
  inline-size: var(--figure-start);
  padding-inline: var(--edge) var(--col-gap);
}
.hero__pills { margin-block-end: clamp(1.5rem, 3.5vh, 2.5rem); }
/* "IBRAHEEM" sets about 5.1em wide at this weight, so 18cqi fills the
   column with a little air to spare. */
.hero__name { font-size: min(18cqi, 8rem); color: #fff; }
.hero__name span { display: block; }
.hero__name .n2 { margin-inline-start: 0.5em; }
.hero__role {
  margin-block-start: clamp(1.1rem, 3vh, 1.75rem);
  font-size: var(--t-lede); font-weight: 340; letter-spacing: -0.015em; line-height: 1.3;
}
.hero__lede {
  max-width: 44ch; margin-block-start: 0.9rem;
  color: var(--muted); font-size: var(--t-small); line-height: 1.7; text-wrap: pretty;
}
.hero__actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1.75rem;
  margin-block-start: clamp(1.5rem, 3.5vh, 2.25rem);
}
.hero__cue {
  position: absolute;
  inset-block-end: clamp(1.25rem, 4vh, 2.5rem); inset-inline-start: var(--edge);
  color: var(--muted);
  opacity: calc(1 - var(--scrub, 0) * 5);   /* its job is done once scrolling starts */
}
.hero__cue .ic { width: 1.25rem; height: 1.25rem; }

/* Phones, and screens squarer than 6:5: the same query the generator puts
   on the <picture> and site.js uses to pick the clip. The phone crop sits
   under the navigation, head and shoulders, never wider than a little over
   its own proportion; its sides are feathered into the black. The text
   stands below it. The portrait scrolls with the page instead of sticking,
   so the name never slides across the face; the clip runs while the
   portrait scrolls out of view. */
@media (max-width: 760px), (max-aspect-ratio: 6/5) {
  .opening { --portrait-h: min(62svh, 118vw); }
  .opening__media { position: relative; }
  .opening[data-scrub] .opening__run { height: 0; }
  .opening__portrait {
    inset: var(--rail-h) 0 auto; margin-inline: auto;
    inline-size: min(100%, var(--portrait-h) * 1.15); height: var(--portrait-h);
    mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  }
  .hero__img, .hero__video { object-position: 52% 0%; }
  .hero__veil { background: linear-gradient(to top, var(--void), rgb(5 5 5 / 0.82) 12%, rgb(5 5 5 / 0) 42%); }
  .hero {
    justify-content: flex-end;
    padding-block: calc(var(--rail-h) + var(--portrait-h) * 0.62) clamp(2.5rem, 7svh, 4rem);
  }
  .hero__body { inline-size: auto; padding-inline: var(--edge); }
  .hero__name { font-size: min(17cqi, 6.5rem); }
  .hero__pills { margin-block-end: 1.25rem; }
  .hero__cue { display: none; }
}


/* 8. Selected work ======================================================== */

/* The projects as tabs: their names down the left, one project at a time
   beside them — the picture, then what it is and where. Without JavaScript
   the names are in-page links and every project is shown in turn. */
.feature { padding-block: clamp(3rem, 12svh, 8rem) var(--section); }

.feature__grid {
  display: grid; grid-template-columns: minmax(9rem, 1.2fr) minmax(0, 7fr);
  column-gap: clamp(1.5rem, 3.5vw, 3.5rem); align-items: start;
}
.feature__tabs { display: grid; gap: 0.15rem; }
.feature__tabs a {
  display: block; padding-block: 0.55rem; color: var(--muted);
  font-size: var(--t-small); line-height: 1.3; text-decoration: none; text-wrap: balance;
  transition: color var(--fast) var(--ease);
}
.feature__tabs a:hover, .feature__tabs a[aria-selected="true"] { color: var(--text); }

.feature__panel {
  display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr);
  column-gap: clamp(1.5rem, 3.5vw, 3.5rem); row-gap: 1.5rem; align-items: stretch;
}
/* a gap, not a margin: hidden panels take no space, so the shown one always
   starts level with the list */
.feature__panels { display: grid; row-gap: clamp(2.5rem, 5vw, 4rem); }

.feature__media {
  display: block; overflow: hidden; border-radius: var(--r-img);
  aspect-ratio: 16 / 9.5; background: var(--surface);
}
.feature__media img { width: 100%; height: 100%; object-fit: cover; }
.feature__media.plate--drawing { background: var(--paper); padding: clamp(0.6rem, 1.5vw, 1.1rem); }
.feature__media.plate--drawing img { object-fit: contain; }

.feature__text { display: flex; flex-direction: column; align-items: flex-start; gap: 0.9rem; }
.feature__no { font-size: var(--t-tiny); letter-spacing: 0.1em; color: var(--faint); }
.feature__title { font-size: var(--t-title); font-weight: 340; line-height: 1.12; letter-spacing: -0.025em; text-wrap: balance; }
.feature__lede { color: var(--muted); font-size: var(--t-small); line-height: 1.7; text-wrap: pretty; }
.feature__meta {
  align-self: stretch; margin-block-start: auto; padding-block-start: 1.25rem;
  display: flex; justify-content: space-between; gap: 1rem;
  font-size: var(--t-tiny); line-height: 1.4;
}
.feature__meta span:first-child { color: var(--muted); }
.feature__meta span:last-child { text-align: end; }
.feature__all { display: flex; justify-content: flex-end; margin-block-start: clamp(2rem, 4vw, 3rem); }

@media (max-width: 900px) {
  .feature__grid { grid-template-columns: minmax(0, 1fr); }
  .feature__tabs {
    display: flex; gap: 0.5rem; overflow-x: auto; scrollbar-width: none;
    margin-block-end: 1.5rem; padding-block: 0.15rem;
  }
  .feature__tabs::-webkit-scrollbar { display: none; }
  .feature__tabs a {
    white-space: nowrap; padding: 0.45rem 0.95rem;
    border: 1px solid var(--line-2); border-radius: 999px;
  }
  .feature__tabs a[aria-selected="true"] { background: var(--text); color: var(--void); border-color: var(--text); }
  .feature__panel { grid-template-columns: minmax(0, 1fr); }
  .feature__all { justify-content: flex-start; }
}


/* 9. About ================================================================ */

.about__grid {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: clamp(2rem, 4vw, 3rem);
}
.about__lede {
  grid-column: 1 / span 10;
  font-size: clamp(1.4rem, 0.95rem + 1.9vw, 2.6rem); font-weight: 300;
  line-height: 1.24; letter-spacing: -0.025em; text-wrap: pretty;
}
.about__facts { grid-column: 1 / span 6; }
.about__focus { grid-column: 8 / -1; display: grid; gap: 1rem; align-content: start; }
@media (max-width: 900px) {
  .about__lede, .about__facts, .about__focus { grid-column: 1 / -1; }
}


/* 10. Expertise =========================================================== */

/* The cards scroll sideways under the visitor's own hand and snap loosely;
   the round buttons move one card at a time. */
.carousel {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: calc((100% - 2 * var(--gap)) / 3);
  gap: var(--gap);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity; scrollbar-width: none;
  padding-block: 0.25rem; border-radius: var(--r-card);
}
.carousel::-webkit-scrollbar { display: none; }
.carousel > * { scroll-snap-align: start; }
.carousel:focus-visible { outline-offset: 6px; border-radius: var(--r-card); }
@media (max-width: 1000px) { .carousel { grid-auto-columns: calc((100% - var(--gap)) / 2); } }
@media (max-width: 640px) { .carousel { grid-auto-columns: 84%; } }


/* 11. Practice ============================================================ */

.topic {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 2rem;
  padding-block: clamp(2.5rem, 5vw, 4rem); border-block-start: 1px solid var(--line);
}
.topic:first-of-type { padding-block-start: 0; border-block-start: 0; }
.topic__head { grid-column: 1 / span 5; }
.topic__title { font-size: var(--t-title); font-weight: 340; line-height: 1.12; letter-spacing: -0.025em; text-wrap: balance; }
.topic__lede { max-width: 40ch; margin-block-start: 0.9rem; color: var(--muted); font-size: var(--t-small); line-height: 1.7; }
.topic__body { grid-column: 7 / -1; }

.flow { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-block-start: 1.5rem; }
.flow .muted { font-size: var(--t-tiny); }

.rows li {
  display: grid; grid-template-columns: 2.6rem minmax(0, 1fr); gap: 1.1rem; align-items: start;
  padding-block: 1.1rem; border-block-end: 1px solid var(--line);
}
.rows li:first-child { padding-block-start: 0; }
.rows__icon {
  display: grid; place-items: center; width: 2.6rem; height: 2.6rem;
  border-radius: 50%; background: var(--surface-2); border: 1px solid var(--line);
}
.rows__icon--no { font-size: var(--t-tiny); color: var(--muted); letter-spacing: 0.05em; }
.rows h4 { font-size: 1rem; font-weight: 460; line-height: 1.3; padding-block-start: 0.1rem; }
.rows p { margin-block-start: 0.25rem; color: var(--muted); font-size: var(--t-small); line-height: 1.6; text-wrap: pretty; }

.quote {
  margin-block-start: 1.75rem; padding: clamp(1.5rem, 3vw, 2.25rem);
  border-radius: var(--r-card); background: var(--surface); border: 1px solid rgba(255, 255, 255, 0.05);
  font-size: clamp(1.1rem, 0.95rem + 0.7vw, 1.5rem); font-weight: 300;
  line-height: 1.45; letter-spacing: -0.015em; text-wrap: pretty;
}
@media (max-width: 900px) { .topic__head, .topic__body { grid-column: 1 / -1; } }


/* 12. Experience ========================================================== */

/* Stacked cards, each with a round monogram where a portrait would go, and
   one soft line swept across behind them. */
.voices { overflow: clip; }
.voices__curve {
  position: absolute; inset-inline: 0; inset-block-end: 4%;
  width: 100%; height: 70%; pointer-events: none;
}
.voices__curve path { fill: none; stroke: url(#voices-curve); stroke-width: 26; stroke-linecap: round; }

.voices__grid {
  position: relative; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 2.5rem; align-items: start;
}
.voices__intro { grid-column: 1 / span 5; position: sticky; inset-block-start: calc(var(--rail-h) + 2rem); }
.voices__lede { max-width: 38ch; margin-block-end: 1.25rem; color: var(--muted); font-size: var(--t-small); line-height: 1.7; }
.voices__list { grid-column: 7 / -1; display: grid; gap: 1.25rem; }

.voice {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 1.25rem; align-items: center;
  padding: clamp(1.25rem, 2.4vw, 1.9rem) clamp(1.25rem, 2.4vw, 2rem);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, rgb(24 24 24 / 0.94), rgb(15 15 15 / 0.94));
  border: 1px solid rgba(255, 255, 255, 0.05);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.voice__role { color: var(--muted); font-size: var(--t-small); line-height: 1.55; }
.voice__org { margin-block-start: 0.7rem; font-size: 1.05rem; font-weight: 480; letter-spacing: -0.01em; line-height: 1.3; }
.voice__when { margin-block-start: 0.35rem; color: var(--faint); font-size: var(--t-tiny); }
.voice__badge {
  display: grid; place-items: center; width: 4rem; height: 4rem; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #f5f5f5, #b9b9b9);
  color: #0b0b0b; font-size: 0.95rem; font-weight: 600; letter-spacing: 0.02em;
  box-shadow: 0 0 0 5px rgba(255, 255, 255, 0.04);
}
.voice__more { grid-column: 1 / -1; margin-block-start: 1rem; }
.voice__more summary {
  display: inline-flex; align-items: center; gap: 0.5rem; min-height: 32px;
  font-size: var(--t-tiny); color: var(--muted); cursor: pointer; list-style: none;
}
.voice__more summary::-webkit-details-marker { display: none; }
.voice__more summary::before { content: "+"; font-size: 1rem; line-height: 1; }
.voice__more[open] summary::before { content: "–"; }
.voice__more summary:hover { color: var(--text); }
.voice__more .duties { margin-block-start: 0.75rem; }
@media (max-width: 900px) {
  .voices__intro, .voices__list { grid-column: 1 / -1; }
  .voices__intro { position: static; }
}


/* 13. Record ============================================================== */

.record__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap); }
.panel--wide { grid-column: span 2; }
@media (max-width: 1000px) { .record__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .record__grid { grid-template-columns: minmax(0, 1fr); } .panel--wide { grid-column: auto; } }


/* 14. Contact ============================================================= */

.contact__grid {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 2.5rem; align-items: end;
}
.contact__main { grid-column: 1 / span 7; }
.contact__side { grid-column: 9 / -1; }
.contact__lede { max-width: 34ch; margin-block-start: 1.25rem; color: var(--muted); font-size: var(--t-lede); line-height: 1.45; }
.bigmail {
  display: inline-block; margin-block-start: clamp(1.75rem, 3.5vw, 2.75rem); padding-block-end: 0.35rem;
  font-size: clamp(1.3rem, 0.6rem + 2.7vw, 3.1rem); font-weight: 300; letter-spacing: -0.035em;
  text-decoration: none; overflow-wrap: anywhere; border-block-end: 1px solid var(--line-2);
  transition: border-color var(--fast) var(--ease);
}
.bigmail:hover { border-color: var(--text); }
.contact__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-block-start: 2rem; }
.contact__closing { margin-block-start: 1.25rem; color: var(--muted); font-size: var(--t-small); line-height: 1.65; }
@media (max-width: 900px) { .contact__main, .contact__side { grid-column: 1 / -1; } }


/* 15. Footer ============================================================== */

.foot {
  border-block-start: 1px solid var(--line); padding-block: clamp(2.5rem, 5vw, 3.5rem) 2.25rem;
  color: var(--muted); font-size: var(--t-small);
}
.foot__top {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 1.5rem; align-items: start;
  padding-block-end: clamp(2rem, 4vw, 3rem); margin-block-end: 1.25rem;
  border-block-end: 1px solid var(--line);
}
.foot__name { grid-column: 1 / span 4; display: grid; gap: 0.3rem; color: var(--text); font-size: 1.05rem; font-weight: 480; }
.foot__name span { color: var(--muted); font-size: var(--t-small); font-weight: 360; }
.foot__map { grid-column: 5 / span 5; display: flex; flex-wrap: wrap; gap: 0 1.75rem; }
.foot__top .foot__top-link { grid-column: 10 / -1; justify-self: end; color: var(--text); padding-block: 0; }
.foot__row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 1.75rem; }
.foot__spacer { flex: 1; min-width: 1rem; }
.foot a {
  display: inline-flex; align-items: center; gap: 0.45rem; padding-block: 0.45rem;
  text-decoration: none; transition: color var(--fast) var(--ease);
}
.foot a:hover { color: var(--text); }
@media (max-width: 900px) {
  .foot__name, .foot__map { grid-column: 1 / -1; }
  .foot__top .foot__top-link { grid-column: 1 / -1; justify-self: start; }
}


/* 16. Pictures ============================================================ */

/* Every picture in the page is shown in black and white and comes back into
   colour under the pointer: on the picture itself, or on the link or figure
   that holds it, so hovering a project's card lights its image too.
   Keyboard focus does the same. Left out: the hero portrait, which is
   monochrome already, and the lightbox, which sits outside <main> and
   always shows colour. On touch screens, where nothing hovers, site.js
   lights a picture while it crosses the middle of the screen (.is-lit).
   A film's poster is treated the same way, and a film stays in colour
   for as long as it plays (.is-playing, also from site.js). */
main img:not(.hero__img),
main video:not(.hero__video) {
  filter: grayscale(1);
  transition: filter 700ms var(--ease);
}
main :is(a, figure, .plate__frame, .projhero__frame):hover :is(img, video),
main :is(a, figure):focus-visible :is(img, video),
main figure:focus-within :is(img, video),
main :is(img, video).is-lit,
main video.is-playing {
  filter: none;
}

/* A plate: the picture, then a caption row with an inspect control. The
   frame reserves its exact ratio before anything downloads. Renders may
   fill it; drawings never do — they keep their proportion on a pale
   ground, because a cropped plan is a broken plan. */
.plate {
  margin: 0; overflow: hidden; border-radius: var(--r-img);
  background: var(--surface); border: 1px solid rgba(255, 255, 255, 0.05);
}
.plate__frame { position: relative; aspect-ratio: var(--plate-ratio, 3 / 2); overflow: hidden; }
.plate__frame img { width: 100%; height: 100%; }
.plate--render .plate__frame img { object-fit: cover; }
.plate--drawing .plate__frame { background: var(--paper); padding: clamp(0.6rem, 1.6vw, 1.25rem); }
.plate--drawing .plate__frame img { object-fit: contain; }
/* A film sits in a plate like a picture, at its own exact proportion. It
   plays only when asked to, with its own controls. */
.plate__frame video { display: block; width: 100%; height: 100%; object-fit: cover; background: var(--surface); }

.plate__cap {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.75rem 0.9rem 0.75rem 1.1rem; color: var(--muted); font-size: var(--t-tiny); line-height: 1.4;
}
.zoom {
  display: inline-flex; align-items: center; gap: 0.45rem; flex: none; min-height: 32px;
  padding: 0.3rem 0.8rem; border: 1px solid var(--line-2); border-radius: 999px;
  color: var(--text); font-size: var(--t-tiny);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.zoom:hover, .zoom:focus-visible { background: var(--text); color: var(--void); }


/* 17. Work index ========================================================== */

.page { padding-block: calc(var(--rail-h) + clamp(2rem, 5vw, 3.5rem)) var(--section); }

.crumbs {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-block-end: clamp(2.25rem, 5vw, 3.5rem); color: var(--muted); font-size: var(--t-small);
}
.crumbs .ic { width: 0.95rem; height: 0.95rem; }

.workgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1.25rem, 2.5vw, 2rem); }
.workcard__link {
  display: flex; flex-direction: column; height: 100%; overflow: hidden; text-decoration: none;
  border-radius: var(--r-card); background: var(--surface); border: 1px solid rgba(255, 255, 255, 0.05);
  transition: border-color var(--mid) var(--ease), background var(--mid) var(--ease);
}
.workcard__link:hover { border-color: var(--line-2); background: var(--surface-2); }
.workcard__media { aspect-ratio: 3 / 2; overflow: hidden; }
.workcard__media img { width: 100%; height: 100%; object-fit: cover; }
.workcard__media.plate--drawing { background: var(--paper); padding: clamp(0.75rem, 2vw, 1.5rem); }
.workcard__media.plate--drawing img { object-fit: contain; }
.workcard__body { display: grid; gap: 0.7rem; align-content: start; padding: clamp(1.25rem, 2.5vw, 1.9rem); }
.workcard__no { font-size: var(--t-tiny); letter-spacing: 0.1em; color: var(--faint); }
.workcard__name { font-size: var(--t-title); font-weight: 340; line-height: 1.12; letter-spacing: -0.025em; text-wrap: balance; }
.workcard__meta { display: flex; flex-wrap: wrap; gap: 0.25rem 1.25rem; color: var(--muted); font-size: var(--t-tiny); }
.workcard__lede { color: var(--muted); font-size: var(--t-small); line-height: 1.65; text-wrap: pretty; }
.workcard .pills { margin-block-start: 0.35rem; }
@media (max-width: 860px) { .workgrid { grid-template-columns: minmax(0, 1fr); } }


/* 18. Project pages ======================================================= */

.projhead {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 2rem; align-items: end;
  margin-block-end: clamp(2.25rem, 5vw, 3.5rem);
}
.projhead__main { grid-column: 1 / span 7; }
.projhead__side { grid-column: 9 / -1; }
.projhead__lede {
  max-width: 46ch; margin-block: 1.4rem 1.5rem;
  color: var(--muted); font-size: var(--t-lede); line-height: 1.5; text-wrap: pretty;
}
@media (max-width: 900px) { .projhead__main, .projhead__side { grid-column: 1 / -1; } }

/* The project opens on its own image, with a restrained parallax. */
.projhero { margin-block-end: clamp(3rem, 6vw, 5rem); }
.projhero__frame { aspect-ratio: 16 / 8; overflow: hidden; border-radius: 24px; background: var(--surface); }
.projhero__frame img {
  width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.06) translateY(calc(var(--parallax, 0) * 2.5%));
  will-change: transform;
}
.projhero__cap { margin-block-start: 0.8rem; color: var(--muted); font-size: var(--t-tiny); }
@media (max-width: 700px) { .projhero__frame { aspect-ratio: 4 / 3; border-radius: var(--r-img); } }
/* A cover that has to be seen whole — a plan, or a tower up to its crown —
   keeps its own proportion (--hero-ratio, set on the figure) at every
   width, and holds still: no crop, no drift. */
.projhero--whole .projhero__frame { aspect-ratio: var(--hero-ratio, 16 / 8); }
.projhero--whole .projhero__frame img { object-fit: contain; transform: none; will-change: auto; }

/* Contents: every chapter of the project, as links to it. */
.chapnav { display: grid; gap: 0.9rem; margin-block-end: clamp(1.5rem, 3vw, 2.5rem); }
.chapnav .pill { white-space: normal; text-align: start; }
.chapnav .pill .muted { font-size: var(--t-tiny); }

.chapter { padding-block: clamp(2.5rem, 5vw, 4rem); border-block-start: 1px solid var(--line); }
.chapter__head {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 0.75rem; margin-block-end: clamp(1.5rem, 3vw, 2.5rem);
}
.chapter__no { grid-column: 1 / span 1; padding-block-start: 0.45rem; font-size: var(--t-tiny); letter-spacing: 0.1em; color: var(--faint); }
.chapter__title { grid-column: 2 / span 5; font-size: var(--t-title); font-weight: 340; line-height: 1.12; letter-spacing: -0.025em; text-wrap: balance; }
.chapter__title--small { font-size: var(--t-card); font-weight: 440; letter-spacing: -0.01em; }
.chapter__text { grid-column: 8 / -1; color: var(--muted); font-size: var(--t-small); line-height: 1.7; text-wrap: pretty; }
@media (max-width: 900px) { .chapter__no, .chapter__title, .chapter__text { grid-column: 1 / -1; } }

.chapter__figs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1rem, 2.5vw, 2rem); }
/* Never stretch an image past the pixels it has: a plate that cannot fill
   its column sits centred in it instead. */
.chapter__figs .plate { width: 100%; max-width: var(--plate-cap, none); margin-inline: auto; }
.chapter__figs.is-single { grid-template-columns: minmax(0, 1fr); }
.chapter__figs.is-single .plate { max-width: min(72rem, var(--plate-cap, 72rem)); }
@media (max-width: 760px) { .chapter__figs { grid-template-columns: minmax(0, 1fr); } }
/* Sets that do not fall into pairs. A plate may run across both columns
   (a long drawing, a film, the odd one out of a set), and an upright
   picture may stand beside two stacked ones and fill their height, giving
   up a little of its sides to do so. The viewer always shows it whole. */
.chapter__figs .plate--wide { grid-column: 1 / -1; }
@media (min-width: 761px) {
  .chapter__figs .plate--tall { grid-row: span 2; display: flex; flex-direction: column; }
  .chapter__figs .plate--tall .plate__frame { flex: 1 1 auto; aspect-ratio: auto; min-height: 0; }
  .chapter__figs .plate--tall .plate__frame img { position: absolute; inset: 0; }
}

.projfoot {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap);
  padding-block-start: clamp(2.5rem, 5vw, 4rem); border-block-start: 1px solid var(--line);
}
.projfoot__link {
  display: flex; align-items: center; gap: 1rem; padding: 1.1rem 1.35rem;
  border-radius: var(--r-card); background: var(--surface); border: 1px solid rgba(255, 255, 255, 0.05);
  text-decoration: none; transition: border-color var(--mid) var(--ease), background var(--mid) var(--ease);
}
.projfoot__link:hover { border-color: var(--line-2); background: var(--surface-2); }
.projfoot__link--next { justify-content: flex-end; text-align: end; }
.projfoot__label { display: block; color: var(--muted); font-size: var(--t-tiny); }
.projfoot__name { display: block; margin-block-start: 0.2rem; font-size: var(--t-card); font-weight: 420; line-height: 1.25; }
@media (max-width: 700px) { .projfoot { grid-template-columns: minmax(0, 1fr); } }


/* 19. CV ================================================================== */

.cvblock {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gap); row-gap: 1rem;
  padding-block: clamp(2rem, 4vw, 3rem); border-block-start: 1px solid var(--line);
}
.cvblock__title { grid-column: 1 / span 4; font-size: var(--t-card); font-weight: 440; }
.cvblock__body { grid-column: 5 / -1; }
.cv__lede { font-size: var(--t-lede); font-weight: 320; line-height: 1.5; letter-spacing: -0.01em; max-width: 60ch; }
.cvpost + .cvpost { margin-block-start: 2rem; }
.cvpost__when { color: var(--faint); font-size: var(--t-tiny); }
.cvpost__org { margin-block-start: 0.3rem; font-size: var(--t-card); font-weight: 460; }
.cvpost__role { margin-block: 0.2rem 0.85rem; color: var(--muted); font-size: var(--t-small); }
.cv__tools { margin-block-start: 1.5rem; }
@media (max-width: 900px) { .cvblock__title, .cvblock__body { grid-column: 1 / -1; } }


/* 20. 404 ================================================================= */

.notfound { min-height: 80svh; display: grid; align-content: center; }
.notfound .section__title { max-width: 16ch; margin-block-start: 1rem; }


/* 21. Lightbox ============================================================ */

.lightbox {
  position: fixed; inset: 0; z-index: 150;
  display: grid; grid-template-rows: auto 1fr auto;
  background: rgb(5 5 5 / 0.97); opacity: 0; visibility: hidden;
  transition: opacity var(--mid) var(--ease), visibility var(--mid) step-end;
}
.lightbox[data-open] { opacity: 1; visibility: visible; transition: opacity var(--mid) var(--ease), visibility 0s; }
.lightbox__bar {
  display: flex; align-items: center; gap: 1rem; padding: 0.9rem var(--gutter);
  border-block-end: 1px solid var(--line); font-size: var(--t-small);
}
.lightbox__sep { flex: 1; }
.lightbox__close {
  display: inline-flex; align-items: center; gap: 0.5rem; min-height: 44px;
  padding: 0.45rem 1rem; border: 1px solid var(--line-3); border-radius: 999px; font-size: var(--t-small);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.lightbox__close:hover { background: var(--text); color: var(--void); }
.lightbox__stage { display: grid; place-items: center; min-height: 0; padding: clamp(1rem, 3vw, 2.5rem); }
.lightbox__stage > * {
  width: min(100%, 1400px); max-height: 100%;
  transform: scale(0.985); transition: transform var(--mid) var(--ease);
}
.lightbox[data-open] .lightbox__stage > * { transform: none; }
.lightbox__stage img {
  width: auto; height: auto; max-width: 100%; max-height: 74svh;
  margin-inline: auto; object-fit: contain; border-radius: 10px; background: var(--paper);
}
.lightbox__stage .plate__frame { aspect-ratio: auto !important; padding: 0; background: none; }
.lightbox__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1.25rem;
  padding: 0.9rem var(--gutter) calc(0.9rem + env(safe-area-inset-bottom));
  border-block-start: 1px solid var(--line); font-size: var(--t-small);
}
.lightbox__foot p { max-width: 70ch; }
.lightbox__nav { display: flex; gap: 0.5rem; margin-inline-start: auto; }
body[data-lightbox-open] { overflow: hidden; }


/* 22. Motion ============================================================== */

/* Written with the design-motion-principles skill, weighted for a
   professional portfolio: production polish first (Jakub Krehel), one
   considered flourish (Jhey Tompkins), restraint on anything done often
   (Emil Kowalski). The rules it follows:

   - arrive, don't decorate: content eases in once, the first time it
     scrolls into view, and never again; whatever is on screen when the
     page loads is never hidden, so the name and navigation are always
     there at once
   - arrivals ease out and nothing bounces; departures are shorter
   - only transform, translate, scale, opacity, filter and clip-path move
   - what the visitor does often (navigation, tabs, arrows) answers in
     under 300ms, and a tab chosen from the keyboard does not animate
   - there are no loops, and no motion that is not caused by the visitor
   - all of it stops under prefers-reduced-motion (section 23)            */

@keyframes arrive {
  from { opacity: 0; transform: translate3d(0, 14px, 0); filter: blur(4px); }
}
@keyframes arrive-media {
  from { opacity: 0; transform: translate3d(0, 24px, 0); }
}
@keyframes settle { from { scale: 1.06; } }
/* The text rises out of a mask fixed at its own bottom edge: the clip and
   the lift move together, so the edge never travels. */
@keyframes title-rise {
  from { transform: translate3d(0, 100%, 0); clip-path: inset(-0.2em -0.2em 100% -0.2em); }
  to   { transform: none; clip-path: inset(-0.2em -0.2em -0.2em -0.2em); }
}
@keyframes panel-in {
  from { opacity: 0; transform: translate3d(0, 8px, 0); filter: blur(4px); }
}

/* Reveal on scroll. site.js only marks as waiting the elements that are
   below the fold when the page loads, so nothing is ever hidden without the
   script that will show it. Siblings that arrive together are staggered by
   --i, set by the script. Blur is kept to text: on a large picture it
   costs more than it gives. */
[data-reveal].is-waiting { opacity: 0; }
[data-reveal].is-in {
  animation: arrive var(--d-enter) var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 70ms);
}
[data-reveal="media"].is-in { animation-name: arrive-media; animation-duration: 820ms; }
[data-reveal="media"].is-in img {
  animation: settle var(--d-settle) var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 70ms);
}
[data-reveal="title"].is-in { animation: title-rise var(--d-title) var(--ease-out) backwards; }

/* A project chosen by pointer crossfades in with its picture settling; one
   chosen from the keyboard simply appears (site.js adds .is-entering only
   for the pointer). The one leaving just goes: exits are subtler. */
.feature__panel.is-entering { animation: panel-in 460ms var(--ease-out); }
.feature__panel.is-entering .feature__media img { animation: settle 900ms var(--ease-out); }

/* Press: a small, immediate give on everything that can be clicked. */
.btn:active, .roundbtn:active:not(:disabled), .pill--link:active, .zoom:active,
.lightbox__close:active, .nav__toggle:active, .nav__links .nav__cta:active { scale: 0.97; }
.iconlink:active .iconlink__ring { scale: 0.92; }

/* Navigation: an underline drawn from the left, under 300ms. */
.nav__links a:not(.nav__cta) { position: relative; }
.nav__links a:not(.nav__cta)::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: -0.4rem; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform 280ms var(--ease-out);
}
.nav__links a:not(.nav__cta):hover::after,
.nav__links a[aria-current]:not(.nav__cta)::after { transform: scaleX(1); }

/* Project tabs: a short rule marks the one shown, and half of it the one
   under the pointer. */
@media (min-width: 901px) {
  .feature__tabs a { position: relative; padding-inline-start: 1.3rem; }
  .feature__tabs a::before {
    content: ""; position: absolute; inset-inline-start: 0; inset-block-start: 50%;
    width: 0.75rem; height: 1px; background: currentColor;
    transform: scaleX(0); transform-origin: left;
    transition: transform 260ms var(--ease-out);
  }
  .feature__tabs a:hover::before { transform: scaleX(0.5); }
  .feature__tabs a[aria-selected="true"]::before { transform: scaleX(1); }
}

/* Cards lift a little, their icon disc turns over, and a soft light follows
   the pointer across them (site.js sets --mx and --my). Mouse only: on a
   touch screen a hover state is a trap. */
.card, .voice {
  transition: translate var(--d-hover) var(--ease-out), border-color var(--d-hover) var(--ease-out);
}
.voice { position: relative; }
.card > *, .voice > * { position: relative; }
.card::before, .voice::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(26rem circle at var(--mx, 50%) var(--my, -30%), rgb(255 255 255 / 0.075), transparent 55%);
  opacity: 0; transition: opacity var(--d-hover) var(--ease-out);
}
.card__icon {
  transition: background var(--d-hover) var(--ease-out), color var(--d-hover) var(--ease-out),
              border-color var(--d-hover) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .card:hover, .voice:hover { translate: 0 -3px; border-color: rgba(255, 255, 255, 0.12); }
  .card:hover::before, .voice:hover::before { opacity: 1; }
  .card:hover .card__icon { background: var(--text); color: var(--void); border-color: var(--text); }
}

/* Pictures that lead somewhere lean in a little under the pointer, slowly,
   as the colour comes back. */
main .feature__media img,
main .workcard__media img {
  transition: filter 700ms var(--ease), transform 900ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .feature__media:hover img, .workcard__link:hover .workcard__media img { transform: scale(1.035); }
}

/* Moving between pages. Where the browser supports cross-document view
   transitions, the old page steps back quickly, the new one arrives, the
   navigation stays exactly where it is, and a project's picture travels
   from the card that was clicked into the cover of its page — the same
   view-transition name is on both. Elsewhere pages simply load. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
.nav { view-transition-name: site-nav; }
.feature__media, .workcard__media, .projhero__frame { view-transition-class: cover; }
::view-transition-old(root) { animation: 200ms cubic-bezier(0.55, 0, 1, 0.45) both page-out; }
::view-transition-new(root) { animation: 440ms cubic-bezier(0.22, 1, 0.36, 1) both page-in; }
@keyframes page-out { to { opacity: 0; } }
@keyframes page-in { from { opacity: 0; transform: translate3d(0, 12px, 0); } }
::view-transition-group(*.cover) {
  animation-duration: 560ms;
  animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}
::view-transition-old(*.cover),
::view-transition-new(*.cover) { height: 100%; object-fit: cover; }


/* 23. Reduced motion, no-JS, RTL, print =================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  /* The static opening: the original photograph, in place, scrolling away
     with the page like any other picture. The portrait does not stick,
     drift or fade, and the clip is never fetched. */
  .opening__media { position: relative; }
  .opening__portrait { opacity: 1; transform: none; }
  .hero__video { display: none !important; }
  .opening[data-scrub] .opening__run { height: 0; }
  .hero__cue { opacity: 1; }
  .projhero__frame img { transform: none; }
  /* nothing waits to arrive, nothing lifts or follows the pointer */
  [data-reveal].is-waiting { opacity: 1; }
  .card:hover, .voice:hover { translate: none; }
  .card::before, .voice::before { display: none; }
  .feature__media:hover img, .workcard__link:hover .workcard__media img { transform: none; }
}

/* Without JavaScript every picture is in place and nothing is hidden: the
   portrait does not stick behind the work, every project is shown, and the
   controls that need a script are not drawn. */
.no-js .opening__media { position: relative; }
.no-js .hero__video { display: none; }
.no-js .nav__toggle, .no-js .drawer, .no-js [data-carousel-nav], .no-js .zoom { display: none !important; }
@media (max-width: 860px) { .no-js .nav__links { display: flex; overflow-x: auto; } }

/* Logical properties carry most of this; these are the exceptions. */
[dir="rtl"] .textlink:hover .ic { transform: translateX(-0.2rem); }

@media print {
  .nav, .drawer, .lightbox, .skip-link, .hero__cue, .opening__track, .zoom,
  .carousel__nav, .voices__curve { display: none !important; }
  body, .opening { background: #fff !important; color: #000 !important; }
  :root { --muted: #444; --faint: #666; --line: #ccc; --line-2: #bbb; --line-3: #999; --surface: #fff; --surface-2: #fff; --surface-3: #eee; --text: #000; }
  .hero { min-height: 0; padding-block: 1.5rem; }
  .hero__name { color: #000; }
  .section { padding-block: 1.5rem; }
  .card, .panel, .voice, .quote, .plate { background: #fff !important; border-color: #ccc !important; box-shadow: none; }
  .voice__badge { background: #eee; }
  .feature__panel[hidden] { display: grid !important; }
  .feature__tabs { display: none; }
  .carousel { overflow: visible; grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); }
  .voice__more .duties { display: grid; }
  main img { filter: none !important; }   /* paper cannot be hovered */
  [data-reveal] { opacity: 1 !important; animation: none !important; }
  a { text-decoration: none; }
  body.cv .foot { display: none; }
}
