/* ==========================================================================
   jen-chung.com — site styles
   Design source: Figma "Portfolio designs 2026" › Home_LightTheme_Final / Home_DarkTheme_Final
   ========================================================================== */

/* ---- Tokens ----------------------------------------------------------------
   Same names as Figma › Style Guide 2026 › Design System 2026 (a Figma variable like text/primary
   is --text-primary here). Colors are set once for light mode, then swapped in the dark block
   below. ✏️ To change a color everywhere, change it here.
   Icons are Heroicons v2 (heroicons.com), outline style with a 1.5 stroke, solid for the active
   light/dark icon. The one exception is the LinkedIn logo (Font Awesome brands). */
/* Color, light mode. [data-theme] on any element (not just the page) switches what's inside it,
   which is how the design system page shows both modes side by side. */
:root, [data-theme="light"] {
  --bg-page: #fcf9ef;
  --bg-image: #d3c6e6;                   /* behind images and the video while they load */
  --bg-toggle: #ffffff;
  --bg-veil: rgb(252 249 239 / .9);      /* page color at 90%: password overlay + full-screen viewer */
  --text-primary: #222222;
  --text-secondary: #75705e;             /* labels, captions, colophon: 4.7:1 on the page (WCAG AA) */
  --text-on-accent: #ffffff;             /* text on a purple button */
  --text-heading: #6432ad;               /* case study section titles, stat numbers, card titles */
  --accent-default: #7961c7;
  --accent-hover: #6432ad;               /* text buttons + password button on hover / press */
  --border-card: linear-gradient(#7961c7, #7961c7);   /* solid for now; an image, so it can become a gradient */
  --border-rule: #cccccc;
  --border-input: #4e4e4e;
  --status-error: #d62022;               /* 4.9:1 on the page */
  --status-highlight: #d62022;           /* red "look here" boxes (screenshots look the same in both modes) */
}
:root {
  /* Type */
  --font-serif: "Crimson Text", Georgia, "Times New Roman", serif;   /* headings */
  --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;   /* body, labels, buttons */

  /* Radius */
  --radius-xs: 4px;         /* focus ring */
  --radius-s: 8px;          /* ✏️ visuals, ✕, skip link, social icons */
  --radius-m: 16px;         /* outlined cards */
  --radius-l: 20px;         /* home cards */
  --radius-pill: 999px;     /* buttons, chips, toggle */

  /* Layout */
  --layout-content: 1022px; /* content column at 1280 (129px each side) */
  --layout-gutter: 16px;
  --layout-nav-height: 64px;

  /* Motion */
  --ease-out: cubic-bezier(.2, .8, .2, 1);
  --ease-rise: cubic-bezier(.16, 1, .3, 1);   /* soft rise, main images */

  /* Page settings */
  --hero-gap: 40px;         /* nav → intro sentence */
  --reveal-dur: 2s;         /* ✏️ how long each card's entrance takes */
}
[data-theme="dark"] {
  --bg-page: #121212;
  --bg-veil: rgb(18 18 18 / .9);
  --text-primary: #f2f2f2;
  --text-secondary: #a5a08f;             /* 7.2:1 on the page */
  --text-on-accent: #222222;
  --text-heading: #d4b5ff;               /* the light-mode purple is too dark to read here */
  --accent-default: #9e81ee;
  --accent-hover: #b39cf2;               /* lighter here, so it keeps contrast */
  --border-card: linear-gradient(to left, #7961c7, #d4b5ff 33%, #7961c7 67%);   /* as in Figma dark */
  --border-rule: #4e4e4e;
  --border-input: #cccccc;
  --status-error: #ef5b5c;               /* 5.6:1 on the page */
}
@media (min-width: 760px)  { :root { --layout-gutter: 24px; } }
@media (min-width: 1000px) { :root { --layout-gutter: max(24px, calc((100vw - var(--layout-content)) / 2)); } }

/* ---- Base ------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0;
  background: var(--bg-page);
  color: var(--text-primary);
  font-family: var(--font-serif);
  -webkit-font-smoothing: antialiased;
  transition: background-color .3s ease, color .3s ease;
}
img { display: block; max-width: 100%; }
a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--accent-default); outline-offset: 3px; border-radius: var(--radius-xs); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip-link { position: absolute; left: 16px; top: -48px; z-index: 100; padding: 8px 12px; border-radius: var(--radius-s); background: var(--text-primary); color: var(--bg-page); font-family: var(--font-sans); font-size: 14px; text-decoration: none; }
.skip-link:focus { top: 12px; }

.wrap { width: 100%; padding-inline: var(--layout-gutter); }
.wrap > * { max-width: var(--layout-content); margin-inline: auto; }

/* ---- Nav -------------------------------------------------------------------- */
.nav { position: relative; z-index: 20; }
.nav-bar {
  height: var(--layout-nav-height);
  display: flex; align-items: center; justify-content: space-between;
}
.logo {
  display: inline-flex; align-items: center; gap: 4px;
  font-weight: 700; font-size: 16px; line-height: 1.28;
  color: var(--accent-default);
  text-decoration: none;
}
.logo img { width: 12px; height: 20px; }
.nav-links { display: flex; align-items: center; gap: 48px; }
.nav-links a, .nav-work-btn {
  font-size: 16px; line-height: 1.37;
  text-decoration: none;
  transition: color .2s ease;
}
.nav-links a:hover { color: var(--accent-default); }
.nav-links a[aria-current] { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 6px; }   /* the page you're on (Design system, or the case study in the Work menu) */

/* Work: opens a list of the case studies + View all (Figma 4802:413; on phones it expands
   inside the full-page menu instead, Figma 4817:691). Opens on hover or click (js/site.js). */
.nav-work-btn { display: inline-flex; align-items: center; gap: 4px; }
.nav-chevron { width: 16px; height: 16px; flex: none; transition: transform .25s var(--ease-out); }
.nav-work-menu > div { display: flex; flex-direction: column; gap: 4px; }
.nav-work-menu a { padding: 10px 0; }
.nav-work-menu a:hover { color: var(--accent-hover); }
/* View all: a text button, like View case study on the cards */
.nav-links .nav-view-all {
  align-self: flex-start;
  padding: 8px; margin-inline: -8px;   /* like .card-cta: lines up with the text around it */
  font-family: var(--font-sans); font-weight: 500; font-size: 16px; line-height: 1.37;
  color: var(--accent-default);
}
.nav-view-all .arrow { display: inline-block; transition: transform .25s var(--ease-out); }
.nav-view-all:hover .arrow, .nav-view-all:focus-visible .arrow { transform: translateX(4px); }
.nav-links .nav-view-all:hover, .nav-links .nav-view-all:focus-visible { color: var(--accent-hover); }
@media (prefers-reduced-motion: reduce) { .nav-view-all:hover .arrow, .nav-view-all:focus-visible .arrow { transform: none; } }

/* Light/dark switch (Figma 6796:8401) */
.theme-toggle {
  display: inline-flex; align-items: center; gap: 16px;
  padding: 8px; border-radius: var(--radius-pill);
  background: var(--bg-toggle);
  box-shadow: 0 1px 2px rgba(10, 13, 18, .05);
}
.theme-toggle img { width: 16px; height: 16px; }
:root[data-theme="dark"] .theme-toggle .is-light,
:root:not([data-theme="dark"]) .theme-toggle .is-dark { display: none; }

/* ☰ turns into the same ✕ as the case-study close buttons (they swap with a quick fade + turn) */
.menu-btn { display: none; width: 32px; height: 32px; place-items: center; }
.menu-btn svg { grid-area: 1 / 1; transition: opacity .2s ease, transform .25s var(--ease-out); }
.menu-close { opacity: 0; transform: rotate(-45deg); }
.nav.is-open .menu-open { opacity: 0; transform: rotate(45deg); }
.nav.is-open .menu-close { opacity: 1; transform: none; }
.nav-tools { display: flex; align-items: center; gap: 16px; }

/* Phones: ☰ opens a full-page menu with lines between the links; Work expands in place,
   its case studies indented underneath */
@media (max-width: 759px) {
  .menu-btn { display: inline-grid; }
  .nav-links .nav-link-list {
    position: absolute; left: 0; right: 0; top: var(--layout-nav-height);
    height: calc(100vh - var(--layout-nav-height));
    height: calc(100dvh - var(--layout-nav-height));
    overflow-y: auto; overscroll-behavior: contain;
    display: flex; flex-direction: column;
    padding: 8px var(--layout-gutter) 20px;
    background: var(--bg-page);
    opacity: 0; transform: translateY(-8px); visibility: hidden;
    transition: opacity .2s ease, transform .25s var(--ease-out), visibility 0s linear .25s;
  }
  .nav.is-open .nav-link-list { opacity: 1; transform: none; visibility: visible; transition-delay: 0s; }
  .nav-link-list > a, .nav-work-btn { padding: 10px 0; font-size: 20px; }
  .nav-link-list > * + * { margin-top: 4px; border-top: 1px solid var(--border-rule); }   /* 4px, the line, 4px */
  .nav-link-list > * + a { padding-top: 13px; }
  .nav-work-btn { width: 100%; justify-content: space-between; text-align: left; }
  .nav-chevron { width: 24px; height: 24px; transition: none; }   /* flips straight to ⌃, no turn */
  .nav-work.is-open .nav-chevron { transform: rotate(180deg); }
  .nav-work-menu { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s var(--ease-out); }
  .nav-work-menu > div { min-height: 0; overflow: hidden; visibility: hidden; transition: visibility 0s linear .3s; }
  .nav-work.is-open .nav-work-menu { grid-template-rows: 1fr; }
  .nav-work.is-open .nav-work-menu > div { visibility: visible; transition-delay: 0s; }
  .nav-work-menu a { padding: 4px 0 4px 24px; font-size: 20px; }
  .nav-work-menu a:first-child { margin-top: 4px; }
  .nav-links .nav-view-all { margin-left: 16px; }   /* 24px indent − 8px padding, so View all lines up with the case studies */
}
:root.menu-locked { overflow: hidden; }   /* the page stays put behind the full-page menu */

/* Desktop: the case studies drop down under Work */
@media (min-width: 760px) {
  .nav-link-list { display: contents; }
  .nav-links, .nav-work { align-self: stretch; }   /* full bar height, so the pointer can travel down to the menu */
  .nav-work { position: relative; display: flex; align-items: center; }
  .nav-work.is-open .nav-work-btn { color: var(--accent-hover); }
  .nav-work-menu {
    position: absolute; top: 100%; left: -10px;
    width: max-content;
    padding: 8px 16px 20px;
    border-radius: var(--radius-s);
    background: var(--bg-page);
    box-shadow: 0 12px 24px -16px rgba(0, 0, 0, .35);
    opacity: 0; transform: translateY(-8px); visibility: hidden;
    transition: opacity .2s ease, transform .25s var(--ease-out), visibility 0s linear .25s;
  }
  .nav-work.is-open .nav-work-menu { opacity: 1; transform: none; visibility: visible; transition-delay: 0s; }
}

/* Every page: the nav stays pinned to the top while you scroll */
.nav-auto {
  position: sticky; top: 0;
  background: var(--bg-page);
  transition: background-color .3s ease;
}

/* ---- Hero (konbini) ----------------------------------------------------------- */
.hero { padding-top: var(--hero-gap); }
/* First visit: the konbini's loading screen (inside the hero frame) takes over the whole page.
   A cover in the page color hides the nav and everything below, the hero sits on top of it,
   and the page can't scroll. When the hero is ready, the cover fades out with its loader. */
.kb-first-load, .kb-first-load body { overflow: hidden; }
.kb-first-load body::before, .kb-first-fade body::before {
  content: ""; position: fixed; inset: 0; z-index: 900;
  background: var(--bg-page);
}
.kb-first-fade body::before { opacity: 0; transition: opacity .4s ease; pointer-events: none; }
.kb-first-load .hero, .kb-first-fade .hero { position: relative; z-index: 901; }
/* Inside the konbini (#konbini): the fridge is a page of its own */
.in-konbini main > :not(.hero), .in-konbini .footer { display: none; }
.hero-frame {
  display: block; width: 100%;
  height: min(805px, calc(100svh - var(--layout-nav-height) - var(--hero-gap)));   /* JS refines this */
  min-height: 420px;
  border: 0;
  background: transparent;
  color-scheme: normal;
  transition: height .35s var(--ease-out);
}

/* ---- Sections ------------------------------------------------------------------ */
.section { scroll-margin-top: calc(var(--layout-nav-height) + 24px); }   /* clear the sticky nav once it comes back */
.section h2 {
  margin: 0 0 48px;
  font-family: var(--font-serif); font-weight: 600;
  font-size: 40px; line-height: 1.2;
}
#work { padding-top: 80px; padding-bottom: 120px; }
#archive { padding-bottom: 80px; }

.grid { display: grid; row-gap: 48px; }
.grid-work { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 48px; }   /* same as the row gap; cards are 487px wide at full width */
.grid-archive { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 48px; }
@media (max-width: 999px) {
  .grid-archive { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 32px; }
}
@media (max-width: 759px) {
  .grid-work, .grid-archive { grid-template-columns: 1fr; row-gap: 40px; }
  .section h2 { font-size: 32px; margin-bottom: 32px; }
  #work { padding-top: 64px; padding-bottom: 80px; }
}

/* ---- Cards ---------------------------------------------------------------------- */
.card { display: flex; flex-direction: column; gap: 24px; text-decoration: none; color: inherit; }
.card-media {
  position: relative;
  border-radius: var(--radius-l); overflow: hidden;
  background: var(--bg-image);
  aspect-ratio: 487 / 350;
}
/* Hover: a dark overlay on the image (clickable cards only) */
a.card .card-media::after {
  content: ""; position: absolute; inset: 0;
  background: rgba(18, 14, 28, .55);
  opacity: 0;
  transition: opacity .35s ease;
  pointer-events: none;
}
a.card:hover .card-media::after,
a.card:focus-visible .card-media::after { opacity: 1; }
.card-media img { transition: transform .8s var(--ease-out); }
a.card:hover .card-media img,
a.card:focus-visible .card-media img { transform: scale(1.06); }   /* slow zoom under the overlay */
.grid-archive .card-media { aspect-ratio: 309 / 308; }
.card-media img { width: 100%; height: 100%; object-fit: cover; }
.card-body { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.card-label { margin: 0; font-family: var(--font-sans); font-weight: 400; font-size: 14px; line-height: 1.37; }
.card-desc { margin: 0; font-weight: 400; font-size: 20px; line-height: 1.05; }
.card-cta {
  padding: 8px;
  margin-inline: -8px;   /* text buttons: the padding stays (tap area, focus ring), but the text lines up with the text around it */
  font-family: var(--font-sans); font-weight: 500; font-size: 16px; line-height: 1.37;
  color: var(--accent-default);
  transition: color .15s ease;
}
.card-cta .arrow { display: inline-block; transition: transform .25s var(--ease-out); }
.card-soon { color: var(--text-secondary); font-weight: 400; font-style: italic; }
a.card:hover .card-cta .arrow,
a.card:focus-visible .card-cta .arrow { transform: translateX(4px); }
/* Text buttons darken on hover; on touch screens that's the brief pressed state instead
   (hover only where there's a real pointer, so a tap doesn't leave it stuck dark) */
@media (hover: hover) {
  a.card:hover .card-cta, .cs-pager a:hover { color: var(--accent-hover); }
}
a.card:focus-visible .card-cta, .cs-pager a:focus-visible,
a.card:active .card-cta, .cs-pager a:active { color: var(--accent-hover); }

/* ---- Entrance: cards drop in from above as they scroll into view (archive: from the left) ----
   Only when JS has marked the page ready (so cards are never hidden without JS).
   Cards come in reading order, 0.5s apart (see js/site.js). */
.reveal-ready .reveal > * {   /* the card's contents animate; the card itself stays measurable */
  opacity: 0;
  transform: translateY(-32px);
  clip-path: inset(0 0 100% 0);
  transition:
    opacity calc(var(--reveal-dur) * .75) ease var(--reveal-delay, 0s),
    transform var(--reveal-dur) var(--ease-out) var(--reveal-delay, 0s),
    clip-path var(--reveal-dur) var(--ease-out) var(--reveal-delay, 0s);
}
.reveal-ready .reveal > .card-body { transition-delay: calc(var(--reveal-delay, 0s) + .2s); }
.reveal-ready .reveal.is-in > * { opacity: 1; transform: none; clip-path: inset(-8px -8px -8px -8px); }
/* Archive cards: quicker, and they wipe in from the left (the row slides sideways) */
.reveal-ready .grid-archive > .reveal > * { --reveal-dur: .8s; transform: translateX(-24px); clip-path: inset(0 100% 0 0); }
.reveal-ready .grid-archive > .reveal > .card-body { transition-delay: calc(var(--reveal-delay, 0s) + .1s); }
.reveal-ready .grid-archive > .reveal.is-in > * { transform: none; clip-path: inset(-8px -8px -8px -8px); }
/* Delays are set per card by js/site.js (reading order, 0.5s apart). */
@media (prefers-reduced-motion: reduce) {
  a.card:hover .card-cta .arrow, a.card:hover .card-media img { transform: none; }
  .reveal-ready .reveal > *, .reveal-ready .grid-archive > .reveal > * { transform: none; clip-path: none; transition: opacity .4s ease; }
}

/* ---- Footer ---------------------------------------------------------------------- */
.footer {
  min-height: 211px;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  gap: 32px;
  padding: 40px var(--layout-gutter);
  text-align: center;
}
.connect { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.connect-title {
  display: flex; align-items: center; gap: 12px;
  margin: 0;
  font-family: var(--font-serif); font-weight: 400; font-size: 24px; line-height: 1.2;   /* heading/connect: Regular, as in the Figma design system */
}
.connect-title img { width: 32px; height: 3px; transform: scaleY(-1); }
.socials { display: flex; gap: 16px; }
.socials a { display: grid; place-items: center; width: 40px; height: 32px; border-radius: var(--radius-s); transition: color .2s ease, transform .2s ease; }
.socials a:hover { color: var(--accent-default); transform: translateY(-2px); }
.socials svg { width: 40px; height: 32px; }
.colophon { margin: 0; font-family: var(--font-sans); font-style: italic; font-size: 12px; line-height: 1.28; color: var(--text-secondary); }
.colophon-end { white-space: nowrap; }   /* the icons never wrap onto a line of their own */
.colophon-icons { display: inline-flex; align-items: center; gap: 2px; margin-left: 4px; vertical-align: -2px; }
.colophon-icons img { width: 12px; height: 15px; }

/* ---- Archive: horizontal scroll ------------------------------------------------------
   A row of cards. js/site.js pins the section and slides the row left as you scroll down;
   with reduced motion or on very short screens it's a row you swipe (with snap). */
.grid-archive {
  display: flex; gap: 48px;
  grid-template-columns: none;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  margin-inline: calc(-1 * var(--layout-gutter)); padding-inline: var(--layout-gutter);
  scroll-padding-inline: var(--layout-gutter);
}
.grid-archive::-webkit-scrollbar { display: none; }
.grid-archive > .card { flex: 0 0 min(380px, 46vh, 78vw); scroll-snap-align: start; }
@media (max-width: 759px) { .grid-archive { gap: 24px; } }

/* pinned (set by JS) */
.archive-pin { position: relative; }
.archive-stage { position: sticky; display: flex; align-items: center; overflow-x: clip; }   /* top: set by JS (centered) */
.archive-stage > div { width: 100%; max-width: var(--layout-content); margin-inline: auto; }
#archive.is-pinned .grid-archive { overflow: visible; scroll-snap-type: none; will-change: transform; }
.archive-pin { max-width: none; margin-inline: calc(-1 * var(--layout-gutter)); }                 /* full-bleed: cards slide off the screen edge */
.archive-stage { padding-inline: var(--layout-gutter); }

/* ---- Case studies ---------------------------------------------------------------------
   Figma "Portfolio designs 2026" › Cube Boards case study (light 9897:8171, dark 9702:17058).
   Each section is a title (left, pinned while its section scrolls by) and a 668px column. */
:root {
  --cs-pin-top: 24px;       /* ✏️ how far below the top of the screen (or the nav, when it's showing) a pinned title sits */
}

.cs { font-family: var(--font-sans); }
.cs :where(p, h1, h2, h3, figure, dl, dd, ul) { margin: 0; }
.cs img { width: 100%; height: auto; }
.cs-video { display: block; width: 100%; height: auto; background: var(--bg-image); }
/* Rounded corners on every visual (a crop frame is rounded instead of the image inside it) */
.cs :is(img:not(.crop img), .crop, .cs-video),
.lb-item > :is(img, .crop) { border-radius: var(--radius-s); }

/* Title + main images */
.cs-head { padding-top: 56px; }                      /* case studies: 56px below the nav (32px on phones, below) */
.ds .cs-head { padding-top: 32px; }                  /* other pages (Design system, About): 32px */
@media (max-width: 759px) { .cs-head { padding-top: 32px; } }   /* phones: every page starts 32px below the nav */
.cs-label { font-family: var(--font-sans); font-size: 24px; line-height: 1.5; color: var(--accent-default); text-transform: uppercase; }
.cs-title { margin-top: 8px; font-family: var(--font-serif); font-weight: 600; font-size: 56px; line-height: 1; }
.cs-hero { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: 32px; }
.cs-hero img { aspect-ratio: 503 / 358; object-fit: cover; }

/* Sections */
.cs-body { padding-top: 80px; }
.cs-section {
  display: grid; grid-template-columns: 314px minmax(0, 1fr); column-gap: 40px; align-items: start;
  padding-top: 80px;
  border-top: 1px solid var(--border-rule);
}
.cs-section + .cs-section { margin-top: 80px; }
.cs-h2 {
  position: sticky; top: calc(var(--layout-nav-height) + var(--cs-pin-top));   /* just below the nav */
  font-family: var(--font-serif); font-weight: 600; font-size: 56px; line-height: 1.2;   /* ✏️ */
  color: var(--text-heading);
}
.cs-main { display: flex; flex-direction: column; gap: 40px; min-width: 0; }
.cs-main-tight { gap: 16px; }
.cs-text { font-size: 18px; line-height: 1.37; }
.cs-text > p + p { margin-top: 1.37em; }             /* one empty line between paragraphs */
.cs-text-joined > p + p { margin-top: 0; }
.cs-text b { font-weight: 700; }
.cs-text a { color: inherit; text-underline-position: from-font; }
.cs-text a:hover { color: var(--accent-default); }
.cs-lede { margin-bottom: 16px; font-family: var(--font-serif); font-weight: 600; font-size: 24px; line-height: 1.5; }

/* Numbered steps: title, text, then images */
.cs-step { display: flex; flex-direction: column; gap: 8px; }
.cs-h3 { font-family: var(--font-serif); font-weight: 600; font-size: 24px; line-height: 1.5; }   /* heading/m: step titles */
.cs-step > p { font-size: 16px; line-height: 1.37; }

/* Images and captions */
.cs-figure, .cs-pair figure { display: flex; flex-direction: column; gap: 8px; }
.cs figcaption { font-size: 16px; line-height: 1.37; color: var(--text-secondary); }
.cs-shots { display: flex; flex-direction: column; gap: 16px; }
/* The two main images rise in on load (once both have loaded, the second a beat later) */
.cs-hero.will-rise img { opacity: 0; transform: translateY(40px); }
.cs-hero.will-rise img.is-in {
  opacity: 1; transform: none;
  transition: opacity 1s ease, transform 1.4s var(--ease-rise);   /* ✏️ speed */
}
.cs-hero.will-rise img + img.is-in { transition-delay: .15s; }

/* Soft rise: titles, paragraphs, images and cards fade in and rise 16px as they scroll into view,
   a beat apart when several arrive together (js/site.js adds .is-in). Same easing as the main images. */
/* (On the design system page the long blocks rise a row at a time, and its intro paragraphs too.) */
.cs-rise-ready :is(.cs-label, .cs-title, .cs-h2, .cs-meta > div, .cs-meta-title, .cs-text > *, .cs-main > :not(.cs-text, .ds-colors, .ds-scale-wrap),
  .ds-intro, .ds .cs-main > .cs-text, .ds-colors > *, .ds-specimen, .ds-step):not(.is-in) {
  opacity: 0; transform: translateY(16px);              /* ✏️ how far it rises */
}
.cs-rise-ready .is-in {
  transition: opacity .6s ease var(--rise-delay, 0s), transform .9s var(--ease-rise) var(--rise-delay, 0s);
}

/* % numbers flip through digits once when they come into view (js/site.js) */
.cs-stat-num { font-variant-numeric: tabular-nums; }
.cs-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; align-items: start; }
.cs-pair img { aspect-ratio: 326 / 232; object-fit: cover; }
/* A window onto part of an image: the frame sets the shape, the image's inline style the crop */
.crop { position: relative; overflow: hidden; }
.cs .crop img { position: absolute; max-width: none; }
.mark { position: absolute; top: 16.25%; height: 20%; border: 2px solid var(--status-highlight); }

/* Role / timeline / platform / team */
.cs-meta { display: flex; flex-direction: column; gap: 40px; }
.cs-meta > div { display: flex; flex-direction: column; gap: 16px; }
.cs-meta dt, .cs-meta-title { font-family: var(--font-sans); font-weight: 600; font-size: 18px; line-height: 1.5; color: var(--text-secondary); text-transform: uppercase; }
.cs-meta dd { font-size: 18px; line-height: 1.37; }
.cs-overview .cs-main { gap: 16px; }
.cs-overview .cs-stats { margin-top: 8px; }          /* 24px below the summary */

/* Outlined cards: stats and use cases */
.cs-stats, .cs-cards { display: flex; gap: 40px; }
.cs-cards { gap: 24px; }
.cs-stat, .cs-card {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; gap: 8px;
  padding: 16px 24px;
  border: 1px solid transparent; border-radius: var(--radius-m);
  background: linear-gradient(var(--bg-page), var(--bg-page)) padding-box, var(--border-card) border-box;
  font-size: 16px; line-height: 1.37;
}
.cs-stat { text-align: center; }
.cs-stat-num { font-family: var(--font-serif); font-weight: 600; font-size: 24px; line-height: 1.5; color: var(--text-heading); }
.cs-card h3 { font-family: var(--font-serif); font-weight: 600; font-size: 18px; line-height: 1.5; color: var(--text-heading); }
.chips { display: flex; gap: 8px; padding: 0; list-style: none; }   /* one row, as in Figma (wraps on smaller screens) */
/* Chip (Figma: Chip, Color=Gray / Purple). Gray is the default; add .chip-purple for the purple one */
.chips li, .chip { padding: 4px 10px; border: 1px solid var(--text-secondary); border-radius: var(--radius-pill); font-size: 14px; line-height: 1.37; white-space: nowrap; }
.chip { font-family: var(--font-sans); font-style: normal; font-weight: 400; }
.chip-purple { border-color: var(--accent-hover); color: var(--text-heading); }

/* Pieces the other case studies add to the Boards template */
.cs-hero-fit img { aspect-ratio: auto; object-fit: initial; }   /* images keep their own shape; columns set per page (style="grid-template-columns: …") */
.cs-hero-single { grid-template-columns: 1fr; }
/* Cube: Comments: two screenshots side by side on a lavender card (Figma 11172:148493: 32px padding and gap, 492 + 137 wide) */
.cs-hero.cc-hero {
  grid-template-columns: 492fr 137fr; gap: 32px; align-items: start;
  padding: 32px max(32px, calc((100% - 661px) / 2));
  background: var(--bg-image); border-radius: var(--radius-s);
}
.cs-hero.cc-hero img { aspect-ratio: auto; object-fit: initial; width: 100%; height: auto; border-radius: var(--radius-s); }
.cs-hero.cc-hero img + img { box-shadow: 0 4px 4px rgba(0, 0, 0, .25); }
.cs-section.cc-soon { display: flex; flex-direction: column; gap: 40px; }
.cc-soon-text { display: flex; flex-direction: column; gap: 24px; }
.cc-soon-title { font-family: var(--font-serif); font-weight: 600; font-size: 40px; line-height: 1.2; }   /* heading/pager */
.cs-pair-fit img { aspect-ratio: auto; object-fit: initial; }   /* a pair whose images keep their own shape */
.cs-embed { display: block; width: 100%; max-width: 534px; aspect-ratio: 534 / 789; border: 1px solid var(--border-rule); border-radius: var(--radius-s); background: var(--bg-image); }   /* an embedded Figma prototype */
.cs-pair .cs-video { width: 100%; }
/* phone screenshots in a row: --n across (desktop), --n-phone across on phones */
.cs-phones { display: grid; grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); gap: 16px; align-items: start; }
.cs-text ul { padding-left: 1.2em; }
.cs-text > * + ul { margin-top: .6em; }
.cs-text li + li { margin-top: .4em; }
.cs-quotes { display: flex; flex-direction: column; gap: 16px; }
.cs-quotes blockquote {
  margin: 0; padding-left: 16px; border-left: 2px solid var(--accent-default);
  font-family: var(--font-serif); font-weight: 600; font-size: 20px; line-height: 1.37;
}
.cs-card p + p { margin-top: 4px; }
/* Speech bubbles (Beacon: The problem): heading/connect on accent, tail at the bottom; the 2nd sits right with its tail on the right.
   Tail as in Figma: a 24px triangle, 8px up from the bottom, half of it tucked under the bubble so it stays attached. */
.cs-bubbles { display: flex; flex-direction: column; gap: 40px; }
.cs-bubbles blockquote, .bubble-live {
  padding: 12px 16px; border-radius: 16px;
  background: var(--accent-default); color: var(--text-on-accent);
  font-family: var(--font-serif); font-weight: 600; font-size: 24px; line-height: 1.2;
}
.cs-bubbles blockquote { position: relative; width: min(320px, 100% - 20px); margin: 0 0 0 20px; }
.cs-bubbles blockquote::before, .bubble-live::before {
  content: ""; position: absolute; bottom: 8px; left: -12px; width: 24px; height: 24px;
  background: inherit; clip-path: polygon(0 50%, 100% 0, 100% 100%);
}
.cs-bubbles blockquote:nth-child(even) { align-self: flex-end; margin: 0 20px 0 0; }
.cs-bubbles blockquote:nth-child(even)::before, .cs-bubbles blockquote:nth-child(even) .bubble-live::before { left: auto; right: -12px; clip-path: polygon(0 0, 100% 50%, 0 100%); }
/* Typing entrance (js/site.js): each blockquote keeps the quote's final size (so nothing below jumps) while a
   live bubble inside it pops in with "…" dots, then grows as the quote types in. */
.cs-bubbles.is-typing blockquote { background: none; }
.cs-bubbles.is-typing blockquote::before { content: none; }
.cs-bubbles.is-typing .bubble-ghost { visibility: hidden; }
.bubble-live {
  position: absolute; left: 0; bottom: 0; width: max-content; max-width: 100%;
  opacity: 0; transform: scale(.5); transform-origin: 0 100%;
  transition: opacity .2s ease, transform .4s var(--ease-rise);
}
.cs-bubbles blockquote:nth-child(even) .bubble-live { left: auto; right: 0; transform-origin: 100% 100%; }
.bubble-live.is-on { opacity: 1; transform: none; }
.bubble-dots { display: inline-flex; gap: 6px; height: 1.2em; align-items: center; padding: 0 2px; }
.bubble-dots span { width: 8px; height: 8px; border-radius: 50%; background: currentColor; animation: bubble-dot 1s ease-in-out infinite; }
.bubble-dots span:nth-child(2) { animation-delay: .15s; }
.bubble-dots span:nth-child(3) { animation-delay: .3s; }
@keyframes bubble-dot { 0%, 60%, 100% { opacity: .4; transform: none; } 30% { opacity: 1; transform: translateY(-4px); } }
.cs-step > p + p { margin-top: calc(1.37em - 8px); }   /* a blank line between paragraphs (the step's 8px gap + this) */
/* Callout (Switchchord: The opportunity): label/eyebrow in secondary, then a heading/pager line */
.cs-callout { display: flex; flex-direction: column; gap: 8px; }
.cs-callout h3 { font-family: var(--font-sans); font-weight: 600; font-size: 18px; line-height: 1.5; color: var(--text-secondary); text-transform: uppercase; }   /* label/meta */
.cs-callout p { font-family: var(--font-serif); font-weight: 600; font-size: 40px; line-height: 1.2; color: var(--text-primary); }
/* Takeaway (Switchchord: Going wide): a paragraph, then outlined cards with one heading/m line each */
.cs-takeaway { display: flex; flex-direction: column; gap: 16px; }
.cs-stat-text { justify-content: center; font-family: var(--font-serif); font-weight: 600; font-size: 24px; line-height: 1.5; color: var(--text-heading); }
/* Card titles that type themselves in: letters flip through random ones, then settle left to right (js/site.js) */
[data-scramble] .scramble { white-space: pre-wrap; }
.cs-videos { display: flex; flex-direction: column; gap: 40px; }      /* videos stacked, each full width */
.cs-videos figure { display: flex; flex-direction: column; gap: 8px; }
/* ✏️ never taller than the screen (below the nav, with its caption): the 3:4 videos get narrower instead */
.cs-videos .cs-video { width: min(100%, (100svh - var(--layout-nav-height) - 48px - 30px) * 3 / 4); height: auto; }

/* Gated part (everything after the summary) */
.cs-body .cs-lock { position: relative; margin-top: 80px; }
.cs-is-locked .cs-lock { max-height: max(1100px, 100vh + 240px); overflow-x: visible; overflow-y: clip; }  /* ✏️ how much blurred page shows */
html.cs-is-locked { overflow-x: clip; }              /* the veil is full-width; never let it add sideways scroll */
.cs-is-locked .cs-pager { display: none; }
.cs-redact { transition: filter .4s ease; }
.cs-is-locked .cs-redact { filter: blur(6px); user-select: none; }   /* numbers kept back until the password is entered (Cube: Boards stats) */

/* Previous / next: two equal halves; a long title wraps inside its half */
.cs-pager { margin-top: 132px; }
.cs-pager > div {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 40px;   /* ✏️ space between the halves */
  padding-block: 80px;
  border-top: 2px solid var(--border-rule);
}
/* Each link = uppercase label (body/l; body/s on phones) over the title + arrow (heading/pager) */
.cs-pager a {
  display: flex; flex-direction: column; gap: 4px; max-width: 100%;
  color: var(--accent-default); text-decoration: none;
  transition: color .15s ease;
}
/* Previous sits at the left edge, Next at the right edge. Each label lines up with its title's text, not its
   arrow: PREVIOUS with where the text starts, NEXT with where it ends (inset by the 40px arrow + 4px gap).
   A wrapped title keeps its arrow on the outside edge. */
.cs-pager-prev { grid-column: 1; justify-self: start; align-items: flex-start; text-align: left; }
.cs-pager-next { grid-column: 2; justify-self: end; align-items: flex-end; text-align: right; }
.cs-pager-prev .cs-pager-label { padding-left: 44px; }
.cs-pager-next .cs-pager-label { padding-right: 44px; }
.cs-pager-label {
  font-family: var(--font-sans); font-weight: 400; font-size: 18px; line-height: 1.37;
  text-transform: uppercase; color: var(--text-secondary);
}
.cs-pager-title { font-family: var(--font-serif); font-weight: 600; font-size: 40px; line-height: 1.2; }
.cs-pager-title .nowrap { white-space: nowrap; }   /* the arrow always stays with its word */
.cs-pager svg {
  display: inline-block; width: 1em; height: 1em; vertical-align: -.17em;
  transition: transform .25s var(--ease-out);
}
.cs-pager-prev svg { margin-right: 4px; }
.cs-pager-next svg { margin-left: 4px; }
.cs-pager-prev:hover svg { transform: translateX(-4px); }
.cs-pager-next:hover svg { transform: translateX(4px); }

/* Back to top: a small round button, right-aligned in the space between the last section and the pager's line.
   It stays hidden until the visitor reaches the last section (e.g. Reflection), then pops in 1s later with a slight bounce
   (the 1s is TO_TOP_DELAY_MS in js/site.js). */
.to-top-wrap { margin-top: 64px; }
.to-top-wrap > div { display: flex; justify-content: flex-end; }   /* ✏️ right-aligned; center with justify-content: center */
.to-top-wrap + .cs-pager { margin-top: 24px; }                       /* 64 + 44 + 24 = the same 132px as before */
.cs-is-locked .to-top-wrap { display: none; }
.to-top {
  display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%;
  background: var(--bg-page); border: 1.5px solid var(--border-rule); color: var(--text-secondary);   /* 1.5px, like the icon stroke */
  box-shadow: 0 8px 20px -12px rgba(0, 0, 0, .35);
  transition: color .15s ease, border-color .15s ease, transform .15s ease;
}
.to-top svg { width: 20px; height: 20px; transition: transform .25s var(--ease-out); }
.to-top:focus-visible, .to-top.is-focus { border-radius: 50%; }
.to-top.is-focus { outline: 2px solid var(--accent-default); outline-offset: 3px; }
.to-top:hover, .to-top:focus-visible, .to-top:active, .to-top.is-hover, .to-top.is-focus, .to-top.is-active { color: var(--accent-hover); border-color: var(--accent-hover); }
.to-top:hover svg, .to-top.is-hover svg { transform: translateY(-3px); }   /* arrow nudges up */
.to-top:active, .to-top.is-active { transform: scale(.94); }               /* pressed */
.to-top-ready .to-top:not(.is-in) { opacity: 0; transform: translateY(16px); pointer-events: none; }
.to-top-ready .to-top.is-in { animation: to-top-in .6s var(--ease-out) backwards; }   /* ✏️ bounce speed */
@keyframes to-top-in {
  0%   { opacity: 0; transform: translateY(16px); }
  55%  { opacity: 1; transform: translateY(-5px); }    /* ✏️ bounce height */
  80%  { transform: translateY(2px); }
  100% { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .to-top-ready .to-top:not(.is-in) { transform: none; }
  .to-top-ready .to-top.is-in { animation: none; transition: opacity .3s ease; }
  .to-top:hover svg, .to-top.is-hover svg { transform: none; }
}

@media (max-width: 999px) {
  .cs-section { grid-template-columns: minmax(180px, 30%) minmax(0, 1fr); }
  .cs-h2, .cs .cs-title { font-size: clamp(40px, 5.2vw, 56px); }
  .chips { flex-wrap: wrap; }
}
/* Pager stacks below 860px: Next first, then Previous, both centered.
   (Side by side, the longest title, "Switchchord: Splits →", fits its half from 814px wide) */
@media (max-width: 859px) {
  .cs-pager > div { display: flex; flex-direction: column; align-items: center; gap: 24px; }
  .cs-pager a { align-items: center; justify-self: auto; margin: 0; text-align: center; }
  .cs-pager a .cs-pager-label { padding-inline: 0; }   /* stacked: labels center over the whole title */
  .cs-pager-next { order: -1; }
}
@media (max-width: 759px) {
  .cs-label { font-size: 20px; }
  .cs-title { font-size: 40px; }
  .cs-hero { grid-template-columns: 1fr; margin-top: 24px; }
  .cs-body { padding-top: 64px; }
  .cs-section { grid-template-columns: 1fr; row-gap: 24px; padding-top: 56px; }
  .cs-section + .cs-section { margin-top: 56px; }
  .cs-h2 { position: static; font-size: 40px; }
  /* Role + Timeline on the left, Platform + Team on the right */
  .cs-meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto auto; grid-auto-flow: column; gap: 32px 24px; }
  .cs-stats { gap: 24px; }                         /* % cards + use-case cards stay side by side; they stack on phones */
  .cs-pager { margin-top: 80px; }
  .to-top-wrap { margin-top: 40px; }
  .to-top-wrap + .cs-pager { margin-top: 16px; }
  .cs-pager > div { padding-block: 56px; }
  .cs-pager-label { font-size: 14px; }             /* body/s */
  .cs-pager-title { font-size: 24px; }
  .cc-soon-title { font-size: 24px; }
  .cs-hero.cc-hero { gap: 12px; padding: 16px; }
  .cs-pager svg { width: 24px; height: 24px; }
  .cs-callout p { font-size: 24px; }
}
@media (max-width: 559px) {
  .cs-pair { grid-template-columns: 1fr; }
  .cs-phones { grid-template-columns: repeat(var(--n-phone, 2), minmax(0, 1fr)); }
  .cs-hero-fit { grid-template-columns: 1fr !important; }
  .cs-hero-phone-43 img { aspect-ratio: 4 / 3; object-fit: cover; object-position: 50% 50%; }   /* very wide heroes (Switchchord) crop to the middle on phones, so they aren't a thin strip; tap still shows the whole image */
  .cs-meta { display: flex; }
  .cs-stats, .cs-cards { flex-direction: column; gap: 16px; }
  .cs-main > .cs-cards + .cs-cards { margin-top: -24px; }   /* two rows of cards stack into one list: 16px apart, like the cards in each row (40px column gap − 24) */
}

/* ---- Enlarged visuals ----------------------------------------------------------------
   Click any case-study image to see it full screen over a veil of the page colour. Side-by-side
   pairs open side by side; on smaller screens they open one at a time with ← → to switch.
   ✕ (top right), the veil or Esc goes back to the case study. */
.cs-zoom { cursor: zoom-in; }
.cs-zoom:focus-visible { outline: 2px solid var(--accent-default); outline-offset: 4px; }
.lb {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center;
  background: var(--bg-veil);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  animation: lb-in .25s ease;
}
.lb[hidden] { display: none; }
@keyframes lb-in { from { opacity: 0; } }
.lb-stage { display: flex; align-items: flex-start; justify-content: center; animation: lb-grow .3s var(--ease-out); }
.lb-page { display: flex; flex-direction: column; align-items: center; gap: 8px; }      /* one or more images side by side, + a shared caption */
.lb-row { display: flex; align-items: flex-start; justify-content: center; gap: 24px; }
@keyframes lb-grow { from { transform: scale(.97); } }
.lb-item { display: flex; flex-direction: column; gap: 8px; margin: 0; }
.lb-item > .crop, .lb-item > img { display: block; box-shadow: 0 8px 40px rgba(0, 0, 0, .12); background: var(--bg-page); }
.lb-item > img { object-fit: cover; }
.lb-item .crop img { position: absolute; max-width: none; }
.lb-page figcaption { font-family: var(--font-sans); font-size: 16px; line-height: 1.37; color: var(--text-secondary); }
.lb-x {
  position: fixed; top: 16px; right: 16px;
  width: 44px; height: 44px; display: grid; place-items: center;
  color: var(--text-primary); border-radius: var(--radius-s);
}
.lb-x svg { width: 32px; height: 32px; }
.lb-x:hover { color: var(--accent-default); }
.lb-nav { display: none; align-items: center; justify-content: center; gap: 24px; margin-top: 8px; font-family: var(--font-sans); font-size: 14px; color: var(--text-secondary); }
.lb.is-gallery.has-many .lb-nav { display: flex; }
.lb-nav button { width: 44px; height: 44px; display: grid; place-items: center; color: var(--text-primary); border-radius: 50%; border: 1px solid var(--border-rule); transition: opacity .2s ease, color .2s ease, border-color .2s ease; }
.lb-nav button:hover:not(:disabled) { color: var(--accent-default); border-color: var(--accent-default); }
.lb-nav button:disabled { opacity: .35; cursor: default; }
.lb-nav svg { width: 24px; height: 24px; }
.lb-x:focus-visible, .lb-nav button:focus-visible { outline: 2px solid var(--accent-default); outline-offset: 2px; }
/* one at a time, side by side in a sideways strip you can scroll, swipe or step through */
.lb.is-gallery .lb-stage { width: 100vw; gap: 0; align-items: center; justify-content: flex-start; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scrollbar-width: none; }
.lb.is-gallery .lb-stage::-webkit-scrollbar { display: none; }
.lb.is-gallery .lb-page { flex: 0 0 100vw; scroll-snap-align: center; }
.lb-wrap { display: flex; flex-direction: column; align-items: center; }
html.lb-open { overflow: hidden; }
@media (prefers-reduced-motion: reduce) { .lb, .lb-stage { animation: none; } }

/* ---- Password (Figma: light 10208:46019, dark 10204:37010) --------------------------------
   A veil of the page colour (90%, blurred) over the start of the hidden part. The form has no box:
   it sits 91px into the veil and stays centered on screen while the veil scrolls by. */
.gate { display: none; }
.cs-is-locked .gate {
  display: block; position: absolute; inset: 0 calc(50% - 50vw); z-index: 5;   /* full width, so the blur fades past the column */
  background: var(--bg-veil);
  -webkit-backdrop-filter: blur(15px); backdrop-filter: blur(15px);
  transition: opacity .4s ease;
}
.gate.is-opening { opacity: 0; }
.gate-card {
  position: sticky; top: max(24px, calc(50vh - 176px));   /* half the form's height: centered on screen */
  width: min(450px, 100%); margin: 91px auto 0;
  display: flex; flex-direction: column; gap: 24px;
  padding: 24px 40px 48px;
  color: var(--text-primary);
  font-family: var(--font-sans);
}
.gate-title { font-family: var(--font-serif); font-weight: 600; font-size: 40px; line-height: 1.2; }
.gate-desc { font-size: 16px; line-height: 1.37; }
.gate-form { display: flex; flex-direction: column; gap: 16px; }
.gate-field { display: flex; flex-direction: column; gap: 6px; }
.gate-field label { font-size: 14px; line-height: 1.37; color: var(--text-secondary); }
.gate-field input {
  width: 100%; padding: 10px 0;
  border: 0; border-bottom: 1px solid var(--border-input); border-radius: 0;
  background: transparent; color: var(--text-primary);
  font: 16px/1.37 var(--font-sans);
  outline: none;
  transition: border-color .2s ease;
}
.gate-field input:focus { border-bottom-color: var(--accent-default); }
.gate.is-wrong .gate-field input { border-bottom-color: var(--status-error); }
.gate-error { font-size: 12px; line-height: 1.37; color: var(--status-error); }
.gate-error:empty { display: none; }
.gate-btn {
  align-self: flex-start;
  padding: 13px 32px; border-radius: var(--radius-pill);
  background: var(--accent-default); color: var(--text-on-accent);
  font-family: var(--font-sans); font-weight: 500; font-size: 16px; line-height: 1.37;
  transition: background-color .2s ease;
}
.gate-btn:hover { background: var(--accent-hover); }
.gate-note { font-style: italic; font-size: 14px; line-height: 1.37; color: var(--text-secondary); }
.gate-note a { color: inherit; text-decoration: underline; text-underline-position: from-font; text-decoration-skip-ink: none; }
.gate-note a:hover { color: var(--text-primary); }
.gate.is-wrong .gate-card { animation: gate-shake .35s ease; }
@keyframes gate-shake { 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
@media (max-width: 559px) { .gate-card { padding: 24px var(--layout-gutter) 32px; margin-top: 56px; } .gate-title { font-size: 32px; } }   /* lines up with the page's side padding */
@media (prefers-reduced-motion: reduce) { .gate, .gate.is-wrong .gate-card { transition: none; animation: none; } }

/* ---- Design system page (design-system.html) -------------------------------------------
   Uses the case study layout (.cs-*). The swatches are filled in by js/site.js. */
.ds { padding-bottom: 120px; }   /* ✏️ space between the last section and the footer */
.ds-intro { margin-top: 16px; font-size: 18px; line-height: 1.37; }

/* Color table: token, then a light and a dark swatch */
.ds-colors-head, .ds-color {
  display: grid; grid-template-columns: minmax(0, 1.1fr) repeat(2, minmax(0, 1fr)); gap: 12px; align-items: center;
  padding-block: 10px; border-bottom: 1px solid var(--border-rule);
}
.ds-color:last-child { border-bottom: 0; }   /* no divider after the last color */
.ds-colors-head { padding-top: 0; font-size: 14px; line-height: 1.37; font-weight: 600; color: var(--text-secondary); }
.ds-colors-head span:not(:first-child) { padding-left: 8px; }
.ds-token b { display: block; font-weight: 600; font-size: 16px; line-height: 1.37; }
.ds-token span { display: block; font-size: 14px; line-height: 1.37; color: var(--text-secondary); }
.ds-swatch {
  display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 8px; border-radius: var(--radius-s);
  background: var(--bg-page); color: var(--text-primary);   /* each swatch sits on its own mode's page color */
}
.ds-chip-color {
  flex: none; display: grid; place-items: center; width: 40px; height: 40px; border-radius: var(--radius-s);
  box-shadow: inset 0 0 0 1px rgb(128 128 128 / .3);
  font: 600 18px/1 var(--font-serif);
}
.ds-hex { min-width: 0; font-size: 14px; line-height: 1.37; overflow-wrap: anywhere; }
.ds-ratio { display: block; font-size: 12px; color: var(--text-secondary); }

/* Type scale: one row per style, biggest first. --d is the desktop size, --m the phone size.
   By default each row shows one sample as the site uses it (.ds-sample). The "Show full type scale" switch (.is-full, js/site.js)
   swaps that for the style in every weight of its typeface (.ds-weights) and adds the Ag specimens. */
/* Switch: a pill track with a white knob; khaki when off, purple when on. Its label sits to the right (body/m). */
.ds-switch {
  display: inline-flex; align-items: center; gap: 10px; align-self: flex-start;
  margin-top: -24px;   /* 16px under the intro (the column's gap is 40) */
  font-family: var(--font-sans); font-size: 16px; line-height: 1.37; color: var(--text-primary);
}
.ds-switch-track {
  position: relative; flex: none; width: 36px; height: 20px;   /* ✏️ switch size */
  border-radius: var(--radius-pill); background: var(--text-secondary);
  transition: background-color .2s ease;
}
.ds-switch-track::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 14px; height: 14px;
  border-radius: 50%; background: var(--bg-toggle);
  transition: transform .25s var(--ease-out);
}
.ds-switch[aria-checked="true"] .ds-switch-track { background: var(--accent-default); }
.ds-switch[aria-checked="true"] .ds-switch-track::after { transform: translateX(16px); }
@media (hover: hover) { .ds-switch:hover .ds-switch-track { background: var(--text-primary); } .ds-switch[aria-checked="true"]:hover .ds-switch-track { background: var(--accent-hover); } }
@media (prefers-reduced-motion: reduce) { .ds-switch-track, .ds-switch-track::after { transition: none; } }
.ds-scale-wrap { display: flex; flex-direction: column; gap: 96px; }
.ds-specimen { display: flex; flex-direction: column; gap: 8px; margin-bottom: 32px; }
.is-full .ds-specimen { margin-bottom: 40px; }
.ds-family-name { font-size: 24px; line-height: 1.3; }
.ds-ag { font-size: 96px; line-height: 1.1; }
.ds-abc { font-size: 28px; line-height: 1.25; overflow-wrap: anywhere; }
.ds-serif :is(.ds-ag, .ds-abc, .ds-weights p, .ds-sample) { font-family: var(--font-serif); }
/* As in Figma: each style is its label + sample(s), closed by a divider underneath (20px below, 40px above the next label).
   The last style of each typeface has no divider. */
.ds-scale { display: flex; flex-direction: column; gap: 40px; padding: 0; list-style: none; }
.ds-step { padding-bottom: 20px; border-bottom: 1px solid var(--border-rule); }
.ds-step:last-child { padding-bottom: 0; border-bottom: 0; }
.ds-caps :is(.ds-sample, .ds-weights p:first-child) { text-transform: uppercase; }   /* label/eyebrow, label/meta: All caps in Figma */
.ds-step-head {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 16px;
  font-size: 12px; line-height: 1.37; color: var(--text-secondary);
}
.ds-step-head b { margin-right: 8px; font-weight: 600; color: var(--text-primary); }
.ds-step-head span { white-space: nowrap; }   /* each spec stays on one line */
.ds-sample { padding-top: 20px; font-weight: var(--w); font-size: var(--d); line-height: var(--lh); overflow-wrap: anywhere; }
.ds-weights { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 16px; padding-top: 20px; }
.ds-weights p { max-width: 100%; font-weight: var(--w); font-size: var(--d); line-height: var(--lh); overflow-wrap: anywhere; }
/* Each weight: the style name, the weight name, and an "In use" chip on the one the site uses. Gap is 20% of the size, at least 4px (as in Figma) */
.ds-weights > div { display: flex; flex-direction: column; align-items: flex-start; gap: max(4px, calc(var(--d) * .2)); min-width: 0; }
/* in use only / in full */
.ds-scale-wrap:not(.is-full) :is(.ds-ag, .ds-abc, .ds-weights), .is-full .ds-sample { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .is-full :is(.ds-ag, .ds-abc, .ds-weights) { animation: ds-fill .6s ease both; }   /* ✏️ the rest fades in as it fills */
}
@keyframes ds-fill { from { opacity: 0; transform: translateY(8px); } }
@media (max-width: 759px) {
  .ds-weights p, .ds-sample { font-size: var(--m); }
  .ds-weights > div { gap: max(4px, calc(var(--m) * .2)); }
  .ds-ag { font-size: 72px; }
  .ds-abc { font-size: 20px; }
  .ds-scale-wrap { gap: 64px; }
}

/* Components, once per mode */
.ds-modes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.ds-panel {
  display: flex; flex-direction: column; align-items: flex-start; gap: 20px; min-width: 0;
  padding: 24px; border: 1px solid var(--border-rule); border-radius: var(--radius-m);
  background: var(--bg-page); color: var(--text-primary);
}
.ds-panel-label { font-size: 14px; line-height: 1.37; font-weight: 600; color: var(--text-secondary); }
.ds-row { display: flex; flex-wrap: wrap; align-items: center; gap: 16px 24px; }
.ds-panel .chips { flex-wrap: wrap; }
.ds-panel .cs-stats, .ds-field { align-self: stretch; }
.ds-static { display: inline-flex; pointer-events: none; }
.ds-states { display: flex; flex-wrap: wrap; gap: 16px 12px; }
.ds-states figure { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 8px; min-width: 56px; }
.ds-states figcaption { font-size: 12px; line-height: 1.37; color: var(--text-secondary); }
.ds-card { align-self: stretch; }
/* Input states (Figma: Input, Label=Off), two to a row */
.ds-inputs { align-self: stretch; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 16px; }
.ds-inputs figure { margin: 0; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ds-inputs figcaption { font-size: 12px; line-height: 1.37; color: var(--text-secondary); }
.ds-input { display: flex; align-items: center; height: 42px; border-bottom: 1px solid var(--border-input); font-size: 16px; line-height: 1.37; }
.ds-input.is-focus { border-bottom-color: var(--accent-default); }
.ds-input.is-error { border-bottom-color: var(--status-error); }
.ds-input.is-disabled { border-bottom-color: var(--border-rule); color: var(--border-rule); }
.ds-caret { display: inline-block; width: 1px; height: 20px; margin-left: 2px; background: var(--text-primary); }
.ds-notes { display: grid; gap: 12px; font-size: 16px; line-height: 1.37; }
.ds-notes div { display: grid; grid-template-columns: 160px minmax(0, 1fr); gap: 16px; }
.ds-notes dt { font-weight: 600; }

/* Icons and radii */
.ds-icons, .ds-radii { display: grid; gap: 12px; padding: 0; list-style: none; font-size: 12px; line-height: 1.37; color: var(--text-secondary); }
.ds-icons { grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); }
.ds-icons li {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 20px 8px 12px; border: 1px solid var(--border-rule); border-radius: var(--radius-s); text-align: center;
}
.ds-icons svg { width: 32px; height: 32px; color: var(--text-primary); }
.ds-icons .o { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.ds-icons .s { fill: currentColor; }
.ds-radii { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 16px; font-size: 14px; }
.ds-radii span { display: block; height: 64px; margin-bottom: 8px; border: 1px solid var(--accent-default); }
.ds-radii b { margin-right: 4px; font-weight: 600; color: var(--text-primary); }

@media (max-width: 559px) {
  .ds-colors-head, .ds-color { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 8px; }
  .ds-colors-head span:first-child { display: none; }
  .ds-token { grid-column: 1 / -1; }
  .ds-modes { grid-template-columns: 1fr; }
  .ds-notes div { grid-template-columns: 1fr; gap: 2px; }
}

/* ---- About ----------------------------------------------------------------------------
   Figma "Portfolio designs 2026" › About page (desktop light 10851:89042 / dark 10822:88917,
   phone light 10759:76847 / dark 10759:76634). */
.about { padding-top: 32px; padding-bottom: 80px; }          /* 32px below the nav, like the Design system page */
.about > div { display: flex; flex-direction: column; gap: 80px; }
.about :where(h1, h2, p, ul) { margin: 0; }
/* Intro, three layouts (Figma About 1280 / 863·768·759 / 758·425·390):
   large  (1000px+)  heading + text on the left, tilted certificate on the right
   medium (760–999)  heading centered on one line, then text left + straight certificate right
   small  (≤759)     heading, then the cropped certificate at a fixed size (centered), then text */
.about-intro {
  display: grid; grid-template-columns: minmax(0, 499fr) minmax(0, 483fr);
  grid-template-areas: "title photo" "body photo"; grid-template-rows: auto 1fr;
  gap: 40px; align-items: start;
}
.about-text { display: contents; }                          /* heading and text are placed on the grid directly */
.about-title { grid-area: title; }
.about-body { grid-area: body; }
.about-photo { grid-area: photo; }
.about-title { font-family: var(--font-serif); font-weight: 600; font-size: 56px; line-height: 1; }   /* display/title */
.about-body { font-family: var(--font-sans); font-size: 18px; line-height: 1.37; }                              /* body/l */
.about-body p + p { margin-top: 1.37em; }                   /* one empty line between paragraphs */
/* The certificate is a cut-out with its own rounded corners. */
.about-photo img {
  display: block; width: calc(100% - 42px); max-width: 396px; height: auto;
  margin: 20px 0 20px 21px;                                  /* room for the tilted corners */
  transform: rotate(6deg);                                   /* = Figma's -6° (Figma and CSS turn opposite ways) */
}
@media (max-width: 999px) {
  .about-intro { grid-template-columns: minmax(0, 1fr) 325px; grid-template-areas: "title title" "body photo"; grid-template-rows: auto; gap: 24px; align-items: center; }
  .about-title { font-size: 40px; line-height: 1.2; text-align: center; }   /* heading/section */
  .about-title br { display: none; }                         /* one line */
  .about-photo img { width: 100%; max-width: none; margin: 0; transform: none; }   /* straight */
}
@media (max-width: 759px) {
  .about-intro { grid-template-columns: minmax(0, 1fr); grid-template-areas: "title" "photo" "body"; }
  .about-title br { display: inline; }                       /* two lines again */
  .about-photo img { width: 100%; max-width: 358px; margin-inline: auto; }   /* stays this size, doesn't stretch */
}
@media (max-width: 479px) {
  .about-title { font-size: 32px; line-height: 1.31; }
}

/* Interests: a row that scrolls sideways, clipped to the content column */
.interests {
  display: flex; gap: 24px;
  padding: 0; list-style: none;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity; scrollbar-width: none;
  border-radius: var(--radius-m);
  cursor: grab;
}
.interests::-webkit-scrollbar { display: none; }
.interests.is-dragging { cursor: grabbing; scroll-snap-type: none; user-select: none; }
.interests:focus-visible { outline: 2px solid var(--accent-default); outline-offset: 4px; border-radius: var(--radius-m); }
.interests li { flex: 0 0 auto; scroll-snap-align: start; }
.interests :is(img, video) {
  display: block; width: 300px; height: 400px;               /* ✏️ tile size (160 × 200 below 600px) */
  object-fit: cover; border-radius: var(--radius-m);
  background: var(--bg-image);
}
/* Chevrons over the row: the same 44px circle as Back to top. The left one waits until the row has moved on. */
.gallery { position: relative; }
.gallery-btn {
  position: absolute; top: 50%; z-index: 1;
  display: grid; place-items: center; width: 44px; height: 44px; margin-top: -22px; padding: 0;
  border-radius: 50%; cursor: pointer;
  background: var(--bg-page); border: 1.5px solid var(--border-rule); color: var(--text-secondary);
  box-shadow: 0 8px 20px -12px rgba(0, 0, 0, .35);
  transition: color .15s ease, border-color .15s ease, transform .15s ease, opacity .3s ease, visibility .3s;
}
.gallery-prev { left: 16px; }
.gallery-next { right: 16px; }
.gallery-btn svg { width: 20px; height: 20px; transition: transform .25s var(--ease-out); }
.gallery-btn:hover, .gallery-btn:focus-visible, .gallery-btn:active { color: var(--accent-hover); border-color: var(--accent-hover); }
.gallery-btn:focus-visible { outline: 2px solid var(--accent-default); outline-offset: 3px; }
.gallery-prev:hover svg { transform: translateX(-3px); }
.gallery-next:hover svg { transform: translateX(3px); }
.gallery-btn:active { transform: scale(.94); }
.gallery-btn.is-hidden { opacity: 0; visibility: hidden; }
@media (prefers-reduced-motion: reduce) { .gallery-btn:hover svg { transform: none; } }
.about-thanks { font-family: var(--font-serif); font-weight: 400; font-size: 24px; line-height: 1.2; text-align: center; }
@media (max-width: 599px) {
  .about > div { gap: 40px; }
  .interests :is(img, video) { width: 160px; height: 200px; }
}
.about [lang="ja"] { font-family: "Noto Sans JP", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", sans-serif; }   /* Japanese in a gothic (sans), as in Figma */

@media (max-width: 759px) {
  .about { padding-bottom: 64px; }
  .gallery-prev { left: 8px; }                               /* both 24px from the screen edges */
  .gallery-next { right: 8px; }
  .about-thanks { padding-top: 40px; font-size: 16px; line-height: 1.05; }
  .about-thanks span { display: inline-block; margin-top: 8px; }
}

/* ---- 404 (Figma: Loading, 404 page › 404_Light, Mobile 404_Light) ------------------------------
   Big: text column (404 centered above left-aligned copy) beside the sold-out fridge.
   Phones: 404, fridge, copy, buttons, stacked. */
.nf { display: grid; grid-template-columns: minmax(320px, 1fr) minmax(0, 504px); gap: 24px; padding-top: 32px; padding-bottom: 80px; }
.nf-text { display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 24px; }
.nf :where(h1, p) { margin: 0; }
.nf-title { font-family: var(--font-serif); font-weight: 600; font-size: 96px; line-height: 1; color: var(--text-primary); }
.nf-body { align-self: stretch; font-family: var(--font-sans); font-size: 18px; line-height: 1.37; color: var(--text-secondary); }   /* body/l */
.nf-body [lang="ja"] { font-family: "Noto Sans JP", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", sans-serif; }
.nf-actions { align-self: stretch; display: flex; flex-wrap: wrap; align-items: center; gap: 16px; }
.nf-actions a { text-decoration: none; }
.nf-btn {   /* Button (pill), as the password Enter button */
  padding: 13px 32px; border-radius: var(--radius-pill);
  background: var(--accent-default); color: var(--text-on-accent);
  font-family: var(--font-sans); font-weight: 500; font-size: 16px; line-height: 1.37;
  transition: background-color .2s ease;
}
.nf-link {   /* Text button, as View case study on the cards */
  padding: 8px;
  font-family: var(--font-sans); font-weight: 500; font-size: 16px; line-height: 1.37;
  color: var(--accent-default); transition: color .15s ease;
}
.nf-link .arrow { display: inline-block; transition: transform .25s var(--ease-out); }
@media (hover: hover) { .nf-btn:hover { background: var(--accent-hover); } .nf-link:hover { color: var(--accent-hover); } .nf-link:hover .arrow { transform: translateX(4px); } }
.nf-btn:active, .nf-btn:focus-visible { background: var(--accent-hover); }
.nf-link:active, .nf-link:focus-visible { color: var(--accent-hover); }
.nf-link:focus-visible .arrow { transform: translateX(4px); }
@media (prefers-reduced-motion: reduce) { .nf-link .arrow { transition: none; } .nf-link:hover .arrow, .nf-link:focus-visible .arrow { transform: none; } }
/* The fridge image has room for its shadow below; the frame trims it like Figma (504 × 690) */
.nf-fridge { aspect-ratio: 504 / 690; overflow: hidden; }
.nf-fridge img { display: block; width: 100%; height: auto; }
@media (max-width: 759px) {
  .nf { grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 24px; padding-bottom: 64px; }
  .nf-text { display: contents; }
  .nf-title { font-size: 56px; }   /* display/title */
  .nf-fridge { order: 1; width: 300px; max-width: 100%; }
  .nf-body, .nf-actions { order: 2; justify-self: stretch; }
}
