@charset "UTF-8";
/* =========================================================
   Nikita Strunkis — portfolio
   Design system: see DESIGN.md. Every value below comes from a token.
   Order: tokens → base → type roles → layout → components → pages → responsive.
   ========================================================= */

/* ---------- 1. Tokens ---------- */
:root {
  /* Color */
  --bg: #F2EFE8;            /* page background (Figma) */
  --bg-raised: #EAE8DC;     /* nav pill, image placeholders, diagrams */
  --text: #161511;          /* primary text (Figma) */
  --text-muted: #4D4B3F;    /* secondary text, mono labels — 8.4:1 on --bg */
  --line: #DFDCCB;          /* all 1px rules and borders */
  --accent: #A87D50;        /* marker only: underlines, focus, ticks — never text */
  --accent-soft: rgb(168 125 80 / 0.16);  /* hover highlight behind text */
  --backdrop: rgb(0 0 0 / 0.55);

  /* Type families */
  --font-sans: "Google Sans Flex", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: "Space Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Type scale (fluid). Values at 1440px in comments. */
  --t-label: clamp(13px, 0.42vw + 8px, 18px);     /* 14 — mono labels, tags, meta */
  --t-body: clamp(17px, 0.3vw + 14px, 24px);      /* 18 — paragraphs, nav, lists */
  --t-lead: clamp(20px, 1.6vw, 40px);             /* 23 — subheads, small card titles */
  --t-title: clamp(24px, 2.5vw, 64px);            /* 36 — item titles */
  --t-statement: clamp(22px, 2.2vw, 56px);        /* 32 — statements (About lead, footer email), medium */
  --t-heading: clamp(32px, 3.6vw, 96px);          /* 52 — section headings (h2) */
  --t-display: clamp(42px, 6.6vw, 240px);         /* 95 — page title (h1), mobile menu */
  --t-number: clamp(56px, 7vw, 280px);            /* 101 — key result numbers (mono) */
  --t-hero: clamp(56px, min(15vw, 30svh), 560px); /* 216 — home hero title only; also capped by the viewport height */

  /* Line height per role */
  --lh-display: 1;
  --lh-heading: 1.05;
  --lh-title: 1.15;
  --lh-statement: 1.25;
  --lh-lead: 1.25;
  --lh-body: 1.4;
  --lh-label: 1.4;
  --lh-number: 0.9;
  --lh-hero: 0.86;

  /* Tracking per role */
  --tr-display: 0;
  --tr-heading: 0;
  --tr-title: 0;
  --tr-statement: 0;
  --tr-lead: 0;
  --tr-body: 0;
  --tr-label: 0;
  --tr-number: -0.06em;
  --tr-hero: -0.015em;

  /* Weight: only two */
  --w-regular: 400;
  --w-medium: 500;

  /* Measure (line length) */
  --measure: 70ch;         /* body text and media inside text */
  --measure-intro: 40ch;   /* short intros next to headings */
  --measure-hero: 36ch;    /* home hero intro */
  --measure-title: 20ch;   /* long h1/h2 titles */
  --measure-caption: 26ch; /* captions under key numbers */

  /* Spacing scale (4px base) */
  --s-1: 4px;  --s-2: 8px;   --s-3: 12px;  --s-4: 16px;
  --s-5: 24px; --s-6: 32px;  --s-7: 48px;  --s-8: 64px;
  --s-9: 96px; --s-10: 128px; --s-11: 256px;

  /* Spacing roles */
  --space-head: clamp(var(--s-9), 13.3vw, var(--s-11)); /* header → page head content (256 @1920) */
  --space-section: var(--s-9);     /* vertical padding of every section */
  --space-after-head: var(--s-7);  /* page head bottom, and rule → first untitled block */
  --space-label: var(--s-6);       /* mono label → heading */
  --space-block: var(--s-5);       /* between blocks inside a text column */
  --space-cards: var(--s-10);      /* between rows of cards */
  --space-story: var(--s-10);      /* content → next ruled story label (About) */
  --space-chrome: var(--s-6);      /* header vertical padding */
  --header-h: calc(var(--space-chrome) * 2 + var(--hit));  /* fixed header height (104) */

  /* Layout */
  --gutter: clamp(16px, 3.33vw, 96px);
  --margin: clamp(16px, 3.33vw, 120px);

  /* Shape and size */
  --radius-s: 2px;         /* images, media */
  --radius-m: 4px;         /* modal */
  --radius-pill: 999px;    /* tags, buttons */
  --rule: 1px solid var(--line);
  --underline: 2px;        /* accent underline of every link (hover or always on) */
  --underline-menu: 3px;   /* mobile menu links (Display size) */
  --underline-offset: 0.15em;
  --icon: 20px;            /* icons in text rows */
  --icon-l: 24px;          /* icons in 40px buttons */
  --hit: 40px;             /* icon button size */
  --nav-h: var(--s-7);     /* desktop nav pill height (48) */
  --about-art-ratio: 1802 / 1174;  /* About photo frame (Figma, content width) */
  --modal-width: 800px;    /* Lab modal */
  --cover-ratio: 28 / 15;  /* case cover image frame (template) */
  --dot: 0.6em;            /* case breadcrumb dot */
  --blur-max: 20px;        /* header progressive blur at its top edge (live Framer site) */
  --blur-tint: 72%;        /* --bg mixed into the header blur: brand and icons stay readable over any image */

  /* Motion */
  --ease: cubic-bezier(.2, .7, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);  /* long soft stop, like a spring with no bounce: reveal, media zoom, arrow swap */
  --dur-fast: .2s;
  --dur: .3s;
  --dur-slow: .4s;         /* media zoom, arrow swap */
  --dur-reveal: .5s;
  --stagger: .05s;         /* delay between items revealed together */
  --rise: var(--s-4);      /* reveal travel (16) */
  --zoom: 1.02;            /* card image scale on hover */

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1B1A18; --bg-raised: #24221F; --text: #F2EFE6; --text-muted: #9C968D; --line: #36332F;
    --accent: #C9A07A; --accent-soft: rgb(201 160 122 / 0.16);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #1B1A18; --bg-raised: #24221F; --text: #F2EFE6; --text-muted: #9C968D; --line: #36332F;
  --accent: #C9A07A; --accent-soft: rgb(201 160 122 / 0.16);
  color-scheme: dark;
}

/* Touch (tablet and phone): every button and icon link is at least 44 × 44 */
@media (max-width: 960px) {
  :root { --hit: 44px; }
}

@media (max-width: 640px) {
  :root {
    --t-body: 17px;
    --space-section: var(--s-8);
    --space-cards: var(--s-8);
    --space-story: var(--s-8);
  }
}

/* ---------- 2. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: var(--header-h); }  /* anchors land below the header */
/* Smooth wheel scrolling: Lenis (vendor/lenis.min.js) and the CSS it requires */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }
/* Theme switch: main.js wraps it in a view transition; the old theme fades into the new one */
.theme-fade::view-transition-old(root),
.theme-fade::view-transition-new(root) { animation-duration: var(--dur); animation-timing-function: var(--ease); }
body {
  margin: 0;
  min-height: 100svh;
  display: flex; flex-direction: column;   /* footer sits at the bottom of short pages */
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  font-weight: var(--w-regular);
  letter-spacing: var(--tr-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body > main { flex: 1 0 auto; }
body > .wrap, body > main { width: 100%; }  /* auto margins on flex items would shrink them */

h1, h2, h3, h4, p, ul, ol, figure, dl, dd { margin: 0; padding: 0; }
h1, h2, h3, h4 { font-weight: var(--w-regular); }
h4 { font-size: inherit; }  /* h4 (experience role) uses the Body role */
ul, ol { list-style: none; }
img, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--radius-s); }

.skip {
  position: absolute; left: var(--margin); top: calc(var(--s-9) * -1);
  background: var(--text); color: var(--bg); padding: var(--s-2) var(--s-3);
}
.skip:focus { top: var(--s-3); }

/* ---------- 3. Type roles ----------
   Each role = size + line height + tracking + weight. Add new elements to a role, never invent values. */

/* Hero: home page title only */
.hero-title {
  font-size: var(--t-hero); line-height: var(--lh-hero); letter-spacing: var(--tr-hero);
  font-weight: var(--w-medium);
}
/* Display: page title h1, mobile menu links */
.work-heading,
.nav-links a,
.footer-title {
  font-size: var(--t-display); line-height: var(--lh-display); letter-spacing: var(--tr-display);
  font-weight: var(--w-medium);
}
/* Heading: section h2, modal title, next case */
.section-heading,
.contact-heading,
.lab-modal-title {
  font-size: var(--t-heading); line-height: var(--lh-heading); letter-spacing: var(--tr-heading);
}
/* Title (regular): titles of items — case cards, companies, skill groups */
.case-title,
.xp-company,
.skills h3 {
  font-size: var(--t-title); line-height: var(--lh-title); letter-spacing: var(--tr-title);
}
/* Statement (medium): one big sentence or a big link */
.lead,
.email-link {
  font-size: var(--t-statement); line-height: var(--lh-statement); letter-spacing: var(--tr-statement);
  font-weight: var(--w-medium);
}
/* Lead (medium): subheads inside long text */
.case-story h3 {
  font-size: var(--t-lead); line-height: var(--lh-lead); letter-spacing: var(--tr-lead);
  font-weight: var(--w-medium);
}
/* Label: mono meta text */
.mono {
  font-family: var(--font-mono); font-size: var(--t-label); line-height: var(--lh-label);
  letter-spacing: var(--tr-label); color: var(--text-muted); font-variant-numeric: tabular-nums;
}
/* Number: key results */
.stat-value {
  font-family: var(--font-mono); font-size: var(--t-number); line-height: var(--lh-number);
  letter-spacing: var(--tr-number); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.brand, .li-term { font-weight: var(--w-medium); }

/* Links. The accent marks, it never colors text. */
/* One underline for every link: --underline thick, --underline-offset below the text, accent color.
   a.link shows it always (hover adds the soft highlight); plain links show it on hover. */
a.link,
.footer-nav a, .footer-social a, .case-head .label a, .case-title, .xp-company a, .contact-email {
  text-decoration-line: underline; text-decoration-thickness: var(--underline);
  text-underline-offset: var(--underline-offset); text-decoration-color: transparent;
  transition: text-decoration-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
a.link { color: var(--text); text-decoration-color: var(--accent); }
a.link:hover { background-color: var(--accent-soft); }
.footer-nav a:hover,
.footer-social a:hover,
.case-head .label a:hover,
.case:hover .case-title, .case:focus-visible .case-title,
.xp-company a:hover,
.contact-email:hover { text-decoration-color: var(--accent); }

/* ---------- 4. Layout ---------- */
.wrap { margin: 0 auto; padding: 0 var(--margin); }
.grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); }

/* Section: every content block below the page head */
.section { padding-block: var(--space-section); border-top: var(--rule); }
/* Extra air before the footer: the last block of every page ends with twice the section padding
   (titled sections, untitled card lists on Cases / Playground, ruled stories) */
main > :not(.page-head):last-child { padding-bottom: calc(var(--space-section) * 2); }

/* Page head: same position and height on every page */
.page-head { padding-top: var(--space-head); padding-bottom: var(--space-after-head); }
/* No divider between the page head and a titled section (Home, Contacts): head bottom 32 + section 96 */
.page-head + .section { border-top: 0; }
.page-head:has(+ .section) { padding-bottom: var(--s-6); }
/* 404: no header or footer; the page head is centered in the viewport */
.notfound { display: grid; align-content: center; padding-block: var(--s-8); }
.notfound .page-head { padding-block: 0; }
.page-head .work-heading { grid-column: 1 / span 10; max-width: var(--measure-title); }
.page-head .work-intro { grid-column: 8 / span 4; }
.page-head .work-heading:has(+ .work-intro) { grid-column: 1 / span 6; }
/* Home hero: fills the viewport under the header; title bottom-left, intro aligned to its bottom.
   min-height (not height): on very short screens the hero grows instead of clipping */
.page-head.hero {
  min-height: calc(100svh - var(--header-h));
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-top: var(--s-8); padding-bottom: var(--space-section);
}
.hero .grid { width: 100%; align-items: end; }
.hero-title { grid-column: 1 / span 8; }
.hero-intro { grid-column: 9 / -1; max-width: var(--measure-hero); display: grid; gap: var(--space-block); }
/* First block after the head without its own label (About photo, case visual, card list):
   48 below the head, no rule. Titled sections keep --space-section. */
.page-head + :not(.section) {
  padding-top: var(--space-after-head);
  padding-bottom: var(--space-section);
}

/* Mono label above a heading or a section */
.label { grid-column: 1 / -1; margin-bottom: var(--space-label); }
.work-intro { align-self: start; padding-top: 0.6em; color: var(--text-muted); max-width: var(--measure-intro); }
.work-intro:has(> p) { display: grid; gap: var(--space-block); justify-items: start; }  /* intro text → link (404) */
.section-heading { grid-column: 1 / span 8; }

/* Story: sticky label on the left, text column on the right */
.story .grid { row-gap: var(--space-label); }  /* label → text when stacked */
.story-label { grid-column: 1 / span 3; align-self: start; position: sticky; top: calc(var(--header-visible, var(--header-h)) + var(--s-5)); }
.header-animating .story-label { transition: top var(--dur) var(--ease); }  /* follows the header sliding back */
.story-body { grid-column: 4 / span 7; display: grid; gap: var(--space-block); }
.story-body > p, .story-body > ul, .story-body > h3, .story-body li { max-width: var(--measure); }
/* Media inside a text column is as wide as the text, never wider */
.story-body > figure, .story-body > .fig-pair { width: 100%; max-width: var(--measure); }
.story-body ul { display: grid; gap: var(--s-2); }
.story-body ul li { position: relative; padding-left: 1.2em; }
.story-body ul li::before { content: "\2014"; position: absolute; left: 0; color: var(--text-muted); }

.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--s-6); }
.split > div { display: grid; gap: var(--space-block); align-content: start; }  /* item title → list 24, like company → roles */

/* ---------- 5. Components ---------- */

/* Header */
/* Header: sticky, no rule under it. main.js moves it up with the page on scroll down
   (inline transform, no transition) and slides it back on scroll up (.header-animating) */
.header {
  padding-block: var(--space-chrome);
  position: sticky; top: 0; z-index: 10;
  background: var(--bg);
  will-change: transform;
}
.header-animating .header { transition: transform var(--dur) var(--ease); }
.header .grid { position: relative; z-index: 1; align-items: center; min-height: var(--hit); }

/* Progressive blur under the header (as on the live Framer site): no fill, the page scrolls under it.
   The live site's top 4 of 8 layers: each twice as strong as the one below (--blur-max / 8 … --blur-max), each
   masked to its own 12.5% band, so the blur grows from the middle of the header to --blur-max at the top edge.
   The 4 weakest layers (under 1.5px, where the tint fades out) are left out: every backdrop-filter layer is
   re-rendered on each scroll frame, whatever its radius, so they cost as much as the strong ones. */
.header-blur { display: none; }
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .header { background: transparent; }
  .header-blur { display: block; position: absolute; inset: 0; pointer-events: none; }
  .header-blur > span {
    --band: 12.5%;   /* 100% / 8 layers */
    position: absolute; inset: 0;
    -webkit-backdrop-filter: blur(calc(var(--blur-max) / var(--div)));
    backdrop-filter: blur(calc(var(--blur-max) / var(--div)));
    -webkit-mask-image: linear-gradient(to top, transparent calc((var(--n) - 1) * var(--band)), black calc(var(--n) * var(--band)), black calc((var(--n) + 1) * var(--band)), transparent calc((var(--n) + 2) * var(--band)));
    mask-image: linear-gradient(to top, transparent calc((var(--n) - 1) * var(--band)), black calc(var(--n) * var(--band)), black calc((var(--n) + 1) * var(--band)), transparent calc((var(--n) + 2) * var(--band)));
  }
  .header-blur > :nth-child(1) { --n: 5; --div: 8; }
  .header-blur > :nth-child(2) { --n: 6; --div: 4; }
  .header-blur > :nth-child(3) { --n: 7; --div: 2; }
  .header-blur > :nth-child(4) { --n: 8; --div: 1; }
  /* Tint in the page color (darkens in the dark theme, lightens in the light one): full from the top edge
     to the middle of the header, where the brand and icons sit, then fading out with the blur */
  .header-blur::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(to bottom, color-mix(in srgb, var(--bg) var(--blur-tint), transparent) 50%, transparent);
  }
}
/* Reduced transparency (OS setting): solid header, as before */
@media (prefers-reduced-transparency: reduce) {
  .header { background: var(--bg); }
  .header-blur { display: none; }
}
.brand { grid-column: 1 / span 4; }
.nav { grid-column: 5 / -1; display: flex; justify-content: flex-end; align-items: center; gap: var(--s-5); }
.nav-links { display: flex; gap: var(--s-5); }
@media (min-width: 961px) {
  /* Links in a pill centered on the page; brand left, theme toggle at the right content edge */
  /* Segmented pill: 4 inset on every side, each link is a 40-tall chip (16 side padding → 32 between labels) */
  .nav-links {
    position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
    align-items: center; gap: 0; height: var(--nav-h); padding: var(--s-1);
    background: var(--bg-raised); border-radius: var(--radius-pill);
  }
  .nav-links a {
    font-size: inherit; line-height: inherit; letter-spacing: var(--tr-body); font-weight: inherit; position: relative;
    display: flex; align-items: center; height: var(--hit); padding-inline: var(--s-4); border-radius: var(--radius-pill);
  }
  /* Hover underline: --underline thick, 2px under the text */
  .nav-links a::after {
    content: ""; position: absolute; left: var(--s-4); right: var(--s-4); bottom: calc((var(--hit) - 1lh) / 2 - 2px); height: var(--underline);
    background: var(--accent); transform: scaleX(0); transform-origin: left;
    transition: transform var(--dur) var(--ease);
  }
  .nav-links a:hover::after, .nav-links a:focus-visible::after { transform: scaleX(1); }
  /* Current section: the chip is filled with the accent tint (--accent-soft), same 4 inset from the pill edge on every side */
  /* A case opened from Home (data-from="home", set in <head>) has no current item: no flash before main.js drops aria-current */
  :root:not([data-from="home"]) .nav-links a[aria-current] { background: var(--accent-soft); }
  :root:not([data-from="home"]) .nav-links a[aria-current]::after { content: none; }
}

/* Icon buttons: theme toggle, burger, modal close */
.theme-toggle, .menu-toggle, .lab-close, .lightbox-close {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--hit); height: var(--hit); padding: 0; margin: calc(var(--s-2) * -1) 0;
  background: none; border: 0; border-radius: var(--radius-pill);
  color: var(--text); cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
/* Theme toggle shows the current theme as an icon only: sun (light) or moon (dark) */
.theme-toggle { margin-right: calc((var(--icon-l) - var(--hit)) / 2); }  /* the icon, not the hit area, ends on the content edge */
.theme-toggle:hover { color: var(--text-muted); }
.lab-close { margin: 0; }
.lab-close:hover, .lightbox-close:hover { background: var(--accent-soft); }
.theme-toggle .icon, .menu-toggle .icon, .lab-close .icon, .lightbox-close .icon { width: var(--icon-l); height: var(--icon-l); }
.menu-toggle { display: none; margin-right: calc((var(--icon-l) - var(--hit)) / 2); }
.menu-toggle .icon-close { display: none; }
.menu-open .menu-toggle .icon-open { display: none; }
.menu-open .menu-toggle .icon-close { display: inline-block; }
.theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: inline-block; }
}
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: inline-block; }

/* Back to top: icon button fixed to the bottom-right corner (--margin from the right, 16 from the bottom
   so it stays below the footer nav at the end of the page),
   built by main.js; fades in once the page is scrolled past half a screen */
.to-top {
  position: fixed; right: var(--margin); bottom: var(--s-4); z-index: 10;
  display: grid; place-items: center; overflow: hidden;
  width: var(--hit); height: var(--hit); padding: 0;
  background: var(--bg-raised); border: 0; border-radius: var(--radius-pill);
  color: var(--text); cursor: pointer;
  opacity: 0; visibility: hidden; transform: translateY(var(--s-2));
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility 0s linear var(--dur), color var(--dur-fast) var(--ease);
}
.to-top.is-visible {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), color var(--dur-fast) var(--ease);
}
.to-top:hover { color: var(--text-muted); }
.to-top .icon { grid-area: 1 / 1; width: var(--icon-l); height: var(--icon-l); transition: transform var(--dur-slow) var(--ease-out); }
/* Hover: the arrow leaves through the top, a copy comes in from the bottom */
.to-top .icon + .icon { transform: translateY(var(--hit)); }
.to-top:hover .icon:first-child { transform: translateY(calc(var(--hit) * -1)); }
.to-top:hover .icon + .icon { transform: none; }
.menu-open .to-top { visibility: hidden; opacity: 0; }

/* Icons inside text */
.icon { width: 1em; height: 1em; display: inline-block; flex: none; vertical-align: -0.125em; }

/* Footer */
/* Footer: contact block (title, email, social) + bottom bar */
.footer { padding-bottom: var(--s-8); }
/* Footer rules are content width, like the rule under a section heading */
.footer-contact { padding-block: var(--s-8); row-gap: var(--s-7); border-top: var(--rule); }
.footer-title { grid-column: 1 / span 10; max-width: var(--measure-title); }
.footer-email { grid-column: 1 / -1; }
.footer-social { grid-column: 1 / span 6; display: grid; gap: var(--space-label); }
.footer-social ul {
  display: grid; grid-template-rows: repeat(2, auto); grid-auto-flow: column; grid-auto-columns: max-content; column-gap: var(--s-7); row-gap: var(--s-3);
}
.footer-social li { display: flex; }
.footer-social a { display: inline-flex; align-items: center; gap: var(--s-2); }
.footer-social .icon { width: var(--icon); height: var(--icon); }
@media (max-width: 960px) {
  /* Touch: each row is a full --hit tall target; rows touch, so the visible gap stays close to desktop */
  .footer-social ul { row-gap: 0; }
  .footer-social a { min-height: var(--hit); }
}
.footer-bar { padding-top: var(--s-8); row-gap: var(--s-2); align-items: center; }
.footer-contact + .footer-bar { border-top: var(--rule); }
.footer-bar > p { grid-column: 1 / span 8; }
.footer-nav { grid-column: 9 / span 4; display: flex; justify-content: flex-end; gap: var(--s-5); }

/* Media */
.media { position: relative; overflow: hidden; border-radius: var(--radius-s); background: var(--bg-raised); }
.media img, .media video { width: 100%; height: 100%; object-fit: cover; }
.ratio-4-3 { aspect-ratio: 4 / 3; }
.fig { display: grid; gap: var(--s-3); }
.fig img, .fig video,
.process-media video {
  width: 100%; height: auto; border-radius: var(--radius-s); background: var(--bg-raised);
}
.fig-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--gutter); row-gap: var(--space-block); }

/* Card list (Case Studies, Lab) */
.work-list {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--gutter); row-gap: var(--space-cards);
}
/* Section head → 32 → rule → 64 → content (Home cards, Contacts location) */
.after-rule { grid-column: 1 / -1; margin-top: var(--s-6); padding-top: var(--s-8); border-top: var(--rule); }
.work-list > li { display: flex; }
.case { flex: 1; display: flex; flex-direction: column; }
/* Case card (Home, Lab, next case): image → 32 → discipline · domain → 16 → title */
.case-media { position: relative; margin-bottom: var(--s-6); }
.case-meta { margin: 0 0 var(--s-4); }
.case-meta:last-child { margin-bottom: 0; }  /* Playground cards end with the meta line */
/* Hover: the image zooms in slowly inside its frame (the frame clips it) */
.case-media .media img, .case-media .media video { transition: transform var(--dur-slow) var(--ease-out); }
.case:hover .case-media .media img, .case:hover .case-media .media video,
.case:focus-visible .case-media .media img, .case:focus-visible .case-media .media video { transform: scale(var(--zoom)); }
/* External card (Playground): arrow after "External"; on hover it leaves up-right and a copy comes in */
.ext-icon { display: inline-grid; overflow: hidden; width: 1em; height: 1em; margin-left: 0.25em; vertical-align: -0.125em; }
.ext-icon .icon { grid-area: 1 / 1; transition: transform var(--dur-slow) var(--ease-out); }
.ext-icon .icon + .icon { transform: translate(-100%, 100%); }
.case:hover .ext-icon .icon:first-child, .case:focus-visible .ext-icon .icon:first-child { transform: translate(100%, -100%); }
.case:hover .ext-icon .icon + .icon, .case:focus-visible .ext-icon .icon + .icon { transform: none; }
.case-corner {
  position: absolute; top: var(--s-4); right: var(--s-4);
  width: 10px; height: 10px;
  border-top: 2px solid var(--accent); border-right: 2px solid var(--accent);
  opacity: 0; transform: translate(calc(var(--s-1) * -1), var(--s-1));
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.case:hover .case-corner, .case:focus-visible .case-corner { opacity: 1; transform: translate(0, calc(var(--s-1) * -1)); }

/* Key results */
.stat { display: grid; gap: var(--s-3); align-content: start; }
.stat-caption { max-width: var(--measure-caption); }


/* ---------- 6. Pages ---------- */

/* About */
/* About photo: content width, cropped to the frame, anchored right like the live site */
.page-head + .about-art { padding-bottom: 0; }   /* the ruled story below brings its own top space */
.about-art-img {
  display: block; width: 100%; height: auto; aspect-ratio: var(--about-art-ratio);
  object-fit: cover; object-position: right center;
  border-radius: var(--radius-s); background: var(--bg-raised);
}
.story-body > .lead + * { margin-top: var(--space-block); }  /* statement → next block: 48 */

/* Ruled story (About): label on a full-width rule, text on columns 4–10 below it */
.story-ruled { padding-top: var(--space-story); padding-bottom: 0; border-top: 0; }
.story-ruled .story-label {
  grid-column: 1 / -1; position: static;
  display: flex; align-items: center; gap: var(--s-6);
}
.story-ruled .story-label::after { content: ""; flex: 1; border-top: var(--rule); }
@media (min-width: 961px) {
  .story-ruled .story-body { grid-column: 4 / span 7; }
}
.skills ul li { padding-left: 0; }
.skills ul li::before { content: none; }
#experience .story-body { grid-column: 4 / span 7; }   /* same text column as the other stories */
/* Experience: employment type → 8 → company → 24 → roles (32 apart); role: title (Body) → date → 8 → text */
.xp-item { display: grid; gap: var(--s-2); padding-block: var(--s-6); border-top: var(--rule); }
.xp-item:first-child { border-top: 0; padding-top: 0; }
.xp-item:last-child { padding-bottom: 0; }
/* Meta row above the company: employment type left, dates at the company right (the whole span) */
.xp-meta { display: flex; justify-content: space-between; gap: var(--s-4); }
.xp-roles { display: grid; gap: var(--s-6); margin-top: var(--s-4); }  /* company → roles: 8 + 16 = 24 */
.xp-position { display: grid; }
/* Growth inside one company (2+ roles): a dot at each role title, joined by a line; newest role on top,
   its dot in the accent. Dots and line sit in a 32 inset on the left of the roles. */
.xp-roles:has(> li + li) { padding-left: var(--s-6); }
.xp-roles:has(> li + li) > .xp-position { position: relative; }
.xp-roles:has(> li + li) > .xp-position::before {
  content: ""; position: absolute; left: calc(var(--s-6) * -1); top: calc((1lh - var(--dot)) / 2);
  width: var(--dot); height: var(--dot); border-radius: var(--radius-pill); background: var(--text-muted);
}
.xp-roles:has(> li + li) > .xp-position:first-child::before { background: var(--accent); }
.xp-roles:has(> li + li) > .xp-position:not(:last-child)::after {
  content: ""; position: absolute; left: calc(var(--s-6) * -1 + (var(--dot) - 1px) / 2);
  top: calc((1lh + var(--dot)) / 2 + var(--s-1));
  height: calc(100% + var(--s-6) - var(--dot) - var(--s-1) * 2);
  border-left: var(--rule); border-color: var(--text-muted);
}
.xp-text { color: var(--text-muted); margin-top: var(--s-2); }

/* Contacts */
.email-link, .contact-email { justify-self: start; }
.contact-heading { grid-column: 1 / -1; }
.location { display: grid; }
.location-note { margin-top: var(--space-label); }

/* Case study (template): head = breadcrumb · h1 · 48 · facts; cover 48 below; ruled stories 96 apart */
.case-head { padding-bottom: 0; }
.page-head + .case-intro { padding-bottom: 0; }   /* the first ruled story brings its own top space */
.case-dot {
  display: inline-block; width: var(--dot); height: var(--dot);
  border-radius: var(--radius-pill); background: currentColor; vertical-align: -0.05em;
}
/* Facts: each label sits on a rule, like a ruled story label. Contribution 6 columns, the rest 2 */
.case-facts {
  grid-column: 1 / -1; margin-top: var(--space-after-head);
  display: grid; grid-template-columns: subgrid; row-gap: var(--s-6);
}
.case-facts > div { grid-column: span 2; display: grid; gap: var(--s-4); align-content: start; }
.case-facts > .fact-wide { grid-column: span 6; }
.case-facts dt { display: flex; align-items: center; gap: var(--s-5); }
.case-facts dt::after { content: ""; flex: 1; border-top: var(--rule); }
/* Cover: full content width, fixed frame */
.case-visual { grid-column: 1 / -1; aspect-ratio: var(--cover-ratio); overflow: hidden; border-radius: var(--radius-s); background: var(--bg-raised); }
.case-visual img { width: 100%; height: 100%; object-fit: cover; }
/* Ruled stories on case pages are one section apart */
.story-ruled.case-section { padding-top: var(--space-section); }
.case-story h3 { margin-top: var(--space-block); }   /* subhead: 48 above, 24 below */
.case-story h3:first-child { margin-top: 0; }        /* label → subhead stays 32 */
.case-story ul li::before { content: "\2022"; }
.case-story figcaption::before { content: "\21B3" " "; }
.case-section .work-list { grid-column: 1 / -1; }
@media (min-width: 961px) {
  /* Text on columns 4–10, media breaks out to 3–11, captions back on the text column */
  /* column-gap: normal = the page gutter (the local `gap` would override it in a subgrid) */
  .case-section .case-story { grid-column: 3 / span 9; grid-template-columns: subgrid; column-gap: normal; }
  .case-story > * { grid-column: 2 / span 7; }
  .case-story > .fig, .case-story > .fig-pair { grid-column: 1 / -1; max-width: none; }
  .case-story > .fig { grid-template-columns: subgrid; column-gap: normal; }
  .case-story > .fig > :not(figcaption) { grid-column: 1 / -1; }
  .case-story > .fig > figcaption { grid-column: 2 / span 7; max-width: var(--measure); }
  .case-story.stats > .stat { grid-column: span 3; }
  .case-story.stats > .stat:first-child { grid-column: 2 / span 3; }
}

/* Case image preview (main.js): full screen on --bg, image fitted, caption below */
.case-story img, .case-visual img { cursor: zoom-in; }
.lightbox {
  width: 100vw; height: 100dvh; max-width: none; max-height: none; margin: 0;
  padding: var(--s-8) var(--margin);
  border: 0; background: var(--bg); color: var(--text); cursor: zoom-out;
}
.lightbox[open] {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-3);
  animation: lab-backdrop-in var(--dur) var(--ease);
}
.lightbox::backdrop { background: var(--bg); }
/* The image shrinks to leave room for the caption; contain keeps its proportions */
.lightbox-img { flex: 0 1 auto; min-height: 0; max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--radius-s); }
.lightbox-caption { max-width: var(--measure); }
.lightbox-caption::before { content: "\21B3" " "; }
.lightbox-close { position: absolute; top: var(--s-4); right: var(--margin); margin: 0; }

/* Lab */
.cards-3 .work-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Lab modal */
html:has(dialog.lab-modal[open]), html:has(dialog.lightbox[open]) { overflow: hidden; }
.lab-modal {
  --modal-pad: var(--s-6);   /* content inset; the bar uses the same edges */
  width: min(var(--modal-width), calc(100vw - 2 * var(--margin))); max-width: none;
  max-height: calc(100dvh - 2 * var(--s-5));
  padding: 0; border: 0; border-radius: var(--radius-m);
  background: var(--bg); color: var(--text);
  overflow: auto; overscroll-behavior: contain;
}
.lab-modal::backdrop { background: var(--backdrop); }
.lab-modal[open] { animation: lab-modal-in var(--dur) var(--ease); }
.lab-modal[open]::backdrop { animation: lab-backdrop-in var(--dur) var(--ease); }
@keyframes lab-modal-in { from { opacity: 0; transform: translateY(var(--s-4)); } }
@keyframes lab-backdrop-in { from { opacity: 0; } }
.lab-modal-bar {
  --bar-inset: max(var(--modal-pad), calc((100% - var(--modal-width)) / 2 + var(--modal-pad)));  /* = body content edge, also when the body is centered */
  position: sticky; top: 0; z-index: 1;
  display: flex; justify-content: space-between; align-items: center;
  padding-block: var(--s-2);
  padding-inline: var(--bar-inset) calc(var(--bar-inset) - (var(--hit) - var(--icon-l)) / 2);
  background: var(--bg); border-bottom: var(--rule);
}
/* Modal body follows the case page language: meta label → 32 → title → 48 → facts / content;
   sections are ruled labels (64 above, 32 to the text), lists use "•", captions start with "↳ " */
.lab-modal-body { display: grid; gap: var(--s-7); padding: var(--s-7) var(--modal-pad) var(--s-8); }
.lab-modal-head { display: grid; gap: var(--space-label); }
.lab-modal-title { max-width: var(--measure-title); }
.lab-modal-content { display: grid; gap: var(--space-block); }
.lab-modal-content figcaption::before { content: "\21B3" " "; }
.lab-modal-content ul { display: grid; gap: var(--s-2); }
.lab-modal-content li { position: relative; padding-left: 1.2em; }
.lab-modal-content li::before { content: "\2022"; position: absolute; left: 0; color: var(--text-muted); }
.lab-section { display: flex; align-items: center; gap: var(--s-6); margin-top: calc(var(--s-8) - var(--space-block)); margin-bottom: calc(var(--s-6) - var(--space-block)); }
.lab-section::after { content: ""; flex: 1; border-top: var(--rule); }
/* Facts, like case facts: each label on a rule (gap 24) → 16 → value; role 1/3, contribution 2/3 */
.lab-section:first-child { margin-top: 0; }
.lab-facts { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--s-6); }
.lab-facts > div { display: grid; gap: var(--s-4); align-content: start; }
.lab-facts dt { display: flex; align-items: center; gap: var(--s-5); }
.lab-facts dt::after { content: ""; flex: 1; border-top: var(--rule); }
html:not(.js) .lab-modal:target { display: block; position: static; max-height: none; margin: var(--s-8) auto; border: var(--rule); }

/* ---------- 7. Utilities: reveal ---------- */

.js .reveal {
  opacity: 0; transform: translateY(var(--rise));
  /* --reveal-delay is set by main.js: items revealed together cascade by --stagger */
  transition: opacity var(--dur-reveal) var(--ease-out) var(--reveal-delay, 0s), transform var(--dur-reveal) var(--ease-out) var(--reveal-delay, 0s);
}
.js .reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
  .js .reveal { opacity: 1; transform: none; }
}


/* ---------- 8. Responsive ----------
   Breakpoints: 1100 (Lab grid), 960 (tablet: burger, single text column), 640 (phone: 4-column grid). */
@media (max-width: 1100px) {
  .cards-3 .work-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 960px) {
  /* No header blur on tablets and phones (backdrop-filter is heavy on mobile GPUs): solid header */
  .header { background: var(--bg); }
  .header-blur { display: none; }

  /* Burger menu */
  html.menu-open { overflow: hidden; }
  .nav { gap: var(--s-3); }
  .menu-toggle { display: inline-flex; }
  .header .brand, .theme-toggle, .menu-toggle { position: relative; z-index: 2; }
  /* No transform / will-change while open: either would make the header the containing block
     of the fixed full-screen .nav-links and squash the menu to the header's height */
  .menu-open .header { position: fixed; inset: 0 0 auto 0; z-index: 100; background: var(--bg); will-change: auto; transform: none !important; }
  .nav-links {
    position: fixed; inset: 0; z-index: 1;
    flex-direction: column; justify-content: flex-end; gap: 0;
    padding: var(--s-9) var(--margin) var(--s-8);
    background: var(--bg);
    visibility: hidden; opacity: 0; transform: translateY(calc(var(--s-2) * -1));
    transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility 0s linear var(--dur);
  }
  .menu-open .nav-links { visibility: visible; opacity: 1; transform: none; transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease); }
  .nav-links a { padding-block: var(--s-3); border-top: var(--rule); }
  .nav-links a:last-child { border-bottom: var(--rule); }
  .nav-links a:hover, .nav-links a:focus-visible, :root:not([data-from="home"]) .nav-links a[aria-current] { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: var(--underline-menu); text-underline-offset: var(--underline-offset); }

  /* Single text column */
  .story-label { grid-column: 1 / -1; position: static; }
  .story-body, #experience .story-body { grid-column: 1 / -1; }
  .footer-title, .footer-social { grid-column: 1 / -1; }
  .hero-title, .hero-intro { grid-column: 1 / -1; }
  .hero-intro { padding-top: var(--space-block); max-width: none; }  /* full content width under the title */
  .case-facts > div { grid-column: span 4; }
  .case-facts > .fact-wide { grid-column: 1 / -1; }

  /* Lab modal: full screen; content keeps the desktop width, centered */
  .lab-modal { width: 100vw; height: 100dvh; max-height: none; margin: 0; border-radius: 0; }
  .lab-modal-body { max-width: var(--modal-width); margin-inline: auto; }
}

@media (max-width: 640px) {
  .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* Everything that spans more than 4 columns goes full width */
  .brand { grid-column: 1 / span 2; }
  .nav { grid-column: 3 / span 2; }
  .page-head .work-heading, .page-head .work-heading:has(+ .work-intro),
  .page-head .work-intro, .section-heading,
  .footer-bar > p, .footer-nav { grid-column: 1 / -1; }
  .page-head .work-intro { padding-top: var(--space-block); }
  .footer-nav { justify-content: flex-start; }
  .work-list, .cards-3 .work-list, .split, .fig-pair { grid-template-columns: 1fr; }
  .case-facts > div { grid-column: span 2; }
  .case-facts > .fact-wide { grid-column: 1 / -1; }
  .lab-modal { --modal-pad: var(--s-4); }
  .lab-modal-body { padding-block: var(--s-5) var(--s-7); }
  .lab-facts { grid-template-columns: 1fr; }
}
