/* =============================================================================
   styles.css — design system + all components
   Structure: 1 Tokens · 2 Reset · 3 Utilities · 4 Chrome (nav/drawer/footer)
              5 Hero · 6 Sections · 7 Components · 8 AI Agent · 9 Palette
              10 Motion · 11 Responsive · 12 A11y
   ========================================================================== */

/* ============================== 1. TOKENS ================================= */
:root {
  --accent: #7c5cff;
  --accent-2: #4f8cff;
  --accent-3: #3ddad7;          /* text-safe per theme: light theme overrides it below */
  --accent-solid: #6a48f5;      /* violet surface under white text (5.44:1); --accent is 4.35:1 */
  --grad: linear-gradient(115deg, #7c5cff 0%, #4f8cff 48%, #3ddad7 100%);
  --grad-soft: linear-gradient(115deg, rgba(124, 92, 255, .16), rgba(61, 218, 215, .12));
  /* Surfaces under white text or icons. Same three hues, each stop darkened in
     OKLCH until #fff reaches 4.8:1; every point between the stops is 4.80:1 or
     better. --grad itself falls to 1.72:1 at its teal end (docs/design-system.md). */
  --grad-surface: linear-gradient(115deg, #7654f6 0%, #336ddd 48%, #057f7d 100%);

  --radius-sm: 10px;
  --radius: 16px;
  --radius-lg: 24px;
  --radius-xl: 32px;

  --shell: 1180px;
  --gutter: clamp(20px, 5vw, 48px);

  --ease: cubic-bezier(.22, .61, .36, 1);
  --ease-spring: cubic-bezier(.34, 1.42, .64, 1);
  --dur: .5s;

  --font-sans: "Inter", "Inter Fallback", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  /* "Space Grotesk Fallback" is declared in fonts.v1.css (size-adjust 110.78%) and was loaded by
     this page and referenced by nothing -- /learn's stack has it, this one did not. That metric
     match is the mechanism behind the hero-title rewrap this file documents as the cause of
     CLS 0.846; the aurora fix absorbed the symptom (design lane). */
  --font-display: "Space Grotesk", "Space Grotesk Fallback", "Inter", "Inter Fallback", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --nav-h: 72px;

  /* Height of the placeholder notice strip. JS measures it and updates this,
     so the fixed nav, progress bar and anchors all shift down to match. */
  --banner-h: 0px;
  --top-offset: calc(var(--nav-h) + var(--banner-h));
}

html[data-theme="dark"] {
  --bg: #08090f;
  --bg-2: #0b0d16;
  --bg-3: #101324;
  --surface: rgba(255, 255, 255, .045);
  --surface-2: rgba(255, 255, 255, .075);
  --border: rgba(255, 255, 255, .09);
  --border-strong: rgba(255, 255, 255, .18);
  --text: #eef0f7;
  --text-dim: #b9c0d4;
  --muted: #8e97af;
  --shadow: 0 24px 60px -20px rgba(0, 0, 0, .8);
  --shadow-glow: 0 0 0 1px rgba(124, 92, 255, .22), 0 18px 50px -18px rgba(124, 92, 255, .55);
  --aurora-a: #6d4cff;
  --aurora-b: #2f6bff;
  --aurora-c: #17c3bd;
  --aurora-opacity: .5;
  --focus-ring: #3ddad7;        /* 10.7-11.6:1 on the dark backgrounds */
  --grad-text: var(--grad);
  color-scheme: dark;
}

html[data-theme="light"] {
  --bg: #f6f7fc;
  --bg-2: #ffffff;
  --bg-3: #eef0f9;
  --surface: rgba(255, 255, 255, .72);
  --surface-2: rgba(255, 255, 255, .92);
  --border: rgba(12, 16, 40, .1);
  --border-strong: rgba(12, 16, 40, .2);
  --text: #0d1024;
  --text-dim: #3b4360;
  --muted: #626b8a;
  --shadow: 0 24px 60px -26px rgba(16, 22, 60, .3);
  --shadow-glow: 0 0 0 1px rgba(124, 92, 255, .18), 0 18px 44px -20px rgba(124, 92, 255, .45);
  --aurora-a: #b7a6ff;
  --aurora-b: #a9c4ff;
  --aurora-c: #9de8e6;
  --aurora-opacity: .65;
  /* D-A10: #3ddad7 is 1.5-1.7:1 on these backgrounds. Deep teal keeps the hue
     and reaches 4.85:1 or better on every light surface (docs/design-system.md). */
  --accent-3: #0a6f6d;
  --focus-ring: #0a6f6d;
  --grad-text: linear-gradient(115deg, #6a48f5 0%, #2c66d8 48%, #0a6f6d 100%);
  color-scheme: light;
}

/* ============================== 2. RESET ================================== */
*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--top-offset) + 16px);
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  transition: background-color .4s var(--ease), color .4s var(--ease);
}

body.is-locked { overflow: hidden; }

img, svg, canvas { display: block; max-width: 100%; }

/* Tritone filter definitions for the background plates. Kept in the document
   (not `display: none`, which would neutralise the filters in some engines)
   but taken out of flow so it occupies no space. */
.photo-filters {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  pointer-events: none;
}

button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }
svg { fill: currentColor; }
kbd { font-family: var(--font-mono); }

/* The `hidden` attribute must beat our flex/grid display rules. */
[hidden] { display: none !important; }

::selection { background: rgba(124, 92, 255, .35); color: var(--text); }

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: 6px;
}

/* Scrollbar */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--muted) 45%, transparent);
  border-radius: 99px;
  border: 2px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--muted) 80%, transparent); background-clip: content-box; }

/* ============================ 3. UTILITIES ================================ */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.grad {
  background: var(--grad-text);
  background-size: 220% 220%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: gradShift 9s ease-in-out infinite;
}

.glass {
  background: var(--surface);
  border: 1px solid var(--border);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  border-radius: var(--radius-lg);
}

.skip-link {
  position: fixed;
  top: 10px; left: 50%;
  transform: translate(-50%, -160%);
  z-index: 200;
  padding: 10px 18px;
  background: var(--accent-solid);
  color: #fff;
  border-radius: 99px;
  font-weight: 600;
  transition: transform .25s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

/* Scroll progress */
.progress {
  position: fixed;
  left: 0; right: 0;
  top: var(--banner-h);
  height: 3px;
  z-index: 120;
  background: transparent;
  pointer-events: none;
  transition: top .3s var(--ease);
}
.progress span {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--grad);
  box-shadow: 0 0 14px rgba(124, 92, 255, .8);
}

/* Cursor spotlight */
.spotlight {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity .6s var(--ease);
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%),
              color-mix(in srgb, var(--accent) 13%, transparent), transparent 70%);
}
body.has-pointer .spotlight { opacity: 1; }

/* Placeholder banner — pinned above the nav, with --banner-h keeping the
   fixed header clear of it. */
.banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 115;
  display: flex;
  gap: 14px;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 8px var(--gutter);
  font-size: .82rem;
  text-align: center;
  color: #2a1d00;
  background: linear-gradient(90deg, #ffd76a, #ffc93c);
  box-shadow: 0 6px 20px -10px rgba(0, 0, 0, .6);
}
.banner code {
  font-family: var(--font-mono);
  font-size: .78rem;
  background: rgba(0, 0, 0, .12);
  padding: 1px 6px;
  border-radius: 5px;
}
.banner__close {
  position: absolute;
  right: 12px; top: 50%;
  transform: translateY(-50%);
  font-size: 1.3rem;
  line-height: 1;
  color: #2a1d00;
  padding: 2px 8px;
  border-radius: 6px;
}
.banner__close:hover { background: rgba(0, 0, 0, .12); }

/* JavaScript-off notice (Derek, 2026-09-24). Fixed to the bottom because the nav is fixed to the top;
   the body gains matching padding only when the notice exists, so it never hides the footer. */
.nojs-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 120; padding: 12px var(--gutter);
  background: var(--bg-3); border-top: 1px solid var(--border); color: var(--text); font-size: .9rem; line-height: 1.45; text-align: center; }
.nojs-bar p { margin: 0 auto; max-width: 60rem; }
.nojs-bar a { color: var(--accent-3); text-decoration: underline; text-underline-offset: 3px; }
body:has(.nojs-bar) { padding-bottom: 10rem; }  /* the bar is ~8 rem tall on a 390 px phone (measured) */
/* Controls that only work with JavaScript are hidden with it off, rather than shown and dead:
   the command palette, Pause motion, the theme switch, the drawer button and the agent launcher. */
body:has(.nojs-bar) :is(#paletteOpen, #motionToggle, #themeToggle, .hamburger, .agent) { display: none; }
@media (max-height: 40rem) { .nojs-bar { position: static; } body:has(.nojs-bar) { padding-bottom: 0; } }

/* ================ 4. CHROME — nav / drawer / footer ======================= */
.nav {
  position: fixed;
  top: var(--banner-h);
  left: 0; right: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  transition: background-color .35s var(--ease), border-color .35s var(--ease),
              backdrop-filter .35s var(--ease), transform .45s var(--ease),
              top .3s var(--ease);
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border-bottom-color: var(--border);
}
.nav.is-hidden { transform: translateY(-110%); }

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
}

.brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
.brand__mark {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  flex: 0 0 40px;
  border-radius: 12px;
  background: var(--grad-surface);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .95rem;
  letter-spacing: .02em;
  box-shadow: 0 8px 22px -8px rgba(124, 92, 255, .9);
}
.brand__text { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; overflow: hidden; }
.brand__text strong, .brand__text em { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.brand__text strong {
  font-family: var(--font-display);
  font-size: .98rem;
  letter-spacing: -.01em;
  /* Never let flex squeeze the brand until the name wraps: a two-line
     wordmark inside a 72px header looks broken, and the nav labels are the
     better thing to shrink (see the responsive block). */
  white-space: nowrap;
}
.brand__text em {
  font-style: normal;
  font-size: .75rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav__links {
  position: relative;
  display: flex;
  gap: 4px;
  align-items: center;
  flex: 0 1 auto;
  min-width: 0;
}
/* Seven links plus the brand and the actions is a tight row: shrink the padding before anything
   overlaps (the brand headline goes first, then the padding, then the hamburger takes over). */
/* The brand keeps its full name; the links give up their padding first. */
@media (max-width: 1500px) { .icon-btn kbd { display: none; } .brand { flex: 0 0 auto; } .nav__inner { gap: 12px; } }
@media (max-width: 1400px) { .nav__links a { padding-inline: 11px; } }
@media (max-width: 1240px) { .nav__links a { padding-inline: 8px; } .brand__text em { display: none; } }
@media (max-width: 1100px) { .nav__inner { gap: 10px; } .nav__links a { padding-inline: 6px; } }
.nav__links a {
  position: relative;
  padding: 9px 15px;
  border-radius: 99px;
  /* 13px, not 14.4px. Seven links, the longest of them "Learn xArm 850", have to clear the brand
     and the action buttons; measured 2026-09-22, 14.4px overlapped the buttons by 20px at 1920
     (where the Cmd-K badge is also shown) and sat flush against them from 1240 to 1500. The
     design system's floor for text is 12px (F-T2), so this keeps a step in hand. */
  font-size: .8125rem;
  font-weight: 500;
  color: var(--text-dim);
  white-space: nowrap;
  transition: color .25s var(--ease), background-color .25s var(--ease);
  z-index: 1;
}
.nav__links a:hover { color: var(--text); }
.nav__links a.is-active { color: var(--text); }

/* Sliding pill behind the active link */
.nav__ink {
  position: absolute;
  top: 0;
  /* Anchored: without this the pill starts at its static position (after the last link) and
     main.js then translates it from there, so it lands outside the list. */
  left: 0;
  height: 100%;
  border-radius: 99px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  opacity: 0;
  transition: transform .45s var(--ease-spring), width .45s var(--ease-spring),
              opacity .3s var(--ease), left .45s var(--ease-spring);
  pointer-events: none;
  z-index: 0;
}
.nav__ink.is-on { opacity: 1; }

.nav__actions { display: flex; align-items: center; gap: 8px; }

.icon-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 40px;
  padding: 0 12px;
  border-radius: 11px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
  font-size: .82rem;
  transition: color .25s var(--ease), border-color .25s var(--ease),
              background-color .25s var(--ease), transform .25s var(--ease);
}
.icon-btn svg { width: 17px; height: 17px; }
.icon-btn:hover {
  color: var(--text);
  border-color: var(--border-strong);
  background: var(--surface-2);
  transform: translateY(-1px);
}
.icon-btn kbd {
  font-size: .75rem;
  padding: 2px 5px;
  border-radius: 5px;
  border: 1px solid var(--border);
  color: var(--muted);
}
.icon-btn--round { width: 40px; padding: 0; justify-content: center; border-radius: 50%; }

#themeToggle .i-sun { display: none; }
html[data-theme="light"] #themeToggle .i-moon { display: none; }
html[data-theme="light"] #themeToggle .i-sun { display: block; }

.hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 42px; height: 42px;
  padding: 0 10px;
  border-radius: 11px;
  border: 1px solid var(--border);
  background: var(--surface);
}
.hamburger span {
  display: block;
  height: 2px;
  border-radius: 2px;
  background: var(--text);
  transition: transform .35s var(--ease), opacity .25s var(--ease), width .35s var(--ease);
}
.hamburger span:nth-child(2) { width: 70%; }
.hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; transform: scaleX(.4); }
.hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Buttons */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 24px;
  border-radius: 13px;
  font-weight: 600;
  font-size: .93rem;
  letter-spacing: -.005em;
  border: 1px solid transparent;
  white-space: nowrap;
  transition: transform .3s var(--ease-spring), box-shadow .35s var(--ease),
              background-color .3s var(--ease), border-color .3s var(--ease), color .3s var(--ease);
  will-change: transform;
  overflow: hidden;
}
.btn svg { width: 17px; height: 17px; transition: transform .3s var(--ease); }
.btn:hover svg { transform: translateX(3px); }

.btn--primary {
  background: var(--grad-surface);
  background-size: 200% 200%;
  color: #fff;
  box-shadow: 0 14px 34px -14px rgba(124, 92, 255, .95);
}
.btn--primary::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, .38) 50%, transparent 70%);
  transform: translateX(-130%);
  transition: transform .7s var(--ease);
}
.btn--primary:hover::after { transform: translateX(130%); }
.btn--primary:hover {
  transform: translateY(-3px);
  box-shadow: 0 22px 48px -16px rgba(124, 92, 255, 1);
  background-position: 100% 50%;
}

.btn--ghost {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
  backdrop-filter: blur(10px);
}
.btn--ghost:hover {
  transform: translateY(-3px);
  background: var(--surface-2);
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border-strong));
  box-shadow: var(--shadow-glow);
}

.btn--text {
  padding: 13px 6px;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border-strong);
  border-radius: 0;
}
.btn--text:hover { color: var(--text); border-bottom-color: var(--accent); }

.btn--sm { padding: 9px 16px; font-size: .84rem; border-radius: 10px; }
.btn--block { width: 100%; }

.btn__spark {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent-3);
  box-shadow: 0 0 0 0 rgba(61, 218, 215, .7);
  animation: pulse 2.2s infinite;
}

/* Mobile drawer */
.drawer {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 18px;
  padding: calc(var(--top-offset) + 30px) var(--gutter) 40px;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
  clip-path: circle(0% at calc(100% - 44px) 40px);
  transition: clip-path .6s var(--ease);
  visibility: hidden;
}
.drawer.is-open { clip-path: circle(150% at calc(100% - 44px) 40px); visibility: visible; }

.drawer__nav { display: flex; flex-direction: column; gap: 4px; }
.drawer__nav a {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 9vw, 2.7rem);
  font-weight: 700;
  letter-spacing: -.03em;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .5s var(--ease), transform .5s var(--ease), color .3s var(--ease);
  transition-delay: calc(var(--i) * 70ms + 120ms);
}
.drawer.is-open .drawer__nav a { opacity: 1; transform: none; }
.drawer__nav a:hover { color: var(--accent-3); }
.drawer__cta { width: 100%; }
.drawer__socials { display: flex; gap: 10px; }

/* Footer */
.footer {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--border);
  padding: 40px 0;
  background: var(--bg);
}
.footer__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  flex-wrap: wrap;
}
.footer__brand { display: flex; align-items: center; gap: 12px; }
.footer__brand strong { display: block; font-family: var(--font-display); font-size: .96rem; }
.footer__brand span { font-size: .8rem; color: var(--muted); }
.footer__note { font-size: .8rem; color: var(--muted); }
.footer__socials { display: flex; gap: 8px; }

/* Social chips */
.social {
  display: inline-grid;
  place-items: center;
  width: 42px; height: 42px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
  transition: transform .3s var(--ease-spring), color .25s var(--ease),
              border-color .25s var(--ease), background-color .25s var(--ease);
}
.social svg { width: 19px; height: 19px; }
.social:hover {
  transform: translateY(-4px);
  color: #fff;
  background: var(--grad-surface);
  border-color: transparent;
  box-shadow: 0 14px 30px -14px rgba(124, 92, 255, .9);
}

/* ============================== 5. HERO =================================== */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: calc(var(--top-offset) + 60px) 0 90px;
  overflow: hidden;
  isolation: isolate;
}

.aurora { position: absolute; inset: -20% -10% auto; height: 140svh; z-index: -2; opacity: var(--aurora-opacity); }
/* `height` is viewport-relative on purpose. With `inset: -20% -10%` the aurora was 1.4x its parent's
   height, so when the display font arrived and the hero title rewrapped from four lines to three,
   a 40px text change moved an 1867px element -- CLS 0.846 in 5 of 6 loads on the documented profile
   (Q30, 2026-09-23). Sized against the viewport, its height cannot be moved by text reflow; the `top` offset is
   still a percentage of the containing block, which is immaterial only because the hero is itself
   viewport-locked at min-height: 100svh. Measured CLS 0.000 over three runs (design A10). */
.aurora__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  will-change: transform;
}
.aurora__blob--1 {
  width: 46vw; height: 46vw; min-width: 320px; min-height: 320px;
  top: 2%; left: -6%;
  background: radial-gradient(circle at 30% 30%, var(--aurora-a), transparent 68%);
  animation: drift1 22s ease-in-out infinite;
}
.aurora__blob--2 {
  width: 40vw; height: 40vw; min-width: 300px; min-height: 300px;
  top: 18%; right: -4%;
  background: radial-gradient(circle at 60% 40%, var(--aurora-b), transparent 68%);
  animation: drift2 26s ease-in-out infinite;
}
.aurora__blob--3 {
  width: 34vw; height: 34vw; min-width: 260px; min-height: 260px;
  bottom: -8%; left: 32%;
  background: radial-gradient(circle at 50% 50%, var(--aurora-c), transparent 68%);
  animation: drift3 30s ease-in-out infinite;
}

.grid-overlay {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(to right, color-mix(in srgb, var(--text) 7%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--text) 7%, transparent) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 90% 70% at 50% 40%, #000 10%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 40%, #000 10%, transparent 78%);
}

.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, .85fr);
  gap: clamp(32px, 5vw, 70px);
  align-items: center;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 7px 15px 7px 11px;
  border-radius: 99px;
  border: 1px solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(10px);
  font-size: .8rem;
  font-weight: 500;
  color: var(--text-dim);
  margin-bottom: 22px;
}
.pill__dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #38d39f;
  box-shadow: 0 0 0 0 rgba(56, 211, 159, .7);
  animation: pulse 2.4s infinite;
}

.hero__title {
  font-family: var(--font-display);
  font-weight: 700;
  /* Stepped down 2026-09-23: this is the h2 since S36, and at its old clamp it rendered ~31%
     larger than the h1 on the first screen — the second screen out-shouting the first (design A3). */
  font-size: clamp(2rem, 4.6vw, 3.1rem);
  line-height: 1.04;
  letter-spacing: -.035em;
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 24px;
}
.hero__greeting {
  display: block;
  font-size: max(.75rem, .42em);  /* max(): .42em of the phone clamp's 25.6px floor was 10.75px */
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--muted);
}
/* The role rotates, and the long titles wrap onto a second line while the
   short one doesn't. Left to itself that changes the height of the copy
   column on every rotation, which shuffles everything below it up and down —
   and the caret, centred beside the whole block, bounced with it. Reserving
   two lines outright pins the column's height, and laying the caret out
   inline rather than as a flex sibling keeps it attached to the end of the
   text instead of floating to the right of the block. */
.hero__role {
  display: block;
  line-height: 1.12;
  min-height: 2.24em;          /* exactly two lines, always */
  color: var(--text-dim);
  font-size: .62em;
  font-weight: 600;
}
.caret {
  display: inline-block;
  width: 3px;
  height: .85em;
  margin-left: 3px;
  vertical-align: -.06em;
  background: var(--accent-3);
  border-radius: 2px;
  animation: blink 1.05s steps(2) infinite;
}

.hero__summary {
  max-width: 54ch;
  font-size: clamp(1rem, 1.1vw, 1.1rem);
  color: var(--text-dim);
  margin-bottom: 34px;
}

.hero__cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 30px; }
.hero__socials { display: flex; gap: 9px; }

/* Hero card */
.hero__card {
  position: relative;
  padding: 26px;
  border-radius: var(--radius-xl);
  overflow: hidden;
  transform-style: preserve-3d;
  transition: transform .18s ease-out, box-shadow .4s var(--ease);
  box-shadow: var(--shadow);
}
.hero__card:hover { box-shadow: var(--shadow-glow); }
.hero__card-head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 20px;
}
.hero__card-head strong { display: block; font-family: var(--font-display); font-size: 1.02rem; }
.hero__card-head span { font-size: .82rem; color: var(--muted); }
.avatar {
  display: grid;
  place-items: center;
  width: 52px; height: 52px;
  flex: 0 0 52px;
  border-radius: 16px;
  background: var(--grad-surface);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  box-shadow: 0 10px 26px -10px rgba(124, 92, 255, .9);
}
.hero__card-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px 12px;
}
.hstat strong {
  display: block;
  font-family: var(--font-display);
  font-size: 1.65rem;
  font-weight: 700;
  letter-spacing: -.03em;
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.hstat span { font-size: .76rem; color: var(--muted); }
.hero__card-foot {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  font-size: .82rem;
  color: var(--text-dim);
}
.ping {
  position: relative;
  width: 8px; height: 8px;
  flex: 0 0 8px;
  border-radius: 50%;
  background: #38d39f;
}
.ping::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: #38d39f;
  animation: ping 1.9s cubic-bezier(0, 0, .2, 1) infinite;
}
.hero__card-glow {
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: radial-gradient(320px circle at var(--gx, 50%) var(--gy, 0%),
              color-mix(in srgb, var(--accent) 65%, transparent), transparent 62%);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  -webkit-mask-composite: xor;
  opacity: 0;
  transition: opacity .4s var(--ease);
  pointer-events: none;
}
.hero__card:hover .hero__card-glow { opacity: 1; }

/* Scroll cue */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 26px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-size: .75rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--muted);
  animation: bob 2.6s ease-in-out infinite;
}
.scroll-cue em { font-style: normal; }
.scroll-cue__mouse {
  width: 24px; height: 38px;
  border: 1.5px solid var(--border-strong);
  border-radius: 99px;
  display: grid;
  justify-items: center;
  padding-top: 7px;
}
.scroll-cue__mouse span {
  width: 3px; height: 7px;
  border-radius: 2px;
  background: var(--accent-3);
  animation: wheel 1.7s ease-in-out infinite;
}

/* Marquee */
.marquee {
  position: relative;
  padding: 20px 0;
  border-block: 1px solid var(--border);
  overflow: hidden;
  background: var(--bg-2);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.marquee__track {
  display: flex;
  gap: 42px;
  width: max-content;
  animation: scrollX 34s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__item {
  display: inline-flex;
  align-items: center;
  gap: 42px;
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.6vw, 1.35rem);
  font-weight: 600;
  letter-spacing: -.02em;
  color: var(--muted);
  white-space: nowrap;
  transition: color .3s var(--ease);
}
.marquee__item::after {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  opacity: .6;
}
.marquee__item:hover { color: var(--text); }

/* ============================ 6. SECTIONS ================================= */
.section {
  position: relative;
  z-index: 2;
  padding: clamp(80px, 11vw, 140px) 0;
  background: var(--bg);
}
.section--alt { background: var(--bg-2); }

.section__head { max-width: 70ch; margin-bottom: clamp(40px, 5vw, 64px); }
.eyebrow {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: .75rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent-3);
  margin-bottom: 16px;
}
.section__title {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 4.2vw, 3.1rem);
  line-height: 1.1;
  letter-spacing: -.035em;
  font-weight: 700;
}
.subhead {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 2vw, 1.5rem);
  letter-spacing: -.02em;
  margin-bottom: 34px;
}

.section__lede {
  max-width: 68ch;
  margin-top: 20px;
  font-size: clamp(.98rem, 1.1vw, 1.06rem);
  color: var(--text-dim);
}

/* About */
.about {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(30px, 5vw, 64px);
  align-items: start;
}
.about__text p {
  color: var(--text-dim);
  margin-bottom: 18px;
  font-size: 1.02rem;
}
.about__text p:last-child { margin-bottom: 0; }

.about__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.highlight {
  position: relative;
  padding: 22px 20px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  overflow: hidden;
  transition: transform .35s var(--ease-spring), border-color .3s var(--ease), background-color .3s var(--ease);
}
.highlight::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--grad-soft);
  opacity: 0;
  transition: opacity .35s var(--ease);
}
.highlight:hover { transform: translateY(-5px); border-color: var(--border-strong); }
.highlight:hover::before { opacity: 1; }
.highlight > * { position: relative; }
.highlight__icon {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border-radius: 11px;
  background: var(--grad-surface);
  color: #fff;
  margin-bottom: 14px;
  box-shadow: 0 10px 24px -12px rgba(124, 92, 255, .9);
}
.highlight__icon svg { width: 19px; height: 19px; }
.highlight strong { display: block; font-size: .95rem; margin-bottom: 5px; font-family: var(--font-display); }
.highlight p { font-size: .84rem; color: var(--muted); line-height: 1.55; }

/* Timeline — sits directly under the Experience section head, so no top margin */
.timeline-wrap { margin-top: 0; }
.timeline { position: relative; padding-left: 40px; }
.timeline__rail {
  position: absolute;
  left: 9px;
  top: 8px; bottom: 8px;
  width: 2px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
}
.timeline__fill {
  display: block;
  width: 100%;
  height: 0%;
  background: var(--grad);
  transition: height .18s linear;
  box-shadow: 0 0 12px rgba(124, 92, 255, .8);
}

.job {
  position: relative;
  padding: 0 0 42px;
}
.job:last-child { padding-bottom: 0; }
.job::before {
  content: "";
  position: absolute;
  left: -37px;
  top: 7px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--border-strong);
  transition: border-color .35s var(--ease), box-shadow .35s var(--ease), transform .35s var(--ease-spring);
  z-index: 1;
}
.job:hover::before {
  transform: scale(1.25);
  border-color: var(--accent);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 18%, transparent);
}
.job.is-current::before { border-color: var(--accent-3); background: var(--accent-3); }

.job__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 14px;
  margin-bottom: 6px;
}
.job__role {
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 2vw, 1.32rem);
  font-weight: 600;
  letter-spacing: -.02em;
}
.job__company { color: var(--accent-3); font-weight: 600; font-size: .95rem; }
.job__when {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: .75rem;
  color: var(--muted);
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 99px;
  white-space: nowrap;
}
.job.is-current .job__when {
  border-color: color-mix(in srgb, var(--accent-3) 45%, transparent);
  color: var(--accent-3);
  background: color-mix(in srgb, var(--accent-3) 10%, transparent);
}
.job__summary { color: var(--text-dim); font-size: .95rem; margin-bottom: 12px; }
.job__list { display: grid; gap: 8px; margin-bottom: 14px; }
.job__list li {
  position: relative;
  padding-left: 22px;
  font-size: .92rem;
  color: var(--text-dim);
}
.job__list li::before {
  content: "";
  position: absolute;
  left: 4px; top: .62em;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
.tags { display: flex; flex-wrap: wrap; gap: 7px; }
.tag {
  font-family: var(--font-mono);
  font-size: .75rem;
  padding: 4px 10px;
  border-radius: 99px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
  transition: border-color .25s var(--ease), color .25s var(--ease), background-color .25s var(--ease);
}
.tag:hover { color: var(--text); border-color: var(--accent); }

/* Sub-section blocks inside About (education / certifications / volunteering) */
.sub-wrap { margin-top: clamp(46px, 6vw, 72px); }
.sub-wrap .subhead { margin-bottom: 22px; }

/* Education & certification cards */
.edu-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 14px;
}
.edu {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 20px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  transition: transform .35s var(--ease-spring), border-color .3s var(--ease);
}
.edu:hover { transform: translateY(-4px); border-color: var(--border-strong); }
.edu__icon {
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  flex: 0 0 36px;
  border-radius: 10px;
  background: var(--grad-soft);
  border: 1px solid var(--border);
  color: var(--accent-3);
}
.edu__icon svg { width: 18px; height: 18px; }
.edu strong { display: block; font-size: .93rem; font-family: var(--font-display); line-height: 1.35; }
/* Scoped classes: a bare `.edu span` also matched `.edu__icon` (0,1,1 beats
   0,1,0) and greyed out the icon. */
.edu__meta { display: block; font-size: .82rem; color: var(--muted); margin-top: 3px; line-height: 1.45; }
.edu__when {
  display: block;
  margin-top: 7px;
  font-family: var(--font-mono);
  font-size: .75rem;
  font-style: normal;
  color: var(--text-dim); /* --muted is 3.82:1 on the light theme at this size */
  opacity: .85;
}
/* In-progress qualification mirrors the "Present" role accent */
.edu.is-current { border-color: color-mix(in srgb, var(--accent-3) 45%, transparent); }
.edu.is-current .edu__icon { background: var(--grad-surface); color: #fff; border-color: transparent; }
.edu.is-current .edu__when { color: var(--accent-3); opacity: 1; }

/* Volunteering */
.vol-grid {
  display: grid;
  /* min(): below a 330px column the track would overflow the shell (320px viewports) */
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
  gap: 16px;
}
.vol {
  display: flex;
  flex-direction: column;
  padding: 24px 22px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  transition: transform .35s var(--ease-spring), border-color .3s var(--ease);
}
.vol:hover { transform: translateY(-4px); border-color: var(--border-strong); }
.vol__head { display: flex; gap: 13px; align-items: flex-start; margin-bottom: 14px; }
.vol__icon {
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  flex: 0 0 36px;
  border-radius: 10px;
  background: var(--grad-soft);
  border: 1px solid var(--border);
  color: var(--accent-3);
}
.vol__icon svg { width: 18px; height: 18px; }
.vol__head strong { display: block; font-family: var(--font-display); font-size: .96rem; line-height: 1.35; }
.vol__head span { display: block; font-size: .8rem; color: var(--muted); margin-top: 3px; }
.vol__summary { font-size: .9rem; color: var(--text-dim); margin-bottom: 14px; }
.vol__list { display: grid; gap: 7px; margin-bottom: 18px; }
.vol__list li { position: relative; padding-left: 20px; font-size: .87rem; color: var(--text-dim); }
.vol__list li::before {
  content: "";
  position: absolute;
  left: 4px; top: .58em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent-3);
}
.vol__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: auto;
}

/* Endorsement strip */
.endorse {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  margin-top: clamp(32px, 4vw, 48px);
  padding: 20px 24px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}
.endorse__label {
  font-family: var(--font-mono);
  font-size: .75rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.endorse__pills { display: flex; flex-wrap: wrap; gap: 8px; }
.endorse__pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 13px;
  border-radius: 99px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 45%, transparent);
  font-size: .8rem;
  color: var(--text-dim);
}
.endorse__pill b {
  font-family: var(--font-mono);
  font-size: .75rem;
  font-weight: 600;
  color: var(--accent-3);
}

/* ========================= 7. COMPONENTS ================================== */
/* Project cards */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
}
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 28px 26px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: linear-gradient(160deg, var(--surface), transparent 70%);
  overflow: hidden;
  transform-style: preserve-3d;
  transition: transform .18s ease-out, border-color .35s var(--ease), box-shadow .4s var(--ease);
  isolation: isolate;
}
.card:hover { border-color: var(--border-strong); box-shadow: var(--shadow); }
.card__glow {
  position: absolute;
  width: 340px; height: 340px;
  border-radius: 50%;
  left: var(--gx, 50%); top: var(--gy, 50%);
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 26%, transparent), transparent 68%);
  opacity: 0;
  transition: opacity .45s var(--ease);
  pointer-events: none;
  z-index: -1;
}
.card:hover .card__glow { opacity: 1; }
.card__index {
  font-family: var(--font-mono);
  font-size: .75rem;
  color: var(--accent-3);
  letter-spacing: .12em;
  margin-bottom: 16px;
}
.card__title {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 2.2vw, 1.5rem);
  font-weight: 600;
  letter-spacing: -.025em;
  margin-bottom: 4px;
}
.card__tagline { font-size: .8rem; color: var(--muted); margin-bottom: 14px; }
.card__desc { font-size: .93rem; color: var(--text-dim); margin-bottom: 20px; flex: 1; }
.card__metrics {
  display: flex;
  gap: 22px;
  padding: 16px 0;
  border-block: 1px solid var(--border);
  margin-bottom: 18px;
}
.card__metric strong {
  display: block;
  font-family: var(--font-display);
  font-size: 1.25rem;
  letter-spacing: -.03em;
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.card__metric span { font-size: .75rem; color: var(--muted); text-transform: lowercase; }
.card__foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.card__links { display: flex; gap: 8px; }
.card__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .82rem;
  font-weight: 600;
  color: var(--text-dim);
  padding: 7px 12px;
  border-radius: 9px;
  border: 1px solid var(--border);
  transition: color .25s var(--ease), border-color .25s var(--ease), transform .25s var(--ease), background-color .25s var(--ease);
}
.card__link svg { width: 15px; height: 15px; }
.card__link:hover {
  color: var(--text);
  border-color: var(--accent);
  transform: translateY(-2px);
  background: var(--surface-2);
}

/* Skills — grouped capability chips */
.skills {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: clamp(28px, 3.5vw, 46px);
}
.skill-group h3 {
  font-family: var(--font-display);
  font-size: 1rem;
  letter-spacing: -.01em;
  margin-bottom: 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.skill-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.skill-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px 8px 11px;
  border-radius: 99px;
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: .84rem;
  line-height: 1.3;
  color: var(--text-dim);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .5s var(--ease), transform .5s var(--ease-spring),
              color .22s var(--ease), border-color .22s var(--ease),
              background-color .22s var(--ease), box-shadow .3s var(--ease);
  transition-delay: calc(var(--i, 0) * 45ms);
}
.skill-chip::before {
  content: "";
  width: 6px; height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: var(--grad);
  opacity: .85;
}
.skill-group.is-in .skill-chip { opacity: 1; transform: none; }
.skill-group.is-in .skill-chip:hover {
  color: var(--text);
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
  background: var(--surface-2);
  box-shadow: var(--shadow-glow);
  transition-delay: 0ms;
  transform: translateY(-2px);
}

/* Testimonials */
.quotes__viewport { overflow: hidden; }
.quotes__track {
  display: flex;
  transition: transform .6s var(--ease);
  will-change: transform;
}
.quote {
  flex: 0 0 100%;
  padding: 34px clamp(26px, 4vw, 52px);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--surface);
  backdrop-filter: blur(12px);
}
.quote__mark {
  font-family: var(--font-display);
  font-size: 3rem;
  line-height: 1;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin-bottom: 10px;
}
.quote__text {
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 2.1vw, 1.5rem);
  line-height: 1.5;
  letter-spacing: -.02em;
  margin-bottom: 22px;
}
.quote__author { display: flex; align-items: center; gap: 12px; }
.quote__avatar {
  display: grid;
  place-items: center;
  width: 42px; height: 42px;
  flex: 0 0 42px;
  border-radius: 50%;
  background: var(--grad-surface);
  color: #fff;
  font-weight: 700;
  font-size: .85rem;
}
.quote__author strong { display: block; font-size: .92rem; }
/* Scoped to explicit classes: a bare `.quote__author span` selector also
   matched `.quote__avatar` (0,1,1 beats 0,1,0) and greyed out the initials. */
.quote__byline { display: block; min-width: 0; }
.quote__role { font-size: .8rem; color: var(--muted); }
.quote__context {
  display: block;
  font-style: normal;
  font-size: .78rem;
  color: var(--text-dim); /* --muted at .85 opacity was 3.82:1 on the light theme */
  margin-top: 3px;
}

.quotes__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 26px;
}
.quotes__dots { display: flex; gap: 2px; }
.quotes__dots button { position: relative; }
/* The target is the button (26x24, WCAG 2.5.8); the dot inside it is the visual. */
.quotes__dots button {
  position: relative;
  width: 26px; height: 24px;
  background: none;
  display: grid;
  place-items: center;
}
.quotes__dots button::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 99px;
  background: var(--border-strong);
  transition: width .4s var(--ease-spring), background-color .3s var(--ease);
}
.quotes__dots button[aria-selected="true"]::before { width: 18px; background: var(--grad); }

/* Pause motion (the same control as /learn): one switch stops every animation on the page. */
/* Scoped to #motionToggle. Unscoped, these also matched #quotePause's glyphs: its `hidden`
   attribute is a UA rule and cannot beat an author one, so pausing the carousel left the button
   with no icon at all, and the global Pause forced a Play glyph onto it while its accessible name
   still read "Pause automatic rotation" (design lane, round 4). */
#motionToggle .i-play { display: none; }
html[data-motion="off"] #motionToggle .i-pause { display: none; }
html[data-motion="off"] #motionToggle .i-play { display: inline; }
html[data-motion="off"] #motionToggle { background: var(--accent-solid); border-color: var(--accent-solid); color: #fff; }
html[data-motion="off"] *, html[data-motion="off"] *::before, html[data-motion="off"] *::after {
  animation: none !important; transition: none !important; scroll-behavior: auto !important;
}
html[data-motion="off"] .reveal, html[data-motion="off"] [data-reveal] { opacity: 1 !important; transform: none !important; filter: none !important; }

/* The hero is already on screen: never hide its text behind a scroll reveal (it is the LCP element). */
.hero .reveal, .hero__copy .reveal { opacity: 1 !important; transform: none !important; }

/* Contact */
.contact__panel {
  /* The portrait's head has to live in the clear band above the copy — the
     top padding plus the eyebrow — or the section title lands across the face.
     Publishing the padding as a variable lets the plate size itself from it
     (see .garnish--contact), so the two can never drift apart. */
  --contact-top: clamp(46px, 6vw, 72px);
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(30px, 5vw, 60px);
  padding: var(--contact-top) clamp(30px, 5vw, 56px) clamp(30px, 5vw, 56px);
  border-radius: var(--radius-xl);
  overflow: hidden;
}
.contact__glow {
  position: absolute;
  width: 520px; height: 520px;
  left: -160px; bottom: -220px;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 30%, transparent), transparent 68%);
  filter: blur(24px);
  pointer-events: none;
}
.contact__copy { position: relative; }
.contact__copy p { color: var(--text-dim); margin: 18px 0 26px; max-width: 42ch; }
.contact__meta { display: grid; gap: 10px; }
.contact__meta li { display: flex; align-items: center; gap: 11px; font-size: .9rem; color: var(--text-dim); }
.contact__meta svg { width: 17px; height: 17px; color: var(--accent-3); flex: 0 0 17px; }
.contact__meta a:hover { color: var(--accent-3); }

.contact__form { position: relative; display: grid; gap: 16px; }
.field { position: relative; }
.field input, .field textarea {
  width: 100%;
  padding: 16px 16px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  color: var(--text);
  font-size: .93rem;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease), background-color .25s var(--ease);
  resize: vertical;
}
.field textarea { min-height: 116px; }
.field label {
  position: absolute;
  left: 16px;
  top: 15px;
  font-size: 1rem;  /* scale(.76) when filled renders 12.2px; .93rem rendered 11.3px, under the floor */
  color: var(--muted);
  pointer-events: none;
  transform-origin: left top;
  transition: transform .22s var(--ease), color .22s var(--ease);
}
.field input:focus, .field textarea:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--accent) 65%, transparent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 14%, transparent);
  background: color-mix(in srgb, var(--bg) 25%, transparent);
}
.field input:focus + label,
.field textarea:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:not(:placeholder-shown) + label {
  transform: translateY(-8px) scale(.76);
  color: var(--accent-3);
}
.field .opt { color: var(--muted); }  /* no size step: .85em under the floated label's scale(.76) rendered 10.3px; colour carries the distinction */
.field.has-error input, .field.has-error textarea { border-color: #ff6b81; }
.contact__note { font-size: .82rem; color: var(--muted); min-height: 1.2em; }
.contact__note.is-ok { color: #38d39f; }
.contact__note.is-err { color: #ff6b81; }

/* --- Send chooser ---------------------------------------------------------
   A static page can't send mail itself, and the usual answer — hand the
   composed message to `mailto:` — quietly assumes a desktop mail client is
   configured. On a machine without one (or with only webmail, which is most
   people now) Windows intercepts the protocol and opens the Store instead of a
   composer, so the message never gets sent.

   Instead the visitor picks the service they actually use and we build that
   service's compose URL. Nothing is sent until they press send over there, and
   no mail client is required at any point. */
.mailer {
  padding: 0;
  border: 0;
  background: transparent;
  width: min(520px, calc(100vw - 32px));
  margin: 14vh auto auto;
  color: var(--text);
}
.mailer::backdrop {
  background: color-mix(in srgb, #05060b 72%, transparent);
  backdrop-filter: blur(6px);
}
.mailer[open] .mailer__box { animation: paletteIn .32s var(--ease-spring) both; }
.mailer__box {
  border-radius: 18px;
  border: 1px solid var(--border-strong);
  background: color-mix(in srgb, var(--bg-2) 96%, transparent);
  box-shadow: 0 40px 100px -30px rgba(0, 0, 0, .95);
  padding: 22px;
}
.mailer__head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 18px; }
.mailer__head strong { display: block; font-family: var(--font-display); font-size: 1.04rem; }
.mailer__head .mailer__sub {
  display: block;
  margin-top: 5px;
  font-size: .8rem;
  color: var(--muted);
  line-height: 1.55;
}
.mailer__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.mailer__opt {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: .9rem;
  font-weight: 500;
  text-align: left;
  transition: border-color .25s var(--ease), background-color .25s var(--ease),
              transform .25s var(--ease);
}
.mailer__opt b {
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  flex: 0 0 26px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 24%, transparent);
  font-family: var(--font-display);
  font-size: .78rem;
  letter-spacing: 0;
}
.mailer__opt span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mailer__opt:hover {
  border-color: var(--border-strong);
  background: var(--surface-2);
  transform: translateY(-1px);
}
.mailer__opt em {
  margin-left: auto;
  font-style: normal;
  font-size: .75rem;
  color: var(--muted);
  white-space: nowrap;
}
.mailer__opt.is-last { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.mailer__head #mailerClose { margin-left: auto; flex: 0 0 auto; }
.mailer__opt--wide { grid-column: 1 / -1; }
.mailer__note { margin-top: 16px; font-size: .8rem; color: var(--muted); min-height: 1.2em; }
.mailer__note.is-ok { color: #38d39f; }
.mailer__note.is-err { color: #ff6b81; }
@media (max-width: 520px) {
  .mailer__grid { grid-template-columns: 1fr; }
}

/* Back to top — sits ABOVE the agent launcher, which owns the bottom-right
   corner (same offset + higher z-index would make this unclickable). */
.totop {
  position: fixed;
  right: 22px;
  bottom: 98px;
  z-index: 90;
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-2);
  backdrop-filter: blur(14px);
  color: var(--text-dim);
  opacity: 0;
  transform: translateY(18px) scale(.85);
  pointer-events: none;
  transition: opacity .35s var(--ease), transform .45s var(--ease-spring), color .25s var(--ease);
}
.totop.is-on { opacity: 1; transform: none; pointer-events: auto; }
.totop:hover { color: var(--accent-3); transform: translateY(-4px); }
.totop svg { width: 19px; height: 19px; }

/* ========================= 7b. JOURNAL ==================================== */
.journal-list { border-top: 1px solid var(--border); }

.journal-entry {
  display: grid;
  grid-template-columns: minmax(170px, 210px) minmax(0, 1fr);
  gap: clamp(16px, 3vw, 46px);
  padding: clamp(26px, 3.5vw, 42px) 0;
  border-bottom: 1px solid var(--border);
}
.journal-entry__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.journal-entry__date {
  font-family: var(--font-mono);
  font-size: .75rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
}
.journal-entry__tag {
  font-size: .78rem;
  line-height: 1.35;
  padding: 5px 12px;
  border-radius: 99px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
}
.journal-entry__latest {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: .75rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent-3);
}
.journal-entry__latest::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent-3);
  box-shadow: 0 0 0 0 rgba(61, 218, 215, .7);
  animation: pulse 2.4s infinite;
}
.journal-entry__title {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 2.2vw, 1.5rem);
  font-weight: 600;
  letter-spacing: -.025em;
  margin-bottom: 14px;
}
.journal-entry__body p {
  max-width: 68ch;
  font-size: .97rem;
  color: var(--text-dim);
  margin-bottom: 13px;
}
.journal-entry__body p:last-child { margin-bottom: 0; }
.journal-entry__link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 18px;
  font-size: .86rem;
  font-weight: 600;
  color: var(--accent-3);
  padding-bottom: 2px;
  border-bottom: 1px solid color-mix(in srgb, var(--accent-3) 40%, transparent);
  transition: border-color .25s var(--ease), gap .25s var(--ease);
}
.journal-entry__link svg { width: 15px; height: 15px; }
.journal-entry__link:hover { border-bottom-color: var(--accent-3); gap: 10px; }

@media (max-width: 720px) {
  .journal-entry { grid-template-columns: 1fr; gap: 14px; }
  .journal-entry__meta { flex-direction: row; flex-wrap: wrap; align-items: center; }
}

/* ======================= 7c. PHOTOGRAPHIC PLATES ========================= */
/* The gallery shot and the profile cut-out, used as colour-toned background
   plates rather than as pictures. Each one is pushed through a tritone ramp
   (the inline SVG filters in index.html) that remaps the photograph's
   luminance onto the brand gradient — indigo shadows, violet midtones, blue
   and teal highlights — so the imagery reads as part of the palette instead
   of as a photo dropped on top of it.

   Why an SVG filter rather than the obvious CSS routes:
     · `grayscale() + sepia()/hue-rotate()` can only ever produce one hue pair
       and crushes skin tones, which is why the previous pass was so faint.
     · A gradient overlay with a blend mode is the other classic duotone, but
       it has no alpha: over the cut-out it would paint a rectangle behind the
       figure. `feComponentTransfer` remaps channels and leaves alpha alone,
       so a transparent cut-out stays transparent.

   JS attaches the source to ::before only once it has decoded, so a missing
   file renders nothing at all — no broken-image icon, no layout shift. */

html[data-theme="dark"]  { --plate-filter: url(#ds-tritone-dark); }
html[data-theme="light"] { --plate-filter: url(#ds-tritone-light); }

.garnish {
  --plate-opacity: .34;        /* overall strength */
  --plate-boost: 1;            /* per-theme scaling of the above */
  --plate-blend: screen;       /* screen = shadows drop out; normal = figure */
  --plate-bright: 1;           /* tonal trims, applied before the ramp */
  --plate-contrast: 1;
  --plate-scale: 1.04;         /* slight over-scale so cropping stays soft */
  --plate-size: cover;         /* how the source fills the plate box */
  --plate-pos: 50% 42%;        /* which part of the source lands in the box */
  --plate-origin: 50% 42%;
  --plate-mask: radial-gradient(ellipse 62% 66% at 50% 44%,
                 #000 0%, rgba(0, 0, 0, .55) 46%, transparent 76%);
  position: absolute;
  pointer-events: none;
  z-index: -1;                 /* above the section background, below the text */
  opacity: 0;
  mix-blend-mode: var(--plate-blend);
  transition: opacity 1.4s var(--ease);
  mask-image: var(--plate-mask);
  -webkit-mask-image: var(--plate-mask);
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  mask-size: 100% 100%;
  -webkit-mask-size: 100% 100%;
}
.garnish.is-ready { opacity: calc(var(--plate-opacity) * var(--plate-boost)); }

.garnish::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--plate-src) var(--plate-pos) / var(--plate-size) no-repeat;
  transform: scale(var(--plate-scale));
  transform-origin: var(--plate-origin);
  filter: brightness(var(--plate-bright)) contrast(var(--plate-contrast))
          var(--plate-filter, url(#ds-tritone-dark));
}

/* A fine scanline over the opaque plate so the photograph sits in the same
   "printed" register as the rest of the page. Opaque plates only: over a
   cut-out the lines would hang in mid-air where the figure isn't. */
.garnish--photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    0deg, rgba(255, 255, 255, .05) 0 1px, transparent 1px 3px);
  mix-blend-mode: overlay;
  opacity: .7;
}

/* `normal` keeps a cut-out a genuine translucent figure; `screen` would blow
   the highlights out into a white blob. */
html[data-theme="dark"] .garnish--cutout { --plate-blend: normal; }

/* On a light theme a glowing plate would smear into the page, so the plates
   multiply instead — ink on paper rather than a light source. The ramp's
   highlight end is near-white precisely so that whites stay white under
   `multiply`, and the tonal trims are reset because a lift that helps a plate
   glow on black will erase it on white. The opacity boost compensates for a
   ramp that is doing much less than the dark one. */
html[data-theme="light"] .garnish {
  --plate-blend: multiply;
  --plate-boost: 2;
  --plate-bright: 1;
  --plate-contrast: 1;
}

/* The cut-outs already carry far more tone than the photos do once the ramp
   has flattened them onto a light ground, so they don't want the boost. */
html[data-theme="light"] .garnish--cutout { --plate-boost: 1; }

/* A plate is deliberately oversized so the mask has slack to fade into — which
   would otherwise count towards the document's scroll width, since `body`
   propagates its `overflow-x: hidden` to the viewport rather than clipping.
   Clipping the hosting section keeps the overflow local. `clip` rather than
   `hidden` so it never becomes a scroll container. */
.section:has(> .garnish) { overflow: clip; }

/* --- Hero: the gallery plate, framed on the figure --- */
/* The source is a 3:4 photograph with the starburst chandelier on the left and
   the figure on the right; measured off the file, the face sits at 54% across
   and 59% down. The plate is a narrow box, so `cover` crops the frame to about
   56% of its width — `--plate-pos` slides that window across to land on the
   face, and the box is anchored high so the head clears the stats card rather
   than sitting entirely behind it. */
.garnish--hero {
  --plate-opacity: .58;
  --plate-bright: 1.3;
  --plate-contrast: 1.12;
  --plate-pos: 60% 46%;        /* 60% puts the face at the centre of the window */
  --plate-scale: 1;
  --plate-origin: 50% 59%;
  --plate-mask: radial-gradient(ellipse 58% 48% at 50% 56%,
                 #000 0%, rgba(0, 0, 0, .6) 44%, transparent 76%);
  top: -17%;
  right: -6%;
  width: min(24vw, 340px);
  height: 84%;
}

/* --- About: the profile cut-out, in the open band above the cards --- */
/* The section head is one column wide, which leaves the whole top-right of
   the section empty — the one place in About a portrait can sit without
   putting a paragraph on top of it. */
.garnish--about {
  --plate-opacity: .32;
  --plate-pos: 50% 0%;
  --plate-scale: 1;
  --plate-origin: 50% 0%;
  --plate-mask: radial-gradient(ellipse 54% 56% at 50% 32%,
                 #000 0%, rgba(0, 0, 0, .5) 44%, transparent 78%);
  top: 1%;
  right: 2%;
  width: min(34vw, 400px);
  height: 44%;
}

/* --- Journal: the museum ceiling, as a wide band along the top --- */
/* `background-size` rather than `cover`, because here the box is short and
   wide and `cover` would scale to the *height* and bring the figure into
   frame. At 135% the window holds the ceiling and the crowns of both
   chandeliers and stops just above his head. */
.garnish--journal {
  --plate-opacity: .3;
  --plate-size: 135% auto;
  --plate-pos: 4% 0%;
  --plate-scale: 1;
  --plate-origin: 50% 0%;
  --plate-mask: radial-gradient(ellipse 62% 60% at 62% 34%,
                 #000 0%, rgba(0, 0, 0, .5) 44%, transparent 78%);
  top: 0;
  right: -8%;
  width: min(60vw, 780px);
  height: 36%;
}

/* --- Contact: the cut-out, head above the copy --- */
/* The panel is two full columns with no clear space beside the text, so the
   portrait has to share the heading column. The one thing it must not do is
   put the section title across the face, so the plate is sized to the panel's
   own top padding and pinned to the top of the box:

     clear band = top padding + eyebrow + gap  ≈  top padding + 35px
     head height = 0.22 × image height = 0.22 × (5.8 × top padding) ≈ 1.28 × top padding

   Since 1.28p < p + 35 for any padding up to 125px, the face always clears the
   headline with room to spare, at every width — measured, the face used to sit
   behind the first two lines with about 29% of it covered.

   The shoulders still pass behind the heading, which is what keeps it reading
   as a plate rather than a floating head. */
.garnish--contact {
  --plate-opacity: .38;
  --plate-bright: 1.6;
  --plate-contrast: .98;
  --plate-size: auto calc(var(--contact-top) * 5.8);
  --plate-pos: 50% 0%;
  --plate-scale: 1;
  --plate-origin: 50% 0%;
  /* Four stops rather than three: the flat middle keeps the whole face at
     similar strength instead of vignetting from crown to chin. */
  --plate-mask: radial-gradient(ellipse 46% 34% at 50% 8%,
                 #000 0%, rgba(0, 0, 0, .85) 34%, rgba(0, 0, 0, .35) 62%, transparent 82%);
  top: 0;
  left: -3%;
  width: min(44%, 440px);
  height: 100%;
}

/* Below 900px every section collapses to one column, so body copy spans the
   full width and anything anchored to a side edge lands directly behind it.
   The plates move to the *bottom* of their section — behind the hero card and
   behind the contact panel, both of which are opaque enough to carry type —
   and weaken. The About portrait has nowhere left to go, so it's dropped. */
@media (max-width: 900px) {
  .garnish--hero {
    --plate-opacity: .3;
    --plate-mask: radial-gradient(ellipse 54% 52% at 50% 52%,
                   #000 0%, rgba(0, 0, 0, .5) 46%, transparent 78%);
    top: auto;
    bottom: -6%;
    right: -30%;
    width: 112vw;
    height: 62%;
  }
  .garnish--journal {
    --plate-opacity: .2;
    right: -22%;
    width: 104vw;
  }
  .garnish--about { display: none; }

  /* Same treatment as desktop, but the panel is far taller here so the plate
     is sized in absolute terms off the top padding instead of as a percentage
     of the panel — a percentage would scale the head up with the panel and
     put it straight back behind the copy. */
  .garnish--contact {
    --plate-opacity: .22;
    --plate-size: auto calc(var(--contact-top) * 3.4);
    --plate-pos: 50% 0%;
    --plate-mask: radial-gradient(ellipse 46% 34% at 50% 8%,
                   #000 0%, rgba(0, 0, 0, .85) 34%, rgba(0, 0, 0, .35) 62%, transparent 82%);
    top: 0;
    left: auto;
    right: -6%;
    width: 66%;
    height: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .garnish { transition: none; }
}

/* ============================ 8. AI AGENT ================================= */
.agent {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 130;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
.agent[data-open="true"] ~ .totop,
body:has(.agent[data-open="true"]) .totop { opacity: 0; pointer-events: none; }

/* Launcher */
.agent__launcher {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 20px 11px 12px;
  border-radius: 99px;
  border: 1px solid var(--border-strong);
  background: color-mix(in srgb, var(--bg-2) 88%, transparent);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow: 0 18px 44px -18px rgba(0, 0, 0, .85), var(--shadow-glow);
  transition: transform .4s var(--ease-spring), box-shadow .4s var(--ease), opacity .3s var(--ease);
}
.agent__launcher:hover { transform: translateY(-3px) scale(1.02); }
.agent[data-open="true"] .agent__launcher { opacity: 0; pointer-events: none; transform: scale(.8); }
.agent__launcher-text { display: flex; flex-direction: column; text-align: left; line-height: 1.25; }
.agent__launcher-text strong { font-size: .87rem; font-weight: 600; }
.agent__launcher-text em { font-style: normal; font-size: .75rem; color: var(--muted); }

.agent__badge {
  position: absolute;
  top: -4px; right: -4px;
  min-width: 20px; height: 20px;
  padding: 0 6px;
  border-radius: 99px;
  background: var(--accent-solid);
  color: #fff;
  font-size: .75rem;
  font-weight: 700;
  display: grid;
  place-items: center;
  box-shadow: 0 6px 16px -6px rgba(124, 92, 255, 1);
  animation: bob 2.4s ease-in-out infinite;
}
.agent__badge.is-hidden { display: none; }

/* Orb */
.agent__orb {
  position: relative;
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  flex: 0 0 38px;
  border-radius: 50%;
  background: var(--grad);
  box-shadow: 0 0 22px -2px rgba(124, 92, 255, .85);
  overflow: hidden;
}
.agent__orb--sm { width: 34px; height: 34px; flex-basis: 34px; }
.agent__orb-core {
  width: 42%;
  height: 42%;
  border-radius: 50%;
  background: #fff;
  opacity: .95;
  animation: corePulse 2.6s ease-in-out infinite;
}
.agent__orb-ring {
  position: absolute;
  inset: -40%;
  border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0deg, rgba(255, 255, 255, .85) 60deg, transparent 130deg);
  animation: spin 3.4s linear infinite;
}

/* Panel */
.agent__panel {
  /* Absolutely positioned so the closed panel takes up no layout space —
     otherwise it would push the launcher up off the bottom of the screen. */
  position: absolute;
  right: 0;
  bottom: calc(100% + 14px);
  width: min(400px, calc(100vw - 32px));
  max-height: min(620px, calc(100svh - 150px));
  display: flex;
  flex-direction: column;
  border-radius: 22px;
  border: 1px solid var(--border-strong);
  background: color-mix(in srgb, var(--bg-2) 94%, transparent);
  backdrop-filter: blur(24px) saturate(170%);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .9);
  overflow: hidden;
  opacity: 0;
  transform: translateY(20px) scale(.94);
  transform-origin: bottom right;
  pointer-events: none;
  transition: opacity .35s var(--ease), transform .45s var(--ease-spring);
}
.agent[data-open="true"] .agent__panel { opacity: 1; transform: none; pointer-events: auto; }

.agent__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 16px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 12%, transparent), transparent);
}
.agent__id { flex: 1; min-width: 0; }
.agent__id strong { display: block; font-family: var(--font-display); font-size: .95rem; }
.agent__status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: .75rem;
  color: var(--muted);
}
.agent__close { width: 34px; height: 34px; }

.agent__log {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  scrollbar-width: thin;
}

.msg { display: flex; gap: 10px; max-width: 92%; animation: msgIn .4s var(--ease) both; }
.msg--user { margin-left: auto; flex-direction: row-reverse; }
.msg__avatar {
  display: grid;
  place-items: center;
  width: 28px; height: 28px;
  flex: 0 0 28px;
  border-radius: 50%;
  background: var(--grad-surface);
  color: #fff;
  font-size: .75rem;
  font-weight: 700;
}
.msg--user .msg__avatar { background: var(--surface-2); color: var(--text-dim); border: 1px solid var(--border); }
.msg__bubble {
  padding: 11px 14px;
  border-radius: 15px;
  font-size: .89rem;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}
.msg--bot .msg__bubble {
  background: var(--surface);
  border: 1px solid var(--border);
  border-bottom-left-radius: 5px;
  color: var(--text-dim);
}
.msg--user .msg__bubble {
  background: var(--grad-surface);
  color: #fff;
  border-bottom-right-radius: 5px;
  box-shadow: 0 12px 30px -14px rgba(124, 92, 255, .95);
}
.msg__bubble strong { color: var(--text); font-weight: 600; }
.msg--user .msg__bubble strong { color: #fff; }
.msg__bubble a { color: var(--accent-3); border-bottom: 1px solid currentColor; }

/* Typing indicator */
.dots { display: inline-flex; gap: 4px; align-items: center; height: 1.2em; }
.dots i {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--muted);
  animation: dot 1.3s ease-in-out infinite;
}
.dots i:nth-child(2) { animation-delay: .16s; }
.dots i:nth-child(3) { animation-delay: .32s; }

.agent__chips {
  display: flex;
  gap: 7px;
  padding: 0 16px 12px;
  overflow-x: auto;
  scrollbar-width: none;
  mask-image: linear-gradient(90deg, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, #000 88%, transparent);
}
.agent__chips::-webkit-scrollbar { display: none; }
.chip {
  flex: 0 0 auto;
  padding: 7px 13px;
  border-radius: 99px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-dim);
  font-size: .78rem;
  white-space: nowrap;
  transition: color .22s var(--ease), border-color .22s var(--ease),
              background-color .22s var(--ease), transform .22s var(--ease-spring);
}
.chip:hover {
  color: var(--text);
  border-color: var(--accent);
  background: var(--surface-2);
  transform: translateY(-2px);
}

.agent__form {
  display: flex;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
}
.agent__input {
  flex: 1;
  min-width: 0;
  padding: 11px 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  font-size: .88rem;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
}
.agent__input:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 13%, transparent);
}
.agent__send {
  display: grid;
  place-items: center;
  width: 42px; height: 42px;
  flex: 0 0 42px;
  border-radius: 12px;
  background: var(--grad-surface);
  color: #fff;
  box-shadow: 0 12px 26px -12px rgba(124, 92, 255, .95);
  transition: transform .3s var(--ease-spring), opacity .25s var(--ease);
}
.agent__send svg { width: 17px; height: 17px; }
.agent__send:hover { transform: translateY(-2px) scale(1.04); }
.agent__send:disabled { opacity: .45; transform: none; cursor: not-allowed; }

.agent__foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 0 16px 12px;
  font-size: .75rem;
  color: var(--muted);
}
.agent__foot button {
  color: var(--muted);
  border-bottom: 1px dashed var(--border-strong);
  font-size: .75rem;
}
.agent__foot button:hover { color: var(--accent-3); }

/* ======================= 9. COMMAND PALETTE =============================== */
.palette {
  padding: 0;
  border: 0;
  background: transparent;
  max-width: min(560px, calc(100vw - 32px));
  width: 100%;
  margin: 12vh auto auto;
  color: var(--text);
}
.palette::backdrop {
  background: color-mix(in srgb, #05060b 72%, transparent);
  backdrop-filter: blur(6px);
}
.palette[open] .palette__box { animation: paletteIn .32s var(--ease-spring) both; }
.palette__box {
  border-radius: 18px;
  border: 1px solid var(--border-strong);
  background: color-mix(in srgb, var(--bg-2) 96%, transparent);
  box-shadow: 0 40px 100px -30px rgba(0, 0, 0, .95);
  overflow: hidden;
}
.palette__search {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
}
.palette__search svg { width: 19px; height: 19px; color: var(--muted); flex: 0 0 19px; }
.palette__search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  font-size: 1rem;
}
.palette__search input:focus { outline: none; }
.palette__search kbd {
  font-size: .75rem;
  padding: 3px 7px;
  border-radius: 6px;
  border: 1px solid var(--border);
  color: var(--muted);
}
.palette__list { max-height: 54vh; overflow-y: auto; padding: 8px; }
.palette__list li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border-radius: 11px;
  cursor: pointer;
  font-size: .91rem;
  color: var(--text-dim);
  transition: background-color .18s var(--ease), color .18s var(--ease);
}
.palette__list li[aria-selected="true"] {
  background: var(--surface-2);
  color: var(--text);
}
.palette__list li svg { width: 17px; height: 17px; color: var(--accent-3); flex: 0 0 17px; }
.palette__list li em {
  margin-left: auto;
  font-style: normal;
  font-size: .75rem;
  font-family: var(--font-mono);
  color: var(--muted);
}
.palette__empty { padding: 22px; text-align: center; color: var(--muted); font-size: .88rem; }

/* ============================= 10. MOTION ================================= */
.reveal { opacity: 0; transform: translateY(26px); }
.reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity .75s var(--ease), transform .85s var(--ease-spring);
}
.card.reveal, .highlight.reveal, .job.reveal, .vol.reveal,
.journal-entry.reveal { transition-delay: var(--d, 0ms); }

@keyframes gradShift {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}
@keyframes drift1 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33% { transform: translate(8vw, 6vh) scale(1.12); }
  66% { transform: translate(-4vw, 10vh) scale(.94); }
}
@keyframes drift2 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  40% { transform: translate(-9vw, 8vh) scale(1.15); }
  70% { transform: translate(-3vw, -5vh) scale(.92); }
}
@keyframes drift3 {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(6vw, -8vh) scale(1.2); }
}
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  70% { box-shadow: 0 0 0 9px transparent; opacity: .85; }
  100% { box-shadow: 0 0 0 0 transparent; opacity: 1; }
}
@keyframes ping {
  0% { transform: scale(1); opacity: .7; }
  75%, 100% { transform: scale(2.6); opacity: 0; }
}
@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes wheel {
  0% { transform: translateY(0); opacity: 1; }
  60% { transform: translateY(9px); opacity: 0; }
  100% { transform: translateY(0); opacity: 0; }
}
@keyframes scrollX {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes corePulse {
  0%, 100% { transform: scale(1); opacity: .95; }
  50% { transform: scale(.72); opacity: .7; }
}
@keyframes msgIn {
  from { opacity: 0; transform: translateY(10px) scale(.97); }
  to { opacity: 1; transform: none; }
}
@keyframes dot {
  0%, 60%, 100% { transform: translateY(0); opacity: .45; }
  30% { transform: translateY(-4px); opacity: 1; }
}
@keyframes paletteIn {
  from { opacity: 0; transform: translateY(-14px) scale(.97); }
  to { opacity: 1; transform: none; }
}

/* ========================== 11. RESPONSIVE ================================ */
/* "IntelliMake Journal" is a long label, and the six of them need ~1021px of
   content width at full size and ~881px tightened. Rather than let flex find
   that space, the nav steps down in measured bands: tighten, then hand over to
   the drawer. Squeezing is not an option — flex takes the space out of the
   brand, whose name then wraps onto two lines inside a 72px header. */
@media (max-width: 1160px) {
  .brand { flex: 0 0 auto; }
  .nav__inner { gap: 12px; }
  .nav__links { gap: 2px; }
  .nav__links a { padding: 9px 10px; }
  /* The shortcut badge is the cheapest thing to lose — the button keeps its
     title and aria-label, and Ctrl/⌘+K still opens the palette. */
  .icon-btn kbd { display: none; }
}

/* The last 100px before the drawer takes over at 1000. All seven links stay visible down to
   1001px; the room comes out of their padding, never out of the list (measured 2026-09-22 —
   at 10px padding the row overlapped the action buttons by 35px at 1001). Must sit after the
   1160 block: that one sets `padding` as a shorthand, which would otherwise win on source order. */
@media (max-width: 1100px) {
  .nav__links { gap: 0; }
  .nav__links a { padding: 9px 6px; }
}

@media (max-width: 1000px) {
  .nav__links { display: none; }
  .hamburger { display: flex; }
  .nav__cta { display: none; }
}

@media (max-width: 1080px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero__card { max-width: 460px; }
  .scroll-cue { display: none; }
}

@media (max-width: 900px) {
  .about { grid-template-columns: 1fr; }
  .contact__panel { grid-template-columns: 1fr; }
}

@media (max-width: 720px) {
  :root { --nav-h: 64px; }
  .icon-btn kbd { display: none; }
  #paletteOpen { width: 40px; padding: 0; justify-content: center; }
  .brand__text em { display: none; }
  .agent { right: 14px; bottom: 14px; left: 14px; align-items: stretch; }
  .agent__panel { width: 100%; max-height: calc(100svh - 150px); }
  .agent__launcher { justify-content: center; }
  .agent__launcher-text em { display: none; }
  .totop { right: 14px; bottom: 92px; }
  .about__grid { grid-template-columns: 1fr; }
  .cards { grid-template-columns: 1fr; }
  .skills { grid-template-columns: 1fr; }
  /* The date-and-location pill is nowrap on wide screens; here it must wrap,
     or the longest one ("… · Los Angeles Metropolitan Area · Remote") made the
     page 502px wide at a 360px viewport. */
  .job__when { margin-left: 0; white-space: normal; }
  .footer__inner { flex-direction: column; align-items: flex-start; }
  .hero { min-height: auto; padding-top: calc(var(--top-offset) + 48px); }
}

@media (max-width: 420px) {
  .hero__cta .btn { width: 100%; }
  .card__metrics { gap: 16px; }
}

/* Below 381px the header needs 379px (brand 189 + three controls (40px fine pointer, 44px coarse — see the (pointer: coarse) rule below; the coarse case is 8px wider and the brand absorbs it by ellipsising, measured 2026-09-23) + gaps +
   gutters): the hamburger was pushed 25px off-screen at 320px, and the palette
   button was squeezed at 360px. The palette button goes first: everything it
   offers (section links, socials, theme) is also in the drawer or the header,
   and Ctrl/⌘+K still opens it. The name may ellipsize as a last resort only
   (with the fallback font), so the controls can never leave the viewport. */
@media (max-width: 380px) {
  #motionToggle { padding: 0; width: 40px; }  /* added with the control, 2026-09-23 */
  #paletteOpen { display: none; }
  #themeToggle { width: 40px; padding: 0; justify-content: center; }
  .nav__inner { gap: 8px; }
  .nav__actions { flex: 0 0 auto; gap: 6px; }
  .brand { flex: 0 1 auto; gap: 10px; }
  .nav .brand__mark { width: 36px; height: 36px; flex-basis: 36px; }
  .brand__text strong { overflow: hidden; text-overflow: ellipsis; }
}

/* Coarse pointers get bigger hit targets on the agent launcher */
@media (hover: none) {
  .agent__launcher { padding: 12px 18px; }
}

/* ============================== 12. A11Y ================================== */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

html[data-motion="off"] .spotlight { display: none; }  /* the OS-setting twin, which it lacked */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
  .spotlight { display: none; }
  .skill-chip { opacity: 1 !important; transform: none !important; }
}

@media print {
  .nav, .agent, .totop, .progress, .drawer, .marquee, .spotlight, .banner,
  .garnish { display: none !important; }
  body { background: #fff; color: #000; }
  .section { padding: 20px 0; page-break-inside: avoid; }
}

/* =============================================================================
   LEARN THE XARM 850 — the index's first section: the way into /learn.
   ========================================================================== */
.learnfeat__inner { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); align-items: center; gap: clamp(1.5rem, 4vw, 4rem); }
.learnfeat__facts { list-style: none; padding: 0; margin: 1.75rem 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .75rem; }
.learnfeat__facts li { padding: .9rem 1rem; border-radius: 16px; background: var(--surface); border: 1px solid var(--border); }
.learnfeat__facts strong { display: block; font: 700 clamp(1.5rem, 1.1rem + 1.2vw, 2.1rem)/1 var(--font-display); letter-spacing: -.03em; background: var(--grad-text, var(--grad)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.learnfeat__facts span { display: block; margin-top: .35rem; font-size: .85rem; color: var(--text-dim); }
.learnfeat__cta { display: flex; flex-wrap: wrap; gap: .75rem; }
.learnfeat__art { display: block; position: relative; }
.learnfeat__art::before { content: ""; position: absolute; inset: 10% 5%; border-radius: 50%; background: radial-gradient(closest-side, rgba(124, 92, 255, .35), rgba(61, 218, 215, .12) 60%, transparent); filter: blur(30px); z-index: -1; }
.learnfeat__art img { display: block; width: 100%; height: auto; max-height: 34rem; object-fit: contain; -webkit-mask-image: radial-gradient(70% 70% at 50% 55%, #000 60%, transparent 100%); mask-image: radial-gradient(70% 70% at 50% 55%, #000 60%, transparent 100%); transition: transform .8s var(--ease); }
.learnfeat__art:hover img { transform: translateY(-6px) scale(1.02); }
@media (max-width: 860px) {
  .learnfeat__inner { grid-template-columns: 1fr; }
  .learnfeat__art { order: -1; max-width: 22rem; margin: 0 auto; }
  .learnfeat__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) { .learnfeat__art img { transition: none; } }


/* ============================================================== landing order (Derek, 2026-09-23)
   The course leads the page and the profile follows it. Derek: "I asked that the Content in Learn
   be the initial / landing content. Before you see my profile info." The spec ranks the course
   grader first and the hiring manager second (§1), so the front door showing the deliverable rather
   than the CV matches that order; the name and role stay in the nav, and the profile is the next
   screen down. */
.hero--learn { display: flex; align-items: center; }
.hero--learn .learnfeat__inner { width: 100%; }
/* 3.2rem, not 3.5: the wider art column narrowed the copy, and at 3.5rem the title took three
   lines with "850" orphaned. 3.2rem holds two lines at 1440 without shrinking the arm. */
.hero--learn .section__title { font: 700 clamp(2.1rem, 1.3rem + 2.4vw, 3.2rem)/1.06 var(--font-display); letter-spacing: -.035em; margin: 0; }
.hero--learn .section__lede { max-width: 46ch; }
.hero--learn .section__head { margin-bottom: .9rem; }
/* The art is its own grid column, so it only adds height when it is taller than the copy: it can be
   generous without pushing the call to action under the fold. */
/* The poster canvas is 900x1100 but the arm only occupies x 1-677, y 300-918 of it -- 42% of the
   frame, with 300px of empty space above. So the element was already the right size and the
   content inside it was small (Derek, 2026-09-23). Cropping to the content in CSS keeps
   /learn's stage poster untouched, and it is still downsampling at this size, so nothing softens. */
/* A definite height, not aspect-ratio: with `height: 100%` on the image and an auto-height box,
   the two depend on each other and the browser falls back to the image's intrinsic ratio -- which
   is why the first attempt at this changed nothing. */
.hero--learn .learnfeat__art { height: min(42rem, 74svh); }
.hero--learn .learnfeat__art img {
  width: 100%; height: 100%; max-height: none;  /* the base .learnfeat__art img caps at 34rem */
  object-fit: cover; object-position: 38% 55%;
  -webkit-mask-image: radial-gradient(78% 78% at 50% 50%, #000 66%, transparent 100%);
  mask-image: radial-gradient(78% 78% at 50% 50%, #000 66%, transparent 100%);
}
/* The arm is the signature of the site and it was rendering at 462x480, 17% of a 1440x900 hero
   -- present but not commanding (Derek, 2026-09-23). It gets the taller cap and a slightly wider
   column; the copy column still drives the row height, so the call to action keeps its fold. */
.hero--learn .learnfeat__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); }

/* The profile is no longer the first screen, so it does not claim a full viewport of height. */
.hero--profile { min-height: 0; padding-block: clamp(3rem, 6vw, 6rem); }

/* Bands are in px, not rem: keyed to rem they scaled with the root font size, so a reader who
   asked for larger text tripped the shrink rules and got smaller type (design A4).
   Short viewports: the hero was min-height 100svh *plus* ~240px of padding, so its content box was
   865px tall whatever the screen, and on anything shorter the call to action fell under the fold --
   101px under at 1280x602 (Derek, 2026-09-23). Below that height the padding and the display type
   come down together so the first screen stays whole. */
@media (max-height: 896px) {
  .hero--profile .hero__title { font-size: clamp(1.6rem, 1rem + 2vw, 2.6rem); }
  .hero { padding: calc(var(--top-offset) + 20px) 0 24px; }
  .hero--learn .section__title { font-size: clamp(1.9rem, 1.2rem + 2.4vw, 2.8rem); }
  .hero--learn .section__lede { margin-block: .75rem; }
  .hero--learn .learnfeat__facts { margin: .75rem 0; }
  .hero--learn .learnfeat__facts li { padding: .6rem .75rem; }
  .hero--learn .learnfeat__art { height: min(34rem, 66svh); }
}
@media (max-height: 768px) {
  .hero--profile .hero__title { font-size: clamp(1.6rem, 1rem + 2vw, 2.2rem); }
  .hero--learn .section__title { font-size: clamp(1.7rem, 1.1rem + 2vw, 2.4rem); }
  .hero--learn .section__lede { margin-block: .5rem; font-size: .95rem; }
  .hero--learn .learnfeat__art { height: min(28rem, 62svh); }
}
/* Shrink rather than hide: the lede says what the course is and the arm is the reason to look at
   it, so neither is dropped just because the window is short. */
@media (max-height: 704px) {
  .hero--profile .hero__title { font-size: clamp(1.6rem, 1rem + 2vw, 1.8rem); }
  .hero--learn .section__title { font-size: clamp(1.5rem, 1rem + 1.8vw, 2rem); }
  .hero--learn .section__lede { font-size: .9rem; margin-block: .4rem; }
  .hero--learn .learnfeat__art { height: min(24rem, 58svh); }
  .hero--learn .learnfeat__facts { margin: .6rem 0; }
  .hero--learn .learnfeat__facts li { padding: .45rem .6rem; }
}

/* Stacked, the course has to introduce itself before the picture of it. `.learnfeat__art` carries
   order: -1 at <=860px, which was right when Learn was a feature band mid-page and wrong now that
   it is the first screen: the arm took the top 60% of a phone and pushed the title under it. */
@media (max-width: 860px) {
  .hero--learn .learnfeat__art { order: 0; max-width: 16rem; }
  .hero--learn .learnfeat__art { height: 30svh; }
  .hero--learn .section__title { font-size: clamp(2rem, 1.2rem + 4vw, 2.6rem); }
  .hero--learn { align-items: flex-start; }
  .hero--learn .learnfeat__inner { padding-block-start: 1rem; }
}

/* The Contact nav item is an envelope rather than a word (Derek, 2026-09-23). It keeps a
   visually-hidden label: that is the link's accessible name, and it is also what the command
   palette reads to build its entry (main.js reads each .nav__links a textContent), so removing
   the text outright would have left a nameless link and a blank palette row. */
.nav__links a.nav__icon { display: inline-flex; align-items: center; justify-content: center; padding-inline: 10px; }
.nav__links a.nav__icon svg { width: 18px; height: 18px; fill: currentColor; display: block; }

/* §8 Attribution: "Every externally sourced image ... carries visible attribution." The hero
   render is derived from UFACTORY's BSD-3 uf850 meshes, and S36 made it the most prominent image
   on the site while its only credit lived on /learn (security lane B2). The credit sits outside
   the aria-hidden art link so assistive technology reaches it. */
.learnfeat__figure { display: flex; flex-direction: column; gap: .5rem; min-width: 0; }
@media (max-width: 860px) { .learnfeat__figure { max-width: 20rem; margin-inline: auto; } }  /* match the art, so the credit reads as its caption rather than the page's */
/* Held at the design system's documented 12px floor (§3.3). A legal credit is the last thing that
   should shrink, and an 11px exception here would have falsified that section (design lane). */
.learnfeat__credit { margin: 0; font-size: .75rem; line-height: 1.45; color: var(--muted); text-align: center; }
/* Light theme takes --text-dim, not --muted. F-C6 measured /learn's stage credit at 4.11:1 with
   --muted in light and had to change it for exactly this reason; carrying the abandoned token on a
   legally-required attribution notice would be repeating a measured failure on an estimate. */
:root[data-theme="light"] .learnfeat__credit { color: var(--text-dim); }
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .learnfeat__credit { color: var(--text-dim); } }
/* Wording, not size, was what made this read loud: at 12px against a 15.84px lede there is little
   hierarchy, and the long form ran to two centred lines 462px wide. It now uses the same short
   credit /learn already shows in tight spaces. BSD-3 clause 2 asks for the notice plus a route to
   the licence text; the notice is here and the text is one link away on /learn/en/credits. */
.learnfeat__credit a { color: inherit; text-decoration: underline; }
.footer__note a { color: inherit; text-decoration: underline; margin-inline-start: .5rem; }

/* The same control on both surfaces: /learn gives its motion button 44x44 under (pointer: coarse)
   and the portfolio's was 41x40. Both clear WCAG 2.5.8, but it is described as one mechanism over
   one origin and should not be two sizes (design lane). */
@media (pointer: coarse) { .nav__actions .icon-btn, .icon-btn--round, .hamburger { min-width: 44px; min-height: 44px; } }


/* ==================== FORCED COLOURS ====================================
   `background-clip: text` with `color: transparent` is the pattern learn.css already remedies
   (`.hero h1, .stat__v .val { color: CanvasText; background: none }`). The portfolio had no
   forced-colours block at all, over five gradient-clipped sites including the front door's h1 and
   the four hero figures -- and it does not load tokens.v1.css, so it did not inherit that file's
   block either. Whether transparent glyphs survive forced colours is engine-dependent; the point is
   that it was unhandled on one surface and handled on the other (design lane, whole-surface B2).
   The first version of this block listed five *selectors* but reached only three *rules* -- two of
   them were subsets of .grad, and the count came from instances (one h1 + four hero figures) rather
   than from grepping the pattern. That missed .card__metric strong, which carries content: the
   project metric values, whose plain-text labels survive, so a forced-colours reader got the caption
   with the number gone. Enumerated by rule now: exactly five. */
@media (forced-colors: active) {
  .grad, .hstat strong, .card__metric strong, .quote__mark, .learnfeat__facts strong {
    background: none; color: CanvasText; -webkit-text-fill-color: CanvasText;
  }
  .btn, .icon-btn, .card, .tag, .hstat, .learnfeat__facts li { border-color: CanvasText; }
  .btn--primary { color: HighlightText; background: Highlight; }
}

/* The reader's font-size setting must scale the front door as it scales /learn. `body` was a fixed
   16px while the headings on the same page were rem-based, so the page scaled unevenly and the
   body text did not scale at all (design lane, whole-surface B1). */
