/* GENERATED by scripts/build-tokens.mjs: fonts.css + tokens.css + base.css + site.css + motion.css. Do not edit by hand. */
/* Self-hosted fonts. Files live in public/fonts/ with their licence texts.
   Paths are relative to public/styles/ (where this file is mirrored while the site is a static placeholder).
   When a framework build takes over, move the fonts next to the stylesheet or adjust the paths.
   Cabinet Grotesk: ITF Free Font License. Aleo: SIL OFL 1.1. Do not subset or convert the Cabinet files (the licence treats that as a derivative work). */

@font-face {
  font-family: "Cabinet Grotesk";
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  src: url("../fonts/cabinet-grotesk-500.woff2") format("woff2");
}
@font-face {
  font-family: "Cabinet Grotesk";
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  src: url("../fonts/cabinet-grotesk-700.woff2") format("woff2");
}
@font-face {
  font-family: "Cabinet Grotesk";
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  src: url("../fonts/cabinet-grotesk-800.woff2") format("woff2");
}

/* Aleo is a variable font: one file per character range covers weights 400 to 700.
   latin-ext carries Czech and Slovak letters (č š ž ť ľ ď ň ô ä ...). */
@font-face {
  font-family: "Aleo";
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  src: url("../fonts/aleo-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Aleo";
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  src: url("../fonts/aleo-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* GENERATED by scripts/build-tokens.mjs from design/tokens/tokens.json. Do not edit by hand. */
:root {
  color-scheme: light;
  --color-black-0: var(--color-white);
  --color-black-50: #f3f3f3;
  --color-black-100: #e6e6e6;
  --color-black-200: #cecece;
  --color-black-300: #b5b5b5;
  --color-black-400: #9c9c9c;
  --color-black-500: #848484;
  --color-black-600: #6b6b6b;
  --color-black-700: #525252;
  --color-black-800: #3a3a3a;
  --color-black-900: #212121;
  --color-white: #ffffff;
  --color-sand: #eddcba;
  --color-accent-red: #ff3b30;
  --color-accent-orange: #ff9500;
  --color-accent-green: #00c853;
  --color-surface-page: var(--color-white);
  --color-surface-raised: var(--color-white);
  --color-surface-sand: var(--color-sand);
  --color-surface-inverse: var(--color-black-900);
  --color-text-primary: var(--color-black-900);
  --color-text-muted: var(--color-black-700);
  --color-text-on-inverse: var(--color-white);
  --color-text-on-sand: var(--color-black-900);
  --color-text-on-accent: var(--color-black-900);
  --color-border-default: var(--color-black-900);
  --color-status-error: var(--color-accent-red);
  --color-status-warning: var(--color-accent-orange);
  --color-status-success: var(--color-accent-green);
  --color-shadow: var(--color-border-default);
  --color-backdrop-soft: color-mix(in srgb, var(--color-black-900) 35%, transparent);
  --color-backdrop-default: color-mix(in srgb, var(--color-black-900) 50%, transparent);
  --color-backdrop-strong: color-mix(in srgb, var(--color-black-900) 85%, transparent);
  --border-width: 6px;
  --border-style: solid;
  --border-default: var(--border-width) solid var(--color-border-default);
  --border-thin: 3px;
  --radius-default: 10px;
  --radius-pill: 999px;
  --radius-inset: calc(var(--radius-default) - var(--space-1));
  --shadow-offset: 8px;
  --shadow-hard: var(--shadow-offset) var(--shadow-offset) 0px 0px var(--color-shadow);
  --focus-width: 4px;
  --focus-offset: 4px;
  --focus-offset-tight: 2px;
  --focus-ring: var(--focus-width) solid var(--color-border-default);
  --font-family-display: "Cabinet Grotesk", "Helvetica Neue", Arial, sans-serif;
  --font-family-text: Aleo, Georgia, "Times New Roman", serif;
  --font-weight-display-medium: 500;
  --font-weight-display-bold: 700;
  --font-weight-display-extrabold: 800;
  --font-weight-text-regular: 400;
  --font-weight-text-bold: 700;
  --type-ratio: 1.25;
  --type-base: 1rem;
  --type-scale-0: 1.0rem;
  --type-scale-1: 1.25rem;
  --type-scale-2: 1.5625rem;
  --type-scale-3: 1.9531rem;
  --type-scale-4: 2.4414rem;
  --type-scale-5: 3.0518rem;
  --type-scale-6: 3.8147rem;
  --type-scale-7: 4.7684rem;
  --type-scale--1: 0.8rem;
  --type-display-family: var(--font-family-display);
  --type-display-weight: var(--font-weight-display-extrabold);
  --type-display-size: clamp(3.0518rem, 2.4474rem + 2.5789vw, 4.7684rem);
  --type-display-line-height: 1;
  --type-display-letter-spacing: -0.02em;
  --type-h1-family: var(--font-family-display);
  --type-h1-weight: var(--font-weight-display-extrabold);
  --type-h1-size: clamp(2.4414rem, 1.9578rem + 2.0632vw, 3.8147rem);
  --type-h1-line-height: 1.05;
  --type-h1-letter-spacing: -0.02em;
  --type-h2-family: var(--font-family-display);
  --type-h2-weight: var(--font-weight-display-extrabold);
  --type-h2-size: clamp(1.9531rem, 1.5662rem + 1.6506vw, 3.0518rem);
  --type-h2-line-height: 1.1;
  --type-h2-letter-spacing: -0.02em;
  --type-h3-family: var(--font-family-display);
  --type-h3-weight: var(--font-weight-display-bold);
  --type-h3-size: clamp(1.5625rem, 1.253rem + 1.3204vw, 2.4414rem);
  --type-h3-line-height: 1.15;
  --type-h3-letter-spacing: -0.015em;
  --type-h4-family: var(--font-family-display);
  --type-h4-weight: var(--font-weight-display-bold);
  --type-h4-size: clamp(1.25rem, 1.0024rem + 1.0563vw, 1.9531rem);
  --type-h4-line-height: 1.25;
  --type-h4-letter-spacing: -0.01em;
  --type-lead-family: var(--font-family-text);
  --type-lead-weight: var(--font-weight-text-regular);
  --type-lead-size: clamp(1.25rem, 1.14rem + 0.4695vw, 1.5625rem);
  --type-lead-line-height: 1.5;
  --type-lead-letter-spacing: 0em;
  --type-body-family: var(--font-family-text);
  --type-body-weight: var(--font-weight-text-regular);
  --type-body-size: 1rem;
  --type-body-line-height: 1.7;
  --type-body-letter-spacing: 0em;
  --type-body-strong-family: var(--font-family-text);
  --type-body-strong-weight: var(--font-weight-text-bold);
  --type-body-strong-size: 1rem;
  --type-body-strong-line-height: 1.7;
  --type-body-strong-letter-spacing: 0em;
  --type-small-family: var(--font-family-text);
  --type-small-weight: var(--font-weight-text-regular);
  --type-small-size: 0.8rem;
  --type-small-line-height: 1.6;
  --type-small-letter-spacing: 0em;
  --type-label-family: var(--font-family-display);
  --type-label-weight: var(--font-weight-display-bold);
  --type-label-size: 1rem;
  --type-label-line-height: 1;
  --type-label-letter-spacing: 0em;
  --type-measure-body: 65ch;
  --type-leading-solid: 1;
  --type-leading-tight: 1.2;
  --type-leading-snug: 1.3;
  --type-leading-compact: 1.4;
  --type-underline-offset: 0.2em;
  --type-underline-offset-ui: 0.3em;
  --type-underline-thickness: 0.1em;
  --type-underline-drop: 0.75em;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-20: 80px;
  --space-24: 96px;
  --space-32: 128px;
  --space-40: 160px;
  --breakpoint-xs: 360px;
  --breakpoint-sm: 375px;
  --breakpoint-md: 768px;
  --breakpoint-wide: 1024px;
  --breakpoint-split: 1100px;
  --breakpoint-xl: 1200px;
  --breakpoint-lg: 1440px;
  --layout-container: 1200px;
  --layout-page-padding: 24px;
  --layout-gutter: var(--space-6);
  --layout-section: var(--space-24);
  --layout-card-padding: var(--space-8);
  --layout-card-gap: var(--space-6);
  --layout-heading-gap: var(--space-4);
  --layout-heading-space: var(--space-10);
  --layout-paragraph-gap: var(--space-6);
  --layout-media-gap: var(--space-8);
  --layout-stack: var(--space-8);
  --layout-grid-row: var(--space-12);
  --layout-field-gap: var(--space-6);
  --layout-hero-gap: var(--space-8);
  --layout-band-gap: var(--space-16);
  --layout-band-padding: var(--space-5);
  --layout-header-padding: var(--space-3);
  --layout-header-gap: var(--space-12);
  --layout-footer-padding: var(--space-12);
  --layout-sticky-top: var(--space-24);
  --layout-collage-width: 26rem;
  --layout-columns-mobile: 4;
  --layout-columns-tablet: 8;
  --layout-columns-desktop: 12;
  --size-hairline: 1px;
  --size-menu-width: 24rem;
  --size-search-width: 44rem;
  --size-search-chrome: 9rem;
  --size-lightbox-width: 87.5rem;
  --size-lightbox-chrome: 13rem;
  --size-form: 40rem;
  --size-reel: 20rem;
  --size-portrait: 20rem;
  --size-card-narrow: 36rem;
  --size-proof: 28rem;
  --size-invite: 26rem;
  --size-mark: 24rem;
  --size-stat-min: 9rem;
  --size-textarea-min: 10rem;
  --size-quote: 30ch;
  --size-marker: 2.5rem;
  --size-marquee-mark: 0.45em;
  --size-badge-offset: 1.9rem;
  --aspect-square: 1;
  --aspect-landscape: 4 / 3;
  --aspect-screen: 16 / 10;
  --aspect-portrait: 4 / 5;
  --aspect-upright: 3 / 4;
  --aspect-tall: 2 / 3;
  --aspect-story: 9 / 16;
  --aspect-print: 32 / 25;
  --aspect-launch: 43 / 24;
  --aspect-collage: 1 / 0.95;
  --touch-target: 48px;
  --touch-gap: 8px;
  --interaction-hover-shift: 5px;
  --interaction-duration: 100ms;
  --motion-duration-fast: 150ms;
  --motion-duration-base: 300ms;
  --motion-duration-slow: 600ms;
  --motion-duration-deal: 800ms;
  --motion-duration-follow: 140ms;
  --motion-duration-marquee: 32s;
  --motion-easing-out: cubic-bezier(0.2, 0, 0, 1);
  --motion-easing-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --motion-easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --motion-distance: var(--space-6);
  --motion-stagger: 60ms;
  --motion-delay-title: 80ms;
  --motion-delay-lead: 420ms;
  --motion-delay-cta: 500ms;
  --motion-delay-deal: 300ms;
  --motion-delay-deal-step: 120ms;
  --motion-tilt-sticker: -2deg;
  --motion-tilt-tooltip: -3deg;
  --motion-tilt-toggle: -30deg;
  --motion-scale-lift: 1.04;
  --motion-scale-zoom: 1.03;
  --motion-scale-press: 0.98;
  --motion-scale-pop: 0.96;
  --motion-scale-toggle: 0.9;
  --motion-scale-tucked: 0.4;
  --motion-nudge-forward: var(--space-1);
  --motion-nudge-diagonal: 3px;
  --motion-nudge-tip: 2px;
  --motion-word-clip: 0.12em;
  --motion-word-pad: 0.06em;
  --collage-tilt-portrait: -2deg;
  --collage-tilt-work: -6deg;
  --collage-tilt-photo: 7deg;
  --opacity-disabled: 0.7;
  --opacity-dim: 0.75;
  --icon-size-sm: 20px;
  --icon-size-md: 24px;
  --icon-size-lg: 32px;
  --icon-stroke-sm: 1.8;
  --icon-stroke-md: 2;
  --icon-stroke-lg: 2.5;
  --component-card-background: var(--color-surface-raised);
  --component-card-border: var(--border-default);
  --component-card-radius: var(--radius-default);
  --component-card-shadow: var(--shadow-hard);
  --component-block-background: var(--color-surface-sand);
  --component-block-border: var(--border-default);
  --component-block-radius: var(--radius-default);
  --component-block-shadow: var(--shadow-hard);
  --component-button-background: var(--color-surface-raised);
  --component-button-text: var(--color-text-primary);
  --component-button-border: var(--border-default);
  --component-button-radius: var(--radius-default);
  --component-button-shadow: var(--shadow-hard);
  --component-button-minHeight: var(--touch-target);
  --component-button-padding: var(--space-6);
  --component-input-background: var(--color-surface-raised);
  --component-input-border: var(--border-default);
  --component-input-radius: var(--radius-default);
  --component-input-minHeight: var(--touch-target);
}

/* Dark theme: system preference unless the visitor chose light, or the visitor chose dark (data-theme set by /scripts/theme.js) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --color-surface-page: var(--color-black-900);
    --color-surface-raised: var(--color-black-800);
    --color-surface-inverse: var(--color-white);
    --color-text-primary: var(--color-white);
    --color-text-muted: var(--color-black-300);
    --color-text-on-inverse: var(--color-black-900);
    --color-border-default: var(--color-black-100);
    --color-shadow: var(--color-black-600);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --color-surface-page: var(--color-black-900);
  --color-surface-raised: var(--color-black-800);
  --color-surface-inverse: var(--color-white);
  --color-text-primary: var(--color-white);
  --color-text-muted: var(--color-black-300);
  --color-text-on-inverse: var(--color-black-900);
  --color-border-default: var(--color-black-100);
  --color-shadow: var(--color-black-600);
}

/* >= 768px: full-size border, radius, shadow and desktop spacing */
@media (min-width: 768px) {
  :root {
    --border-width: 10px;
    --radius-default: 15px;
    --shadow-offset: 15px;
    --layout-page-padding: 48px;
    --layout-gutter: var(--space-12);
    --layout-section: var(--space-40);
    --layout-card-padding: var(--space-12);
    --layout-card-gap: var(--space-8);
    --layout-heading-gap: var(--space-6);
    --layout-heading-space: var(--space-16);
    --layout-media-gap: var(--space-12);
    --layout-stack: var(--space-12);
    --layout-grid-row: var(--space-16);
    --layout-field-gap: var(--space-8);
    --layout-hero-gap: var(--space-10);
    --layout-band-gap: var(--space-24);
    --layout-band-padding: var(--space-6);
    --layout-header-gap: var(--space-16);
    --layout-footer-padding: var(--space-16);
  }
}

/* Base styles and components. Every value comes from tokens.css (generated from design/tokens/tokens.json): no raw hex,
   px, rem or ms here. Mobile first: the defaults are the phone values; tokens.css switches border, radius, shadow and
   spacing at 768px.
   How to space things: headings sit closer to what follows (--layout-heading-gap) than to what came before
   (--layout-heading-space); paragraphs are --layout-paragraph-gap apart; media after text gets --layout-media-gap. */

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

html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; overflow-x: hidden;
  /* Keyboard focus and #anchors stop below the sticky header (its height plus room for the focus ring), never under it */
  scroll-padding-top: calc(var(--touch-target) + var(--space-3) * 2 + var(--border-width) + var(--space-4)); } /* full-bleed bands use 100vw, which includes a desktop scrollbar. On the root this moves to the viewport, so the sticky header still works */

body {
  margin: 0;
  padding: var(--layout-page-padding);
  background: var(--color-surface-page);
  color: var(--color-text-primary);
  font-family: var(--type-body-family);
  font-weight: var(--type-body-weight);
  font-size: var(--type-body-size);
  line-height: var(--type-body-line-height);
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

.page { max-width: var(--layout-container); margin-inline: auto; }

/* Type roles */
h1, h2, h3, h4 { margin: 0 0 var(--layout-heading-gap); text-wrap: balance; }
/* More room above a heading than below it, when it follows other content in the same block */
:is(p, ul, ol, figure, blockquote, img, video, div) + :is(h1, h2, h3, h4) { margin-top: var(--layout-heading-space); }
h1 { font: var(--type-h1-weight) var(--type-h1-size)/var(--type-h1-line-height) var(--type-h1-family); letter-spacing: var(--type-h1-letter-spacing); }
h2 { font: var(--type-h2-weight) var(--type-h2-size)/var(--type-h2-line-height) var(--type-h2-family); letter-spacing: var(--type-h2-letter-spacing); }
h3 { font: var(--type-h3-weight) var(--type-h3-size)/var(--type-h3-line-height) var(--type-h3-family); letter-spacing: var(--type-h3-letter-spacing); }
h4 { font: var(--type-h4-weight) var(--type-h4-size)/var(--type-h4-line-height) var(--type-h4-family); letter-spacing: var(--type-h4-letter-spacing); }

.display { font: var(--type-display-weight) var(--type-display-size)/var(--type-display-line-height) var(--type-display-family); letter-spacing: var(--type-display-letter-spacing); }

p { margin: 0 0 var(--layout-paragraph-gap); max-width: var(--type-measure-body); text-wrap: pretty; }
.lead { font: var(--type-lead-weight) var(--type-lead-size)/var(--type-lead-line-height) var(--type-lead-family); }
.small { font: var(--type-small-weight) var(--type-small-size)/var(--type-small-line-height) var(--type-small-family); }
strong, .strong { font-weight: var(--type-body-strong-weight); }
.muted { color: var(--color-text-muted); }

a { color: inherit; text-decoration: underline; text-underline-offset: var(--type-underline-offset); text-decoration-thickness: var(--type-underline-thickness); }

/* <picture> (AVIF with a JPEG or PNG fallback) must not change layout: the wrapper vanishes and the <img> sits where it
   always did. <source> is not hidden by default; inside a flex or grid parent it would count as an item and add a gap.
   Scroll reveals animate the <img> inside a <picture> directly (motion.css), since a vanished wrapper has no box. */
picture { display: contents; }
picture > source { display: none; }

/* Keyboard focus: visible against the thick border thanks to the offset gap */
:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }

/* Surfaces: card (white) and block (sand) share one recipe */
.card, .block {
  border: var(--component-card-border);
  border-radius: var(--component-card-radius);
  box-shadow: var(--component-card-shadow);
  padding: var(--layout-card-padding);
  background: var(--component-card-background);
}
.block { background: var(--component-block-background); }

/* Button: >= 48px tall, label role, pressed feedback on every device, hover on pointer devices only */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--component-button-minHeight);
  min-width: var(--touch-target);
  padding: 0 var(--component-button-padding);
  font: var(--type-label-weight) var(--type-label-size)/var(--type-label-line-height) var(--type-label-family);
  color: var(--color-text-primary);
  text-decoration: none;
  background: var(--component-button-background);
  border: var(--component-button-border);
  border-radius: var(--component-button-radius);
  box-shadow: var(--component-button-shadow);
  cursor: pointer;
  transition: transform var(--interaction-duration) ease-out, box-shadow var(--interaction-duration) ease-out;
}
.btn--sand { background: var(--color-surface-sand); }
@media (hover: hover) {
  .btn:hover {
    transform: translate(var(--interaction-hover-shift), var(--interaction-hover-shift));
    box-shadow: calc(var(--shadow-offset) - var(--interaction-hover-shift)) calc(var(--shadow-offset) - var(--interaction-hover-shift)) 0 0 var(--color-shadow);
  }
}
.btn:active { transform: translate(var(--shadow-offset), var(--shadow-offset)); box-shadow: 0 0 0 0 var(--color-shadow); }
.btn[disabled], .btn[aria-disabled="true"] { color: var(--color-text-muted); background: var(--color-black-100); box-shadow: none; transform: none; cursor: not-allowed; }

/* Form field: 16px label-role text so iOS does not zoom */
.input {
  width: 100%;
  min-height: var(--component-input-minHeight);
  padding: 0 var(--space-4);
  font: var(--type-label-weight) var(--type-label-size)/var(--type-label-line-height) var(--type-label-family);
  color: var(--color-text-primary);
  background: var(--component-input-background);
  border: var(--component-input-border);
  border-radius: var(--component-input-radius);
}

/* Status tag: accent fill, black text, black border; always carries a text label (and an icon where used) */
.tag { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--space-8); padding: 0 var(--space-3); font: var(--type-label-weight) var(--type-small-size)/var(--type-leading-solid) var(--type-label-family); border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-pill); }
.tag--error { background: var(--color-status-error); }
.tag--warning { background: var(--color-status-warning); }
.tag--success { background: var(--color-status-success); }

/* Icons: Lucide sprite (public/icons/sprite.svg). <svg class="icon" aria-hidden="true"><use href="/icons/sprite.svg#menu"></use></svg>
   Decorative icons get aria-hidden; an icon-only button needs an accessible name on the button (aria-label or visible text). */
.icon {
  width: var(--icon-size-md); height: var(--icon-size-md); flex: none;
  fill: none; stroke: currentColor; stroke-width: var(--icon-stroke-md);
  stroke-linecap: round; stroke-linejoin: round;
  vertical-align: middle;
}
.icon--sm { width: var(--icon-size-sm); height: var(--icon-size-sm); stroke-width: var(--icon-stroke-sm); }
.icon--lg { width: var(--icon-size-lg); height: var(--icon-size-lg); stroke-width: var(--icon-stroke-lg); }
.btn .icon { margin-inline: calc(var(--space-1) * -1) 0; }
.btn .icon + span, .btn span + .icon { margin-inline-start: var(--space-2); }
.btn--icon { padding: 0; width: var(--touch-target); }

.stack > * + * { margin-top: var(--layout-stack); }
.stack > p + p { margin-top: var(--layout-paragraph-gap); } /* prose in a stack keeps paragraph rhythm */

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

/* ---- Theme-safe colours ------------------------------------------------------------------------
   Sand and the accent fills keep black text in both themes; everything else follows the semantic tokens. */
.btn--sand, .block, .stat--sand { color: var(--color-text-on-sand); }
.block .muted, .stat--sand .stat__source { color: var(--color-black-700); }
.block a:not(.btn) { color: var(--color-text-on-sand); }
.tag { color: var(--color-text-on-accent); }
.btn[disabled], .btn[aria-disabled="true"] { color: var(--color-black-700); }
dialog { background: var(--color-surface-page); color: var(--color-text-primary); }
.artwork { background: var(--color-white); color: var(--color-black-900); }

/* Skip link: hidden until focused */
.skip-link { position: absolute; left: var(--space-4); top: calc(var(--touch-target) * -2); z-index: 50; padding: var(--space-3) var(--space-4); background: var(--color-surface-inverse); color: var(--color-text-on-inverse); border-radius: var(--radius-default); font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family); }
.skip-link:focus { top: var(--space-4); }
main:focus { outline: none; }

/* Text for screen readers only */
.sr-only { position: absolute; width: var(--size-hairline); height: var(--size-hairline); padding: 0; margin: calc(var(--size-hairline) * -1); overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Site layout and page components. Values come from tokens.css; base elements and .card/.block/.btn/.icon from base.css.
   Raw px appear only in @media conditions (custom properties cannot be read there; the numbers mirror breakpoint.* in
   tokens.json) and in the skills donut block at the end of this file, which is being reworked separately (PR #2) and
   gets the same token pass once that lands. Percentages, fr, ch and container units are relative geometry, not raw values. */

/* Header: slim, sticky, bottom border only */
.site-header { position: sticky; top: 0; z-index: 10; background: var(--color-surface-page); border-bottom: var(--border-default); margin: calc(var(--layout-page-padding) * -1) calc(var(--layout-page-padding) * -1) var(--layout-header-gap); padding: var(--layout-header-padding) var(--layout-page-padding); }
.site-header__inner { max-width: var(--layout-container); margin-inline: auto; display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); }
.site-header__logo { display: inline-flex; align-items: center; gap: var(--space-3); min-height: var(--touch-target); font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family); text-decoration: none; }
.site-header__logo img { width: var(--icon-size-md); height: auto; }
.site-nav { display: none; gap: var(--space-6); align-items: center; }
.site-nav a { display: inline-flex; align-items: center; min-height: var(--touch-target); font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family); text-decoration: none; }
.site-nav a[aria-current="page"] { text-decoration: underline; text-underline-offset: var(--type-underline-offset-ui); text-decoration-thickness: var(--border-thin); }
.site-header .btn { border-width: var(--border-thin); box-shadow: none; }
.site-header .btn:hover, .site-header .btn:active { transform: none; box-shadow: none; text-decoration: underline; }
.menu-btn { gap: var(--space-2); }
@media (min-width: 768px) { .site-nav { display: flex; } .menu-btn { display: none; } }

/* Mobile menu (no framework: a dialog opened by the Menu button) */
.mobile-menu { border: var(--border-default); border-radius: var(--radius-default); padding: var(--space-8); width: min(100% - 2 * var(--layout-page-padding), var(--size-menu-width)); margin: var(--space-16) auto auto; }
.mobile-menu::backdrop { background: var(--color-backdrop-soft); }
.mobile-menu ul { list-style: none; margin: var(--space-6) 0 0; padding: 0; }
.mobile-menu li a { display: flex; align-items: center; justify-content: space-between; min-height: var(--touch-target); padding-block: var(--space-2); font: var(--type-h4-weight) var(--type-h4-size)/var(--type-leading-solid) var(--type-h4-family); text-decoration: none; border-bottom: var(--border-thin) solid var(--color-border-default); }
.mobile-menu__top { display: flex; justify-content: space-between; align-items: center; }

/* Footer */
.site-footer { border-top: var(--border-default); margin: var(--layout-section) calc(var(--layout-page-padding) * -1) calc(var(--layout-page-padding) * -1); padding: var(--layout-footer-padding) var(--layout-page-padding); }
.site-footer__inner { max-width: var(--layout-container); margin-inline: auto; display: grid; gap: var(--layout-stack) var(--layout-gutter); }
@media (min-width: 768px) { .site-footer__inner { grid-template-columns: 2fr 1fr 1fr; } }
.site-footer h2 { font: var(--type-h4-weight) var(--type-h4-size)/var(--type-h4-line-height) var(--type-h4-family); }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li a { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--touch-target); }

/* Sections */
.section { margin-bottom: var(--layout-section); }
.kicker { font: var(--type-label-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-label-family); color: var(--color-text-muted); margin-bottom: var(--space-2); }
.row { display: flex; flex-wrap: wrap; gap: var(--space-6); align-items: center; }
/* A row of buttons: rows apart like a stack, buttons a gutter apart (their shadows never touch) */
.actions, .hero__cta { gap: var(--space-6) var(--layout-gutter); }
/* Flow inside a section: text to the media that follows it, media to the actions or note under it */
.section > :is(p, ul, ol):not(.findings, .process, .chips) + :is(.media, .grid, .photo, .reels, .invites, .photo-grid) { margin-top: var(--layout-media-gap); }
.section__more { margin-top: var(--layout-media-gap); }
/* Media that directly follows other media keeps the grid rhythm: one gutter */
.follows-media { margin-top: var(--layout-gutter); }

/* Stat dashboard: gap larger than the shadow so shadows never touch */
.stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--layout-gutter); margin: var(--layout-media-gap) 0; padding: 0; list-style: none; }
.stats li:first-child { grid-column: 1 / -1; }
@media (min-width: 768px) { .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); } .stats li:first-child { grid-column: auto; } }
.stat { display: flex; flex-direction: column; justify-content: space-between; min-height: var(--size-stat-min); padding-block: var(--space-8); } /* short numeric cards: full side padding, less height */
.stat__number { font: var(--type-h1-weight) var(--type-h1-size)/var(--type-leading-solid) var(--type-h1-family); letter-spacing: var(--type-h1-letter-spacing); margin: 0; }
.stat__label { font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-snug) var(--type-label-family); margin: var(--space-5) 0 0; }
.stat__source { font: var(--type-small-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-small-family); color: var(--color-text-muted); margin: var(--space-2) 0 0; }
.stat--sand { background: var(--color-surface-sand); }

/* Grids and cards */
.grid { display: grid; grid-template-columns: 1fr; gap: var(--layout-grid-row) var(--layout-gutter); }
.grid--top { align-items: start; }
@media (min-width: 768px) { .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* Case card rhythm: image, then a roomy gap; kicker, title and text close together; a roomy gap before the button */
.case-card { display: flex; flex-direction: column; text-decoration: none; }
.case-card :where(h3, p) { margin: 0; }
.case-card > * + * { margin-top: var(--space-3); }
.case-card > .kicker + * { margin-top: var(--space-2); }
.case-card > .media + * { margin-top: var(--layout-card-gap); }
.case-card .btn { align-self: flex-start; margin-top: auto; }
.case-card > :has(+ .btn) { margin-bottom: var(--layout-card-gap); }
.case-card--next { max-width: var(--size-card-narrow); }
.media { display: block; width: 100%; height: auto; border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-inset); background: var(--color-black-100); }
video.media { aspect-ratio: var(--aspect-launch); }
/* Image crops: photo category covers, case card images (photo or artwork), images shown at their own size */
.media--landscape { aspect-ratio: var(--aspect-landscape); object-fit: cover; }
.media--screen { aspect-ratio: var(--aspect-screen); object-fit: cover; }
.media--screen-fit { aspect-ratio: var(--aspect-screen); object-fit: contain; }
.media--natural { width: auto; max-width: 100%; }
.media--proof { max-width: var(--size-proof); }
/* A card that is a figure or quote drops the browser's figure margin */
.card--flush { margin: 0; }
/* A vertical list of buttons (Elsewhere on Book me): shadows need room between them */
.btn-list { display: grid; justify-items: start; gap: var(--space-8); list-style: none; padding: 0; margin: 0; }
/* Artwork shown on its own, centred in a card */
.artwork-card { display: grid; place-items: center; }
.artwork-card--roomy { padding: var(--space-12); }
.artwork-card__mark { max-width: var(--size-mark); width: 100%; height: auto; }

/* Placeholder for media not supplied yet (preview only) */
.ph { aspect-ratio: var(--aspect-screen); border: var(--border-default); border-radius: var(--radius-default); background: repeating-linear-gradient(135deg, var(--color-black-50) 0 var(--space-3), var(--color-black-100) var(--space-3) var(--space-6)); display: grid; /* diagonal stripes: geometry, not a tilt */ place-items: center; text-align: center; padding: var(--space-4); }
.ph span { font: var(--type-label-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-label-family); background: var(--color-surface-page); border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-pill); padding: var(--space-1) var(--space-3); }

/* Photography */
.photo { margin: 0; border: var(--border-default); border-radius: var(--radius-default); box-shadow: var(--shadow-hard); overflow: hidden; background: var(--color-black-100); }
.photo img { display: block; width: 100%; height: 100%; aspect-ratio: var(--aspect-portrait); object-fit: cover; }
.photo img.artwork { object-fit: contain; } /* drawings are never cropped */
.photo .ratio-story { aspect-ratio: var(--aspect-story); }
.photo .ratio-print { aspect-ratio: var(--aspect-print); }
.photo figcaption { padding: var(--space-3) var(--space-4); border-top: var(--border-thin) solid var(--color-border-default); font: var(--type-small-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-small-family); }

/* Lists in his arrow notation */
.process { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: 0; margin: 0 0 var(--layout-media-gap); list-style: none; font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-compact) var(--type-label-family); }
.process li + li::before { content: "→"; margin-right: var(--space-3); }

/* Case study */
.breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); font: var(--type-label-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-label-family); margin-bottom: var(--space-2); padding: 0; list-style: none; }
.breadcrumb a { display: inline-flex; align-items: center; min-height: var(--touch-target); }
.breadcrumb li + li::before { content: "/"; margin-right: var(--space-2); }
.meta { display: flex; flex-wrap: wrap; gap: var(--space-5) var(--space-10); padding: 0; margin: var(--space-8) 0; list-style: none; }
.meta li { font: var(--type-small-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-small-family); }
.meta strong { display: block; margin-bottom: var(--space-1); font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-snug) var(--type-label-family); }
.findings { padding: 0; margin: 0 0 var(--space-8); list-style: none; counter-reset: f; }
.findings li { counter-increment: f; display: grid; grid-template-columns: var(--size-marker) 1fr; gap: var(--space-3); margin-bottom: var(--space-6); }
.findings li::before { content: counter(f); font: var(--type-h3-weight) var(--type-h4-size)/var(--type-leading-solid) var(--type-h3-family); }
.findings li p { margin: 0; }
.decision { display: grid; gap: var(--layout-stack) var(--layout-gutter); align-items: start; }
@media (min-width: 1024px) { .decision { grid-template-columns: 5fr 7fr; } }
.decision h3 { margin-bottom: var(--space-2); }
.quote { font: var(--type-h3-weight) var(--type-h3-size)/var(--type-h3-line-height) var(--type-h3-family); letter-spacing: var(--type-h3-letter-spacing); margin: 0 0 var(--space-6); max-width: var(--size-quote); }

/* Preview-only marker for copy the owner must confirm. Remove before launch. */
.confirm { display: inline-block; margin-top: var(--space-1); padding: var(--space-1) var(--space-2); border: var(--border-thin) dashed var(--color-border-default); border-radius: var(--radius-default); font: var(--type-label-weight) var(--type-small-size)/var(--type-leading-snug) var(--type-label-family); }
.confirm--spaced { margin-top: var(--layout-media-gap); }

/* Contact form */
.form { display: grid; gap: var(--layout-field-gap); max-width: var(--size-form); }
.field { display: grid; gap: var(--space-3); }
.field label { font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-snug) var(--type-label-family); }
.field .hint { font: var(--type-small-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-small-family); color: var(--color-text-muted); margin: 0; }
textarea.input { min-height: var(--size-textarea-min); padding: var(--space-3) var(--space-4); line-height: var(--type-body-line-height); font-family: var(--type-body-family); font-weight: var(--type-body-weight); resize: vertical; }
.input[aria-invalid="true"] { outline: var(--focus-width) solid var(--color-status-error); outline-offset: var(--focus-offset-tight); }
.field-error { font: var(--type-label-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-label-family); margin: 0; min-height: 1lh; }
.field-error:not(:empty)::before { content: "✕ "; }
.hp { position: absolute; left: -100vw; width: var(--size-hairline); height: var(--size-hairline); overflow: hidden; }
.contact-status { min-height: var(--touch-target); padding: var(--space-2) var(--space-4); }
.btn[disabled] { opacity: var(--opacity-disabled); }

/* Preview-only: copy written by Claude that the owner has not approved yet. The production build refuses to ship it. */
[data-unconfirmed] { outline: var(--border-thin) dashed var(--color-status-warning); outline-offset: var(--space-2); position: relative; }
[data-unconfirmed]::before { content: "Needs your OK"; position: absolute; top: calc(var(--size-badge-offset) * -1); right: 0; font: var(--type-label-weight) var(--type-small-size)/var(--type-leading-solid) var(--type-label-family); background: var(--color-status-warning); border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-pill); padding: var(--space-1) var(--space-2); }

/* Photography: clickable category list, grid, lightbox */
.cat-nav { display: flex; flex-wrap: wrap; gap: var(--space-3); list-style: none; padding: 0; margin: var(--space-8) 0 0; }
.cat-nav a { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--touch-target); padding: 0 var(--space-5); border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-pill); font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family); text-decoration: none; background: var(--color-surface-page); }
.cat-nav a:hover { background: var(--color-black-50); }
.cat-nav a[aria-current="page"] { background: var(--color-black-900); color: var(--color-text-on-inverse); }
.cat-nav a[aria-current="page"] .muted { color: var(--color-black-200); }
.photo-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--layout-gutter); }
@media (min-width: 768px) { .photo-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .photo-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.photo-tile { display: block; border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-inset); overflow: hidden; background: var(--color-black-100); }
.photo-tile img { display: block; width: 100%; height: auto; aspect-ratio: var(--aspect-square); object-fit: cover; transition: transform var(--interaction-duration) ease-out; }
@media (hover: hover) { .photo-tile:hover img { transform: scale(var(--motion-scale-zoom)); } }
.lightbox { width: min(100vw - var(--space-4), var(--size-lightbox-width)); max-height: calc(100vh - var(--space-4)); padding: var(--space-4); border: var(--border-default); border-radius: var(--radius-default); background: var(--color-surface-page); }
.lightbox::backdrop { background: var(--color-backdrop-strong); }
.lightbox__bar, .lightbox__nav { display: flex; justify-content: space-between; align-items: center; gap: var(--space-4); }
.lightbox__count { font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family); }
.lightbox__img { display: block; max-width: 100%; max-height: calc(100vh - var(--size-lightbox-chrome)); width: auto; height: auto; margin: var(--space-4) auto; border-radius: var(--radius-inset); }
/* Phones: categories become one swipeable row so the photos stay near the top */
@media (max-width: 767px) {
  .cat-nav { flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x proximity; padding-bottom: var(--space-3); margin-inline: calc(var(--layout-page-padding) * -1); padding-inline: var(--layout-page-padding); scrollbar-width: thin; }
  .cat-nav li { flex: none; scroll-snap-align: start; }
}

/* ---- Header: language switch and theme toggle ----------------------------------------------------- */
.site-header__logo .logo { width: var(--icon-size-md); height: auto; flex: none; }
.site-header__actions { display: flex; align-items: center; gap: var(--space-2); }
.site-header .menu-btn { padding: 0 var(--space-4); }
@media (max-width: 359px) { .site-header__name { position: absolute; width: var(--size-hairline); height: var(--size-hairline); overflow: hidden; clip: rect(0 0 0 0); } }
.lang-switch { display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--touch-target); min-width: var(--touch-target); justify-content: center; font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family); text-decoration: none; }
.lang-switch:hover span { text-decoration: underline; text-underline-offset: var(--type-underline-offset-ui); }
.mobile-menu__lang { margin: var(--space-8) 0 0; }
.mobile-menu__lang .btn { width: 100%; }
.theme-toggle .theme-toggle__sun { display: none; }
:root[data-theme="dark"] .theme-toggle .theme-toggle__moon { display: none; }
:root[data-theme="dark"] .theme-toggle .theme-toggle__sun { display: inline; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .theme-toggle .theme-toggle__moon { display: none; }
  :root:not([data-theme]) .theme-toggle .theme-toggle__sun { display: inline; }
}
.site-header .theme-toggle { border-width: var(--border-thin); box-shadow: none; }
.site-header .theme-toggle:hover, .site-header .theme-toggle:active { transform: none; box-shadow: none; background: var(--color-black-50); }
:root[data-theme="dark"] .site-header .theme-toggle:hover { background: var(--color-black-700); }

/* Dark theme: the active category pill and the unconfirmed badge keep readable colours */
.cat-nav a[aria-current="page"] { background: var(--color-surface-inverse); color: var(--color-text-on-inverse); }
.cat-nav a[aria-current="page"] .muted { color: inherit; opacity: var(--opacity-dim); }
.cat-nav a:hover { background: var(--color-surface-raised); }
[data-unconfirmed]::before { color: var(--color-black-900); }
.confirm { color: var(--color-text-primary); }

/* Chips: a set of equal items with no order (tools, skills). The arrow list (.process) is only for steps in sequence. */
.chips { display: flex; flex-wrap: wrap; gap: var(--space-3); list-style: none; padding: 0; margin: 0; }
.chips li { display: inline-flex; align-items: center; min-height: var(--space-10); padding: 0 var(--space-4); border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-pill); font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family); }

/* Editorial split for text sections on wide screens: the heading sits in a narrow left column and stays in view while
   its text scrolls past; the text keeps its 65ch measure on the right. Phones and tablets keep one column. */
@media (min-width: 1100px) {
  .section--split { display: grid; grid-template-columns: 4fr 8fr; column-gap: var(--layout-gutter); align-items: start; }
  .section--split > h2 { grid-column: 1; grid-row: 1 / span 6; position: sticky; top: var(--layout-sticky-top); }
  .section--split > :not(h2) { grid-column: 2; }
}
/* Inside a split section the side heading is the h2, so sub-headings step down one size to keep the hierarchy clear */
@media (min-width: 1100px) {
  .section--split h3 { font: var(--type-h4-weight) var(--type-h4-size)/var(--type-h4-line-height) var(--type-h4-family); letter-spacing: var(--type-h4-letter-spacing); }
}


/* Page intro with a portrait (About). Phones: portrait under the text. From 1024px: text left, portrait right. */
.intro__photo { margin: var(--layout-media-gap) 0 0; max-width: var(--size-portrait); }
.intro__photo img { display: block; width: 100%; height: auto; aspect-ratio: var(--aspect-tall); object-fit: cover; border: var(--border-default); border-radius: var(--radius-default); box-shadow: var(--shadow-hard); background: var(--color-black-100); }
@media (min-width: 1024px) {
  .intro { display: grid; grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); grid-template-rows: 1fr auto auto 1fr; column-gap: var(--space-16); }
  .intro > h1 { grid-column: 1; grid-row: 2; } .intro > .lead { grid-column: 1; grid-row: 3; }
  .intro__photo { grid-column: 2; grid-row: 1 / -1; margin: 0 var(--shadow-offset) var(--shadow-offset) 0; max-width: none; }
}

/* ---- Home hero ------------------------------------------------------------------------------------------------
   Phones: info bar, headline, card collage, lead, actions, skills band, stats.
   From 1024px: headline, lead and actions on the left, the collage on the right; info bar, band and stats span the width.
   The collage is three bordered cards (portrait, a case study, a photo) that deal in on load, spread on hover and fan
   out as the hero scrolls away (motion.css). Its sizes are in container units, so it scales with its column. */
.hero { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: var(--space-16); isolation: isolate;
  grid-template-areas: "meta" "title" "collage" "lead" "cta" "stats" "marquee"; }
/* The info bar has its own rule lines, so the hero starts one hero-gap under the header instead of the full header-gap */
main > .hero:first-child { margin-top: calc(var(--layout-hero-gap) - var(--layout-header-gap)); }
.hero__meta { grid-area: meta; } .hero__title { grid-area: title; } .collage { grid-area: collage; }
.hero__lead { grid-area: lead; } .hero__cta { grid-area: cta; } .marquee { grid-area: marquee; } .hero > .stats { grid-area: stats; }

.hero__meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5) var(--layout-gutter); list-style: none; margin: 0 0 var(--layout-hero-gap); padding: var(--space-5) 0; border-block: var(--border-thin) solid var(--color-border-default); }
.hero__meta li { display: grid; gap: var(--space-1); font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-snug) var(--type-label-family); min-width: 0; }
.hero__meta a { display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--touch-target); margin-block: calc((var(--touch-target) - 1lh) / -2); }
.hero__label { font: var(--type-small-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-small-family); color: var(--color-text-muted); }
.hero__meta time { font-variant-numeric: tabular-nums; }

.hero__title { margin: 0 0 var(--layout-hero-gap); text-wrap: balance; }
@media (max-width: 359px) { .hero__title { font-size: var(--type-h1-size); } } /* long Slovak words still fit at 320px */
/* Two-word motto under the name in the info bar: a sand sticker with a black border, tilted a little */
.hero__tag { justify-self: start; margin: 0; padding: var(--space-1) var(--space-3); border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-pill); background: var(--color-surface-sand); color: var(--color-text-on-sand); font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family); rotate: var(--motion-tilt-sticker); }
.hero__title .word { display: inline-block; overflow: clip; overflow-clip-margin: var(--motion-word-clip); padding-bottom: var(--motion-word-pad); margin-bottom: calc(var(--motion-word-pad) * -1); }
.hero__title .word > span { display: inline-block; }
.hero__lead { margin-bottom: var(--layout-hero-gap); }

.collage { position: relative; z-index: 0; container-type: inline-size; aspect-ratio: var(--aspect-collage); width: min(100%, var(--layout-collage-width)); justify-self: center; margin: var(--space-4) 0 var(--space-12); }
.collage__card { position: absolute; display: block; margin: 0; border: var(--border-default); border-radius: var(--radius-default); box-shadow: var(--shadow-hard); overflow: hidden; background: var(--color-black-100); color: inherit; cursor: pointer; }
.collage__card img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Collage tooltip: one shared pill that follows the pointer (/scripts/motion.js creates it). Inverse colours, so it is
   black with white text in the light theme and white with black text in the dark theme; a sand hard shadow. */
.collage__cursor { position: absolute; left: 0; top: 0; z-index: 10; pointer-events: none; display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-pill); white-space: nowrap;
  background: var(--color-surface-inverse); color: var(--color-text-on-inverse);
  box-shadow: var(--interaction-hover-shift) var(--interaction-hover-shift) 0 0 var(--color-surface-sand);
  font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-solid) var(--type-label-family);
  translate: var(--x, 0) var(--y, 0); rotate: var(--tilt, var(--motion-tilt-tooltip)); scale: var(--motion-scale-tucked); opacity: 0;
  transition: translate var(--motion-duration-follow) var(--motion-easing-out), rotate var(--motion-duration-base) var(--motion-easing-spring), scale var(--motion-duration-base) var(--motion-easing-spring), opacity var(--motion-duration-fast) linear; }
.collage__cursor.is-on { scale: 1; opacity: 1; }
.collage__cursor .icon { transition: transform var(--motion-duration-base) var(--motion-easing-spring); }
.collage__cursor.is-on .icon { transform: translateX(var(--motion-nudge-tip)); }
/* Each card: place in the box, resting tilt (--r), where it moves on hover spread (--dx, --dy), deal order (--n) */
.collage__card--portrait { left: 22%; top: 2%; width: 52%; aspect-ratio: var(--aspect-upright); z-index: 2; --r: var(--collage-tilt-portrait); --dx: -1cqw; --dy: -2cqw; --n: 0; }
.collage__card--photo { left: 58%; top: 8%; width: 40%; aspect-ratio: var(--aspect-portrait); z-index: 1; --r: var(--collage-tilt-photo); --dx: 8cqw; --dy: -5cqw; --n: 2; }
.collage__card--work { left: 0; top: 56%; width: 60%; aspect-ratio: var(--aspect-screen); z-index: 3; --r: var(--collage-tilt-work); --dx: -7cqw; --dy: 6cqw; --n: 1; }
.collage__card--work img { object-position: left top; }

/* Skills band: full-bleed, sand, black rules, scrolling slowly (motion.css). Without motion it is a static, wrapping row. */
.marquee { display: flex; overflow: clip; margin: var(--layout-band-gap) calc(50% - 50vw + var(--scrollbar, 0vw) / 2) 0; width: calc(100vw - var(--scrollbar, 0vw)); background: var(--color-surface-sand); color: var(--color-text-on-sand); border-block: var(--border-default); }
.marquee__group { display: flex; flex: none; align-items: center; gap: var(--space-10); margin: 0; padding: var(--layout-band-padding) 0 var(--layout-band-padding) var(--space-10); list-style: none; font: var(--type-h3-weight) var(--type-h3-size)/var(--type-leading-solid) var(--type-h3-family); letter-spacing: var(--type-h3-letter-spacing); white-space: nowrap; }
.marquee__group li { display: inline-flex; align-items: center; gap: var(--space-10); }
.marquee__group li::after { content: ""; width: var(--size-marquee-mark); height: var(--size-marquee-mark); background: currentColor; rotate: 45deg; } /* a square turned into a diamond: geometry, not a tilt */
.hero > .stats { margin: var(--space-12) 0 0; position: relative; z-index: 1; } /* the collage fans out behind the stats, never over them */

@media (min-width: 1024px) {
  .hero { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); grid-template-rows: auto auto auto 1fr auto auto;
    grid-template-areas: "meta meta" "title collage" "lead collage" "cta collage" "stats stats" "marquee marquee"; }
  .hero__meta { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .collage { width: 100%; align-self: center; margin: 0; }
  .hero > .stats { margin-top: var(--layout-hero-gap); }
}

/* Reels: 9:16 promo videos. Phones: one per row, phone-sized. From 768px: three equal columns.
   width and height attributes reserve the 9:16 box from the first paint, so nothing resizes when a video starts. */
.reels { display: grid; justify-items: center; gap: var(--layout-grid-row); list-style: none; padding: 0; margin: var(--layout-media-gap) 0; }
.reel { margin: 0; width: min(100%, var(--size-reel)); }
.reel__video { display: block; width: 100%; height: auto; aspect-ratio: var(--aspect-story); object-fit: cover; border: var(--border-default); border-radius: var(--radius-default); box-shadow: var(--shadow-hard); background: var(--color-black-900); }
.reel__title { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); margin: var(--space-5) 0 0; font: var(--type-label-weight) var(--type-label-size)/var(--type-leading-snug) var(--type-label-family); }
.reel__title .muted { font: var(--type-small-weight) var(--type-small-size)/var(--type-leading-compact) var(--type-small-family); }
@media (min-width: 768px) { .reels { grid-template-columns: repeat(3, minmax(0, 1fr)); justify-items: stretch; gap: var(--layout-gutter); } .reel { width: auto; } }
.reels__more { margin: 0; }

/* Invitations: a portrait card and a small landscape card side by side, bottoms aligned; stacked on phones */
.invites { display: grid; gap: var(--layout-gutter); align-items: end; }
.invites .media { max-width: var(--size-invite); }
@media (min-width: 768px) { .invites { grid-template-columns: 7fr 5fr; } }
/* Large screens: a wider text column, so long Slovak headlines stay at three lines and the stats stay in the first view */
@media (min-width: 1200px) { .hero { grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); } }

/* ---- Site search (dialog from /scripts/search.js) ------------------------------------------------------------ */
.search-toggle { gap: var(--space-2); padding: 0 var(--space-4); }
.search-toggle--header { display: none; }
@media (min-width: 768px) { .search-toggle--header { display: inline-flex; } }
.site-header .search-toggle { border-width: var(--border-thin); box-shadow: none; }
.site-header .search-toggle:hover, .site-header .search-toggle:active { transform: none; box-shadow: none; background: var(--color-surface-raised); }
@media (min-width: 768px) and (max-width: 1099px) { .search-toggle--header span { position: absolute; width: var(--size-hairline); height: var(--size-hairline); overflow: hidden; clip: rect(0 0 0 0); } .search-toggle--header { padding: 0; width: var(--touch-target); } }
.mobile-menu__lang { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.mobile-menu__lang .btn { flex: 1 1 auto; width: auto; }

.search { width: min(100% - 2 * var(--layout-page-padding), var(--size-search-width)); max-height: min(80vh, var(--size-search-width)); margin: var(--space-16) auto auto; padding: var(--space-6);
  border: var(--border-default); border-radius: var(--radius-default); box-shadow: var(--shadow-hard); background: var(--color-surface-page); color: var(--color-text-primary); }
.search::backdrop { background: var(--color-backdrop-default); }
.search__bar { display: flex; align-items: center; gap: var(--space-3); border-bottom: var(--border-thin) solid var(--color-border-default); padding-bottom: var(--space-4); }
.search__input { flex: 1; min-width: 0; min-height: var(--touch-target); border: 0; background: none; color: inherit; font: var(--type-h4-weight) var(--type-h4-size)/var(--type-leading-tight) var(--type-h4-family); }
.search__input:focus { outline: none; }
.search__input::placeholder { color: var(--color-text-muted); }
/* Focus: the rule under the field doubles in the border colour (a sand line on white was under 3:1, too faint to see) */
.search__bar:focus-within { box-shadow: 0 var(--border-thin) 0 0 var(--color-border-default); }
.search__status { margin: var(--space-4) 0; }
.search__results { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); overflow-y: auto; max-height: calc(min(80vh, var(--size-search-width)) - var(--size-search-chrome)); }
.search__hit { display: grid; gap: var(--space-1); padding: var(--space-4) var(--space-5); border: var(--border-thin) solid var(--color-border-default); border-radius: var(--radius-inset); text-decoration: none; transition: background-color var(--motion-duration-fast) var(--motion-easing-out), transform var(--motion-duration-fast) var(--motion-easing-out); }
.search__hit .kicker { margin: 0; }
.search__hit .small { color: var(--color-text-muted); }
.search__hit:hover, .search__hit:focus-visible { background: var(--color-surface-sand); color: var(--color-text-on-sand); }
.search__hit:hover .small, .search__hit:focus-visible .small, .search__hit:hover .kicker, .search__hit:focus-visible .kicker { color: var(--color-black-700); }
@media (hover: hover) { .search__hit:hover { transform: translateX(var(--space-1)); } }
.search__input::-webkit-search-cancel-button, .search__input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.search__bar .btn { border-width: var(--border-thin); box-shadow: none; }
.search__bar .btn:hover, .search__bar .btn:active { transform: none; box-shadow: none; background: var(--color-surface-raised); }
.search__results { overflow-x: clip; padding-right: var(--space-2); }

/* ---- Stats: three numbers, then the skills donut across the row ------------------------------------------------ */
/* Phones and tablets: label, donut centred, 2x2 legend. Desktop: donut left, label and legend beside it. */
.stats .stat--skills { --skills-line: calc(var(--border-width) / 2); grid-column: 1 / -1; display: grid; min-width: 0; gap: var(--space-6);
  grid-template-columns: minmax(0, 1fr); grid-template-areas: "label" "chart" "legend"; }
.stat--skills > .stat__label { grid-area: label; margin: 0; }
@media (min-width: 1024px) {
  .stats .stat--skills { grid-template-columns: clamp(13rem, 20vw, 16rem) minmax(0, 1fr); grid-template-rows: 1fr auto auto 1fr;
    grid-template-areas: "chart ." "chart label" "chart legend" "chart ."; column-gap: var(--space-16); row-gap: var(--space-4); }
}
.skills__chart { grid-area: chart; justify-self: center; position: relative; width: min(100%, 14rem); aspect-ratio: 1; }
@media (min-width: 1024px) { .skills__chart { width: 100%; } }
.skills__donut { display: block; width: 100%; height: 100%; pointer-events: none; }
/* Each slice is an outlined ring sector with its own fill, so no two rely on colour alone: solid ink, black stripes on
   sand, black dots on grey, ink hatching on the card. The legend swatches paint with the same patterns. */
.skills__seg, .skills__swatch circle { stroke: var(--color-border-default); stroke-width: var(--skills-line); stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.skills__seg[data-skill="0"], .skills__legend [data-skill="0"] .skills__swatch circle { fill: var(--color-text-primary); }
.skills__seg[data-skill="1"], .skills__legend [data-skill="1"] .skills__swatch circle { fill: url(#skills-stripes); }
.skills__seg[data-skill="2"], .skills__legend [data-skill="2"] .skills__swatch circle { fill: url(#skills-dots); }
.skills__seg[data-skill="3"], .skills__legend [data-skill="3"] .skills__swatch circle { fill: url(#skills-hatch); }
.skills__pat--stripes .skills__bg { fill: var(--color-surface-sand); }
.skills__pat--dots .skills__bg { fill: var(--color-black-500); }
.skills__pat--stripes .skills__ink, .skills__pat--dots .skills__ink { fill: var(--color-black-900); }
.skills__pat--hatch .skills__bg { fill: var(--color-surface-raised); }
.skills__pat--hatch .skills__ink { fill: var(--color-text-primary); }
.skills__sweep { fill: none; stroke: var(--color-white); stroke-width: 44; stroke-dasharray: calc(var(--c) * 1px) 0; }
.skills__hit { fill: transparent; stroke: none; pointer-events: all; cursor: pointer; }
.skills__seg { transform: translate(0, 0);
  transition: transform var(--motion-duration-base) var(--motion-easing-spring), opacity var(--motion-duration-fast) var(--motion-easing-out); }
/* The centre holds one number: the total, or the active slice's count. Its words live in the tooltip and the legend. */
.skills__num { position: absolute; inset: 0; display: grid; place-content: center; margin: 0; pointer-events: none;
  font: var(--type-h2-weight) var(--type-h2-size)/1 var(--type-h2-family); letter-spacing: var(--type-h2-letter-spacing); }
.skills__legend { grid-area: legend; list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--touch-gap); }
@media (max-width: 359px) { .skills__legend { grid-template-columns: minmax(0, 1fr); } }
@media (min-width: 1024px) { .skills__legend { gap: var(--space-3); } }
.stats .skills__legend li { grid-column: auto; container-type: inline-size; min-width: 0; }
/* Pills adapt to their own width: on phones the swatch sits on top and name and count stack under it; mid widths put the
   swatch beside the two lines; wide pills are one row with the count on the right. */
.skills__legend a { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: var(--space-3); height: 100%; box-sizing: border-box;
  min-height: var(--touch-target); padding: var(--space-3); border: var(--skills-line) solid var(--color-border-default); border-radius: var(--radius-default);
  color: var(--color-text-primary); text-decoration: none;
  transition: background-color var(--motion-duration-fast) var(--motion-easing-out), color var(--motion-duration-fast) var(--motion-easing-out),
    translate var(--motion-duration-fast) var(--motion-easing-out), box-shadow var(--motion-duration-fast) var(--motion-easing-out); }
.skills__swatch { grid-row: 1 / span 2; width: var(--space-6); height: var(--space-6); overflow: visible; transition: scale var(--motion-duration-base) var(--motion-easing-spring), opacity var(--motion-duration-fast) var(--motion-easing-out); }
.skills__name { font: var(--type-label-weight) var(--type-label-size)/1.2 var(--type-label-family); hyphens: auto; }
.skills__count { font: var(--type-small-weight) var(--type-small-size)/1.3 var(--type-small-family); color: var(--color-text-muted); }
@container (max-width: 11.99rem) {
  .skills__legend a { grid-template-columns: minmax(0, 1fr); align-content: start; row-gap: var(--space-1); padding: var(--space-3) var(--space-2) var(--space-3) var(--space-3); }
  .skills__swatch { grid-row: auto; margin-bottom: var(--space-2); transform-origin: left center; }
}
@container (min-width: 20rem) {
  .skills__legend a { grid-template-columns: auto minmax(0, 1fr) auto; padding: 0 var(--space-4); border-radius: 999px; }
  .skills__swatch { grid-row: auto; }
  .skills__count { white-space: nowrap; }
}
/* One slice active (hover, tap or keyboard focus): its slice pops out of the ring, its pill turns sand and lifts with a
   hard shadow, its swatch grows; the other slices and pills step back. Dimmed pill text stays at muted contrast. */
.stat--skills[data-active] .skills__seg:not([data-on]) { opacity: .5; }
.skills__seg[data-on] { transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)); }
.stat--skills[data-active] .skills__legend a:not([data-on]) { color: var(--color-text-muted); }
.stat--skills[data-active] .skills__legend a:not([data-on]) .skills__swatch { opacity: .6; }
.skills__legend a[data-on], .skills__legend a:hover, .skills__legend a:focus-visible { background: var(--color-surface-sand); color: var(--color-text-on-sand);
  translate: calc(var(--interaction-hover-shift) * -1) calc(var(--interaction-hover-shift) * -1); box-shadow: var(--interaction-hover-shift) var(--interaction-hover-shift) 0 0 var(--color-shadow); }
.skills__legend a[data-on] .skills__count, .skills__legend a:hover .skills__count, .skills__legend a:focus-visible .skills__count { color: var(--color-black-700); }
.skills__legend a[data-on] .skills__swatch, .skills__legend a:hover .skills__swatch, .skills__legend a:focus-visible .skills__swatch { opacity: 1; scale: 1.3; }

/* Motion: page transitions, reveal on scroll, hero intro, microinteractions. Values from tokens.css (motion.*).
   Rules: content is never hidden waiting for JavaScript; nothing travels more than --motion-distance; no scroll-jacking or
   parallax; prefers-reduced-motion turns everything here off (and base.css stops all transitions and animations).
   Durations, delays, tilts, scales and nudges are motion.* tokens; the skills donut lines are left for PR #2. */

/* ---- Microinteractions (every visitor; tiny, fast) ---------------------------------------------------------------- */

/* Whole-card links behave like the buttons: lift toward the page on hover, press flat on tap. The card's inner "Read"
   label is a cue, not a second button, so it loses its own shadow (no shadow inside a shadow). */
.case-card { transition: transform var(--motion-duration-fast) var(--motion-easing-out), box-shadow var(--motion-duration-fast) var(--motion-easing-out); }
.case-card .btn { box-shadow: none; }
@media (hover: hover) {
  .case-card:hover {
    transform: translate(var(--interaction-hover-shift), var(--interaction-hover-shift));
    box-shadow: calc(var(--shadow-offset) - var(--interaction-hover-shift)) calc(var(--shadow-offset) - var(--interaction-hover-shift)) 0 0 var(--color-shadow);
  }
  .case-card:hover .btn span { text-decoration: underline; text-underline-offset: var(--type-underline-offset-ui); }
}
.case-card:active { transform: translate(var(--shadow-offset), var(--shadow-offset)); box-shadow: 0 0 0 0 var(--color-shadow); }

/* Arrows point where they go: a forward arrow nudges forward, an outbound arrow nudges up and out */
.btn svg:has(use[href$="#arrow-right"]), .btn svg:has(use[href$="#arrow-up-right"]),
.site-footer svg:has(use[href$="#arrow-up-right"]) { transition: transform var(--motion-duration-fast) var(--motion-easing-out); }
@media (hover: hover) {
  .btn:hover svg:has(use[href$="#arrow-right"]), .case-card:hover svg:has(use[href$="#arrow-right"]) { transform: translateX(var(--motion-nudge-forward)); }
  .btn:hover svg:has(use[href$="#arrow-up-right"]), a:hover > svg:has(use[href$="#arrow-up-right"]) { transform: translate(var(--motion-nudge-diagonal), calc(var(--motion-nudge-diagonal) * -1)); }
}

/* Navigation links: the underline draws in from the left; the current page keeps a full one */
.site-nav a:not(.btn) { background: linear-gradient(currentColor, currentColor) left bottom / 0 var(--border-thin) no-repeat; transition: background-size var(--motion-duration-base) var(--motion-easing-out); }
.site-nav a:not(.btn)[aria-current="page"] { text-decoration: none; background-size: 100% var(--border-thin); }
@media (hover: hover) { .site-nav a:not(.btn):hover { background-size: 100% var(--border-thin); } }
.site-nav a:not(.btn) { background-position: left calc(50% + var(--type-underline-drop)); }

/* Form fields: the active field gets the standard focus ring, evenly around it */
.input { transition: outline-offset var(--motion-duration-fast) var(--motion-easing-out); }
.input:focus { outline: var(--focus-ring); outline-offset: var(--focus-offset); } /* one even ring on all four sides; it eases out from the border */
.input:not(:focus) { outline-offset: 0; }

/* Theme toggle: the icon turns as it swaps */
.theme-toggle .icon { transition: transform var(--motion-duration-base) var(--motion-easing-out); }
.theme-toggle:active .icon { transform: rotate(var(--motion-tilt-toggle)) scale(var(--motion-scale-toggle)); }

/* Header: slides away while reading down, comes back on any scroll up (/scripts/motion.js sets data-hidden) */
.site-header { transition: transform var(--motion-duration-base) var(--motion-easing-in-out); }
.site-header[data-hidden] { transform: translateY(-100%); }

@media (prefers-reduced-motion: no-preference) {

  /* ---- Page transitions: the header stays, the page crossfades and rises (browsers without support just navigate) */
  @view-transition { navigation: auto; }
  .site-header { view-transition-name: site-header; }
  ::view-transition-old(root) { animation: var(--motion-duration-fast) var(--motion-easing-in-out) both fade-out; }
  ::view-transition-new(root) { animation: var(--motion-duration-base) var(--motion-easing-out) both rise-in; }

  /* ---- Hero intro: the first section's parts arrive one after another on load */
  main > .section:first-child:not(.hero) > *, main > nav:first-child + .section > * { animation: rise-in var(--motion-duration-slow) var(--motion-easing-out) both; }
  main > .section:first-child:not(.hero) > :nth-child(2), main > nav:first-child + .section > :nth-child(2) { animation-delay: calc(var(--motion-stagger) * 1); }
  main > .section:first-child:not(.hero) > :nth-child(3), main > nav:first-child + .section > :nth-child(3) { animation-delay: calc(var(--motion-stagger) * 2); }
  main > .section:first-child:not(.hero) > :nth-child(4), main > nav:first-child + .section > :nth-child(4) { animation-delay: calc(var(--motion-stagger) * 3); }
  main > .section:first-child:not(.hero) > :nth-child(n+5), main > nav:first-child + .section > :nth-child(n+5) { animation-delay: calc(var(--motion-stagger) * 4); }
  /* The same for an image wrapped in <picture> (display: contents, no box of its own): its <img> takes the part */
  :is(main > .section:first-child:not(.hero), main > nav:first-child + .section) > picture > img { animation: rise-in var(--motion-duration-slow) var(--motion-easing-out) both; }
  :is(main > .section:first-child:not(.hero), main > nav:first-child + .section) > picture:nth-child(2) > img { animation-delay: calc(var(--motion-stagger) * 1); }
  :is(main > .section:first-child:not(.hero), main > nav:first-child + .section) > picture:nth-child(3) > img { animation-delay: calc(var(--motion-stagger) * 2); }
  :is(main > .section:first-child:not(.hero), main > nav:first-child + .section) > picture:nth-child(4) > img { animation-delay: calc(var(--motion-stagger) * 3); }
  :is(main > .section:first-child:not(.hero), main > nav:first-child + .section) > picture:nth-child(n+5) > img { animation-delay: calc(var(--motion-stagger) * 4); }
  .stats > li { animation: rise-in var(--motion-duration-slow) var(--motion-easing-out) both; }
  .stats > li:nth-child(2) { animation-delay: calc(var(--motion-stagger) * 3); }
  .stats > li:nth-child(3) { animation-delay: calc(var(--motion-stagger) * 5); }

  /* ---- Reveal on scroll: tied to scroll position (no JavaScript, no hidden content). Anything already on screen when
     the page loads is past its range and simply shows. Browsers without scroll-driven animations show everything. */
  @supports (animation-timeline: view()) {
    main > .section:not(:first-child):not(nav:first-child + .section) > :not(.grid, .photo-grid, .stack, .findings, .process),
    main .grid > *, main .photo-grid > *, main .stack > *, main .findings > li, main .process > li,
    .site-footer__inner > * {
      animation: rise-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 90%;
    }
    /* Photos in a row arrive in a slight cascade: later columns start a little later in the scroll */
    main .photo-grid > :nth-child(4n+2), main .grid > :nth-child(3n+2) { animation-range: entry 8% entry 98%; }
    main .photo-grid > :nth-child(4n+3), main .grid > :nth-child(3n+3) { animation-range: entry 16% cover 30%; }
    main .photo-grid > :nth-child(4n+4) { animation-range: entry 24% cover 34%; }
    /* Images wrapped in <picture> (display: contents): the <img> inside takes the reveal */
    main > .section:not(:first-child):not(nav:first-child + .section) > picture > img, main .grid > picture > img, main .stack > picture > img {
      animation: rise-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 90%;
    }
    main .grid > picture:nth-child(3n+2) > img { animation-range: entry 8% entry 98%; }
    main .grid > picture:nth-child(3n+3) > img { animation-range: entry 16% cover 30%; }

    /* Case studies: a progress bar just below the header shows how far through the story you are (Goal-Gradient).
       It hangs under the header's border, so it stays on screen when the header slides away. */
    body:has(main .meta) .site-header::after {
      content: ""; position: absolute; left: 0; right: 0; bottom: calc(var(--border-width) * -2); height: var(--border-width);
      background: var(--color-surface-sand); transform-origin: left; transform: scaleX(0);
      animation: progress linear both; animation-timeline: scroll(root);
    }
  }

  /* ---- Dialogs: the menu and the photo viewer scale in, their backdrop fades */
  .mobile-menu[open], .lightbox[open], .search[open] { animation: pop-in var(--motion-duration-base) var(--motion-easing-out); }
  .mobile-menu[open]::backdrop, .lightbox[open]::backdrop, .search[open]::backdrop { animation: fade-in var(--motion-duration-base) var(--motion-easing-out); }
  .mobile-menu[open] li { animation: rise-in var(--motion-duration-base) var(--motion-easing-out) both; }
  .mobile-menu[open] li:nth-child(2) { animation-delay: calc(var(--motion-stagger) * 1); }
  .mobile-menu[open] li:nth-child(3) { animation-delay: calc(var(--motion-stagger) * 2); }
  .mobile-menu[open] li:nth-child(4) { animation-delay: calc(var(--motion-stagger) * 3); }

  /* Photo viewer: the new photo slides in from the side it came from (/scripts/lightbox.js sets data-dir) */
  .lightbox__img[data-dir="next"] { animation: slide-from-right var(--motion-duration-base) var(--motion-easing-out); }
  .lightbox__img[data-dir="prev"] { animation: slide-from-left var(--motion-duration-base) var(--motion-easing-out); }

  /* Form result: the status tag pops in */
  .contact-status:not([hidden]) { animation: pop-in var(--motion-duration-base) var(--motion-easing-out); }
}

/* ---- Home hero: collage geometry. Three registered numbers drive every card, so the effects add up instead of
   overriding each other: --deal (1 = still in the stack, on load), --spread (hover), --fan (scrolling away). */
@property --deal { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --spread { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --fan { syntax: "<number>"; inherits: true; initial-value: 0; }
/* Phones: the collage fills the column, so it fans out mostly upwards and only a little sideways (no sideways scroll) */
@media (max-width: 1023px) { .collage { --fan-x: 0.35; } }
@media (min-width: 1024px) and (max-width: 1439px) { .collage { --fan-x: 1; } } /* less room beside the column */
.collage__card {
  translate: calc(var(--dx) * (var(--spread) + var(--fan) * var(--fan-x, 2.5))) calc(var(--dy) * var(--spread) - var(--fan) * 10cqw + var(--deal) * 30cqw);
  rotate: calc(var(--r) * (1 - var(--deal) + var(--spread) * .6 + var(--fan)));
  opacity: calc(1 - var(--deal));
  transition: --spread var(--motion-duration-base) var(--motion-easing-out), scale var(--motion-duration-fast) var(--motion-easing-out), box-shadow var(--motion-duration-fast) var(--motion-easing-out);
}
@media (hover: hover) {
  .collage:hover .collage__card { --spread: 1; }
  .collage__card:hover { scale: var(--motion-scale-lift); z-index: 4; }
  a.collage__card:hover { box-shadow: calc(var(--shadow-offset) + var(--interaction-hover-shift)) calc(var(--shadow-offset) + var(--interaction-hover-shift)) 0 0 var(--color-shadow); }
}
a.collage__card:active { scale: var(--motion-scale-press); }
a.collage__card:focus-visible { --spread: 1; z-index: 4; }

@media (prefers-reduced-motion: no-preference) {
  /* Headline: each word rises out of its own line box, one after another */
  .hero__title .word > span { animation: word-up var(--motion-duration-slow) var(--motion-easing-out) backwards; animation-delay: calc(var(--i) * var(--motion-stagger) + var(--motion-delay-title)); }
  .hero__meta li { animation: fade-in var(--motion-duration-slow) var(--motion-easing-out) backwards; }
  .hero__meta li:nth-child(2) { animation-delay: calc(var(--motion-stagger) * 1); }
  .hero__meta li:nth-child(3) { animation-delay: calc(var(--motion-stagger) * 2); }
  .hero__meta li:nth-child(4) { animation-delay: calc(var(--motion-stagger) * 3); }
  .hero__tag { animation: pop-in var(--motion-duration-base) var(--motion-easing-spring) backwards; animation-delay: var(--motion-stagger); }
  .hero__lead, .hero__cta { animation: rise-in var(--motion-duration-slow) var(--motion-easing-out) backwards; animation-delay: var(--motion-delay-lead); }
  .hero__cta { animation-delay: var(--motion-delay-cta); }
  /* Collage: the photo and the case study are dealt onto the portrait. The portrait is on screen from the first frame: it
     is the page's largest paint (LCP), and fading it in held that back by about a second. */
  .collage__card:not(.collage__card--portrait) { animation: deal var(--motion-duration-deal) var(--motion-easing-out) backwards; animation-delay: calc(var(--motion-delay-deal) + var(--n) * var(--motion-delay-deal-step)); }
  /* Skills band scrolls slowly; it pauses under the pointer */
  .marquee__group { animation: marquee var(--motion-duration-marquee) linear infinite; }
  .marquee:hover .marquee__group { animation-play-state: paused; }
  /* As the hero leaves the screen the fan opens up (scroll-driven; static where unsupported) */
  @supports (animation-timeline: view()) {
    .collage { animation: fan linear both; animation-timeline: view(); animation-range: exit -20% exit 80%; }
  }
}
/* Without motion the band is a plain wrapping row of the four skills (the copies for the loop go away) */
@media (prefers-reduced-motion: reduce) {
  .marquee { flex-wrap: wrap; }
  .marquee__group { flex: 1 1 auto; min-width: 0; white-space: normal; flex-wrap: wrap; row-gap: var(--space-4); }
  .marquee__group + .marquee__group, .marquee__group li:nth-child(n+5) { display: none; }
}

@keyframes deal { from { --deal: 1; } }
@keyframes fan { to { --fan: 1; } }
@keyframes word-up { from { transform: translateY(105%); } }
@keyframes marquee { to { transform: translateX(-100%); } }
/* Skills donut: a mask sweeps clockwise from the top and draws the slices in. Without motion there is no mask at all. */
@media (prefers-reduced-motion: no-preference) {
  .skills__ring { mask: url(#skills-sweep); }
  .skills__sweep { animation: draw-seg 1000ms var(--motion-easing-out) 500ms backwards; }
}
@keyframes draw-seg { from { stroke-dasharray: 0 calc(var(--c) * 1px); } }
@keyframes rise-in { from { opacity: 0; transform: translateY(var(--motion-distance)); } }
@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }
@keyframes pop-in { from { opacity: 0; transform: scale(var(--motion-scale-pop)); } }
@keyframes slide-from-right { from { opacity: 0; transform: translateX(var(--motion-distance)); } }
@keyframes slide-from-left { from { opacity: 0; transform: translateX(calc(var(--motion-distance) * -1)); } }
@keyframes progress { to { transform: scaleX(1); } }
