/* ==========================================================================
   Font Face Declarations
   ========================================================================== */

@font-face {
  font-family: "Monument Grotesk";
  src: url("../fonts/MonumentGrotesk-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Subset to what tags and the tooltip use: letters, digits, space and
   - . / : [ ] – (OFL, see fonts/GeistMono-OFL.txt). Re-subset from v1.7.2 if
   other characters are needed. */
@font-face {
  font-family: "Geist Mono";
  src: url("../fonts/GeistMono-Regular-subset.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0020, U+002D-002F, U+0030-003A, U+0041-005B, U+005D, U+0061-007A, U+2013;
}

/* ==========================================================================
   Design Tokens
   ========================================================================== */

:root {
  /* Color Primitives */
  --color-white: #FFFFFF;
  --color-black: #000000;
  --color-gray-950: #080C04;
  --color-gray-900: #151812;
  --color-gray-800: #20241A;
  --color-gray-700: #3E403A;
  --color-gray-600: #646660;
  --color-gray-500: #8E908A;
  --color-gray-400: #AEB0AA;
  --color-gray-300: #CED0CA;
  --color-gray-200: #E8EAE5;
  --color-gray-100: #F2F4EF;
  --color-gray-50: #F8FAF5;
  --color-irwin: #D22D04;
  --color-ruud: #FD3E21;

  /* Color Semantic - Light Theme (default in :root) */
  --color-background: var(--color-gray-50);
  --color-background-subtle: var(--color-gray-200);
  --color-background-hover: var(--color-gray-100);
  --color-background-hover-rgb: 242, 244, 239;
  --color-body: var(--color-gray-800);
  --color-body-subtle: var(--color-gray-600);
  --color-border: var(--color-gray-200);
  --color-border-hover: var(--color-gray-300);
  --color-underline: var(--color-gray-400);
  --color-accent: var(--color-irwin);
  --color-shadow: rgba(0, 0, 0, 0.04);

  /* Fonts */
  --font-family-sans: "Monument Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-family-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Typography */
  --type-body-font-family: var(--font-family-sans);
  --type-body-font-size: 16px;
  --type-body-sm-font-size: 12px;
  --type-body-line-height: 20px;
  --type-body-sm-line-height: 16px;
  --type-body-font-weight: 400;
  --type-body-letter-spacing: 0;
  --type-display-letter-spacing: -0.01em;
  --type-heading-font-family: var(--font-family-sans);
  --type-heading-xl-font-size: 52px;
  --type-heading-lg-font-size: 44px;
  --type-heading-md-font-size: 28px;
  --type-heading-sm-font-size: 19px;
  --type-heading-xs-font-size: 16px;
  --type-heading-xl-line-height: 56px;
  --type-heading-lg-line-height: 48px;
  --type-heading-md-line-height: 32px;
  --type-heading-sm-line-height: 24px;
  --type-heading-xs-line-height: 20px;
  --type-heading-font-weight: 400;
  --type-tag-font-size: 11px;

  /* Breakpoints */
  --breakpoint-sm: 375px;
  --breakpoint-md: 768px;
  --breakpoint-lg: 1024px;
  --breakpoint-xl: 1360px;
  --breakpoint-max: 1600px;

  /* Grid */
  --grid-margin: 16px;
  --grid-gap: 16px;
  --grid-row: 16px;
  --grid-readable-width: 480px;
  --grid-content-width: 1600px;

  /* Spacing */
  --space-4: 4px;
  --space-8: 8px;
  --space-12: 12px;
  --space-16: 16px;
  --space-20: 20px;
  --space-24: 24px;
  --space-32: 32px;
  --space-40: 40px;
  --space-48: 48px;
  --space-56: 56px;
  --space-64: 64px;
  --space-72: 72px;
  --space-96: 96px;
  --space-144: 144px;
  --space-192: 192px;
  --space-320: 320px;
  --space-section-sm: var(--space-96);
  --space-section-lg: var(--space-144);

  /* Layout */
  --nav-height: 48px;

  /* Border Radius */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 16px;
  --radius-lg: 48px;

  /* Easing */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

/* Color Semantic - Dark theme */
body.theme-dark {
  --color-background: var(--color-gray-950);
  --color-background-subtle: var(--color-gray-900);
  --color-background-hover: var(--color-gray-900);
  --color-background-hover-rgb: 21, 24, 18;
  --color-body: var(--color-gray-100);
  --color-body-subtle: var(--color-gray-500);
  --color-border: var(--color-gray-800);
  --color-border-hover: var(--color-gray-700);
  --color-underline: var(--color-gray-700);
  --color-accent: var(--color-ruud);
  --color-shadow: rgba(255, 255, 255, 0.04);
}

/* ==========================================================================
   Base Styles
   ========================================================================== */

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

*:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* Stops iOS enlarging text when the phone is turned to landscape */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  font-family: var(--type-body-font-family);
  font-size: var(--type-body-font-size);
  line-height: var(--type-body-line-height);
  font-weight: var(--type-body-font-weight);
  color: var(--color-body);
  background-color: var(--color-background);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--color-underline);
  text-decoration-thickness: .075em;
  text-underline-offset: 2px;
  transition: color 150ms ease, text-decoration-color 150ms ease;
  -webkit-tap-highlight-color: transparent;
}

@media (hover: hover) and (pointer: fine) {
  a:hover {
    color: var(--color-accent);
    text-decoration-color: oklch(from var(--color-accent) l c h / 0.45);
  }
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-weight: var(--type-heading-font-weight);
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

::selection {
  background-color: var(--color-background-subtle);
  color: var(--color-body);
}

/* ==========================================================================
   Utility Classes
   ========================================================================== */

.text-strikethrough {
  text-decoration: line-through;
}

.text-nowrap {
  white-space: nowrap;
}

.text-body {
  font-family: var(--type-body-font-family);
  font-size: var(--type-body-font-size);
  line-height: var(--type-body-line-height);
  font-weight: var(--type-body-font-weight);
  color: var(--color-body);  
}
   
.text-subtle {
  color: var(--color-body-subtle);  
}

.text-tag {
  align-self: flex-start;
  color: var(--color-body);
  font-family: var(--font-family-mono);
  font-size: var(--type-tag-font-size);
  line-height: var(--type-body-sm-line-height);
  font-feature-settings: "lnum", "ordn";
  text-transform: uppercase;
  white-space: nowrap;
}

.text-tag::before,
.text-tag::after {
  color: var(--color-body-subtle);
}

.text-tag::before {
  content: "[" / "";
}

.text-tag::after {
  content: "]" / "";
}

/* Links out of the site keep their text and arrow on one line */
a:has(.icon-external) {
  white-space: nowrap;
}

/* A CSS mask rather than an <img>, so the arrow's colour comes from a token */
.icon-external {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: middle;
  position: relative;
  top: -0.05em;
  opacity: 0.6;
  background-color: var(--color-body-subtle);
  -webkit-mask: url("../images/arrow-up-right.svg") center / contain no-repeat;
  mask: url("../images/arrow-up-right.svg") center / contain no-repeat;
  -webkit-user-select: none;
  user-select: none;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ==========================================================================
   Preloader
   ========================================================================== */

.preloader {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: var(--color-background);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  opacity: 1;
  transition: opacity 260ms var(--ease-out);
}

.preloader video {
  width: 256px;
  height: auto;
}

.preloader.fade-out {
  opacity: 0;
  pointer-events: none;
}

body.loading main,
body.loading .footer {
  opacity: 0;
}

body.loaded main,
body.loaded .footer {
  opacity: 1;
  transition-property: opacity;
  transition-duration: 260ms;
  transition-timing-function: var(--ease-out);
}

body.loaded main {
  transition-delay: 50ms;
}

body.loaded .footer {
  transition-delay: 100ms;
}

/* The rise is scoped to the hero because it is the only content guaranteed to
   be in view on load. Applying it to all of main shifts the whole document by
   12px when a refresh restores a mid-page scroll position. The projects join it
   from 768px, where the split puts them in view alongside the hero. */
body.loading .hero {
  transform: translateY(12px);
}

body.loaded .hero {
  transform: translateY(0);
  transition: transform 400ms var(--ease-out) 50ms;
}

/* ==========================================================================
   Navigation
   ========================================================================== */

.navigation {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--grid-gap);
  height: var(--nav-height);
  padding: var(--space-16) var(--grid-margin) var(--space-12);
  margin-inline: calc(var(--grid-margin) * -1);
}

.nav-name {
  flex: 1;
  min-width: 0;
  font-size: var(--type-body-font-size);
  font-weight: var(--type-body-font-weight);
  text-transform: uppercase;
  white-space: nowrap;
}

.nav-name:last-child {
  display: grid;
  justify-items: end;
}

.nav-name a {
  display: inline-grid;
  text-decoration: none;
  transition: opacity 150ms ease;
}

.nav-name-short,
.nav-name-full {
  grid-area: 1 / 1;
  transition: opacity 150ms ease, filter 150ms ease;
}

.nav-name:last-child .nav-name-short,
.nav-name:last-child .nav-name-full {
  transition-delay: 40ms;
}

.nav-name-full {
  opacity: 0;
  filter: blur(2px);
}

.nav-name a:active {
  opacity: 0.6;
}

.navigation:has(a:focus-visible) .nav-name-short {
  opacity: 0;
  transition: none;
}

.navigation:has(a:focus-visible) .nav-name-full {
  opacity: 1;
  filter: none;
  transition: none;
}

@media (hover: hover) and (pointer: fine) {
  .nav-name a:hover {
    color: inherit;
  }

  .navigation:has(a:hover) .nav-name-short {
    opacity: 0;
    filter: blur(2px);
  }

  .navigation:has(a:hover) .nav-name-full {
    opacity: 1;
    filter: none;
  }
}

.nav-symbol {
  position: relative;
  flex-shrink: 0;
  width: 12px;
  height: 12px;
  fill: var(--color-accent);
  -webkit-user-select: none;
  user-select: none;
}

.nav-symbol svg {
  display: block;
  width: 100%;
  height: 100%;
  transition: scale 100ms var(--ease-out);
}

.nav-symbol:has(.symbol-step:active) svg {
  scale: 0.9;
}

.nav-symbol:has(.verse-state:focus-visible) {
  outline: 2px solid var(--color-accent);
  outline-offset: 4px;
}

@keyframes nav-symbol-fade {
  to {
    opacity: 0;
    visibility: hidden;
  }
}

.symbol-step {
  position: absolute;
  inset: calc(var(--space-8) * -1);
  z-index: 1;
  cursor: pointer;
  pointer-events: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.nav-symbol:not(:has(.verse-state:checked)) .symbol-step:nth-of-type(1),
.nav-symbol:has(.verse-4:checked) .symbol-step:nth-of-type(1),
.nav-symbol:has(.verse-1:checked) .symbol-step:nth-of-type(2),
.nav-symbol:has(.verse-2:checked) .symbol-step:nth-of-type(3),
.nav-symbol:has(.verse-3:checked) .symbol-step:nth-of-type(4) {
  pointer-events: auto;
}

.verse-states {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@property --pulse-depth {
  syntax: "<number>";
  inherits: false;
  initial-value: 1;
}

.nav-symbol path {
  animation: nav-symbol-think 1200ms ease-in-out -300ms infinite paused;
  transition: --pulse-depth 300ms var(--ease-out);
}

.nav-symbol path:nth-child(2) {
  animation-delay: 0ms;
}

.nav-symbol path:nth-child(3) {
  animation-delay: 300ms;
}

.nav-symbol path:nth-child(4) {
  animation-delay: 600ms;
}

.nav-symbol:has(.verse-state:checked) path {
  --pulse-depth: 0.5;
  animation-iteration-count: 2;
  animation-play-state: running;
}

.nav-symbol:has(.verse-1:checked, .verse-3:checked) path {
  animation-name: nav-symbol-think-alt;
}

@keyframes nav-symbol-think {
  0%,
  100% {
    fill: var(--color-accent);
  }

  50% {
    fill: oklch(from var(--color-accent) calc(l * var(--pulse-depth)) calc(c * var(--pulse-depth)) h);
  }
}

@keyframes nav-symbol-think-alt {
  0%,
  100% {
    fill: var(--color-accent);
  }

  50% {
    fill: oklch(from var(--color-accent) calc(l * var(--pulse-depth)) calc(c * var(--pulse-depth)) h);
  }
}

@media (hover: hover) and (pointer: fine) {
  .navigation .nav-symbol:hover path {
    --pulse-depth: 0.5;
    animation-iteration-count: infinite;
    animation-play-state: running;
  }
}

.tooltip {
  position: absolute;
  top: calc(100% + var(--space-12));
  left: 50%;
  display: none;
  justify-items: center;
  align-content: center;
  height: 32px;
  padding: var(--space-8) var(--space-12);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-background-subtle);
  color: var(--color-body);
  font-family: var(--font-family-mono);
  font-size: var(--type-tag-font-size);
  line-height: var(--type-body-sm-line-height);
  white-space: nowrap;
  translate: -50% 0;
  pointer-events: none;
  transition: opacity 150ms var(--ease-out), transform 150ms var(--ease-out);
}

.nav-symbol:has(.verse-1:checked, .verse-3:checked) .tooltip {
  display: grid;
  animation: tooltip-life 3000ms forwards;
}

.nav-symbol:has(.verse-2:checked, .verse-4:checked) .tooltip {
  display: grid;
  animation: tooltip-life-alt 3000ms forwards;
}

@starting-style {
  .nav-symbol:has(.verse-state:checked) .tooltip {
    opacity: 0;
    transform: translateY(-4px);
  }
}

@keyframes tooltip-life {
  0%,
  93% {
    filter: none;
  }

  100% {
    filter: opacity(0) blur(2px);
    display: none;
    visibility: hidden;
  }
}

@keyframes tooltip-life-alt {
  0%,
  93% {
    filter: none;
  }

  100% {
    filter: opacity(0) blur(2px);
    display: none;
    visibility: hidden;
  }
}

.verse {
  grid-area: 1 / 1;
  opacity: 0;
  filter: blur(2px);
  visibility: hidden;
  transition: opacity 150ms ease, filter 150ms ease, visibility 0s 150ms;
}

.nav-symbol:has(.verse-1:checked) .verse:nth-child(1),
.nav-symbol:has(.verse-2:checked) .verse:nth-child(2),
.nav-symbol:has(.verse-3:checked) .verse:nth-child(3),
.nav-symbol:has(.verse-4:checked) .verse:nth-child(4) {
  opacity: 1;
  filter: none;
  visibility: inherit;
  transition-delay: 0s;
}

/* Post pages and the 404: a single link back to the homepage */
.navigation-post {
  height: var(--nav-height);
  margin-inline: calc(var(--grid-margin) * -1);
}

.navigation-post-link {
  display: inline-flex;
  padding: var(--space-16) var(--grid-margin);
  text-decoration: none;
}

@media (hover: hover) and (pointer: fine) {
  .navigation-post-link:hover .text-tag {
    color: var(--color-accent);
  }
}

/* ==========================================================================
   Split Layout
   ========================================================================== */

.split {
  --split-height: 100vh;
  padding-inline: var(--grid-margin);
}

@supports (height: 100svh) {
  .split {
    --split-height: 100svh;
  }
}

/* ==========================================================================
   Hero Section
   ========================================================================== */

.hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: calc(var(--split-height) - var(--nav-height));
  padding: var(--space-16) 0;
}

.hero-title > * + * {
  margin-top: var(--space-16);
}

.hero-contact {
  margin-top: var(--space-32);
}

.hero-contact a {
  color: var(--color-body);
  text-underline-position: from-font;
}

@media (hover: hover) and (pointer: fine) {
  .hero-contact a:hover {
    color: var(--color-accent);
    text-decoration-color: oklch(from var(--color-accent) l c h / 0.45);
  }
}

/* ==========================================================================
   On Repeat
   ========================================================================== */

.on-repeat {
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
  padding: 0 var(--grid-margin) var(--space-48);
  font-size: var(--type-body-sm-font-size);
  line-height: var(--type-body-sm-line-height);
}

.on-repeat-title {
  color: var(--color-body-subtle);
  font-size: inherit;
  font-weight: var(--type-body-font-weight);
}

.tracks {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  list-style: none;
}

.track {
  display: grid;
  grid-template-columns: 32px auto;
  justify-content: start;
  grid-template-rows: auto auto;
  column-gap: var(--space-8);
}

/* Cover and title share one link (one tab stop per track); the artist sits
   outside it on the second row */
.track-link {
  position: relative;
  grid-column: 1 / -1;
  grid-row: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}

/* Hit area spans half the gap either side, so neighbouring rows meet */
.track-link::before {
  content: "";
  position: absolute;
  inset: calc(var(--space-12) / -2) 0;
}

.track picture {
  display: contents;
}

.track source {
  display: none;
}

.track-cover {
  grid-column: 1;
  grid-row: 1 / 3;
  width: 32px;
  height: 32px;
  object-fit: cover;
  border-radius: var(--radius-xs);
  background-color: var(--color-background-subtle);
}

.track-title,
.track-artist {
  grid-column: 2;
}

.track-title {
  grid-row: 1;
}

.track-artist {
  grid-row: 2;
}

/* Blurred copy of the cover, added by main.js */
.track-glow {
  grid-column: 1;
  grid-row: 1 / 3;
  z-index: -1;
  width: 32px;
  height: 32px;
  object-fit: cover;
  border-radius: var(--radius-xs);
  filter: blur(10px) saturate(1.6);
  opacity: 0;
  transform: scale(0.8);
  will-change: transform;
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .track-link {
    isolation: isolate;
  }

  .track-link:hover {
    text-decoration-color: var(--color-underline);
  }

  .track-glow {
    transition: opacity 150ms var(--ease-out), transform 150ms var(--ease-out);
  }

  .track-link:hover .track-glow,
  .track-link:focus-visible .track-glow {
    opacity: 0.72;
    transform: scale(1.25);
    transition-duration: 200ms;
  }
}

@media (prefers-reduced-motion: reduce) {
  .track-glow {
    transform: scale(1.25);
  }
}

.track-title {
  color: var(--color-body);
}

.track-artist {
  color: var(--color-body-subtle);
  pointer-events: none;
}

/* ==========================================================================
   Projects Section
   ========================================================================== */

.projects {
  display: flex;
  flex-direction: column;
  gap: var(--space-32);
  padding: var(--space-64) 0 var(--space-96);
}

.project {
  padding-top: var(--space-16);
  border-top: 1px solid var(--color-border);
}

.project-header {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.project-description {
  margin-bottom: var(--space-24);
}

.project-images {
  display: flex;
  flex-direction: column;
  gap: var(--grid-row);
}

.project-media {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-24);
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border-radius: var(--radius-xs);
  background-color: var(--color-background-subtle);
}

.project-media picture {
  display: contents;
}

.project-media source {
  display: none;
}

.project-image {
  height: auto;
}

.project-image--wide {
  width: 80%;
}

.project-image--tall {
  width: 60%;
}

.project-image--phone {
  width: 25%;
}

/* The load-in fade is a WAAPI animation fired on the image's load event (see
   main.js). Nothing is pre-hidden in CSS on purpose - opacity would take the
   placeholder background down with it, leaving a hole for the whole fetch. */

/* ==========================================================================
   About Section
   ========================================================================== */

.about {
  padding: 0 var(--grid-margin) var(--space-section-sm);
}

.section-two-up {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-16);
  padding-top: var(--space-16);
  border-top: 1px solid var(--color-border);
}

.section-two-up-body {
  grid-column: auto;
}

.section-two-up-body p {
  margin-bottom: var(--space-16);
}

.section-two-up-body p:last-child {
  margin-bottom: 0;
}

.claude-logo {
  vertical-align: -0.15em;
}

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-16);
  padding: 0 var(--grid-margin) var(--space-16);
}

.footer-contact {
  display: none;
  font-size: var(--type-body-font-size);
  color: var(--color-body);
}

.footer-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
}

.footer-links {
  display: flex;
  order: -1;
  gap: var(--space-8);
}

.footer-links a:not(:last-child)::after {
  content: "," / "";
  position: absolute;
  left: 100%;
  pointer-events: none;
  color: var(--color-body);
}

.footer-links a {
  position: relative;
  font-size: var(--type-body-font-size);
  text-decoration-line: none;
}

.footer-links a:active {
  color: inherit;
  text-decoration-line: underline;
}

@media (hover: hover) and (pointer: fine) {
  .footer-links a:hover {
    color: var(--color-accent);
    text-decoration-line: underline;
    text-decoration-color: oklch(from var(--color-accent) l c h / 0.45);
  }
}

.footer-year {
  color: var(--color-body-subtle);
  font-size: var(--type-body-font-size);
}

/* ==========================================================================
   Not Found (404.html)
   ========================================================================== */

.page-404 {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

.not-found {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding-inline: var(--grid-margin);
}

.not-found-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
  margin-block: auto;
  padding-block: var(--space-16);
}

.not-found-text {
  max-width: 512px;
  padding-bottom: var(--space-16);
}

.not-found-title {
  margin-bottom: var(--space-8);
}

.not-found-link {
  margin-top: var(--space-16);
}

.not-found-figure {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.not-found-image {
  width: 100%;
  height: auto;
  aspect-ratio: 459 / 288;
  object-fit: cover;
}

.not-found-caption {
  font-size: var(--type-tag-font-size);
  line-height: var(--type-body-sm-line-height);
  color: var(--color-body-subtle);
}

/* ==========================================================================
   Responsive - Tablet (--breakpoint-md, 768px and up)
   ========================================================================== */

@media (min-width: 768px) {
  .preloader video {
    width: 320px;
  }

  /* Hero and nav stay pinned while the projects scroll; both release together
     when the projects end. The nav's track stops one hero-height short of the
     split's bottom, which is the same moment the hero's sticky range runs out. */
  /* The bio starts on the halfway line, rising (to 96px at most) when the rest
     of the hero wouldn't fit below it. --hero-rest is the rest of the hero at
     its tallest for the width - bio, gap, link and bottom padding. The
     projects start 16px higher so the first title lines up with the bio. */
  .split {
    --hero-rest: 363px;
    --split-top: clamp(var(--space-96), calc(var(--split-height) - var(--hero-rest)), calc(var(--split-height) / 2));
    position: relative;
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--grid-gap);
    align-items: start;
  }

  .nav-track {
    position: absolute;
    top: 0;
    right: 0;
    bottom: calc(var(--split-height) - var(--nav-height));
    left: 0;
    z-index: 10;
    padding-inline: var(--grid-margin);
    pointer-events: none;
  }

  .navigation {
    pointer-events: auto;
  }

  .hero {
    grid-column: 1 / 7;
    display: grid;
    grid-template-columns: subgrid;
    grid-template-rows: auto 1fr;
    row-gap: var(--space-32);
    min-height: 0;
    padding: var(--split-top) 0 var(--space-16);
  }

  .hero-title {
    grid-column: 1 / -1;
  }

  /* Bottom of the hero row, so on a window too short to pin it simply
     follows the bio */
  .hero-contact {
    grid-column: 1 / -1;
    align-self: end;
    margin-top: 0;
  }

  .projects {
    grid-column: 7 / 13;
    display: grid;
    grid-template-columns: subgrid;
    gap: var(--space-32) normal;
    padding-top: calc(var(--split-top) - var(--space-16));
  }

  .project {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
  }

  .project:first-child {
    border-top: 0;
  }

  .project-header,
  .project-description,
  .project-images {
    grid-column: 1 / -1;
  }

  body.loading .projects {
    transform: translateY(12px);
  }

  body.loaded .projects {
    transform: translateY(0);
    transition: transform 400ms var(--ease-out) 50ms;
  }

  .section-two-up {
    grid-template-columns: repeat(12, 1fr);
  }

  .section-two-up-title {
    grid-column: 1 / 7;
    margin-bottom: 0;
  }

  .section-two-up-body {
    grid-column: span 6;
  }

  /* On Repeat lines up with the About body column */
  .on-repeat {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: var(--space-16) var(--grid-gap);
  }

  .on-repeat > * {
    grid-column: 7 / 13;
  }

  .footer {
    grid-template-columns: 1fr 1fr;
  }

  .footer-contact {
    display: block;
  }

  .footer-content {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
  }

  .footer-links {
    order: 0;
  }

  .not-found-body {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    align-items: start;
    gap: var(--grid-gap);
  }

  .not-found-text {
    grid-column: 1 / 7;
  }

  .not-found-figure {
    grid-column: 7 / 13;
  }
}

/* ==========================================================================
   Split pinning (--breakpoint-md and at least 600px tall)
   The hero needs up to 456px of height at its tallest (768px wide).
   Shorter windows, such as phones in landscape, keep the split layout but
   scroll normally so the end of the bio is never cut off. Raise the
   threshold if the bio gets longer.
   ========================================================================== */

@media (min-width: 768px) and (min-height: 600px) {
  /* Release the pin early enough that the contact link lands level with the
     last project image: the projects end 96px below that image, the hero only
     16px below the link. The nav's track ends by the same amount so the two
     still leave together. */
  .split {
    --split-release: calc(var(--space-96) - var(--space-16));
  }

  .nav-track {
    bottom: calc(var(--split-height) - var(--nav-height) + var(--split-release));
  }

  .navigation {
    position: sticky;
    top: 0;
  }

  @supports (animation-timeline: scroll()) {
    .nav-symbol {
      animation: nav-symbol-fade linear both;
      animation-timeline: scroll(root);
      animation-range: calc((var(--split-top) - var(--space-16) - var(--nav-height)) / 2) calc(var(--split-top) - var(--space-16) - var(--nav-height));
    }
  }

  .hero {
    position: sticky;
    top: 0;
    height: var(--split-height);
    margin-bottom: var(--split-release);
  }
}

/* ==========================================================================
   Responsive - Desktop (--breakpoint-lg, 1024px and up)
   ========================================================================== */

@media (min-width: 1024px) {
  .split {
    --hero-rest: 323px;
  }

  .hero-title,
  .project-description {
    grid-column: 1 / 6;
  }

  .projects {
    row-gap: var(--space-64);
  }

  .project-header {
    justify-content: space-between;
  }

  .project-media {
    gap: var(--space-32);
  }

  .on-repeat {
    padding-bottom: var(--space-64);
  }

  .section-two-up-body {
    grid-column: 7 / 12;
  }

  .not-found-text {
    grid-column: 1 / 6;
  }

  .not-found-figure {
    grid-column: 7 / 12;
  }
}

/* ==========================================================================
   Responsive - Large Desktop (--breakpoint-xl, 1360px and up)
   ========================================================================== */

@media (min-width: 1360px) {
  .hero-title,
  .project-description {
    grid-column: 1 / 5;
  }

  .section-two-up-body {
    grid-column: span 4;
  }

  .not-found-text {
    grid-column: 1 / 5;
  }

  .not-found-figure {
    grid-column: 7 / 11;
  }
}

/* ==========================================================================
   Reduced Motion
   Keep opacity and colour changes; drop movement and scaling.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  @starting-style {
    .nav-symbol:has(.verse-state:checked) .tooltip {
      transform: none;
    }
  }

  body.loaded main,
  body.loaded .footer {
    transition: none;
  }

  body.loading .hero,
  body.loaded .hero,
  body.loading .projects,
  body.loaded .projects {
    transform: none;
    transition: none;
  }

  .preloader video {
    display: none;
  }
}
