/* ============================================================
   Lizzie Kevan Curtis — Site Styles
   Three themes: Light (paper + forest), Dark (forest + paper),
   Jazzy (paper + rose, with overlaid shapes).
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,400;0,500;0,600;1,400;1,500&family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,600;1,400&family=IBM+Plex+Serif:ital,wght@0,300;0,400;0,500;0,600;1,300;1,400;1,500;1,600&display=swap');

/* ---------- Tokens ---------- */

:root, [data-theme="light"] {
  --paper:        #F5F5ED;
  --paper-soft:   #FFFFFF;
  --paper-tint:   #ECEDDF;

  --moss-50:      #F4FFE1;
  --moss-200:     #D8E5BE;
  --moss-400:     #AEC697;
  --moss-600:     #6E8A4F;
  --moss-800:     #1D3A00;

  --rose-100:     #FFE8F0;
  --rose-300:     #FFD0E2;
  --rose-700:     #8C1F47;

  --bg:            var(--paper);
  --bg-elevated:   var(--paper-soft);

  --fg:            var(--moss-800);
  --fg-muted:      var(--moss-600);
  --fg-faint:      #6E8A4F;

  --card-bg:       var(--moss-50);
  --card-border:   var(--moss-400);

  --border:        var(--moss-400);
  --border-subtle: color-mix(in oklab, var(--moss-400) 50%, var(--paper));

  --selection-bg:  var(--moss-50);
  --selection-fg:  var(--moss-800);

  --switch-fg:     #1D3A00;
  --switch-bg:     #FFFFFF;
  --switch-bg-active: #FFFCCB;
  --switch-fg-active: #1D3A00;
  --switch-border: var(--moss-400);

  --focus-ring: 2px solid var(--moss-800);
}

[data-theme="dark"] {
  --bg:            #1D3A00;
  --bg-elevated:   #29460B;

  --fg:            #F5F5ED;
  --fg-muted:      #C9D9B6;
  --fg-faint:      #AEC697;

  --card-bg:       transparent;
  --card-border:   #AEC697;

  --border:        #AEC697;
  --border-subtle: #6E8A4F;

  --selection-bg:  #FFFCCB;
  --selection-fg:  #1D3A00;

  --switch-fg:     #F5F5ED;
  --switch-bg:     #1D3A00;
  --switch-bg-active: #4D7C1E;
  --switch-fg-active: #F5F5ED;
  --switch-border: #AEC697;

  --focus-ring: 2px solid #F5F5ED;
}

[data-theme="jazzy"] {
  --bg:            #EEFCD5;     /* paler paper, slight green */
  --bg-elevated:   #FFFFFF;

  --fg:            #1D3A00;
  --fg-muted:      #4A6A2C;
  --fg-faint:      #6E8A4F;

  --card-bg:       var(--moss-50);
  --card-border:   #AEC697;

  --border:        #AEC697;
  --border-subtle: color-mix(in oklab, #AEC697 50%, #EEFCD5);

  --selection-bg:  #FFD0E2;
  --selection-fg:  #1D3A00;

  --switch-fg:     #1D3A00;
  --switch-bg:     #FFD0E2;
  --switch-bg-active: #BDFFC7;
  --switch-fg-active: #1D3A00;
  --switch-border: #AEC697;

  --focus-ring: 2px solid #1D3A00;

  /* Per-card accents for Jazzy */
  --jazzy-card-1: #FFEE95;
  --jazzy-card-2: #F4E7FF;
  --jazzy-card-3: #D4EAFF;
}

:root {
  --font-serif: "IBM Plex Serif", Georgia, "Times New Roman", serif;
  --font-mono:  "IBM Plex Mono", "Courier New", ui-monospace, monospace;
  --font-sans:  "IBM Plex Sans", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;

  --content-w:  680px;
  --max-w:      1200px;
  --page-pad-x: clamp(20px, 5vw, 96px);
  --page-pad-y: clamp(24px, 4vh, 40px);

  --dur:      200ms;
  --dur-slow: 360ms;
  --ease-out: cubic-bezier(0.2, 0.6, 0.2, 1);
}

/* ---------- Reset + base ---------- */

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

html {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body {
  background: var(--bg);
  color: var(--fg);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  transition: background var(--dur) var(--ease-out),
              color var(--dur) var(--ease-out);
  position: relative;
  overflow-x: hidden;
}

::selection { background: var(--selection-bg); color: var(--selection-fg); }

/* Skip link */
.skip-link {
  position: absolute;
  left: 12px;
  top: 12px;
  padding: 8px 12px;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 13px;
  text-decoration: none;
  transform: translateY(-200%);
  z-index: 100;
}
.skip-link:focus { transform: translateY(0); outline: var(--focus-ring); outline-offset: 2px; }

/* Focus rings — visible across all themes */
:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---------- Layout ---------- */

.page {
  width: 100%;
  max-width: var(--max-w);
  margin: 0 auto;
  padding: var(--page-pad-y) var(--page-pad-x);
  position: relative;
  z-index: 2;
  flex: 1;
  display: flex;
  flex-direction: column;
}

/* ---------- Header ---------- */

.site-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
}

.wordmark {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  color: var(--fg);
  text-decoration: none;
  letter-spacing: 0.005em;
  white-space: nowrap;
}
.wordmark:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Breadcrumb beside the wordmark on subpages — same font/size as the
   wordmark; faint slash separator. */
.header-left {
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
}
.breadcrumb-sep,
.breadcrumb-current {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.005em;
  color: var(--fg);
}
.breadcrumb-sep { opacity: 0.45; }
.breadcrumb-current { white-space: nowrap; }

.nav-link {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--fg);
  text-decoration: none;
  letter-spacing: 0.005em;
}
.nav-link:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- Hero ---------- */

main {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: clamp(56px, 10vh, 112px);
  padding-bottom: clamp(28px, 4vh, 56px);
  position: relative;
}

/* Bands that the Jazzy shapes anchor to. Always reserve space so layout
   stays identical across themes — only the shapes themselves toggle. */
.shape-band {
  position: relative;
  width: 100%;
  flex: 0 0 clamp(150px, 22vh, 200px);
  min-height: clamp(150px, 22vh, 200px);
  pointer-events: none;
}
.shape-band--top { margin-bottom: clamp(20px, 3vh, 32px); }

.hero {
  font-family: var(--font-serif);
  font-size: clamp(30px, 4.7vw, 65px);
  line-height: 1.18;
  font-weight: 300;
  letter-spacing: -0.012em;
  color: var(--fg);
  margin: 0 0 clamp(64px, 10vh, 112px);
  text-wrap: pretty;
}

.hero .hero-link {
  font-family: var(--font-mono);
  font-style: italic;
  font-weight: 400;
  font-size: 0.86em;
  letter-spacing: 0;
  text-decoration: none;
  color: inherit;
  padding: 0 0.15em;
  border-radius: 2px;
  transition: color var(--dur) var(--ease-out),
              background-color var(--dur) var(--ease-out);
}
.hero .hero-link:hover,
.hero .hero-link:focus-visible {
  color: #4D7C1E;
  background-color: #F4FFE1;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
[data-theme="jazzy"] .hero .hero-link:hover,
[data-theme="jazzy"] .hero .hero-link:focus-visible {
  background-color: #BDFFC7;
}
[data-theme="dark"] .hero .hero-link:hover,
[data-theme="dark"] .hero .hero-link:focus-visible {
  color: #F5F5ED;
  background-color: #52792C;
}

/* ---------- Projects ---------- */

.projects {
  margin: 0;
  padding: 0;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--fg);
  margin: 0 0 28px;
  letter-spacing: 0.005em;
  font-weight: 400;
}

.project-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  width: 100%;
}

.project-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  min-height: 56px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  color: var(--fg);
  text-decoration: none;
  transition: background var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out),
              transform var(--dur) var(--ease-out);
}
.project-card:hover,
.project-card:focus-visible {
  background: color-mix(in oklab, var(--card-bg) 80%, var(--fg) 8%);
}
[data-theme="dark"] .project-card:hover,
[data-theme="dark"] .project-card:focus-visible {
  background: color-mix(in oklab, var(--bg) 80%, var(--fg) 12%);
}

.project-card .arrow {
  flex-shrink: 0;
  width: 31px;
  height: 19px;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.29;
  transition: transform var(--dur) var(--ease-out);
}
.project-card:hover .arrow,
.project-card:focus-visible .arrow {
  transform: translateX(4px);
}

/* Jazzy: per-card accent backgrounds. Each <a class="project-card"> is\n   wrapped in an <li>, so we scope nth-child to the <li>. */
[data-theme="jazzy"] .project-grid li:nth-child(1) .project-card { background: var(--jazzy-card-1); }
[data-theme="jazzy"] .project-grid li:nth-child(2) .project-card { background: var(--jazzy-card-2); }
[data-theme="jazzy"] .project-grid li:nth-child(3) .project-card { background: var(--jazzy-card-3); }

/* ---------- Footer ---------- */

.site-footer {
  border-top: 1px solid var(--border);
  padding: clamp(20px, 3vh, 28px) 0 0;
  margin-top: clamp(40px, 6vh, 64px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 24px;
}

.footer-left {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--fg);
  white-space: nowrap;
}

.footer-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  font-family: var(--font-mono);
  font-size: 13px;
}
.footer-right a { color: var(--fg); text-decoration: none; }
.footer-right a:hover { text-decoration: underline; text-underline-offset: 3px; }

.footer-bottom {
  grid-column: 1 / -1;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: clamp(28px, 4vh, 40px);
}

.copyright {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--fg);
}

/* ---------- Theme switcher ---------- */

.theme-switcher {
  display: inline-flex;
  gap: 0;
  padding: 0;
  margin: 0;
  border: 0;
}
.theme-switcher legend {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap;
}

.theme-btn {
  appearance: none;
  -webkit-appearance: none;
  background: var(--switch-bg);
  color: var(--switch-fg);
  border: 1px solid var(--switch-border);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  padding: 7px 14px 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  letter-spacing: 0.005em;
  transition: background var(--dur) var(--ease-out),
              color var(--dur) var(--ease-out);
}
.theme-btn + .theme-btn { margin-left: -1px; }
.theme-btn:hover,
.theme-btn:focus-visible:not([aria-pressed="true"]) {
  background: var(--switch-bg-active);
  color: var(--switch-fg-active);
}
.theme-btn[aria-pressed="true"] {
  background: var(--switch-bg-active);
  color: var(--switch-fg-active);
  z-index: 1;
}

.theme-btn .glyph {
  width: 14px; height: 14px;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.3;
  flex-shrink: 0;
}

/* ---------- Jazzy shapes (static, decorative) ----------
   Shapes live INSIDE the .shape-band elements so they reflow with
   content. Hidden in Light + Dark; revealed in Jazzy.
*/

.shape-band > .shape { opacity: 0; pointer-events: none; }
[data-theme="jazzy"] .shape-band > .shape {
  opacity: 1;
  pointer-events: auto;
  cursor: pointer;
}

.shape {
  position: absolute;
  display: block;
  --mx: 0px;
  --my: 0px;
  --rest-rot: 0deg;
  --hover-rot: 0deg;
  --rot: var(--rest-rot);
  /* Use individual transform properties so magnetic (translate)
     and hover (rotate) can compose with the scroll-driven fall
     animation, which uses the `transform` property. */
  translate: var(--mx) var(--my);
  rotate: var(--rot);
  transform-origin: 50% 50%;
  transition: translate 450ms cubic-bezier(0.34, 1.56, 0.64, 1),
              rotate 450ms cubic-bezier(0.34, 1.56, 0.64, 1);
  will-change: translate, rotate, transform;
}
.shape:hover {
  --rot: var(--hover-rot);
}

@media (prefers-reduced-motion: reduce) {
  .shape {
    transition: none;
  }
  .shape:hover {
    --rot: var(--rest-rot);
    --mx: 0px;
    --my: 0px;
  }
}

/* Top cluster — 6 shapes spread across the band, above the hero.
   Each gets its own --hover-rot so the row tilts asymmetrically. */
.shape-band--top .shape--triangle-orange {
  top: 6%; left: 0%;
  width: 150px; height: 138px;
  background: #F2A372;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
  --hover-rot: -14deg;
}
.shape-band--top .shape--bar-yellow {
  top: 42%; left: 18%;
  width: 150px; height: 38px;
  background: #F2D060;
  border-radius: 2px;
  --hover-rot: 18deg;
}
.shape-band--top .shape--circle-lavender {
  top: 12%; left: 36%;
  width: 140px; height: 140px;
  background: #C9A8E5;
  border-radius: 999px;
  --hover-rot: 0deg;
}
.shape-band--top .shape--bowtie-moss {
  top: 16%; left: 53%;
  width: 140px; height: 124px;
  background: #97AC7E;
  clip-path: polygon(0 0, 100% 0, 50% 50%, 100% 100%, 0 100%, 50% 50%);
  --hover-rot: 22deg;
}
.shape-band--top .shape--triangle-pink {
  top: 18%; left: 70%;
  width: 150px; height: 132px;
  background: #F8C9D6;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  --hover-rot: -16deg;
}
.shape-band--top .shape--square-orange {
  top: 22%; right: 0%; left: auto;
  width: 130px; height: 130px;
  background: #E8A348;
  border-radius: 2px;
  --hover-rot: 12deg;
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* ---------- Mobile ---------- */

@media (max-width: 760px) {
  .project-grid {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  .hero { font-size: clamp(24px, 6.4vw, 32px); }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
  .shape-band { flex-basis: 88px; min-height: 88px; }
  .shape-band > .shape {
    scale: 0.7;
    transform-origin: top left;
  }
}

@media (max-width: 520px) {
  /* Keep Jazzy palette, drop the floating shapes — they crowd content. */
  .shape-band { display: none; }
}

/* Swifts project page — warmer neutral paper. Light theme only;
   dark theme keeps its dark moss background. */
html[data-page="swifts"][data-theme="light"] {
  --bg: #EBE4DE;
}

/* Arrival & departure season-band gradient stops. Per-theme so the
   band reads cleanly against each background. Light mode uses a
   yellow ramp peaking at #FFF997. Dark and Jazzy approximate the
   previous moss-on-bg gradient with explicit colors. */
[data-theme="light"] {
  --ad-band-out:  #EBE4DE;
  --ad-band-mid:  #FCEEB6;
  --ad-band-peak: #FFF997;
  --ad-band-tail: #FBE9A8;
}
[data-theme="dark"] {
  --ad-band-out:  #1D3A00;
  --ad-band-mid:  #62764C;
  --ad-band-peak: #A3AE93;
  --ad-band-tail: #788964;
}
[data-theme="jazzy"] {
  --ad-band-out:  #EEFCD5;
  --ad-band-mid:  #ECD7FF;
  --ad-band-peak: #DAAFFF;
  --ad-band-tail: #E4C8FF;
}

/* ============================================================
   Project page (e.g. swifts-migration.html)
   ============================================================ */

/* Match homepage above-hero spacing: main already supplies the top
   padding; we add the equivalent of the homepage's top shape-band
   (height + bottom margin) so the hero sits on the same baseline. */
.project-page {
  padding-top: calc(clamp(56px, 10vh, 112px) + clamp(150px, 22vh, 200px) + clamp(20px, 3vh, 32px));
}

.project-hero {
  font-family: var(--font-serif);
  font-size: clamp(30px, 4.7vw, 65px);
  line-height: 1.18;
  font-weight: 300;
  letter-spacing: -0.012em;
  color: var(--fg);
  margin: 0 0 clamp(40px, 6vh, 64px);
  text-wrap: pretty;
}

/* ---------- Filter pills ---------- */

.pill-group {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0 0 clamp(28px, 4vh, 40px);
}

.pill {
  appearance: none;
  -webkit-appearance: none;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--fg);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 7px 14px 8px;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease-out),
              color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out);
}
.pill:hover {
  background: color-mix(in oklab, var(--bg) 88%, var(--fg) 8%);
}
.pill[aria-checked="true"],
.pill[aria-selected="true"] {
  background: var(--pill-active-bg, #FFFCCB);
  color: var(--pill-active-fg, var(--moss-800, #1D3A00));
  border-color: var(--pill-active-bg, #FFFCCB);
}
.pill:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 2px;
}

/* Dark theme: active pill stays butter-yellow but with dark ink for legibility. */
[data-theme="dark"] .pill {
  border-color: var(--border);
}
[data-theme="dark"] .pill[aria-checked="true"],
[data-theme="dark"] .pill[aria-selected="true"] {
  background: #FFFCCB;
  color: #1D3A00;
  border-color: #FFFCCB;
}
[data-theme="jazzy"] .pill[aria-checked="true"],
[data-theme="jazzy"] .pill[aria-selected="true"] {
  background: #DCBDF6;
  color: #1D3A00;
  border-color: #DCBDF6;
}

/* ---------- Visualisation panels ----------
   Each pill controls a sibling .viz-panel inside .viz-area. Inactive
   panels are toggled via the [hidden] attribute (display:none). The
   placeholder fills the same dimensions as the map so swapping pills
   doesn't shift the rest of the page. */
.viz-area {
  position: relative;
}
.viz-panel[hidden] { display: none; }

.viz-placeholder {
  width: 100%;
  height: clamp(380px, 62vh, 620px);
  margin: 0 0 clamp(48px, 8vh, 96px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px dashed var(--border);
  border-radius: 6px;
  background: color-mix(in oklab, var(--bg) 92%, var(--fg) 6%);
  color: var(--fg);
  font-family: var(--font-mono);
  text-align: center;
}
.viz-placeholder__label {
  margin: 0;
  font-size: 18px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.viz-placeholder__note {
  margin: 0;
  font-size: 13px;
  opacity: 0.7;
}
@media (max-width: 760px) {
  .viz-placeholder { height: clamp(320px, 55vh, 480px); }
}

/* ---------- Arrival & departure (composite year strip) ----------
   Single horizontal calendar strip with a three-tier season band, four
   guide-line tooltips, and two average markers. Inherits color: var(--fg)
   so the band gradient (currentColor stops) and marker fills track the
   active theme without per-theme overrides. */
.ad-chart {
  position: relative;
  width: 100%;
  margin: clamp(96px, 14vh, 140px) 0 16px;
  color: var(--fg);
  font-family: var(--font-mono);
}
.ad-svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}

/* Strip outline so the unshaded months still read as part of the year. */
.ad-strip {
  fill: color-mix(in oklab, var(--bg) 92%, var(--fg) 6%);
  stroke: currentColor;
  stroke-opacity: 0.15;
  stroke-width: 1;
}
.ad-band { color: var(--fg); }

/* Month axis below the strip. */
.ad-axis {
  stroke: currentColor;
  stroke-width: 1;
  opacity: 0.32;
}
.ad-tick {
  stroke: currentColor;
  stroke-width: 1;
  opacity: 0.5;
}
.ad-month {
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  fill: currentColor;
  opacity: 0.75;
}

/* Guide lines — focusable hover targets that reveal labelled tooltips. */
.ad-guide-group {
  cursor: default;
  outline: none;
}
.ad-guide-hit {
  fill: transparent;
}
.ad-guide {
  stroke: currentColor;
  stroke-width: 1;
  stroke-dasharray: 2 3;
  opacity: 0.55;
  transition: opacity 120ms var(--ease-out, ease-out);
}
.ad-guide-handle {
  fill: currentColor;
  opacity: 0.75;
  transition: r 120ms var(--ease-out, ease-out), opacity 120ms var(--ease-out, ease-out);
}
.ad-guide-group:hover .ad-guide,
.ad-guide-group:focus-visible .ad-guide {
  opacity: 1;
  stroke-dasharray: none;
}
.ad-guide-group:hover .ad-guide-handle,
.ad-guide-group:focus-visible .ad-guide-handle {
  r: 4;
  opacity: 1;
}
.ad-guide-group:focus-visible .ad-guide-handle {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* Average markers. */
.ad-marker {
  cursor: default;
  outline: none;
  transition: transform 120ms var(--ease-out, ease-out);
}
.ad-marker--arrival {
  fill: currentColor;
  stroke: var(--bg);
  stroke-width: 1.2;
}
.ad-marker--departure {
  fill: var(--bg);
  stroke: currentColor;
  stroke-width: 1.4;
}
.ad-marker:hover,
.ad-marker:focus-visible {
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(1.2);
}
.ad-marker:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* Tooltip — single shared element, positioned above the target. */
.ad-tooltip {
  position: absolute;
  transform: translate(-50%, calc(-100% - 10px));
  background: #F8F1EB;
  color: var(--fg);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.4;
  padding: 8px 10px;
  border-radius: 4px;
  width: max-content;
  max-width: 260px;
  pointer-events: none;
  z-index: 5;
}
[data-theme="dark"] .ad-tooltip {
  background: #29460B;
  color: #F5F5ED;
  border-color: #6E8A4F;
}
[data-theme="jazzy"] .ad-tooltip {
  background: #F4E7FF;
  color: #1D3A00;
  border-color: #1D3A00;
}
.ad-tooltip[hidden] { display: none; }
.ad-tip__year {
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  font-size: 11px;
  margin-bottom: 2px;
}
.ad-tip__date { font-size: 13px; }
.ad-tip__notes {
  margin-top: 6px;
  opacity: 0.78;
  font-size: 11px;
  line-height: 1.45;
}

/* Legend. */
.ad-legend {
  list-style: none;
  margin: 0 0 clamp(48px, 8vh, 96px);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--fg);
}
.ad-legend:has(+ .route-note) { margin-bottom: clamp(20px, 3vh, 32px); }
.ad-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.ad-legend__glyph { flex-shrink: 0; color: currentColor; }
.ad-legend__title {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  margin-right: 4px;
}
.ad-legend__swatch {
  display: inline-block;
  width: 22px; height: 22px;
  background: var(--ad-band-mid, currentColor);
  flex-shrink: 0;
}
.ad-legend__swatch--vanguard  { background: var(--ad-band-mid,  currentColor); }
.ad-legend__swatch--peak      { background: var(--ad-band-peak, currentColor); }
.ad-legend__swatch--departure { background: var(--ad-band-tail, currentColor); }

/* Captions below the chart. */
.ad-captions {
  margin: 0 0 clamp(48px, 8vh, 96px);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ad-caption {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.55;
  color: var(--fg);
  opacity: 0.78;
  max-width: 60ch;
}

.ad-error {
  font-family: var(--font-mono);
  color: var(--fg);
  opacity: 0.7;
  padding: 24px 0;
}

@media (max-width: 760px) {
  .ad-month { font-size: 10px; }
}

/* ============================================================
   Population trend (BBS index 1995–2023)
   ============================================================ */

.pt-chart {
  position: relative;
  width: 100%;
  margin: clamp(96px, 14vh, 140px) 0 16px;
  color: var(--fg);
  font-family: var(--font-mono);
}
.pt-svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}

/* Plot grid lines. Faint by default, the baseline (100) sits on top
   as a dashed reference. */
.pt-grid {
  stroke: currentColor;
  stroke-width: 1;
  opacity: 0.18;
}
.pt-baseline {
  stroke: currentColor;
  stroke-width: 1;
  stroke-dasharray: 3 4;
  opacity: 0.55;
  fill: none;
}

/* Y-axis labels and X-axis ticks/labels. */
.pt-y-label {
  font-size: 11px;
  letter-spacing: 0.04em;
  fill: currentColor;
  opacity: 0.65;
}
.pt-axis {
  stroke: currentColor;
  stroke-width: 1;
  opacity: 0.45;
}
.pt-tick {
  stroke: currentColor;
  stroke-width: 1;
  opacity: 0.5;
}
.pt-year-label {
  font-size: 11px;
  letter-spacing: 0.04em;
  fill: currentColor;
  opacity: 0.7;
}

/* Baseline label sits at top-left of plot, just above the dashed line. */
.pt-baseline-label {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  fill: currentColor;
  opacity: 0.85;
}

/* Filled area under the curve — vertical yellow gradient, saturated at
   the top, fading to near-transparent at the floor. */
.pt-area {
  fill: url(#pt-area-gradient);
}
.pt-grad-top    { stop-color: #FFF997; stop-opacity: 1; }
.pt-grad-bottom { stop-color: #FFF997; stop-opacity: 0.05; }
[data-theme="dark"] .pt-grad-top    { stop-color: #DDF267; stop-opacity: 0.95; }
[data-theme="dark"] .pt-grad-bottom { stop-color: #DDF267; stop-opacity: 0.04; }
[data-theme="jazzy"] .pt-grad-top    { stop-color: #FFB6D5; stop-opacity: 1; }
[data-theme="jazzy"] .pt-grad-bottom { stop-color: #FFB6D5; stop-opacity: 0.05; }

/* Hover handles per year — invisible until focus/hover. */
.pt-handle-group { cursor: default; outline: none; }
.pt-handle-hit { fill: transparent; }
.pt-handle-dot {
  fill: var(--bg);
  stroke: var(--fg);
  stroke-width: 1;
  opacity: 0;
  transition: opacity 120ms var(--ease-out, ease-out), r 120ms var(--ease-out, ease-out);
}
.pt-handle-group:hover .pt-handle-dot,
.pt-handle-group:focus-visible .pt-handle-dot {
  opacity: 1;
  r: 4;
}
.pt-handle-group:focus-visible .pt-handle-dot {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* Pinned annotations: dot + label. */
.pt-annotation-dot {
  fill: #FFF997;
}
[data-theme="jazzy"] .pt-annotation-dot { fill: #FFEE95; }
.pt-annotation-label {
  font-size: 11px;
  letter-spacing: 0.04em;
  fill: currentColor;
  opacity: 0.85;
  font-weight: 500;
}

/* Legend below the chart — same vocabulary as .ad-legend. */
.pt-legend {
  list-style: none;
  margin: 0 0 clamp(20px, 3vh, 32px);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--fg);
}
.pt-legend__title {
  font-family: var(--font-mono);
  margin-right: 4px;
  display: inline-flex;
  align-items: center;
}
.pt-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.pt-legend__swatch {
  display: inline-block;
  width: 22px; height: 12px;
  flex-shrink: 0;
}
.pt-legend__swatch--lost {
  background: #8D7F73;
}
.pt-legend__swatch--remaining {
  background: #B4ABA2;
}
[data-theme="dark"] .pt-legend__swatch--lost {
  background: #788964;
}
[data-theme="dark"] .pt-legend__swatch--remaining {
  background: #A3AE93;
}
[data-theme="jazzy"] .pt-legend__swatch--lost {
  background: #E4C8FF;
}
[data-theme="jazzy"] .pt-legend__swatch--remaining {
  background: #DAAFFF;
}

@media (max-width: 760px) {
  .pt-y-label, .pt-year-label, .pt-annotation-label { font-size: 10px; }
}

/* ---------- Map ---------- */

/* Sized to fill the content column horizontally and comfortably fit
   inside the viewport vertically. clamp keeps it generous on tall
   screens but never taller than ~62vh. */
.map {
  width: 100%;
  height: clamp(380px, 62vh, 620px);
  background: #8D7F73;          /* sea — light mode */
  margin-bottom: clamp(20px, 3vh, 32px);
  position: relative;
  z-index: 0;
}

/* Map legend — horizontal row of stroke-glyph + label pairs sitting
   under the map. Mono type, dark ink, gentle gap. Wraps on narrow
   viewports so the two items stack rather than overflow. */
.map-legend {
  list-style: none;
  margin: 0 0 clamp(20px, 3vh, 32px);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 12px clamp(32px, 6vw, 64px);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.01em;
  color: var(--fg);
}
.map-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 14px;
}
.map-legend__glyph {
  flex-shrink: 0;
  color: var(--fg);
  display: block;
  overflow: visible;
}

/* Short prose note about the migratory route, sits below the map and
   legend. Sans (Plex Sans) so it sits clearly below the serif headline
   and the mono legend without competing with either. */
.route-note {
  max-width: var(--content-w);
  margin: 0 0 clamp(48px, 8vh, 96px);
  font-family: var(--font-serif);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--fg);
  opacity: 0.88;
}
.route-note:has(+ .route-note) {
  margin-bottom: 1em;
}
.route-note + .route-note {
  margin-top: 0;
}
.route-note a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  padding: 0 0.15em;
  border-radius: 2px;
  transition: color var(--dur) var(--ease-out),
              background-color var(--dur) var(--ease-out);
}
.route-note a:hover,
.route-note a:focus-visible {
  color: #4D7C1E;
  background-color: #F4FFE1;
  text-underline-offset: 4px;
}
[data-theme="jazzy"] .route-note a:hover,
[data-theme="jazzy"] .route-note a:focus-visible {
  background-color: #BDFFC7;
}
[data-theme="dark"] .route-note a:hover,
[data-theme="dark"] .route-note a:focus-visible {
  color: #F5F5ED;
  background-color: #52792C;
}

/* Leaflet container fills the map div; sea color sits behind the vector
   land layer. No tile filter — we render flat GeoJSON, not raster. */
.leaflet-container {
  background: #8D7F73;
  font-family: var(--font-mono);
  outline: none;
}

/* Land polygon styling. Flat fill, no stroke, no shadow — pure two-tone
   look matching the reference comment. */
.land-fill {
  fill: #B4ABA2;
  stroke: none;
  filter: none;
}

/* Hide Leaflet's default zoom buttons; map is non-interactive (locked
   bounds + zoom). Attribution stays for licensing. */
.leaflet-control-zoom { display: none !important; }
.leaflet-control-attribution {
  font-family: var(--font-mono);
  font-size: 10px;
  background: rgba(245, 240, 232, 0.7);
}

/* Route line vector styles (applied to <path> elements rendered by
   Leaflet's SVG renderer). Inline stroke/weight come from Leaflet
   options; class is here so themes can override. */
.route-spring {
  stroke: #F4FFE1;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.route-autumn {
  stroke: #F4FFE1;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Static shadow routes — sit beneath the animated trails so the full
   path remains visible at all times. Spring solid, autumn dashed. */
.route-shadow {
  stroke: #6F6154;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Dark theme: deeper sea, slightly lifted land. */
[data-theme="dark"] .map { background: #1F3308; }
[data-theme="dark"] .leaflet-container { background: #1F3308; }
[data-theme="dark"] .land-fill { fill: #3A5A1A; }
[data-theme="dark"] .route-spring { stroke: #F4FFE1; }
[data-theme="dark"] .route-autumn { stroke: #F4FFE1; }
[data-theme="dark"] .route-shadow { stroke: #6C8D4C; }

/* Jazzy theme: warm coral sea against mossy-green land. */
[data-theme="jazzy"] .map { background: #FE9B64; }
[data-theme="jazzy"] .leaflet-container { background: #FE9B64; }
[data-theme="jazzy"] .land-fill { fill: #AEC697; }

/* Hover-target overlays — invisible wide polylines beneath the routes
   that catch pointer events and trigger Leaflet tooltips. The cursor
   change is the only visual feedback we want. */
.route-hover {
  fill: none;
  stroke: transparent;
  cursor: default;
}

/* Route hover tooltips — match the project's other tooltip vocabulary
   (.ad-tooltip): paper bg, dark text, mono type, no shadow. Override
   Leaflet's default white box + drop shadow + arrow. */
.leaflet-tooltip.route-tooltip {
  background: #F8F1EB;
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.4;
  padding: 8px 10px;
  max-width: 260px;
  white-space: normal;
  box-shadow: none;
}
.leaflet-tooltip.route-tooltip strong {
  font-weight: 600;
}
.leaflet-tooltip.route-tooltip::before { display: none; }
[data-theme="dark"] .leaflet-tooltip.route-tooltip {
  background: #29460B;
  color: #F5F5ED;
  border-color: #6E8A4F;
}
[data-theme="jazzy"] .leaflet-tooltip.route-tooltip {
  background: #F4E7FF;
  color: #1D3A00;
  border-color: #1D3A00;
}

/* ---------- Illustration page ----------
   3-column CSS-columns masonry: each <li> flows into a column
   without breaking, and columns balance height automatically — items
   pack tight beneath whatever sits above them, like Pinterest.
   Captions live inside the same <li> so they travel with their image. */
.ill-section-title {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: clamp(32px, 5vh, 56px) 0 clamp(16px, 2.5vh, 24px);
  opacity: 0.78;
}
.ill-section-title:first-child {
  margin-top: 0;
}
.ill-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  column-count: 3;
  column-gap: clamp(12px, 1.5vw, 20px);
}
.ill-grid + .ill-section-title {
  margin-top: clamp(40px, 6vh, 72px);
}
.ill-item {
  margin: 0 0 clamp(12px, 1.5vw, 20px);
  display: block;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
}
.ill-thumb {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  color: inherit;
  border-radius: 4px;
  overflow: hidden;
  transition: transform 200ms var(--ease-out, ease-out), opacity 200ms;
}
.ill-thumb img {
  display: block;
  width: 100%;
  height: auto;
  /* Reserve space before the image decodes so the masonry layout
     doesn't reflow as thumbnails fade in. Per-grid overrides below
     match each section's source ratio. */
  aspect-ratio: 1 / 1;
  /* Soft load-in: start slightly faded and shifted up; settle when
     the img completes. Honours reduced motion. */
  opacity: 0;
  transform: translateY(8px) scale(1.01);
  transition:
    opacity 520ms var(--ease-out, ease-out),
    transform 520ms var(--ease-out, ease-out);
}
.ill-thumb img.is-loaded {
  opacity: 1;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .ill-thumb img,
  .ill-thumb img.is-loaded {
    transition: none;
    opacity: 1;
    transform: none;
  }
}
.ill-thumb:hover { opacity: 0.9; }
.ill-thumb:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}
.ill-caption {
  display: none;
}

/* Per-section aspect ratios so layout is correct pre-decode. */
#ill-grid-cats .ill-thumb img { aspect-ratio: 2048 / 1082; }
#ill-grid-patterns .ill-thumb img { aspect-ratio: 1 / 1; }

@media (max-width: 640px) {
  .ill-grid { column-count: 2; }
}
@media (max-width: 420px) {
  .ill-grid { column-count: 1; }
}

/* Lightbox: full-viewport dim overlay with the image centred. Close,
   prev/next, caption rendered as siblings of the figure so they sit
   above the image and stay clickable. */
body.ill-lb-open { overflow: hidden; }
.ill-lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(20, 24, 18, 0.86);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(24px, 5vh, 64px) clamp(48px, 6vw, 96px);
}
.ill-lightbox[hidden] { display: none; }
.ill-lb__figure {
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}
.ill-lb__img {
  display: block;
  max-width: 100%;
  max-height: calc(100vh - 160px);
  width: auto;
  height: auto;
  object-fit: contain;
}
.ill-lb__caption {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: #F5F0E8;
  opacity: 0.85;
  text-align: center;
}
.ill-lb__close,
.ill-lb__nav {
  position: absolute;
  background: transparent;
  border: 0;
  color: #F5F0E8;
  cursor: pointer;
  padding: 10px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 150ms;
}
.ill-lb__close { top: 16px; right: 16px; }
.ill-lb__nav  { top: 50%; transform: translateY(-50%); }
.ill-lb__nav--prev { left: 16px; }
.ill-lb__nav--next { right: 16px; }
.ill-lb__close svg,
.ill-lb__nav svg { width: 24px; height: 24px; fill: none; }
.ill-lb__close:hover,
.ill-lb__nav:hover { background: rgba(255,255,255,0.12); }
.ill-lb__close:focus-visible,
.ill-lb__nav:focus-visible {
  outline: 2px solid #F5F0E8;
  outline-offset: 2px;
}

@media (max-width: 760px) {
  .project-hero { font-size: clamp(24px, 6.4vw, 32px); max-width: none; }
  .map { height: clamp(320px, 55vh, 480px); }
}
