/* ==========================================================================
   Kirsten — Portfolio
   Visual system: soft-grey ground, white panel, heavy geometric sans,
   pastel project blocks. All design decisions live in the token block.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Ground + surfaces */
  --ground:   #e6e6e6;
  --panel:    #ffffff;
  --chip:     #f2f2f2;
  --chip-2:   #ebebeb;
  --line:     #e4e4e4;

  /* Ink */
  --ink:      #0d0d0d;
  --ink-2:    #5c5c5c;
  --ink-3:    #6b6b6b;
  --on-ink:   #ffffff;   /* text and icons sitting on an --ink surface */

  /* Effect colours, so light/dark can tune them independently */
  --shadow-rgb: 13, 13, 13;
  --glow:  rgba(255,255,255,.85);  /* cursor spotlight on cards */
  --sheen: rgba(255,255,255,.5);   /* light sweep across a pastel block */

  /* Pastel blocks */
  --lavender: #c6caf6;
  --yellow:   #f0ec6f;
  --purple:   #bb9dd8;
  --mint:     #a9dcc6;
  --peach:    #f8c9ac;

  /* Illustration fills */
  --fill-orange: #f5873a;
  --fill-coral:  #e8697b;
  --fill-violet: #9d7fd0;
  --fill-teal:   #3fa98a;

  /* Type */
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          Helvetica, Arial, sans-serif;

  --step--2: 0.6875rem;
  --step--1: 0.8125rem;
  --step-0:  0.9375rem;
  --step-1:  clamp(1.05rem, 1rem + 0.25vw, 1.25rem);
  --step-2:  clamp(1.35rem, 1.2rem + 0.7vw, 1.75rem);
  --step-3:  clamp(1.9rem, 1.5rem + 1.8vw, 2.75rem);
  --step-4:  clamp(2.5rem, 1.7rem + 3.6vw, 4.25rem);

  /* Space */
  --sp-1: 0.375rem; --sp-2: 0.75rem; --sp-3: 1.125rem; --sp-4: 1.75rem;
  --sp-5: 2.75rem;  --sp-6: 4.25rem; --sp-7: 6rem;

  /* Shape */
  --r-sm:  10px;
  --r:     18px;
  --r-lg:  26px;
  --r-xl:  34px;
  --shadow:    0 1px 2px rgba(var(--shadow-rgb),.04), 0 10px 30px -14px rgba(var(--shadow-rgb),.18);
  --shadow-lg: 0 2px 6px rgba(var(--shadow-rgb),.05), 0 30px 60px -24px rgba(var(--shadow-rgb),.3);

  /* Motion */
  --ease:        cubic-bezier(.2,.7,.3,1);
  --ease-out:    cubic-bezier(.16,1,.3,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
  --dur-fast: .18s;
  --dur:      .35s;
  --dur-slow: .7s;
  --stagger:  80ms;

  --measure: 62ch;
  --wrap: 1240px;

  color-scheme: light;
}

/* --------------------------------------------------------------------------
   1b. DARK THEME
   Only colour tokens are redefined — every size, space, and timing token is
   shared. The same block appears twice on purpose: once for visitors whose
   system asks for dark (unless they have explicitly chosen light here), and
   once for an explicit choice of dark. Keep the two in sync when editing.
   -------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground:   #0b0b0c;
    --panel:    #161618;
    --chip:     #202024;
    --chip-2:   #2a2a30;
    --line:     #2c2c32;

    --ink:      #f4f4f5;
    --ink-2:    #b2b2ba;
    --ink-3:    #9a9aa6;
    --on-ink:   #0b0b0c;

    --shadow-rgb: 0, 0, 0;
    --glow:  rgba(255,255,255,.10);
    --sheen: rgba(255,255,255,.16);

    /* Deepened so they don't glare against a dark panel, but still light
       enough that the black line art inside the illustrations reads. */
    --lavender: #9aa0e8;
    --yellow:   #d8d35c;
    --purple:   #a684c6;
    --mint:     #86c8ab;
    --peach:    #e5ab84;

    --fill-orange: #ef7c2c;
    --fill-coral:  #de5a6d;
    --fill-violet: #8d6cc4;
    --fill-teal:   #2f9c7c;

    --shadow:    0 1px 2px rgba(var(--shadow-rgb),.3), 0 10px 30px -14px rgba(var(--shadow-rgb),.6);
    --shadow-lg: 0 2px 6px rgba(var(--shadow-rgb),.35), 0 30px 60px -24px rgba(var(--shadow-rgb),.8);

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --ground:   #0b0b0c;
  --panel:    #161618;
  --chip:     #202024;
  --chip-2:   #2a2a30;
  --line:     #2c2c32;

  --ink:      #f4f4f5;
  --ink-2:    #b2b2ba;
  --ink-3:    #9a9aa6;
  --on-ink:   #0b0b0c;

  --shadow-rgb: 0, 0, 0;
  --glow:  rgba(255,255,255,.10);
  --sheen: rgba(255,255,255,.16);

  --lavender: #9aa0e8;
  --yellow:   #d8d35c;
  --purple:   #a684c6;
  --mint:     #86c8ab;
  --peach:    #e5ab84;

  --fill-orange: #ef7c2c;
  --fill-coral:  #de5a6d;
  --fill-violet: #8d6cc4;
  --fill-teal:   #2f9c7c;

  --shadow:    0 1px 2px rgba(var(--shadow-rgb),.3), 0 10px 30px -14px rgba(var(--shadow-rgb),.6);
  --shadow-lg: 0 2px 6px rgba(var(--shadow-rgb),.35), 0 30px 60px -24px rgba(var(--shadow-rgb),.8);

  color-scheme: dark;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

body {
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  padding: clamp(0px, 2.5vw, 28px);
}

img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }

h1, h2, h3, h4 {
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.035em;
  text-wrap: balance;
}
p { text-wrap: pretty; }

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

.skip-link {
  position: absolute; left: 1rem; top: -100px; z-index: 200;
  background: var(--ink); color: var(--on-ink);
  padding: .7rem 1.1rem; border-radius: var(--r-sm);
  transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: 1rem; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------------------------
   3. PANEL + LAYOUT
   -------------------------------------------------------------------------- */
/* Only the two large surfaces cross-fade on a theme change. Deliberately not
   applied more widely: most components already own their `transition`
   property for transform/shadow, and redeclaring it here would clobber them. */
body, .panel {
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

.panel {
  background: var(--panel);
  border-radius: clamp(var(--r), 2vw, var(--r-xl));
  max-width: var(--wrap);
  margin-inline: auto;
  overflow: clip;
}

.wrap { width: min(100% - clamp(2rem, 6vw, 5.5rem), 1120px); margin-inline: auto; }
.wrap--narrow { width: min(100% - clamp(2rem, 6vw, 5.5rem), 760px); margin-inline: auto; }

.section { padding-block: clamp(var(--sp-5), 7vw, var(--sp-7)); }
.section--tight { padding-block: clamp(var(--sp-5), 5vw, var(--sp-6)); }
.section + .section { border-top: 1px solid var(--line); }

.stack > * + * { margin-top: var(--sp-3); }

/* Small uppercase label */
.label {
  font-size: var(--step--2);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.lede { font-size: var(--step-1); line-height: 1.5; color: var(--ink-2); max-width: var(--measure); }

/* Pill badge, as on the reference cards */
.pill {
  display: inline-flex; align-items: center; gap: .4em;
  background: var(--chip);
  color: var(--ink-2);
  font-size: var(--step--1);
  font-weight: 500;
  padding: .4em 1em;
  border-radius: 999px;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   4. HEADER / NAV
   -------------------------------------------------------------------------- */
.nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3);
  padding-block: clamp(var(--sp-3), 3vw, var(--sp-4));
}

.brand { display: inline-flex; align-items: center; gap: .6rem; }
.brand__mark { width: 26px; height: 26px; flex: none; }
.brand__name {
  font-weight: 700; letter-spacing: -0.03em; font-size: var(--step-0);
}

.nav__links {
  display: flex; align-items: center;
  gap: clamp(var(--sp-3), 2.4vw, var(--sp-5));
  list-style: none; padding: 0;
  font-size: var(--step-0); font-weight: 500;
}
.nav__links a { color: var(--ink-2); transition: color var(--dur) var(--ease); }
.nav__links a:hover, .nav__links a[aria-current="page"] { color: var(--ink); }

.nav__cta {
  display: inline-flex; align-items: center; gap: .5em;
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: 999px;
  padding: .6em 1.2em;
  font-size: var(--step-0); font-weight: 500;
  box-shadow: 0 1px 2px rgba(var(--shadow-rgb),.05);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.nav__cta:hover { background: var(--ink); color: var(--on-ink); border-color: var(--ink); transform: translateY(-1px); }

/* Theme toggle ------------------------------------------------------------ */
.nav__actions { display: flex; align-items: center; gap: var(--sp-2); }

.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 38px; height: 38px;
  flex: none;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink-2);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform var(--dur) var(--ease-spring);
}
.theme-toggle:hover { color: var(--ink); border-color: var(--ink-3); transform: rotate(-18deg) scale(1.06); }
.theme-toggle svg { width: 17px; height: 17px; }

/* Only one of the two icons is shown, depending on the resolved theme. */
.theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun  { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
}
:root[data-theme="dark"] .theme-toggle .icon-sun  { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
/* An explicit choice of light always wins over the system preference. */
:root[data-theme="light"] .theme-toggle .icon-sun  { display: block; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: none; }

/* On narrow screens the links wrap to their own scrollable row rather than
   collapsing into a menu — the list is short enough to stay visible. */
@media (max-width: 760px) {
  .nav { flex-wrap: wrap; row-gap: var(--sp-2); }
  .brand { order: 1; }
  .nav__actions { order: 2; }
  .nav__links {
    order: 3;
    width: 100%;
    gap: var(--sp-3);
    font-size: var(--step--1);
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: 2px;
    margin-inline: calc(-1 * clamp(1rem, 3vw, 2.75rem));
    padding-inline: clamp(1rem, 3vw, 2.75rem);
  }
  .nav__links::-webkit-scrollbar { display: none; }
  .nav__links li { flex: none; }
}

/* --------------------------------------------------------------------------
   5. HERO
   -------------------------------------------------------------------------- */
.hero {
  display: grid;
  gap: clamp(var(--sp-5), 5vw, var(--sp-6));
  padding-block: clamp(var(--sp-4), 4vw, var(--sp-6)) clamp(var(--sp-5), 6vw, var(--sp-7));
  align-items: start;
}
@media (min-width: 940px) {
  .hero { grid-template-columns: minmax(300px, 27rem) 1fr; gap: clamp(var(--sp-5), 4vw, var(--sp-6)); }
}

.hero__title {
  font-size: var(--step-4);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: .98;
}
.hero__copy { margin-top: var(--sp-4); color: var(--ink-2); max-width: 34ch; }

/* Contact form — mirrors the reference's subscribe block */
.signup { margin-top: clamp(var(--sp-4), 4vw, var(--sp-5)); max-width: 25rem; }
.signup__field {
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--ink);
  background: transparent;
  padding: .55rem 0;
  font-size: var(--step-0);
}
.signup__field::placeholder { color: var(--ink-3); }
.signup__field:focus { outline: 0; border-bottom-width: 2px; }
.signup__row { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .55em;
  background: var(--ink); color: var(--on-ink);
  border: 1px solid var(--ink);
  border-radius: 999px;
  padding: .85em 1.8em;
  font-size: var(--step-0); font-weight: 600;
  cursor: pointer;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.btn--grow { flex: 1; }
.btn--ghost { background: var(--chip); color: var(--ink); border-color: transparent; }
.btn--ghost:hover { background: var(--chip-2); }
.btn--icon { padding: .85em; aspect-ratio: 1; flex: none; }
.btn__arrow { transition: transform var(--dur) var(--ease); }
.btn:hover .btn__arrow { transform: translate(2px, -2px); }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* --------------------------------------------------------------------------
   6. CARD RAIL
   -------------------------------------------------------------------------- */
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(255px, 1fr);
  gap: var(--sp-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--sp-3);
  /* let cards bleed to the panel edge on the right, like the reference */
  margin-right: calc(-1 * clamp(1rem, 3vw, 2.75rem));
  padding-right: clamp(1rem, 3vw, 2.75rem);
  scrollbar-width: thin;
  scrollbar-color: var(--chip-2) transparent;
}
.rail::-webkit-scrollbar { height: 6px; }
.rail::-webkit-scrollbar-thumb { background: var(--chip-2); border-radius: 999px; }
.rail > * { scroll-snap-align: start; }

/* --------------------------------------------------------------------------
   7. PROJECT CARD
   -------------------------------------------------------------------------- */
.pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--chip);
  border-radius: var(--r-lg);
  padding: var(--sp-3);
}
/* Hover transform is composed from custom properties in section 12e. */
.pcard:hover { box-shadow: var(--shadow-lg); }

.pcard__top {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-2);
}
.pcard__arrow {
  flex: none;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: var(--ink);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.pcard:hover .pcard__arrow { background: var(--ink); color: var(--on-ink); transform: translate(2px, -2px); }

.pcard__title {
  font-size: var(--step-2);
  margin-top: var(--sp-3);
  letter-spacing: -0.035em;
}
.pcard__desc {
  font-size: var(--step--1);
  line-height: 1.5;
  color: var(--ink-2);
  margin-top: var(--sp-2);
  margin-bottom: var(--sp-3);
}
.pcard__art {
  margin-top: auto;
  border-radius: var(--r);
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  padding: 12%;
  overflow: hidden;
}
.pcard__art svg { width: 100%; height: 100%; overflow: visible; }

/* Pastel variants */
.pcard__art--lavender { background: var(--lavender); }
.pcard__art--yellow   { background: var(--yellow); }
.pcard__art--purple   { background: var(--purple); }
.pcard__art--mint     { background: var(--mint); }
.pcard__art--peach    { background: var(--peach); }

/* Whole-card link target */
.pcard__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }

/* Gentle float on the illustrations */
.bob { animation: bob 6s var(--ease) infinite; transform-origin: center; }
@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3.5%); }
}
@media (prefers-reduced-motion: reduce) { .bob { animation: none; } }

/* --------------------------------------------------------------------------
   8. ABOUT
   -------------------------------------------------------------------------- */
.about {
  display: grid;
  gap: clamp(var(--sp-4), 4vw, var(--sp-6));
}
@media (min-width: 900px) {
  .about { grid-template-columns: 1fr minmax(240px, 20rem); align-items: start; }
}
.about__title { font-size: var(--step-3); margin-block: var(--sp-3) var(--sp-4); }
.about__body { color: var(--ink-2); max-width: var(--measure); }
.about__body p + p { margin-top: var(--sp-3); }

.side-card {
  background: var(--chip);
  border-radius: var(--r-lg);
  padding: var(--sp-4);
}
.skill-group + .skill-group { margin-top: var(--sp-4); }
.skill-group h3 {
  font-size: var(--step--2); font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: var(--sp-2);
}
.skill-list { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.skill-list li {
  background: var(--panel);
  border-radius: 999px;
  padding: .35em .9em;
  font-size: var(--step--1);
  color: var(--ink-2);
}

/* --------------------------------------------------------------------------
   9. WORK GRID (full list, below hero)
   -------------------------------------------------------------------------- */
.section__head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); margin-bottom: var(--sp-4);
}
.section__title { font-size: var(--step-3); margin-top: var(--sp-2); }

.work-grid { display: grid; gap: var(--sp-3); }
@media (min-width: 760px) { .work-grid { grid-template-columns: repeat(2, 1fr); } }

/* Wide card used in the work grid */
.wcard {
  position: relative;
  display: grid;
  gap: var(--sp-4);
  background: var(--chip);
  border-radius: var(--r-lg);
  padding: var(--sp-4);
}
/* Hover transform is composed from custom properties in section 12e. */
.wcard:hover { box-shadow: var(--shadow-lg); }
.wcard__art {
  border-radius: var(--r);
  aspect-ratio: 16 / 10;
  display: grid; place-items: center;
  padding: 6% 12%;
}
.wcard__art svg { width: 100%; height: 100%; overflow: visible; }
.wcard__title { font-size: var(--step-2); margin-block: var(--sp-3) var(--sp-2); }
.wcard__desc { font-size: var(--step--1); color: var(--ink-2); line-height: 1.55; }
.wcard__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }

.tags { display: flex; flex-wrap: wrap; gap: .35rem; list-style: none; padding: 0; margin-top: var(--sp-3); }
.tags li {
  font-size: var(--step--2); font-weight: 500;
  background: var(--panel); color: var(--ink-2);
  padding: .35em .85em; border-radius: 999px;
}

/* --------------------------------------------------------------------------
   9b. ART GALLERY
   -------------------------------------------------------------------------- */
.art-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr));
  gap: var(--sp-3);
  margin-top: var(--sp-5);
}

.art-tile { display: flex; flex-direction: column; gap: var(--sp-2); }
/* A couple of wide tiles break up the grid so it doesn't read as a plain matrix. */
.art-tile--wide { grid-column: span 2; }
@media (max-width: 620px) { .art-tile--wide { grid-column: span 1; } }

.art-tile__frame {
  position: relative;
  border-radius: var(--r-lg);
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  padding: 9%;
  overflow: hidden;
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
.art-tile--wide .art-tile__frame { aspect-ratio: 2 / 1; }
.art-tile__frame svg {
  width: 100%; height: 100%; overflow: visible;
  transition: transform var(--dur-slow) var(--ease-spring);
}
.art-tile:hover .art-tile__frame { transform: translateY(-5px); box-shadow: var(--shadow-lg); }
.art-tile:hover .art-tile__frame svg { transform: scale(1.05) rotate(-1.2deg); }

/* Same light sweep the project cards use, for consistency. */
.art-tile__frame::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--sheen), transparent);
  transform: translateX(-120%) skewX(-18deg);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .art-tile:hover .art-tile__frame::after { animation: sheen 1.1s var(--ease-out); }
}

.art-tile__cap {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-2); padding-inline: .15rem;
}
.art-tile__name { font-weight: 600; font-size: var(--step-0); letter-spacing: -0.02em; }
.art-tile__medium {
  font-size: var(--step--2); font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); white-space: nowrap;
}

/* --------------------------------------------------------------------------
   10. PROJECT PAGE
   -------------------------------------------------------------------------- */
.back-link {
  display: inline-flex; align-items: center; gap: .5em;
  font-size: var(--step--1); font-weight: 500; color: var(--ink-3);
  transition: color var(--dur) var(--ease), gap var(--dur) var(--ease);
}
.back-link:hover { color: var(--ink); gap: .8em; }

.phero { padding-block: var(--sp-4) var(--sp-5); }
.phero__title { font-size: var(--step-4); letter-spacing: -0.045em; margin-block: var(--sp-3) var(--sp-4); max-width: 16ch; }
.phero__meta { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-4); }

.pbanner {
  border-radius: var(--r-lg);
  aspect-ratio: 21 / 9;
  display: grid; place-items: center;
  padding: 3% 8%;
  margin-bottom: clamp(var(--sp-5), 5vw, var(--sp-6));
}
.pbanner svg { width: 100%; height: 100%; overflow: visible; }
@media (max-width: 640px) { .pbanner { aspect-ratio: 4 / 3; } }

.facts { display: grid; gap: var(--sp-4); margin-bottom: clamp(var(--sp-5), 5vw, var(--sp-6)); }
@media (min-width: 720px) { .facts { grid-template-columns: repeat(4, 1fr); } }
.fact dt {
  font-size: var(--step--2); font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: .4rem;
}
.fact dd { margin: 0; font-size: var(--step--1); line-height: 1.5; }

.prose { max-width: var(--measure); }
.prose h2 { font-size: var(--step-2); margin-top: clamp(var(--sp-5), 5vw, var(--sp-6)); margin-bottom: var(--sp-3); }
.prose h3 { font-size: var(--step-1); margin-top: var(--sp-4); margin-bottom: var(--sp-2); letter-spacing: -0.025em; }
.prose p { color: var(--ink-2); }
.prose p + p { margin-top: var(--sp-3); }
.prose ul, .prose ol { color: var(--ink-2); padding-left: 1.2rem; margin-top: var(--sp-3); display: grid; gap: .55rem; }
.prose strong { color: var(--ink); font-weight: 600; }
.prose > .btn-row { margin-top: var(--sp-4); }

.pull {
  font-size: var(--step-3);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1.08;
  margin-block: clamp(var(--sp-5), 5vw, var(--sp-6));
  max-width: 20ch;
}
.pull span { color: var(--ink-3); }

.feature-grid { display: grid; gap: var(--sp-3); margin-top: var(--sp-4); list-style: none; padding: 0; }
@media (min-width: 700px) { .feature-grid { grid-template-columns: repeat(2, 1fr); } }
.feature { background: var(--chip); border-radius: var(--r); padding: var(--sp-4); }
.feature h3 { font-size: var(--step-0); font-weight: 600; letter-spacing: -0.02em; margin-bottom: .35rem; }
.feature p { font-size: var(--step--1); color: var(--ink-2); line-height: 1.55; margin: 0; }

.steps { counter-reset: step; list-style: none; padding: 0; display: grid; gap: var(--sp-2); margin-top: var(--sp-4); }
.steps li {
  counter-increment: step;
  display: grid; grid-template-columns: 2rem 1fr; gap: var(--sp-3);
  align-items: baseline;
  background: var(--chip);
  border-radius: var(--r);
  padding: var(--sp-3);
  font-size: var(--step--1);
  color: var(--ink-2);
}
.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-weight: 700; font-size: var(--step--1); color: var(--ink);
  letter-spacing: -0.02em;
}
.steps b { color: var(--ink); font-weight: 600; }

.next {
  position: relative;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-3);
  margin-top: clamp(var(--sp-5), 6vw, var(--sp-7));
  background: var(--chip);
  border-radius: var(--r-lg);
  padding: clamp(var(--sp-4), 4vw, var(--sp-5));
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.next:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.next__title { font-size: var(--step-2); margin-top: .3rem; }
/* Filled variant of the circular arrow, used on the next-project card. */
.pcard__arrow--solid { background: var(--ink); color: var(--on-ink); }
.next__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }

/* --------------------------------------------------------------------------
   11. CONTACT + FOOTER
   -------------------------------------------------------------------------- */
.contact { text-align: center; }
.contact__title { font-size: var(--step-4); letter-spacing: -0.045em; margin-block: var(--sp-3) var(--sp-4); }
.contact .lede { margin-inline: auto; }
.contact .btn-row { justify-content: center; margin-top: var(--sp-5); }

.site-footer {
  max-width: var(--wrap);
  margin: var(--sp-3) auto 0;
  padding: var(--sp-3) clamp(1rem, 3vw, 2rem);
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  align-items: center; justify-content: space-between;
  font-size: var(--step--1);
  color: var(--ink-3);
}
.site-footer a:hover { color: var(--ink); }
.footer__links { display: flex; gap: var(--sp-3); list-style: none; padding: 0; }

/* ==========================================================================
   12. MOTION
   Everything below is decorative. Two safety rules hold throughout:
   - Hidden start states are gated on `html.js`, so if JavaScript fails to run
     the content is simply visible rather than stranded at opacity 0.
   - Hidden start states are also gated on `prefers-reduced-motion:
     no-preference`, so reduced-motion users get the finished state instantly.
   ========================================================================== */

/* ---- 12a. Keyframes ------------------------------------------------------ */
@keyframes rise      { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }
@keyframes riseLine  { from { transform: translateY(105%) rotate(3deg); } to { transform: none; } }
@keyframes fadeIn    { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop       { 0% { opacity: 0; transform: scale(.92) translateY(18px); }
                       70% { transform: scale(1.015) translateY(0); }
                       100% { opacity: 1; transform: none; } }
@keyframes blink     { 0%, 91%, 100% { transform: scaleY(1); } 94.5% { transform: scaleY(.08); } }
@keyframes drift     { 0%, 100% { transform: translate(0, 0) rotate(0deg); }
                       33%  { transform: translate(2%, -3%) rotate(2deg); }
                       66%  { transform: translate(-2%, 1.5%) rotate(-1.5deg); } }
/* Two identical tracks sit side by side; shifting each by its own width plus
   the gap lands the second exactly where the first began, so the loop is seamless. */
@keyframes marquee   { from { transform: translateX(0); }
                       to   { transform: translateX(calc(-100% - var(--gap, 2rem))); } }
@keyframes sheen     { from { transform: translateX(-120%) skewX(-18deg); } to { transform: translateX(320%) skewX(-18deg); } }
@keyframes pulseRing { 0% { box-shadow: 0 0 0 0 rgba(var(--shadow-rgb),.16); } 70%, 100% { box-shadow: 0 0 0 14px rgba(var(--shadow-rgb),0); } }

/* ---- 12b. Scroll reveal -------------------------------------------------- */
[data-reveal] { transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out); }

@media (prefers-reduced-motion: no-preference) {
  html.js [data-reveal]              { opacity: 0; transform: translateY(22px); }
  html.js [data-reveal="left"]       { transform: translateX(-26px); }
  html.js [data-reveal="right"]      { transform: translateX(26px); }
  html.js [data-reveal="scale"]      { transform: scale(.94); }
  html.js [data-reveal].is-visible   { opacity: 1; transform: none; }
  /* Children of a staggered group come in one after another. */
  html.js [data-stagger] > *         { opacity: 0; transform: translateY(20px);
                                       transition: opacity var(--dur-slow) var(--ease-out),
                                                   transform var(--dur-slow) var(--ease-out);
                                       transition-delay: calc(var(--i, 0) * var(--stagger)); }
  html.js [data-stagger].is-visible > * { opacity: 1; transform: none; }
}

/* ---- 12c. On-load entrance ---------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  html.js [data-load] {
    animation: rise var(--dur-slow) var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * var(--stagger));
  }
  html.js [data-load="pop"] { animation-name: pop; }

  /* Headline lines wipe up from behind a clipping mask. */
  html.js .line { display: block; overflow: hidden; padding-bottom: .06em; margin-bottom: -.06em; }
  html.js .line > span {
    display: block;
    animation: riseLine .95s var(--ease-out) backwards;
    animation-delay: calc(.06s + var(--i, 0) * 110ms);
  }
}

/* ---- 12d. Illustration idle life ---------------------------------------- */
/* Eyes blink on a long, offset cycle so the three cards never sync up. */
.eye { transform-box: fill-box; transform-origin: center; }
@media (prefers-reduced-motion: no-preference) {
  .eye { animation: blink 6.5s var(--ease) infinite; }
  .pcard:nth-child(2) .eye { animation-duration: 7.9s; animation-delay: -2s; }
  .pcard:nth-child(3) .eye { animation-duration: 5.8s; animation-delay: -4s; }

  /* Loose background shapes drift independently of the main character. */
  .drift { transform-box: fill-box; transform-origin: center; animation: drift 11s var(--ease) infinite; }
  .drift--slow { animation-duration: 16s; animation-delay: -5s; }
}

/* ---- 12e. Card interaction ---------------------------------------------- */
/* Transform is composed from custom properties so the CSS hover lift and the
   JS pointer-tilt can coexist without overwriting each other. */
.rail, .work-grid { perspective: 1200px; }

.pcard, .wcard {
  transform:
    translateY(var(--lift, 0))
    scale(var(--scale, 1))
    rotateX(var(--rx, 0deg))
    rotateY(var(--ry, 0deg));
  transform-style: preserve-3d;
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
  will-change: transform;
}
.pcard:hover, .pcard:focus-within { --lift: -6px; }
.wcard:hover, .wcard:focus-within { --lift: -5px; }

/* Cursor spotlight */
.pcard::before, .wcard::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
  background: radial-gradient(
    22rem circle at var(--mx, 50%) var(--my, 50%),
    var(--glow),
    transparent 60%
  );
  /* Negative z-index keeps the glow above the card's own background but
     behind its text, so nothing ever washes out. */
  z-index: -1;
}
.pcard:hover::before, .wcard:hover::before { opacity: 1; }

/* The pastel block breathes and the character leans in */
.pcard__art, .wcard__art { transition: transform var(--dur-slow) var(--ease-out); overflow: hidden; }
.pcard__art svg, .wcard__art svg { transition: transform var(--dur-slow) var(--ease-spring); }
.pcard:hover .pcard__art svg,
.wcard:hover .wcard__art svg { transform: scale(1.07) rotate(-1.5deg); }

/* Light sweeping across the pastel block on hover */
.pcard__art::after, .wcard__art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, var(--sheen), transparent);
  transform: translateX(-120%) skewX(-18deg);
  pointer-events: none;
}
.pcard__art, .wcard__art { position: relative; }
@media (prefers-reduced-motion: no-preference) {
  .pcard:hover .pcard__art::after,
  .wcard:hover .wcard__art::after { animation: sheen 1.1s var(--ease-out); }
}

/* Title nudges, arrow spins into place */
.pcard__title, .wcard__title { transition: transform var(--dur) var(--ease-out); }
.pcard:hover .pcard__title { transform: translateX(3px); }
.pcard__arrow svg { transition: transform var(--dur) var(--ease-spring); }
.pcard:hover .pcard__arrow svg, .next:hover .pcard__arrow svg { transform: rotate(45deg); }

/* Tags cascade up on hover */
.tags li { transition: transform var(--dur) var(--ease-spring), background var(--dur) var(--ease); }
.wcard:hover .tags li { transform: translateY(-3px); }
.wcard:hover .tags li:nth-child(2) { transition-delay: 40ms; }
.wcard:hover .tags li:nth-child(3) { transition-delay: 80ms; }
.wcard:hover .tags li:nth-child(4) { transition-delay: 120ms; }

/* ---- 12f. Small interactions -------------------------------------------- */
.brand__mark { transition: transform var(--dur-slow) var(--ease-spring); }
.brand:hover .brand__mark { transform: rotate(-12deg) scale(1.08); }

.btn:active, .nav__cta:active { transform: translateY(0) scale(.97); transition-duration: var(--dur-fast); }

/* Ripple-ish focus ring for keyboard users on the primary action */
@media (prefers-reduced-motion: no-preference) {
  .btn:focus-visible { animation: pulseRing 1.4s var(--ease) infinite; }
}

.pill { transition: background var(--dur) var(--ease), transform var(--dur) var(--ease-spring); }
.pcard:hover .pill { background: var(--chip-2); transform: translateY(-2px); }

.skill-list li { transition: transform var(--dur) var(--ease-spring), background var(--dur) var(--ease); }
.skill-list li:hover { transform: translateY(-3px) rotate(-2deg); background: var(--panel); }

.feature { transition: transform var(--dur) var(--ease-out), background var(--dur) var(--ease); }
.feature:hover { transform: translateY(-4px); }

.steps li { transition: transform var(--dur) var(--ease-out), background var(--dur) var(--ease); }
.steps li:hover { transform: translateX(6px); }

.fact { transition: transform var(--dur) var(--ease-out); }
.fact:hover { transform: translateY(-3px); }

.signup__field { transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease); }

.back-link svg, .back-link { transition: color var(--dur) var(--ease), gap var(--dur) var(--ease); }

.footer__links a, .nav__links a { transition: color var(--dur) var(--ease); }

/* ---- 12g. Scroll progress bar ------------------------------------------- */
.progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 3px;
  z-index: 100;
  pointer-events: none;
  background: transparent;
}
.progress span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--ink);
  transform: scaleX(var(--p, 0));
  transform-origin: 0 50%;
  transition: transform .1s linear;
}

/* ---- 12h. Sticky header ------------------------------------------------- */
/* The bar spans the panel's full width — its background and bottom rule run edge
   to edge of the card — while the nav inside lines up with the page content. */
.site-head {
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: 1px solid transparent;
  /* The header changes its own height when it collapses. Without this, scroll
     anchoring compensates for that shift by moving scrollY, which can flip the
     collapse state back and forth. The JS uses hysteresis for the same reason —
     belt and braces, since anchoring behaviour varies between browsers. */
  overflow-anchor: none;
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  transition: box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.site-head[data-scrolled="true"] {
  border-bottom-color: var(--line);
  box-shadow: 0 8px 24px -18px rgba(var(--shadow-rgb),.5);
}

/* Same measure as .wrap, so the brand and actions sit on the same vertical lines
   as the hero, the work grid, and everything else down the page. */
.site-head .nav {
  width: min(100% - clamp(2rem, 6vw, 5.5rem), 1120px);
  margin-inline: auto;
  transition: padding-block var(--dur) var(--ease-out);
}
.site-head[data-scrolled="true"] .nav { padding-block: var(--sp-2); }

/* On mobile the nav wraps to two rows, which is too much screen to pin. Once
   scrolled, the links row collapses away and only the brand and the contact
   CTA stay stuck. `visibility` (not just opacity) keeps the hidden links out
   of the tab order; scrolling back to the top restores them. */
@media (max-width: 760px) {
  .site-head .nav__links {
    max-height: 3rem;
    opacity: 1;
    visibility: visible;
    transition: max-height var(--dur) var(--ease-out),
                opacity var(--dur-fast) var(--ease),
                visibility 0s linear 0s;
  }
  /* The wrapped row's gap would otherwise still reserve space once the
     links collapse to zero height. */
  .site-head[data-scrolled="true"] .nav { row-gap: 0; }
  .site-head[data-scrolled="true"] .nav__links {
    max-height: 0;
    opacity: 0;
    visibility: hidden;
    overflow: hidden;
    transition: max-height var(--dur) var(--ease-out),
                opacity var(--dur-fast) var(--ease),
                visibility 0s linear var(--dur);
  }
}

/* ---- 12i. Marquee band --------------------------------------------------- */
.marquee {
  --gap: var(--sp-4);
  display: flex;
  overflow: hidden;
  user-select: none;
  gap: var(--gap);
  border-block: 1px solid var(--line);
  padding-block: var(--sp-3);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex;
  gap: var(--gap);
  flex: none;
  min-width: 100%;
  align-items: center;
  font-size: var(--step-2);
  font-weight: 700;
  letter-spacing: -0.03em;
  white-space: nowrap;
}
.marquee__track span { display: inline-flex; align-items: center; gap: var(--gap); }
.marquee__track em { font-style: normal; color: var(--ink-3); }
@media (prefers-reduced-motion: no-preference) {
  .marquee__track { animation: marquee 34s linear infinite; }
  .marquee:hover .marquee__track { animation-play-state: paused; }
}
@media (prefers-reduced-motion: reduce) {
  /* No scroll: show one static copy and hide the duplicate. */
  .marquee { overflow-x: auto; }
  .marquee__track[aria-hidden="true"] { display: none; }
}

/* ---- 12j. Cross-page view transitions ----------------------------------- */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) { animation: fadeIn .25s var(--ease) reverse; }
  ::view-transition-new(root) { animation: fadeIn .35s var(--ease); }
}

/* ---- 12k. Global reduced-motion backstop -------------------------------- */
@media (prefers-reduced-motion: reduce) {
  [data-reveal], [data-stagger] > *, [data-load], .line > span { opacity: 1 !important; transform: none !important; }
}
