/* =========================================================
   Michael Smith — portfolio
   Idea: summit to sea. The page is one descent — the hero
   is the mountain top, the trail runs down through the
   projects and experience, and contact is out on the water.
   A </> flag marks the summit; an altitude gauge tracks it.
   ========================================================= */

/* the landscape colours are registered as real colours so they can fade between
   day and night while the sun sets and the moon rises (browsers without @property just switch) */
@property --sky-top    { syntax: "<color>"; inherits: true; initial-value: #cfe6ee; }
@property --sky-bottom { syntax: "<color>"; inherits: true; initial-value: #eef4f5; }
@property --ridge-far  { syntax: "<color>"; inherits: true; initial-value: #a7c3c6; }
@property --ridge-near { syntax: "<color>"; inherits: true; initial-value: #4f7a72; }
@property --water      { syntax: "<color>"; inherits: true; initial-value: #1ea5d6; }
@property --water-2    { syntax: "<color>"; inherits: true; initial-value: #238bb1; }

:root {
  /* palette: light (morning) */
  --sky-top:    #cfe6ee;
  --sky-bottom: #eef4f5;
  --sun:        #ffb547;
  --moon:       #f1e6c4;
  --moon-shade: #d8cba6;  /* craters */
  --ridge-far:  #a7c3c6;
  --ridge-near: #4f7a72;
  --water:      #1ea5d6;
  --water-2:    #238bb1;
  --hull:       #ff5a1f;

  --bg:      #eef4f5;
  --shore:   #dfece9;
  --surface: #f8fbfb;
  --ink:     #10303a;
  --muted:   #4d6770;
  --line:    #cadadc;
  --line-2:  #8fb0b3;

  --accent:     #ff5a1f;  /* lifejacket orange */
  --ridge-acent: #ff2f00; /*for dotted line*/
  --accent-hi:  #ff7440;
  --accent-ink: #0a2029;  /* text on orange: 5.4:1 */
  --accent-text:#c2410c;  /* orange that passes contrast as text on light */
  --accent-deep:#c2410c;  /* darker orange inside the figures (backpack, cockpit) */

  /* open water: deeper is darker, and dark enough for light text to pass AA */
  --deep:       #0b5e7c;  /* contact: 6.2:1 with --deep-ink */
  --deep-2:     #08475e;  /* footer */
  --deep-ink:   #e2f0f2;
  --deep-muted: #c9e3e8;  /* 5.4:1 on --deep */
  --deep-error: #ffd0c9;  /* 5.2:1 on --deep */
  --deep-ok:    #b8f0d8;
  --track:      #3e4d53;  /* go-kart track tarmac */

  --font: "Archivo", "Helvetica Neue", Arial, system-ui, sans-serif;

  --step--1: clamp(0.84rem, 0.8rem + 0.1vw, 0.9rem);
  --step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.1rem);
  --step-1:  clamp(1.2rem, 1.1rem + 0.5vw, 1.45rem);
  --step-2:  clamp(1.5rem, 1.3rem + 1vw, 2rem);
  --step-3:  clamp(2.1rem, 1.6rem + 2.2vw, 3.4rem);

  --gutter: clamp(1.25rem, 4vw, 3rem);
  --max: 72rem;
  --topbar-h: 4rem;

  color-scheme: light;
  transition: --sky-top 1.6s ease, --sky-bottom 1.6s ease, --ridge-far 1.6s ease,
              --ridge-near 1.6s ease, --water 1.6s ease, --water-2 1.6s ease;
}

/* dark: night hike, night swim (keep both blocks identical) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --sky-top: #081620; --sky-bottom: #0e1d25;
    --ridge-far: #1d3a44; --ridge-near: #143039; --water: #0f5260; --water-2: #0a3e4a;
    --bg: #0e1d25; --shore: #0c2129; --surface: #13262f; --ink: #e2edf0; --muted: #9ab3ba;
    --line: #24404a; --line-2: #3d6069; --accent-text: #ff9a6c;
    --deep: #0f5260; --deep-2: #0a3e4a; --track: #1c2b32;
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --sky-top: #081620; --sky-bottom: #0e1d25;
  --ridge-far: #1d3a44; --ridge-near: #143039; --water: #0f5260; --water-2: #0a3e4a;
  --bg: #0e1d25; --shore: #0c2129; --surface: #13262f; --ink: #e2edf0; --muted: #9ab3ba;
  --line: #24404a; --line-2: #3d6069; --accent-text: #ff9a6c;
  --deep: #0f5260; --deep-2: #0a3e4a; --track: #1c2b32;
  color-scheme: dark;
}

/* ---------- living sky: time of day, season and weather ----------
   The <head> script and script.js set data-phase (dawn, day, dusk, night), data-season and
   data-weather on <html> from Fareham's real clock, calendar and live weather. These blocks
   only change colours; the colour-vision palettes further down come later and still win. */

/* dawn and dusk: warm skies (light theme only; night is the dark theme).
   Grey text is darkened a touch so it still passes contrast on the warmer sky. */
:root[data-phase="dawn"] { --sky-top: #f7d3c4; --sky-bottom: #fdeedf; --sun: #ff9f5a; --muted: #3b525b; }
:root[data-phase="dusk"] { --sky-top: #eec4cf; --sky-bottom: #fbe3cc; --sun: #ff7a45; --muted: #3b525b; }

/* seasons: the mountains change colour, and winter puts snow on the far peaks */
:root[data-season="spring"] { --ridge-far: #b3cfc3; --ridge-near: #58876a; }
:root[data-season="autumn"] { --ridge-far: #c9b8a2; --ridge-near: #8a5d3b; }
:root[data-season="winter"] { --ridge-far: #c4d1d8; --ridge-near: #5d6f78; }

/* weather: grey skies for cloud, fog, rain, snow and storms */
:root:is([data-weather="cloudy"], [data-weather="fog"]) { --sky-top: #c3d0d4; --sky-bottom: #e6ecee; --muted: #2f444b; }
:root:is([data-weather="rain"], [data-weather="snow"], [data-weather="sleet"])  { --sky-top: #aebdc3; --sky-bottom: #dbe3e6; --muted: #2f444b; }
:root[data-weather="storm"]                               { --sky-top: #a3b1b7; --sky-bottom: #cdd5d8; --muted: #2f444b; }

/* the same, at night */
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"]))[data-season="spring"] { --ridge-far: #1f3d3a; --ridge-near: #163a31; }
  :root:where(:not([data-theme="light"]))[data-season="autumn"] { --ridge-far: #3a3029; --ridge-near: #2c231b; }
  :root:where(:not([data-theme="light"]))[data-season="winter"] { --ridge-far: #253844; --ridge-near: #192b34; }
  :root:where(:not([data-theme="light"])):is([data-weather="cloudy"], [data-weather="fog"]) { --sky-top: #101c23; --sky-bottom: #16242c; --muted: #9ab3ba; }
  :root:where(:not([data-theme="light"])):is([data-weather="rain"], [data-weather="snow"], [data-weather="sleet"]) { --sky-top: #0d171d; --sky-bottom: #141f26; --muted: #9ab3ba; }
  :root:where(:not([data-theme="light"]))[data-weather="storm"] { --sky-top: #0a1116; --sky-bottom: #10191e; --muted: #9ab3ba; }
}
:root:where([data-theme="dark"])[data-season="spring"] { --ridge-far: #1f3d3a; --ridge-near: #163a31; }
:root:where([data-theme="dark"])[data-season="autumn"] { --ridge-far: #3a3029; --ridge-near: #2c231b; }
:root:where([data-theme="dark"])[data-season="winter"] { --ridge-far: #253844; --ridge-near: #192b34; }
:root:where([data-theme="dark"]):is([data-weather="cloudy"], [data-weather="fog"]) { --sky-top: #101c23; --sky-bottom: #16242c; --muted: #9ab3ba; }
:root:where([data-theme="dark"]):is([data-weather="rain"], [data-weather="snow"], [data-weather="sleet"]) { --sky-top: #0d171d; --sky-bottom: #141f26; --muted: #9ab3ba; }
:root:where([data-theme="dark"])[data-weather="storm"] { --sky-top: #0a1116; --sky-bottom: #10191e; --muted: #9ab3ba; }

/* ---------- accessibility preferences: colour ----------
   Set from the accessibility panel as data attributes on <html>.
   Each colour-vision mode is a full palette built from colours that type can tell apart.
   The -anomaly (milder) types share a palette with their full versions.
   Order matters: light palettes, then their dark versions, then high contrast last.
   The dark versions use :where() so every block here has the same specificity
   and the later one wins. */

/* red-green (protanopia, protanomaly, deuteranopia, deuteranomaly):
   they see blue against yellow clearly, but red, orange and green blur into olive.
   Accent becomes amber, the mountains blue-grey, and error/success yellow/blue. */
:root[data-cvd^="rg-"] {
  --accent: #e69f00; --accent-hi: #f5b733; --accent-ink: #0a2029;
  --accent-text: #8a5a00; --accent-deep: #a36f00; --ridge-acent: #e69f00;
  --sun: #ffd166;
  --ridge-far: #b3c3d6; --ridge-near: #56708f;
  --deep-error: #ffe08a; --deep-ok: #cfe4ff;
}

/* blue-yellow (tritanopia, tritanomaly):
   they see red against green clearly, but blue and green merge, as do yellow and pink.
   Accent becomes coral red and the mountains neutral grey, so nothing sits next to the sea in a similar hue. */
:root[data-cvd^="by-"] {
  --accent: #ff5c7a; --accent-hi: #ff7d95; --accent-ink: #0a2029;
  --accent-text: #b3123f; --accent-deep: #c21f4a; --ridge-acent: #ff5c7a;
  --sun: #fff1f3;
  --ridge-far: #c8c3c6; --ridge-near: #5a5358;
}

/* little or no colour (achromatopsia, blue cone monochromacy):
   the whole site becomes greyscale and everything is told apart by lightness.
   Photos and figures are greyed further down (see "colour vision: imagery"). */
:root[data-cvd^="mono-"] {
  --sky-top: #d4d4d4; --sky-bottom: #f2f2f2; --sun: #ffffff; --moon: #e6e6e6; --moon-shade: #bdbdbd;
  --ridge-far: #a6a6a6; --ridge-near: #555555; --water: #7a7a7a; --water-2: #5c5c5c;
  --bg: #f2f2f2; --shore: #e6e6e6; --surface: #fafafa; --ink: #111111; --muted: #4a4a4a;
  --line: #c4c4c4; --line-2: #8a8a8a;
  --accent: var(--ink); --accent-hi: #333333; --accent-ink: var(--bg);
  --accent-text: var(--ink); --accent-deep: #333333; --ridge-acent: var(--ink);
  --deep: #2b2b2b; --deep-2: #1c1c1c; --deep-ink: #f2f2f2; --deep-muted: #cfcfcf;
  --deep-error: #ffffff; --deep-ok: #e0e0e0; --track: #444444;
}

/* dark versions of the three palettes */
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"]))[data-cvd^="rg-"] {
    --accent-text: #ffc94d; --ridge-far: #1f3350; --ridge-near: #16263d;
  }
  :root:where(:not([data-theme="light"]))[data-cvd^="by-"] {
    --accent-text: #ff8fa6; --ridge-far: #2e2a2d; --ridge-near: #211d20;
  }
  :root:where(:not([data-theme="light"]))[data-cvd^="mono-"] {
    --sky-top: #0d0d0d; --sky-bottom: #161616;
    --ridge-far: #333333; --ridge-near: #262626; --water: #4d4d4d; --water-2: #3a3a3a;
    --bg: #161616; --shore: #121212; --surface: #1f1f1f; --ink: #ededed; --muted: #b3b3b3;
    --line: #3a3a3a; --line-2: #666666; --accent-hi: #ffffff;
    --deep: #2e2e2e; --deep-2: #1f1f1f;
  }
}
:root:where([data-theme="dark"])[data-cvd^="rg-"] {
  --accent-text: #ffc94d; --ridge-far: #1f3350; --ridge-near: #16263d;
}
:root:where([data-theme="dark"])[data-cvd^="by-"] {
  --accent-text: #ff8fa6; --ridge-far: #2e2a2d; --ridge-near: #211d20;
}
:root:where([data-theme="dark"])[data-cvd^="mono-"] {
  --sky-top: #0d0d0d; --sky-bottom: #161616;
  --ridge-far: #333333; --ridge-near: #262626; --water: #4d4d4d; --water-2: #3a3a3a;
  --bg: #161616; --shore: #121212; --surface: #1f1f1f; --ink: #ededed; --muted: #b3b3b3;
  --line: #3a3a3a; --line-2: #666666; --accent-hi: #ffffff;
  --deep: #2e2e2e; --deep-2: #1f1f1f;
}

/* high contrast (last, so it also applies on top of any colour-vision palette):
   muted text becomes full-strength, lines get much darker */
:root[data-contrast="high"] {
  --muted: var(--ink);
  --line: color-mix(in srgb, var(--ink) 55%, var(--bg));
  --line-2: color-mix(in srgb, var(--ink) 75%, var(--bg));
  --deep-muted: var(--deep-ink);
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth; scroll-padding-top: calc(var(--topbar-h) + 1rem); -webkit-text-size-adjust: 100%;
  /* keep room for the scrollbar even while a project is open (which locks scrolling),
     so the page doesn't shift sideways when the viewer opens and closes */
  scrollbar-gutter: stable;
}
body {
  margin: 0;
  /* the page gets more "coastal" the further down you go */
  background: linear-gradient(180deg, var(--bg) 0%, var(--bg) 45%, var(--shore) 100%);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--step-0);
  font-variation-settings: "wdth" 100;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
h1, h2, h3 { line-height: 1.05; margin: 0; letter-spacing: -0.015em; }
p { margin: 0 0 1em; }
a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
a:hover { text-decoration-thickness: 2px; }
button { font: inherit; color: inherit; }
svg { width: 1em; height: 1em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* the darker text-orange keeps the focus ring above 3:1 against the page in both themes */
:focus-visible { outline: 3px solid var(--accent-text); outline-offset: 3px; border-radius: 4px; }

.skip-link {
  position: absolute; left: 1rem; top: -4rem; z-index: 100;
  background: var(--accent); color: var(--accent-ink); padding: .6rem 1rem; border-radius: 6px; font-weight: 600;
}
.skip-link:focus { top: 1rem; }

/* hidden visually but still read by screen readers */
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- top bar ---------- */
.topbar {
  position: sticky; top: 0; z-index: 50;
  height: var(--topbar-h);
  display: flex; align-items: center; gap: 1.5rem;
  padding: 0 var(--gutter);
  background: color-mix(in srgb, var(--sky-top) 80%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color .2s, background-color .2s;
}
.topbar.scrolled { background: color-mix(in srgb, var(--bg) 85%, transparent); border-bottom-color: var(--line); }

.brand {
  display: flex; align-items: center; gap: .6rem; margin-right: auto;
  text-decoration: none; font-weight: 700; font-size: 1.05rem;
  font-variation-settings: "wdth" 112;
}
.brand-mark {
  width: 1.2rem; height: 1rem; background: var(--accent);
  clip-path: polygon(0 100%, 42% 12%, 62% 50%, 74% 32%, 100% 100%);
}

.nav { display: flex; gap: .25rem; }
.nav a {
  position: relative; text-decoration: none; font-weight: 500; font-size: .95rem;
  padding: .45rem .75rem; border-radius: 6px; color: var(--muted);
}
.nav a:hover, .nav a.active { color: var(--ink); }
.nav a.active::after {
  content: ""; position: absolute; left: .75rem; right: .75rem; bottom: .15rem;
  height: 3px; background: var(--accent); border-radius: 2px;
}

.topbar-tools { display: flex; align-items: center; gap: .5rem; }

.theme-toggle, .a11y-toggle, .palette-toggle {
  display: grid; place-items: center; width: 2.4rem; height: 2.4rem;
  border: 1px solid var(--line-2); border-radius: 50%; background: transparent; cursor: pointer; font-size: 1.05rem;
}
.theme-toggle:hover, .a11y-toggle:hover, .palette-toggle:hover, .a11y-toggle[aria-expanded="true"] { border-color: var(--ink); }
.i-sun { display: none; }
:root[data-theme="dark"] .i-sun { display: block; }
:root[data-theme="dark"] .i-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .i-sun { display: block; }
  :root:not([data-theme="light"]) .i-moon { display: none; }
}

/* ---------- accessibility panel ---------- */
.a11y { position: relative; }
.a11y-panel {
  position: absolute; top: calc(100% + .75rem); right: 0; z-index: 5;
  width: min(23rem, calc(100vw - 2rem));
  max-height: calc(100vh - var(--topbar-h) - 2rem); overflow-y: auto;
  padding: 1rem 1.25rem 1.25rem;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 12px 32px rgb(6 28 36 / .22);
}
.a11y-panel[hidden] { display: none; }
.a11y-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: .5rem; }
.a11y-head h2 { font-size: var(--step-1); font-weight: 800; font-variation-settings: "wdth" 112; }
.a11y-reset {
  border: 0; background: none; padding: .25rem 0; cursor: pointer;
  color: var(--accent-text); font-weight: 600; text-decoration: underline; text-underline-offset: .2em;
}
.a11y-list { list-style: none; margin: 0; padding: 0; }

.switch {
  display: grid; grid-template-columns: 1fr auto; gap: .15rem 1rem; align-items: center;
  padding: .75rem 0; border-top: 1px solid var(--line);
}
.switch label { font-weight: 600; cursor: pointer; }
.switch-hint { grid-column: 1; margin: 0; font-size: var(--step--1); line-height: 1.4; color: var(--muted); }
.switch input { grid-column: 2; grid-row: 1 / span 2; }

/* the slider: knob position shows the state, not just colour */
input[role="switch"] {
  appearance: none; -webkit-appearance: none; position: relative; flex: none;
  width: 2.75rem; height: 1.6rem; margin: 0; cursor: pointer;
  background: var(--surface); border: 2px solid var(--muted); border-radius: 999px;
  transition: background-color .15s, border-color .15s;
}
input[role="switch"]::before {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 1.1rem; height: 1.1rem; border-radius: 50%;
  background: var(--muted);
  transition: transform .15s, background-color .15s;
}
input[role="switch"]:checked { background: var(--accent); border-color: var(--accent); }
input[role="switch"]:checked::before { transform: translateX(1.15rem); background: var(--accent-ink); }
input[role="switch"]:focus-visible { outline-offset: 2px; border-radius: 999px; }

.a11y-field { display: grid; gap: .4rem; padding-top: .75rem; border-top: 1px solid var(--line); }
.a11y-field label { font-weight: 600; }
.a11y-field select {
  font: inherit; font-size: .95rem; color: var(--ink); width: 100%;
  background: var(--surface); border: 1.5px solid var(--muted); border-radius: 8px; padding: .6rem .75rem;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .8rem 1.3rem; border-radius: 999px;
  font-weight: 600; font-size: .98rem; text-decoration: none; cursor: pointer;
  border: 1.5px solid var(--ink); background: transparent; color: var(--ink);
  transition: transform .15s, background-color .15s, color .15s;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: var(--accent-hi); border-color: var(--accent-hi); }
.btn-ghost { background: color-mix(in srgb, var(--surface) 55%, transparent); }
.btn-ghost:hover { background: var(--ink); color: var(--bg); }
.btn svg { font-size: .95em; }
.btn[disabled] { opacity: .6; cursor: progress; transform: none; }

/* ---------- hero: the summit ---------- */
.hero {
  position: relative; overflow: hidden;
  min-height: max(100svh, 62vw);
  margin-top: calc(-1 * var(--topbar-h));
  padding: calc(var(--topbar-h) + clamp(2rem, 7vh, 5rem)) var(--gutter) 0;
  background: linear-gradient(180deg, var(--sky-top) 0%, var(--sky-bottom) 70%);
  display: flex; flex-direction: column;
}
.hero-inner { position: relative; z-index: 1; width: 100%; max-width: calc(var(--max) - 2 * var(--gutter)); margin: 0 auto; }
.hero-hello { font-size: var(--step-1); color: var(--muted); margin: 0 0 .4rem; }
.hero-name {
  font-size: clamp(3.1rem, 10.5vw, 8.4rem);
  font-weight: 850;
  font-variation-settings: "wdth" 125;
  line-height: .88;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  margin: 0 0 1.75rem;
}
.hero-name span { display: block; }
.hero-lede { font-size: var(--step-1); max-width: 34ch; line-height: 1.45; margin-bottom: 1.75rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .75rem; }

/* landscape sits behind the text on wide screens */
.landscape {
  position: absolute; left: 0; right: 0; bottom: 0;
  /* never taller than the drawing's own proportions, so the peaks don't get cropped */
  width: 100%; height: min(70%, 45.8vw);
  pointer-events: none;
}
.landscape :not(.me, .me *) { stroke: none; }
.landscape.party { overflow: visible; }  /* easter egg confetti can fly above the drawing */
.landscape .me { stroke: none; }
.landscape .trail-reveal { stroke: #fff; }
.landscape .sun { fill: var(--sun); }
.landscape .moon-disc { fill: var(--moon); }
.landscape .moon-crater { fill: var(--moon-shade); }

/* day and night: whichever is up sits behind the peak, the other waits out of sight
   below the ridge. On a theme switch the one in the sky sets first, then the other rises. */
.landscape .sun,
.landscape .moon { transition: transform 1.1s cubic-bezier(.5,0,.3,1); }
.landscape .sun  { transform: none; transition-delay: .9s; }            /* rising: wait for the moon to set */
.landscape .moon { transform: translateY(170px); transition-delay: 0s; } /* setting: go straight away */
:root[data-theme="dark"] .landscape .sun  { transform: translateY(170px); transition-delay: 0s; }
:root[data-theme="dark"] .landscape .moon { transform: none; transition-delay: .9s; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .landscape .sun  { transform: translateY(170px); transition-delay: 0s; }
  :root:not([data-theme="light"]) .landscape .moon { transform: none; transition-delay: .9s; }
}
.landscape .ridge-far { fill: var(--ridge-far); }
.landscape .ridge-near { fill: var(--ridge-near); }
.landscape .trail {
  fill: none; stroke: var(--accent); stroke-width: 3.5;
  stroke-dasharray: 2 11; stroke-linecap: round;
}
/* no-colour mode: a white trail stands out from the ridges by lightness alone */
:root[data-cvd^="mono-"] .landscape .trail { stroke: #fff; }
.landscape .flag-pole { stroke: var(--ink); stroke-width: 3; }
:root[data-theme="dark"] .landscape .flag-pole { stroke: var(--deep-ink); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .landscape .flag-pole { stroke: var(--deep-ink); } }
.landscape .flag-cloth { fill: var(--accent); stroke: none; }
.landscape .flag-text { fill: var(--accent-ink); font: 700 13px var(--font); stroke: none; }
.landscape .wave-back { fill: var(--water); stroke: none; }
.landscape .wave-front { fill: var(--water-2); stroke: none; }

/* living sky in the drawing: low sun at dawn and dusk, stars at night, clouds, fog and winter snow */
:root:is([data-phase="dawn"], [data-phase="dusk"]) .landscape .sun { transform: translateY(38px); }
:root:is([data-weather="cloudy"], [data-weather="rain"], [data-weather="snow"], [data-weather="sleet"], [data-weather="storm"], [data-weather="fog"]) .landscape :is(.sun, .moon) { opacity: .45; }
/* add a fade to the sun and moon's existing rise-and-set movement (longhands, so the set-then-rise delays stay) */
.landscape .sun, .landscape .moon { transition-property: transform, opacity; transition-duration: 1.1s, 1.6s; }

.landscape .star { fill: #fff; }
.landscape .stars { opacity: 0; transition: opacity 1.6s; }
:root[data-theme="dark"] .landscape .stars { opacity: .9; }
:root[data-theme="dark"]:is([data-weather="cloudy"], [data-weather="rain"], [data-weather="snow"], [data-weather="sleet"], [data-weather="storm"], [data-weather="fog"]) .landscape .stars { opacity: .12; }

.landscape .cloud { fill: #ffffff; transition: fill 1.6s; }
:root:is([data-weather="rain"], [data-weather="sleet"], [data-weather="storm"]) .landscape .cloud { fill: #c5d0d5; }
:root[data-theme="dark"] .landscape .cloud { fill: #2b3c45; }
:root[data-theme="dark"]:is([data-weather="rain"], [data-weather="sleet"], [data-weather="storm"]) .landscape .cloud { fill: #1c2a31; }
.landscape .clouds { opacity: 0; transition: opacity 1.6s; }
:root:is([data-weather="rain"], [data-weather="snow"], [data-weather="sleet"], [data-weather="storm"]) .landscape .clouds { opacity: .92; }
:root[data-weather="cloudy"][data-cloud="low"] .landscape .clouds { opacity: .3; }
:root[data-weather="cloudy"][data-cloud="medium"] .landscape .clouds { opacity: .65; }
:root[data-weather="cloudy"][data-cloud="high"] .landscape .clouds { opacity: .95; }
:root[data-weather="clear"][data-cloud="medium"] .landscape .clouds { opacity: .3; }
:root[data-weather="fog"] .landscape .clouds { opacity: .5; }

.landscape .snowcap { fill: #ffffff; opacity: 0; transition: opacity 1.6s; }
:root[data-theme="dark"] .landscape .snowcap { fill: #c9d6de; }
:root[data-season="winter"] .landscape .snowcap { opacity: .95; }

.landscape .mist { fill: url(#mistFade); opacity: 0; transition: opacity 1.6s; }
.landscape .mist-stop { stop-color: #ffffff; }
:root[data-theme="dark"] .landscape .mist-stop { stop-color: #9fb3bd; }
:root[data-weather="fog"] .landscape .mist { opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
  .landscape .clouds { animation: clouds-drift 90s ease-in-out infinite alternate; }
  .landscape .star:nth-child(3n) { animation: twinkle 3.2s ease-in-out infinite alternate; }
  .landscape .star:nth-child(4n) { animation: twinkle 4.6s ease-in-out infinite alternate-reverse; }
}
@keyframes clouds-drift { to { transform: translateX(90px); } }
@keyframes twinkle { to { opacity: .35; } }

/* rain and snow fall in front of the mountains but behind the hero text */
.sky-fx { position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: 0; transition: opacity 1.6s; }
:root:is([data-weather="rain"], [data-weather="storm"]) .sky-fx {
  opacity: 1;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90' height='90'%3E%3Cg stroke='%2346697a' stroke-opacity='.45' stroke-width='1.3' stroke-linecap='round'%3E%3Cpath d='M12 6l-3 13M48 30l-3 13M78 4l-3 13M30 58l-3 13M66 66l-3 13'/%3E%3C/g%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='130' height='130'%3E%3Cg stroke='%2346697a' stroke-opacity='.3' stroke-width='1' stroke-linecap='round'%3E%3Cpath d='M20 10l-2 9M90 40l-2 9M55 80l-2 9M115 100l-2 9'/%3E%3C/g%3E%3C/svg%3E");
}
:root[data-theme="dark"]:is([data-weather="rain"], [data-weather="storm"]) .sky-fx {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90' height='90'%3E%3Cg stroke='%23ffffff' stroke-opacity='.3' stroke-width='1.3' stroke-linecap='round'%3E%3Cpath d='M12 6l-3 13M48 30l-3 13M78 4l-3 13M30 58l-3 13M66 66l-3 13'/%3E%3C/g%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='130' height='130'%3E%3Cg stroke='%23ffffff' stroke-opacity='.2' stroke-width='1' stroke-linecap='round'%3E%3Cpath d='M20 10l-2 9M90 40l-2 9M55 80l-2 9M115 100l-2 9'/%3E%3C/g%3E%3C/svg%3E");
}
:root[data-weather="snow"] .sky-fx {
  opacity: 1;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cg fill='%23ffffff'%3E%3Ccircle cx='15' cy='20' r='2'/%3E%3Ccircle cx='70' cy='8' r='1.6'/%3E%3Ccircle cx='100' cy='60' r='2.2'/%3E%3Ccircle cx='40' cy='85' r='1.7'/%3E%3C/g%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='170'%3E%3Cg fill='%23ffffff' fill-opacity='.7'%3E%3Ccircle cx='30' cy='40' r='1.3'/%3E%3Ccircle cx='120' cy='100' r='1.1'/%3E%3Ccircle cx='80' cy='150' r='1.4'/%3E%3C/g%3E%3C/svg%3E");
}
:root[data-weather="sleet"] .sky-fx {
  opacity: 1;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90' height='90'%3E%3Cg stroke='%2346697a' stroke-opacity='.5' stroke-width='1.3'%3E%3Cpath d='M12 6l-3 13M48 30l-3 13M78 4l-3 13M30 58l-3 13M66 66l-3 13'/%3E%3C/g%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cg fill='%23ffffff'%3E%3Ccircle cx='15' cy='20' r='2'/%3E%3Ccircle cx='70' cy='8' r='1.6'/%3E%3Ccircle cx='100' cy='60' r='2.2'/%3E%3Ccircle cx='40' cy='85' r='1.7'/%3E%3C/g%3E%3C/svg%3E");
}
:root[data-weather-intensity="light"] .sky-fx { opacity: .55; }
:root[data-weather="storm"] .sky-fx::after {
  content: ""; position: absolute; inset: 0;
  background: #f3faff; opacity: 0; pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  :root:is([data-weather="rain"], [data-weather="storm"]) .sky-fx { animation: rain-fall .9s linear infinite; }
  :root[data-weather="storm"] .sky-fx { animation-duration: .6s; }
  :root[data-weather="snow"] .sky-fx { animation: snow-fall 14s linear infinite; }
  :root[data-weather="sleet"] .sky-fx { animation: sleet-fall 2s linear infinite; }
  :root[data-weather="storm"] .sky-fx::after { animation: lightning-flash 11s linear infinite; }
}
@keyframes rain-fall { to { background-position: -90px 360px, -130px 520px; } }
@keyframes snow-fall { to { background-position: 120px 480px, -170px 680px; } }
@keyframes sleet-fall { to { background-position: -90px 360px, 120px 360px; } }
@keyframes lightning-flash { 0%, 87%, 89%, 90%, 92%, 100% { opacity: 0; } 88%, 91% { opacity: .36; } }
/* high contrast: no falling weather over the hero */
:root[data-contrast="high"] .sky-fx { display: none; }

/* the live reading under the hero buttons */
.sky-status {
  display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .75rem;
  margin: 1.25rem 0 0; font-size: var(--step--1); color: var(--muted);
}
.sky-status[hidden] { display: none; }
.sky-status::before {
  content: ""; width: .5rem; height: .5rem; border-radius: 50%; flex: none;
  background: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent);
}
.sky-auto {
  border: 0; background: none; padding: .35rem 0; cursor: pointer;
  font: inherit; font-weight: 600; color: var(--ink); text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: .2em;
}
.sky-auto[hidden] { display: none; }

/* ---------- now playing on Spotify ----------
   The summit flag becomes clickable once the server says Spotify is connected. */
.landscape .flag-hit { fill: transparent; }
.landscape .flag.is-live { pointer-events: auto; cursor: pointer; }
.landscape .flag.is-live:hover .flag-cloth { filter: brightness(1.12); }
.landscape .np-note { fill: var(--ink); font: 700 22px var(--font); opacity: 0; transition: opacity .6s; }
:root[data-theme="dark"] .landscape .np-note { fill: var(--deep-ink); }
.landscape .flag.is-playing .np-note { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .landscape .flag.is-playing .np-note { animation: note-float 2.4s ease-in-out infinite; }
  .np-card:not([hidden]) { animation: pop .22s cubic-bezier(.2,.8,.2,1); }
  .np-card.is-playing .np-eq i { animation: eq .8s ease-in-out infinite alternate; }
  .np-card.is-playing .np-eq i:nth-child(2) { animation-delay: -.3s; }
  .np-card.is-playing .np-eq i:nth-child(3) { animation-delay: -.55s; }
}
@keyframes note-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes eq { from { height: 25%; } to { height: 100%; } }

.np-card {
  position: absolute; z-index: 3; top: 6rem; right: var(--gutter);
  width: min(19rem, calc(100% - 2rem)); padding: 1rem 1.1rem 1.1rem;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 18px 44px rgb(6 28 36 / .25);
}
.np-card[hidden] { display: none; }
.np-card:focus { outline: none; }
.np-card:focus-visible { outline: 3px solid var(--accent-text); outline-offset: 3px; }
.np-close {
  position: absolute; top: .45rem; right: .45rem; width: 2.25rem; height: 2.25rem;
  display: grid; place-items: center; border: 0; border-radius: 50%;
  background: none; color: var(--muted); cursor: pointer; font-size: 1rem;
}
.np-close:hover { background: var(--bg); color: var(--ink); }
.np-label { display: flex; align-items: center; gap: .55rem; margin: 0 2.25rem .85rem 0; font-size: var(--step--1); font-weight: 600; color: var(--muted); }
.np-eq { display: inline-flex; align-items: flex-end; gap: 2px; height: 12px; }
.np-eq i { width: 3px; height: 45%; border-radius: 1px; background: var(--accent); }
.np-body { display: grid; grid-template-columns: 72px 1fr; gap: .85rem; align-items: center; }
.np-body[hidden] { display: none; }
.np-cover { width: 72px; height: 72px; border-radius: 8px; object-fit: cover; background: var(--line); }
.np-title { margin: 0; font-weight: 700; line-height: 1.25; }
.np-artist { margin: .2rem 0 0; font-size: var(--step--1); color: var(--muted); line-height: 1.35; }
.np-link { display: inline-block; margin-top: .85rem; font-weight: 600; color: var(--accent-text); }
.np-link[hidden] { display: none; }

/* the one orchestrated moment: name rises, flag goes up, and I walk up the trail
   from the sea (the dotted trail appearing behind my boots), then wave by the flag.
   The walk and trail are driven by script.js; after that only the sea keeps moving. */
@media (prefers-reduced-motion: no-preference) {
  .js .hero-name span { animation: rise .8s cubic-bezier(.2,.8,.2,1) both; }
  .js .hero-name span + span { animation-delay: .08s; }

  .js .landscape .flag { animation: fade .4s .3s both; }
  .js .landscape .flag-cloth,
  .js .landscape .flag-text { transform-box: fill-box; transform-origin: left center; animation: raise .5s .35s cubic-bezier(.2,.8,.2,1) both; }

  .landscape .wave-back  { animation: drift 22s linear infinite; }
  .landscape .wave-front { animation: drift 14s linear infinite reverse; }
  .landscape .kayak-bob  { transform-box: fill-box; transform-origin: center; animation: bob 4.5s ease-in-out infinite; }
  .landscape .me-kayak .paddle { transform-box: fill-box; transform-origin: center; animation: stroke 2.4s ease-in-out infinite alternate; }
}
@keyframes rise  { from { opacity: 0; transform: translateY(.25em); } }
@keyframes fade  { from { opacity: 0; } }
@keyframes raise { from { transform: scaleX(0); } }
@keyframes drift { to { transform: translateX(-720px); } }
@keyframes bob {
  0%, 100% { transform: translateY(0) rotate(-2deg); }
  50%      { transform: translateY(4px) rotate(2deg); }
}

/* hero hiker: hidden until script.js places him at the bottom of the trail,
   so he never flashes at the summit first. Without JavaScript there's no .js class,
   so he just stands at the top. */
.js .landscape .me-hiker { visibility: hidden; }
.js .landscape .trail-reveal { stroke-dasharray: 0 10000; }

/* the hero hiker is a <g> inside the big drawing, so pivots are set on each part's own box:
   legs swing from the hip (top middle), the arm from the shoulder (top left) */
.landscape .me-hiker .leg { transform-box: fill-box; transform-origin: 50% 0; }
.landscape .me-hiker .arm { transform-box: fill-box; transform-origin: 0 0; }

@media (prefers-reduced-motion: no-preference) {
  .landscape .me-hiker.walking .leg-a { animation: step .45s ease-in-out infinite alternate; }
  .landscape .me-hiker.walking .leg-b { animation: step .45s ease-in-out infinite alternate-reverse; }
  .landscape .me-hiker.walking .arm   { animation: swing .45s ease-in-out infinite alternate-reverse; }
  /* arm (and walking pole) goes up, waves three times, comes back down */
  .landscape .me-hiker.waving .arm { animation: wave 2s ease-in-out both; }
}
@keyframes wave {
  0%   { transform: rotate(0); }
  18%  { transform: rotate(-150deg); }
  32%  { transform: rotate(-122deg); }
  46%  { transform: rotate(-150deg); }
  60%  { transform: rotate(-122deg); }
  74%  { transform: rotate(-150deg); }
  100% { transform: rotate(0); }
}

/* me in the hero: a faint outline on the drawn parts so they don't sink into the night scene */
:root[data-theme="dark"] .landscape .me > :not(image),
:root[data-theme="dark"] .landscape .me-hiker > :not(image) { filter: drop-shadow(0 0 1.2px rgb(255 255 255 / .4)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .landscape .me > :not(image) { filter: drop-shadow(0 0 1.2px rgb(255 255 255 / .4)); }
}

/* ---------- altitude gauge ---------- */
.gauge {
  position: fixed; right: 1.1rem; top: 50%; transform: translateY(-50%); z-index: 40;
  display: flex; flex-direction: column; align-items: center; gap: .6rem;
  font-size: .8rem; font-variant-numeric: tabular-nums; color: var(--muted);
  pointer-events: none;
}
.gauge-read { font-weight: 700; color: var(--ink); font-variation-settings: "wdth" 88; white-space: nowrap; }
.gauge-track {
  position: relative; width: 4px; height: 38vh; border-radius: 4px;
  background: var(--line);
  /* the track doubles as a scrollbar: click to glide there, or drag the dot */
  pointer-events: auto; cursor: pointer; touch-action: none;
}
.gauge-track::after {
  /* a wider invisible hit area, so the thin track is easy to grab */
  content: ""; position: absolute; inset: -10px -14px;
}
.gauge-sea {
  /* everything below sea level is water */
  position: absolute; left: 0; right: 0; bottom: 0; height: 6%;
  background: var(--water); border-radius: 0 0 4px 4px;
}
.gauge-sea::before {
  content: ""; position: absolute; left: -5px; right: -5px; top: -1px; height: 2px; background: var(--water);
}
.gauge-dot {
  position: absolute; left: 50%; top: 0; z-index: 1; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  background: var(--accent); border: 2px solid var(--bg); border-radius: 50%;
  cursor: grab; transition: transform .15s;
}
.gauge-track:hover .gauge-dot, .gauge.dragging .gauge-dot { transform: scale(1.35); }
.gauge.dragging, .gauge.dragging .gauge-track, .gauge.dragging .gauge-dot { cursor: grabbing; }
.gauge-label {
  writing-mode: vertical-rl; transform: rotate(180deg); letter-spacing: .02em;
  /* fixed length: "altitude" and "depth" are different lengths, and without this the whole
     gauge re-centres (and the track shifts under your pointer) as you pass sea level */
  height: 4.2rem; text-align: center;
}
.gauge.under .gauge-read { color: var(--deep-ink); }
.gauge.under .gauge-label { color: var(--deep-muted); }
.gauge.under .gauge-track { background: color-mix(in srgb, var(--deep-ink) 20%, transparent); }
.gauge.under .gauge-dot { border-color: var(--deep); }

@media (max-width: 1180px) { .gauge { display: none; } }

/* ---------- sections ---------- */
.section { max-width: var(--max); margin: 0 auto; padding: clamp(4rem, 9vw, 7rem) var(--gutter); }
.section-head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .5rem 2rem;
  margin-bottom: 2.5rem; padding-bottom: 1rem;
  border-bottom: 2px dotted var(--line-2);
}
.section-head h2 { font-size: var(--step-3); font-weight: 800; font-variation-settings: "wdth" 118; }
.section-head p { color: var(--muted); margin: 0; max-width: 42ch; }

/* ---------- projects ---------- */
.project-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(6, 1fr); gap: 3rem 2rem; }
.project { grid-column: span 2; }
.project--lead { grid-column: 1 / -1; }

.project-open { all: unset; box-sizing: border-box; cursor: pointer; display: grid; gap: 1rem; width: 100%; }
.project--lead .project-open { grid-template-columns: 1.35fr 1fr; gap: 2.5rem; align-items: center; }
.project-open:focus-visible { outline: 3px solid var(--accent-text); outline-offset: 6px; border-radius: 14px; }

/* placeholder covers: a patch of sky over a scalloped waterline.
   data-tone (0-3) picks the hue; the colour-vision modes swap in their own set. */
.project-cover {
  --hue: 192;
  position: relative; display: grid; place-items: center; overflow: hidden;
  aspect-ratio: 16 / 10; border-radius: 14px; border: 1px solid var(--line);
  background: linear-gradient(180deg, hsl(var(--hue) 45% 90%), hsl(var(--hue) 35% 82%));
}
.project-cover::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 32%;
  background: hsl(var(--hue) 45% 42% / .35);
  -webkit-mask: radial-gradient(16px at 50% 0, #0000 97%, #000) 0 0 / 32px 100%;
          mask: radial-gradient(16px at 50% 0, #0000 97%, #000) 0 0 / 32px 100%;
}
:root[data-theme="dark"] .project-cover { background: linear-gradient(180deg, hsl(var(--hue) 30% 22%), hsl(var(--hue) 30% 16%)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .project-cover { background: linear-gradient(180deg, hsl(var(--hue) 30% 22%), hsl(var(--hue) 30% 16%)); }
}
.project-cover[data-tone="1"] { --hue: 158; }
.project-cover[data-tone="2"] { --hue: 24; }
.project-cover[data-tone="3"] { --hue: 212; }
/* red-green: alternate blue and yellow so neighbouring covers never match */
:root[data-cvd^="rg-"] .project-cover { --hue: 210; }
:root[data-cvd^="rg-"] .project-cover[data-tone="1"] { --hue: 45; }
:root[data-cvd^="rg-"] .project-cover[data-tone="2"] { --hue: 220; }
:root[data-cvd^="rg-"] .project-cover[data-tone="3"] { --hue: 50; }
/* blue-yellow: alternate teal and red */
:root[data-cvd^="by-"] .project-cover { --hue: 190; }
:root[data-cvd^="by-"] .project-cover[data-tone="1"] { --hue: 350; }
:root[data-cvd^="by-"] .project-cover[data-tone="2"] { --hue: 170; }
:root[data-cvd^="by-"] .project-cover[data-tone="3"] { --hue: 10; }
.project-cover img { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; object-fit: cover; object-position: top center; transition: transform .5s cubic-bezier(.2,.8,.2,1); }
.project-open:hover .project-cover img { transform: scale(1.03); }

/* corner ribbon: shown in the project viewer ("No longer live", "Team project"), set per project in home.ejs */
.ribbon {
  position: absolute; top: 0; left: 0; z-index: 2;
  width: 10rem; height: 10rem; overflow: hidden;
  border-top-left-radius: inherit; pointer-events: none;
}
.ribbon[hidden] { display: none; }
.ribbon-text {
  position: absolute; top: 2.4rem; left: -3.2rem; width: 14rem;
  padding: .45rem 0; transform: rotate(-45deg);
  background: var(--accent); color: var(--accent-ink);
  font-size: .8rem; font-weight: 700; font-variation-settings: "wdth" 100;
  line-height: 1; letter-spacing: .05em; text-transform: uppercase;
  text-align: center; white-space: nowrap;
  box-shadow: 0 2px 6px rgb(6 28 36 / .25);
}

.project-initials {
  position: relative; z-index: 1;
  font-weight: 900; font-variation-settings: "wdth" 125; font-size: clamp(3rem, 8vw, 5.5rem);
  letter-spacing: -0.04em; color: var(--ink); opacity: .85;
}

.project-body { display: flex; flex-direction: column; gap: .4rem; }
.project-meta { font-size: var(--step--1); color: var(--muted); margin: 0; }
.project-title { font-weight: 700; font-size: var(--step-2); line-height: 1.1; letter-spacing: -0.015em; font-variation-settings: "wdth" 110; }
.project--lead .project-title { font-size: var(--step-3); font-weight: 800; font-variation-settings: "wdth" 118; }
/* hover underline: grows in from the left and slides back out the same way.
   It's a background on the inner text span, so on a title that wraps it runs across
   each line in turn rather than under the whole block. */
.project-title-text {
  background: linear-gradient(var(--accent), var(--accent)) no-repeat left bottom / 0% 3px;
  transition: background-size .45s cubic-bezier(.2,.8,.2,1);
}
.project-open:is(:hover, :focus-visible) .project-title-text { background-size: 100% 3px; }
.project-summary { color: var(--muted); max-width: 46ch; }

/* tag filter: a row of chips above the grid (only with JavaScript, which does the filtering).
   The chosen chip is filled, not just recoloured, so the state doesn't rely on colour. */
.project-filters { display: none; flex-wrap: wrap; gap: .5rem; margin: -1rem 0 2.25rem; }
.js .project-filters { display: flex; }
.filter-chip {
  font: inherit; font-size: .85rem; font-weight: 600; min-height: 2.25rem; padding: .35rem .95rem;
  border: 1.5px solid var(--line-2); border-radius: 999px; background: var(--surface); color: var(--muted);
  cursor: pointer; transition: background-color .15s, color .15s, border-color .15s;
}
.filter-chip:hover { border-color: var(--ink); color: var(--ink); }
.filter-chip[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--bg); }

/* more projects: only the first 4 cards show until the button is pressed.
   The button only exists when there are more than 4 projects, and without JavaScript
   every card simply shows and the button stays hidden. */
.js .project-grid:not(.is-expanded):not(.is-filtered) .project--extra { display: none; }
.more-projects { display: none; justify-content: center; margin-top: 3rem; }
.js .more-projects { display: flex; }
.more-projects[hidden] { display: none; }
.more-projects-btn svg { transition: transform .25s; }
.more-projects-btn[aria-expanded="true"] svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: no-preference) {
  .project-grid.is-expanded .project--extra { animation: rise .5s cubic-bezier(.2,.8,.2,1) both; }
}

.tags { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .4rem; }
.tag {
  font-size: .8rem; font-weight: 500; padding: .2rem .65rem;
  border: 1px solid var(--line); border-radius: 999px; color: var(--muted); background: var(--surface);
}

/* ---------- scroll crossings: hiker and kayak ---------- */
.crossing { position: relative; height: 116px; overflow: hidden; }
.crossing-hills { position: absolute; left: 0; bottom: 0; width: 100%; height: 80px; fill: var(--ridge-near); stroke: none; opacity: .55; }
.crossing-path { position: absolute; left: 0; right: 0; bottom: 14px; border-top: 3px dotted var(--ridge-acent); }

.mover { position: absolute; left: 0; will-change: transform; }
/* the figures carry their own colours (drawn from the photo), so switch off the global icon styling */
.mover svg { width: 100%; height: 100%; fill: none; stroke: none; overflow: visible; }
.mover-face { transform-origin: center; transition: transform .25s; }
.mover.back .mover-face { transform: scaleX(-1); }
:root[data-theme="dark"] .mover svg > :not(image) { filter: drop-shadow(0 0 1.2px rgb(255 255 255 / .4)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .mover svg > :not(image) { filter: drop-shadow(0 0 1.2px rgb(255 255 255 / .4)); }
}

.hiker { bottom: 16px; width: 58px; height: 90px; }
.hiker .leg { transform-box: view-box; transform-origin: 30px 51px; }
.mover image { image-rendering: auto; }
.hiker .arm { transform-box: view-box; transform-origin: 32px 29px; }

.kayaker { bottom: calc(100% + 7px); width: 150px; height: 75px; }
.kayaker .paddle { transform-box: view-box; transform-origin: 61px 30px; }

/* go-kart: drives along a strip of track between Experience and About */
.crossing--track { height: 116px; }
.track {
  position: absolute; left: 0; right: 0; bottom: 0; height: 30px;
  background: var(--track);
}
.track::before {
  /* kerb: accent and white blocks, so it follows the colour-vision modes */
  content: ""; position: absolute; left: 0; right: 0; top: -5px; height: 5px;
  background: repeating-linear-gradient(90deg, var(--accent) 0 22px, var(--surface) 22px 44px);
}
.track::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  border-top: 2px dashed color-mix(in srgb, #fff 55%, transparent);
}
.karter { bottom: 6px; width: 196px; height: 106px; }  /* keep the 855 × 461 ratio of its viewBox */

@media (prefers-reduced-motion: no-preference) {
  /* legs, arms and paddle only move while you're actually scrolling */
  .hiker.moving .leg-a { animation: step .45s ease-in-out infinite alternate; }
  .hiker.moving .leg-b { animation: step .45s ease-in-out infinite alternate-reverse; }
  .hiker.moving .arm   { animation: swing .45s ease-in-out infinite alternate-reverse; }
  .kayaker.moving .paddle { animation: stroke .7s ease-in-out infinite alternate; }
  .kayaker-bob { animation: bob 4.5s ease-in-out infinite; }
  /* the kart rumbles only while you're scrolling */
  .karter.moving .karter-body { animation: rumble .12s steps(2) infinite alternate; }
}
@keyframes rumble { to { transform: translateY(-4px); } }  /* in the kart photo's units, about 1px on screen */
@keyframes step   { from { transform: rotate(-20deg); } to { transform: rotate(20deg); } }
@keyframes swing  { from { transform: rotate(-12deg); } to { transform: rotate(12deg); } }
@keyframes stroke { from { transform: rotate(-22deg); } to { transform: rotate(22deg); } }

/* ---------- experience: a waymarked trail ----------
   As you scroll, orange footprints walk down the grey trail (script.js sets --trail-p, 0 to 1),
   and each waymarker is planted as the footprints reach it. Without JavaScript the trail
   and markers simply show in full. */
.trail { list-style: none; margin: 0; padding: 0 0 0 2.5rem; position: relative; max-width: 52rem; }
.trail::before {
  content: ""; position: absolute; left: .6rem; top: .6rem; bottom: .6rem;
  border-left: 3px dotted var(--line-2);
}
.js .trail::after {
  /* the walked part: same dots in orange, clipped to how far you've scrolled */
  content: ""; position: absolute; left: .6rem; top: .6rem; bottom: .6rem;
  border-left: 3px dotted var(--accent);
  clip-path: inset(0 0 calc((1 - var(--trail-p, 0)) * 100%) 0);
}
.waypoint { position: relative; padding-bottom: 2.75rem; }
.waypoint:last-child { padding-bottom: 0; }
.waypoint::before {
  /* waymarker: a small diamond sign, above the trail lines */
  content: ""; position: absolute; left: -2.3rem; top: .35rem; z-index: 1;
  width: 1rem; height: 1rem; transform: rotate(45deg); border-radius: 3px;
  background: var(--bg); border: 2.5px solid var(--accent);
}
.waypoint--tech::before { background: var(--accent); }
/* not reached yet: a faint grey marker waiting on the trail */
.js .trail .waypoint:not(.reached)::before { border-color: var(--line-2); background: var(--bg); transform: rotate(45deg) scale(.7); }

@media (prefers-reduced-motion: no-preference) {
  /* reached: the marker is planted with a small overshoot, then a ring ripples out once */
  .js .trail .waypoint.reached::before { animation: plant .45s cubic-bezier(.3,1.6,.5,1) both; }
  .js .trail .waypoint.reached::after {
    content: ""; position: absolute; left: -2.3rem; top: .35rem;
    width: 1rem; height: 1rem; border-radius: 3px; border: 2px solid var(--accent);
    pointer-events: none; animation: ripple .7s ease-out both;
  }
}
@keyframes plant  { from { transform: rotate(45deg) scale(.3); } to { transform: rotate(45deg) scale(1); } }
@keyframes ripple { from { transform: rotate(45deg) scale(1); opacity: .8; } to { transform: rotate(45deg) scale(2.4); opacity: 0; } }
.waypoint-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: .25rem 1.5rem; margin-bottom: .6rem; }
.waypoint h3 { font-size: var(--step-1); font-weight: 700; }
.waypoint .at { font-weight: 400; color: var(--muted); }
.waypoint .dates { margin: 0; color: var(--muted); font-size: var(--step--1); font-variant-numeric: tabular-nums; white-space: nowrap; }
.waypoint ul { margin: 0; padding-left: 1.1rem; max-width: 62ch; }
.waypoint li { margin-bottom: .3rem; }
.waypoint li::marker { color: var(--line-2); }

/* ---------- about ---------- */
.about { display: grid; grid-template-columns: 1.4fr 1fr; gap: 3rem 4rem; }
.about-text { max-width: 60ch; }
.about-big { font-size: var(--step-2); font-weight: 500; line-height: 1.3; letter-spacing: -0.01em; margin-bottom: 1.25em; }
.about-text p:not(.about-big) { color: var(--muted); }

.facts { margin: 0; display: grid; gap: 1.75rem; align-content: start; }
.facts dt { font-weight: 700; margin-bottom: .35rem; }
.facts dd { margin: 0 0 .2rem; color: var(--muted); }

/* ---------- contact: open water ----------
   Every colour here is checked against --deep for WCAG AA in both themes. */
.section--contact {
  position: relative; max-width: none; margin-top: 3rem;
  background: var(--deep); color: var(--deep-ink);
}
/* no-colour mode: a light button on the dark water instead of a dark one */
:root[data-cvd^="mono-"] .section--contact { --accent: var(--deep-ink); --accent-hi: #fff; --accent-ink: var(--deep); }

.wave-edge {
  position: absolute; left: 0; bottom: 100%; width: 100%; height: 48px; margin-bottom: -1px;
  fill: var(--deep); stroke: none;
}
.contact { max-width: calc(var(--max) - 2 * var(--gutter)); margin: 0 auto; display: grid; grid-template-columns: 1fr 1.2fr; gap: 3rem 4rem; }
.contact h2 { font-size: var(--step-3); font-weight: 800; font-variation-settings: "wdth" 118; margin-bottom: 1rem; }
.contact-intro p { color: var(--deep-muted); max-width: 36ch; }
/* the link text stays light so it's readable; the orange is carried by the underline */
.contact-alt a { color: var(--deep-ink); font-weight: 600; text-decoration-color: var(--accent); text-decoration-thickness: 2px; }
.contact-alt a:hover { text-decoration-thickness: 3px; }
.section--contact :focus-visible { outline-color: var(--deep-ink); }

.form { display: grid; gap: 1.25rem; }
.field { display: grid; gap: .35rem; }
.field label { font-weight: 600; color: var(--deep-ink); }
.field input, .field textarea {
  font: inherit; color: var(--deep-ink);
  background: color-mix(in srgb, var(--deep-ink) 8%, transparent);
  border: 1.5px solid var(--deep-muted);
  border-radius: 8px; padding: .75rem .9rem; width: 100%;
  transition: border-color .15s, background-color .15s;
}
.field textarea { resize: vertical; min-height: 8rem; }
.field input:focus, .field textarea:focus {
  outline: 3px solid var(--deep-ink); outline-offset: 2px;
  border-color: var(--deep-ink); background: color-mix(in srgb, var(--deep-ink) 12%, transparent);
}
.field [aria-invalid="true"] { border-color: var(--deep-error); border-width: 2px; }
.field-error { color: var(--deep-error); font-size: var(--step--1); font-weight: 600; margin: 0; }
.form .btn { justify-self: start; }
.form-status { margin: 0; min-height: 1.6em; font-weight: 600; }
.form-privacy { margin: -.5rem 0 0; color: var(--muted); font-size: .9rem; line-height: 1.5; }
.form-privacy a { color: var(--accent-text); }
.form-status.ok { color: var(--deep-ok); }
.form-status.err { color: var(--deep-error); }
.gotcha { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

/* ---------- Query dropdown ---------- */
.field select { appearance: none; -webkit-appearance: none; display: block; width: 100%; min-height: 54px; padding: 0 3rem 0 1rem; font: inherit; color: #f2f7f8; background-color: #355f6c; border: 2px solid #dbe9ec; border-radius: 10px; cursor: pointer; transition: border-color .2s ease, box-shadow .2s ease; }
.field select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23dbe9ec' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 1rem center; background-size: 16px; }
.field select:invalid { color: rgba(242, 247, 248, .55); }
.field select option { color: #f2f7f8; background-color: #1c3440; }
.field select option[value=""] { color: rgba(242, 247, 248, .55); }
.field select:focus { outline: none; border-color: #fff; box-shadow: 0 0 0 3px rgba(219, 233, 236, .35); }
.field select:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* ---------- footer: the deep end ---------- */
.footer { background: var(--deep-2); color: var(--deep-muted); font-size: var(--step--1); }
.footer-inner {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: .5rem 2rem;
  max-width: var(--max); margin: 0 auto; padding: 2rem var(--gutter) 2.5rem;
}
.footer p { margin: 0; }
.footer-links { display: flex; flex-wrap: wrap; gap: .25rem 1.25rem; }
.footer-links a { color: var(--deep-ink); font-weight: 600; text-decoration-color: var(--accent); text-underline-offset: .25em; }

/* ---------- project viewer ---------- */
.viewer {
  width: min(64rem, calc(100% - 2rem)); max-height: calc(100dvh - 2rem);
  padding: 0; border: 1px solid var(--line); border-radius: 18px;
  background: var(--surface); color: var(--ink); overflow: auto;
}
.viewer::backdrop { background: rgb(6 28 36 / .65); backdrop-filter: blur(4px); }
.viewer[open] { animation: pop .25s cubic-bezier(.2,.8,.2,1); }
@keyframes pop { from { opacity: 0; transform: translateY(12px) scale(.98); } }
/* card-to-viewer morph (view transitions): the cover grows into the viewer's picture area */
.viewer.morphing[open] { animation: none; }
::view-transition-group(project-media) { animation-duration: .42s; animation-timing-function: cubic-bezier(.2,.8,.2,1); }
/* the rest of the page just cross-fades quickly under the morph */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .2s; }
::view-transition-old(project-media),
::view-transition-new(project-media) { width: 100%; height: 100%; object-fit: cover; }

.viewer-inner { position: relative; display: grid; grid-template-columns: 1.5fr 1fr; }
.viewer-close {
  position: absolute; top: .75rem; right: .75rem; z-index: 2;
  display: grid; place-items: center; width: 2.5rem; height: 2.5rem; font-size: 1.1rem;
  border-radius: 50%; border: 1px solid var(--line); background: var(--surface); cursor: pointer;
}
.viewer-close:hover { border-color: var(--ink); }

.viewer-media {
  position: relative; min-height: 18rem; display: grid; place-items: center;
  background: var(--bg); border-right: 1px solid var(--line);
}
.viewer-media img { width: 100%; height: 100%; max-height: 70vh; object-fit: contain; }
.viewer-media .project-initials { display: none; }
.viewer-media.no-img img { display: none; }
.viewer-media.no-img .project-initials { display: block; }
.viewer-nav {
  position: absolute; bottom: .75rem; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: .5rem; padding: .25rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: 999px;
  font-size: var(--step--1); font-variant-numeric: tabular-nums;
}
.viewer-nav[hidden] { display: none; }
.viewer-nav button { display: grid; place-items: center; width: 2rem; height: 2rem; border: 0; background: transparent; border-radius: 50%; cursor: pointer; }
.viewer-nav button:hover { background: var(--bg); }

.viewer-text { padding: 2.5rem 2rem 2rem; display: flex; flex-direction: column; gap: .75rem; }
.viewer-text h2 { font-size: var(--step-2); font-weight: 800; font-variation-settings: "wdth" 115; padding-right: 2rem; }
.viewer-text p { margin: 0; }
.viewer-text .btn { align-self: flex-start; margin-top: .75rem; }
.viewer-actions { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: .75rem; }
.viewer-actions .btn { margin-top: 0; }
.viewer-text .btn[hidden] { display: none; }

body.viewer-open { overflow: hidden; }

/* ---------- command palette (Ctrl + K) ---------- */
.palette {
  width: min(36rem, calc(100% - 2rem)); margin: 12vh auto auto; padding: 0;
  border: 1px solid var(--line); border-radius: 16px;
  background: var(--surface); color: var(--ink);
  box-shadow: 0 24px 60px rgb(6 28 36 / .3);
}
.palette::backdrop { background: rgb(6 28 36 / .55); backdrop-filter: blur(3px); }
.palette[open] { animation: pop .2s cubic-bezier(.2,.8,.2,1); }
.palette-field { display: flex; align-items: center; gap: .75rem; padding: .9rem 1.1rem; border-bottom: 1px solid var(--line); }
.palette-field svg { font-size: 1.15rem; color: var(--muted); flex: none; }
.palette-field input {
  flex: 1; min-width: 0; font: inherit; font-size: 1.05rem; color: var(--ink);
  background: none; border: 0; padding: .2rem 0;
}
.palette-field input:focus { outline: none; }
.palette-field input::placeholder { color: var(--muted); opacity: 1; }
.palette kbd {
  font: 600 .75rem var(--font); color: var(--muted);
  border: 1px solid var(--line-2); border-radius: 6px; padding: .15rem .45rem;
}
.palette-list { list-style: none; margin: 0; padding: .5rem; max-height: min(50vh, 26rem); overflow-y: auto; }
.palette-list [role="option"] {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: .6rem .8rem; border-radius: 10px; cursor: pointer;
  border-left: 3px solid transparent;
}
.palette-list [aria-selected="true"] {
  background: color-mix(in srgb, var(--accent) 14%, var(--surface));
  border-left-color: var(--accent-text);
}
.palette-label { font-weight: 600; }
.palette-group { font-size: var(--step--1); color: var(--muted); white-space: nowrap; }
.palette-empty { margin: 0; padding: 1rem 1.25rem 1.25rem; color: var(--muted); }
.palette-empty[hidden] { display: none; }

/* ---------- toast (easter egg and other short messages) ---------- */
.toast {
  position: fixed; left: 50%; bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px)); z-index: 70;
  max-width: calc(100% - 2rem); padding: .75rem 1.2rem; border-radius: 999px;
  background: var(--ink); color: var(--bg); font-weight: 600; text-align: center;
  box-shadow: 0 10px 30px rgb(6 28 36 / .25);
  transform: translate(-50%, 150%); opacity: 0; pointer-events: none;
  transition: transform .35s cubic-bezier(.2,.8,.2,1), opacity .35s;
}
.toast.show { transform: translate(-50%, 0); opacity: 1; }

/* ---------- colour vision: imagery ---------- */

/* the figures' orange is written into their SVG; these match those exact colours
   and swap them for the mode's accent, so the kayak and backpack change with the site */
:root:is([data-cvd^="rg-"], [data-cvd^="by-"]) :is(.mover, .landscape) [fill="#ff5a1f"] { fill: var(--accent); }
:root:is([data-cvd^="rg-"], [data-cvd^="by-"]) :is(.mover, .landscape) [fill="#c2410c"] { fill: var(--accent-deep); }
:root:is([data-cvd^="rg-"], [data-cvd^="by-"]) :is(.mover, .landscape) [stroke="#c2410c"] { stroke: var(--accent-deep); }

/* red-green: amber is light, so the trail markers use the darker text amber to stay clear on the page */
:root[data-cvd^="rg-"] .waypoint::before { border-color: var(--accent-text); }
:root[data-cvd^="rg-"] .waypoint--tech::before { background: var(--accent-text); }
:root[data-cvd^="rg-"] .trail::after,
:root[data-cvd^="rg-"] .waypoint::after { border-color: var(--accent-text); }

/* no colour: photos, screenshots, covers and the figures go greyscale too */
:root[data-cvd^="mono-"] :is(.project-cover, .viewer-media img, .mover svg, .landscape .me, .landscape .me-hiker, .landscape .me-kayak) {
  filter: grayscale(1);
}

/* ---------- accessibility preferences: layout and text ---------- */

/* high contrast: heavier outlines on the small controls, solid button backs */
:root[data-contrast="high"] :is(.tag, .filter-chip, .theme-toggle, .a11y-toggle, .palette-toggle, .project-cover, .viewer-close, .viewer-nav) { border-width: 2px; }
:root[data-contrast="high"] .btn-ghost { background: var(--surface); }

/* larger text: everything is sized in rem, so this scales the whole page */
:root[data-text="large"] { font-size: 125%; }

/* readable font: Atkinson Hyperlegible, loaded only when this is switched on */
:root[data-font="readable"] { --font: "Atkinson Hyperlegible", Verdana, Tahoma, sans-serif; }

/* text spacing: more room between lines, letters, words and paragraphs */
:root[data-spacing="wide"] body { line-height: 1.8; }
:root[data-spacing="wide"] :is(p, li, dt, dd, label, input, textarea, select, .btn, .tag, .nav a, .project-meta, .project-summary, .switch-hint) {
  letter-spacing: .06em; word-spacing: .16em;
}
:root[data-spacing="wide"] :is(.about-text, .contact-intro, .viewer-text) p { margin-bottom: 1.5em; }

/* underline links: every link and project title gets a visible underline */
:root[data-links="underline"] a:not(.btn, .skip-link),
:root[data-links="underline"] .project-title {
  text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: .2em;
}

/* ---------- other pages: project pages, CV, trail notes, 404 ----------
   They share the top bar, footer and settings with the home page. */
.page { max-width: var(--max); margin: 0 auto; padding: clamp(2rem, 5vw, 4rem) var(--gutter) clamp(4rem, 8vw, 6rem); }
.page-head { margin-bottom: 2.5rem; }
.page-title { font-size: var(--step-3); font-weight: 800; font-variation-settings: "wdth" 118; margin: .25rem 0 1rem; }
.page-lede { font-size: var(--step-1); color: var(--muted); max-width: 46ch; line-height: 1.45; }
.page-lede a { color: var(--accent-text); font-weight: 600; }
.case-copy { max-width: 68ch; font-size: 1rem; line-height: 1.7; }
.case-copy h2 { margin: 2rem 0 .5rem; font-size: var(--step-1); }
.case-copy p { margin: 0 0 1rem; }
.case-copy a { color: var(--accent-text); text-underline-offset: .15em; }
.back-link {
  display: inline-flex; align-items: center; gap: .35rem; margin-bottom: 1.5rem;
  color: var(--muted); font-weight: 600; text-decoration: none;
}
.back-link:hover { color: var(--ink); }

/* project page */
.case-head { display: grid; gap: .5rem; justify-items: start; margin-bottom: 2.5rem; }
.case-head .page-lede { margin: 0; }
.case-head .btn { margin-top: .75rem; }
.case-badge {
  margin: 0; padding: .3rem .8rem; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font-size: .8rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
}
.tag-link { text-decoration: none; }
.tag-link:hover { border-color: var(--ink); color: var(--ink); }
.case-gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); gap: 1.5rem; margin-bottom: 3rem; }
.case-gallery figure { margin: 0; }
.case-gallery img { width: 100%; border-radius: 14px; border: 1px solid var(--line); background: var(--surface); }
.case-gallery figcaption { margin-top: .5rem; font-size: var(--step--1); color: var(--muted); }
.case-nav {
  display: flex; justify-content: space-between; gap: 1rem; margin-top: 4rem; padding-top: 1.5rem;
  border-top: 2px dotted var(--line-2);
}
.case-nav-link { display: grid; gap: .15rem; text-decoration: none; max-width: 48%; }
.case-nav-next { text-align: right; margin-left: auto; }
.case-nav-dir { font-size: var(--step--1); color: var(--muted); }
.case-nav-title { font-weight: 700; font-size: var(--step-1); }
.case-nav-link:hover .case-nav-title { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 3px; }

/* long-form text: project write-ups and trail notes */
.prose { max-width: 66ch; }
.prose h2 { font-size: var(--step-2); font-weight: 800; font-variation-settings: "wdth" 112; margin: 2.25rem 0 .75rem; }
.prose h3 { font-size: var(--step-1); margin: 1.75rem 0 .5rem; }
.prose > :first-child { margin-top: 0; }
.prose ul, .prose ol { padding-left: 1.25rem; margin: 0 0 1em; }
.prose li { margin-bottom: .35rem; }
.prose li::marker { color: var(--accent-text); }
.prose a { color: var(--accent-text); font-weight: 600; }
.prose img { border-radius: 12px; margin: 1.5rem 0; }
.prose blockquote { margin: 1.5rem 0; padding: .25rem 0 .25rem 1.25rem; border-left: 3px solid var(--accent); color: var(--muted); }
.prose code { font-size: .9em; padding: .1em .35em; border-radius: 5px; background: var(--surface); border: 1px solid var(--line); }
.prose pre { overflow-x: auto; padding: 1rem 1.25rem; border-radius: 12px; background: var(--surface); border: 1px solid var(--line); }
.prose pre code { padding: 0; border: 0; background: none; }

/* trail notes list */
.notes-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.25rem; max-width: 48rem; }
.note-card { padding: 1.5rem; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); }
.note-card h2 { font-size: var(--step-2); font-weight: 800; font-variation-settings: "wdth" 112; margin: .25rem 0 .5rem; }
.note-card h2 a { text-decoration: none; }
.note-card h2 a:hover { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 3px; }
.note-summary { color: var(--muted); margin-bottom: .5rem; }
.note { max-width: 66ch; }

/* CV: on screen it's a sheet of paper; printed, it's just the sheet */
.cv-sheet {
  max-width: 52rem; padding: clamp(1.5rem, 5vw, 3.5rem);
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: 0 12px 32px rgb(6 28 36 / .08);
}
.cv-head { padding-bottom: 1.25rem; margin-bottom: 1.5rem; border-bottom: 3px solid var(--accent); }
.cv-head h1 { font-size: var(--step-3); font-weight: 850; font-variation-settings: "wdth" 120; }
.cv-role { font-size: var(--step-1); font-weight: 600; margin: .5rem 0 .25rem; }
.cv-contact { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0; color: var(--muted); }
.cv-contact a { color: inherit; }
.cv-section { margin-bottom: 1.75rem; }
.cv-section h2 {
  font-size: .85rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent-text); margin-bottom: .9rem;
}
.cv-item { margin-bottom: 1.1rem; break-inside: avoid; }
.cv-item-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: .1rem 1rem; }
.cv-item h3 { font-size: 1.05rem; font-weight: 700; letter-spacing: 0; }
.cv-org { font-weight: 400; color: var(--muted); }
.cv-dates { margin: 0; font-size: var(--step--1); color: var(--muted); white-space: nowrap; }
.cv-item ul, .cv-section ul { margin: .35rem 0 0; padding-left: 1.1rem; }
.cv-item li { margin-bottom: .2rem; }
.cv-item p { margin: .35rem 0 0; }
.cv-tools { color: var(--muted); font-size: var(--step--1); }
.cv-two { display: grid; grid-template-columns: 1fr 1fr; gap: 0 2.5rem; }
@media (max-width: 640px) { .cv-two { grid-template-columns: 1fr; } }

@media print {
  @page { size: A4; margin: 14mm 16mm; }
  .topbar, .footer, .gauge, .skip-link, .toast, .palette { display: none !important; }
  html, body { background: #fff !important; color: #111 !important; }
  .page { padding: 0; max-width: none; }
  .cv-sheet { max-width: none; padding: 0; border: 0; box-shadow: none; background: none; color: #111; font-size: 10.5pt; line-height: 1.45; }
  .cv-sheet a { color: inherit; text-decoration: none; }
  .cv-head { border-bottom-color: #c2410c; }
  .cv-section h2 { color: #c2410c; }
  .cv-org, .cv-dates, .cv-tools, .cv-contact { color: #444; }
  * { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}

/* 404 */
.page--lost { text-align: center; padding-top: clamp(4rem, 12vh, 8rem); }
.page--lost .page-lede { margin: 0 auto 2rem; }
.lost-altitude { font-weight: 800; font-variation-settings: "wdth" 88; color: var(--accent-text); letter-spacing: .05em; margin-bottom: .5rem; }

/* ---------- responsive ---------- */
@media (max-width: 1000px) {
  .project { grid-column: span 3; }
  .project--lead { grid-column: 1 / -1; }
}
@media (max-width: 860px) {
  .project--lead .project-open { grid-template-columns: 1fr; gap: 1rem; }
  .about, .contact { grid-template-columns: 1fr; }
  .viewer-inner { grid-template-columns: 1fr; }
  .viewer-media { border-right: 0; border-bottom: 1px solid var(--line); }

  /* landscape drops below the text instead of sitting behind it */
  .hero { min-height: 100svh; }
  .landscape { position: relative; flex: none; height: clamp(16rem, 70vw, 24rem); margin: auto calc(-1 * var(--gutter)) 0; width: calc(100% + 2 * var(--gutter)); }
  .hero-inner { margin: 0 0 2.5rem; }
}

@media (max-width: 640px) {
  .project-grid { grid-template-columns: 1fr; }
  .project, .project--lead { grid-column: 1 / -1; }
  .ribbon { width: 8.5rem; height: 8.5rem; }
  .ribbon-text { top: 2rem; left: -3rem; width: 12rem; font-size: .72rem; }

  /* backdrop-filter would trap the fixed nav inside the bar */
  .topbar { backdrop-filter: none; -webkit-backdrop-filter: none; background: var(--sky-top); }
  .topbar.scrolled { background: var(--bg); }

  /* accessibility panel drops down full width, clear of the bottom nav */
  .a11y-panel {
    position: fixed; top: calc(var(--topbar-h) + .5rem); left: 1rem; right: 1rem; width: auto;
    max-height: calc(100svh - var(--topbar-h) - 6.5rem);
  }

  /* nav becomes a floating bar at the bottom, thumb-reachable */
  .nav {
    position: fixed; left: 50%; bottom: calc(.75rem + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%);
    z-index: 60; padding: .3rem; gap: 0;
    max-width: calc(100% - 1.5rem); overflow-x: auto;  /* still fits with larger text on */
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
    border: 1px solid var(--line); border-radius: 999px;
    box-shadow: 0 8px 24px rgb(6 28 36 / .18);
  }
  .nav a { padding: .55rem .8rem; font-size: .9rem; border-radius: 999px; white-space: nowrap; }
  /* extend the sea under the floating nav so it doesn't cover the kayak */
  .hero {
    padding-bottom: 4.75rem;
    background:
      linear-gradient(180deg, var(--sky-top) 0%, var(--sky-bottom) 70%) top / 100% calc(100% - 4.75rem) no-repeat,
      var(--water-2);
  }
  .nav a.active { background: var(--accent); color: var(--accent-ink); }
  .nav a.active::after { display: none; }
  .footer-inner { padding-bottom: 6rem; }
  .toast { bottom: calc(5rem + env(safe-area-inset-bottom, 0px)); }
}

/* ---------- reduced motion: the system setting, or the switch in the accessibility panel ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; transition-delay: 0s !important; }
}
:root[data-motion="reduce"] { scroll-behavior: auto; }
:root[data-motion="reduce"],
:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before,
:root[data-motion="reduce"] *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; transition-delay: 0s !important; }
