/* ---------- Palette ----------
   Dark is the default, so it lives on bare :root; [data-theme="light"] is the
   override the toggle sets (see assets/js/theme.js). The globe reads these same
   variables at runtime (assets/js/globe.js), so recolouring the earth never
   means touching JavaScript.

   The dark set follows the Claude app: warm near-black ground, ivory text,
   clay accent. The light set is the original cream palette, unchanged. */
:root {
  color-scheme: dark;
  --bg: #1F1E1D;
  --ink: #F5F4EF;
  --muted: #A5A298;
  --band: #D97757;
  /* globe */
  --sea-deep: #33496E;
  --sea-shallow: #6BA0C7;
  --forest: #4C9873;
  --grass: #A6C468;
  --desert: #E0A964;
  --ice: #F2EFE7;
  /* panels */
  --surface: #262624;
  --rule: #3A3935;
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg: #ECE8DD;
  --ink: #1B2552;
  --muted: #4E5884;
  --band: #2F6F62;
  --sea-deep: #3D5A9E;
  --sea-shallow: #8FB8D9;
  --forest: #2F6F4E;
  --grass: #7FA650;
  --desert: #D9A24E;
  --ice: #FFFFFF;
  --surface: #F5F2EA;
  --rule: #D3CDBD;
}

/* ---------- Base ---------- */
* { box-sizing: border-box; margin: 0; }
html, body { height: 100%; }

body {
  background: var(--bg);
  color: var(--ink);
  font: 400 1.05rem/1.6 Manrope, system-ui, sans-serif;
  overflow: hidden;
}

a:focus-visible { outline: 2px solid var(--band); outline-offset: 6px; }
/* Icon sprite holder: present in the DOM, never painted. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ---------- Globe canvas ---------- */
#globe { position: fixed; inset: 0; width: 100%; height: 100%; }

/* ---------- Corner navigation ---------- */
.slot {
  position: fixed;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: clamp(.9rem, 2vw, 1.5rem);
}
.tl { top: clamp(1.25rem, 4vw, 2.5rem); left: clamp(1.25rem, 4vw, 3rem); }
.tr { top: clamp(1.25rem, 4vw, 2.5rem); right: clamp(1.25rem, 4vw, 3rem); }
.bl { bottom: clamp(1.25rem, 4vw, 2.5rem); left: clamp(1.25rem, 4vw, 3rem); }
.br { bottom: clamp(1.25rem, 4vw, 2.5rem); right: clamp(1.25rem, 4vw, 3rem); }

/* A panel covers two of the four corners. Leaving those links floating on top
   of it makes them read as the panel's own buttons, so they step aside. */
.slot { transition: opacity .35s, visibility 0s; }
:root[data-panel="left"] .slot.tl,
:root[data-panel="left"] .slot.bl,
:root[data-panel="right"] .slot.tr,
:root[data-panel="right"] .slot.br {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .25s, visibility 0s .25s;
}

.corner {
  color: var(--ink);
  text-decoration: none;
  font-size: clamp(1rem, 1.6vw, 1.2rem);
  font-weight: 500;
  line-height: 1;
  padding: .5rem 0;
  border-bottom: 1.5px solid transparent;
  transition: border-color .2s;
}
.corner:hover,
.corner:focus-visible,
.corner[aria-current="page"] { border-color: var(--band); }
.corner:focus-visible { outline: 2px solid var(--band); outline-offset: 6px; }

/* ---------- Theme toggle ---------- */
.theme-toggle {
  display: flex;
  align-items: center;
  font: inherit;
  background: none;
  border: 0;
  border-bottom: 1.5px solid transparent;
  padding: .4rem 0;
  color: var(--ink);
  cursor: pointer;
}
.theme-toggle .icon { width: 1.15rem; height: 1.15rem; }
.theme-toggle:hover { color: var(--band); }
.icon-moon { display: none; }
:root[data-theme="light"] .icon-sun { display: none; }
:root[data-theme="light"] .icon-moon { display: block; }

/* ---------- Intro, centred under the globe ---------- */
.intro {
  position: fixed;
  z-index: 2;
  left: 50%;
  bottom: clamp(4.5rem, 9vh, 6rem);
  transform: translateX(-50%);
  width: min(46rem, calc(100% - 2.5rem));
  text-align: center;
  pointer-events: none;
  transition: opacity .5s .25s;
}
.intro > * { pointer-events: auto; }
.intro.away {
  opacity: 0;
  visibility: hidden;
  transition: opacity .25s, visibility 0s .25s;
}

h1 {
  font-weight: 700;
  font-size: clamp(2.25rem, 6vw, 4.25rem);
  line-height: 1;
  letter-spacing: -.035em;
  margin-bottom: .6rem;
}
.intro p { color: var(--muted); max-width: 32rem; margin-inline: auto; }
.role { color: var(--ink); font-weight: 500; font-size: 1.15rem; margin-bottom: .35rem; }

/* The name is the joke: pigeon + geom. The globe tells the other half of it,
   with an origami pigeon folded into the coastlines. */
.pun { margin-top: 1.4rem; font-size: .88rem; letter-spacing: .005em; }
.pun span { color: var(--band); font-weight: 500; }

/* ---------- Section panels ----------
   Each slides in from the side opposite the corner link that opened it. */
.panel {
  position: fixed;
  z-index: 2;
  top: 0;
  bottom: 0;
  right: 0;
  width: min(44rem, 62vw);
  background: var(--surface);
  border-left: 1px solid var(--rule);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform .7s cubic-bezier(.2, .9, .25, 1), visibility 0s .7s;
}
.panel[data-side="left"] {
  right: auto;
  left: 0;
  border-left: 0;
  border-right: 1px solid var(--rule);
  transform: translateX(-100%);
}

.panel.open {
  transform: none;
  visibility: visible;
  transition: transform .7s cubic-bezier(.2, .9, .25, 1), visibility 0s;
}

/* Without JavaScript, nothing sets .open, so plain #hash links take over.
   Scoped to .no-js because Chrome keeps matching :target after history.pushState
   has already dropped the fragment, which would wedge a panel open. */
.no-js .panel:target {
  transform: none;
  visibility: visible;
  transition: none;
}

/* The scrolling area stops short of the corner links, so text never runs under them. */
.panel-body {
  position: absolute;
  inset: 5.5rem 0 5rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 clamp(1.5rem, 4vw, 3.5rem) 2rem;
}

.close {
  font: inherit;
  font-weight: 500;
  font-size: .95rem;
  color: var(--ink);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: .4rem 1rem;
  cursor: pointer;
}
.close:hover { border-color: var(--band); }
.close:focus-visible { outline: 2px solid var(--band); outline-offset: 3px; }

.panel h2 {
  font-size: clamp(2.25rem, 4.5vw, 3.25rem);
  font-weight: 700;
  letter-spacing: -.035em;
  line-height: 1.05;
  margin: 1.75rem 0 .75rem;
}
.panel h2:focus { outline: none; }
.lede { color: var(--muted); max-width: 34rem; margin-bottom: 2.5rem; }

/* ---------- Project entries ---------- */
.project { padding: 1.75rem 0; border-top: 1px solid var(--rule); }
.project h3,
.project h4 { font-size: 1.3rem; font-weight: 700; letter-spacing: -.015em; line-height: 1.3; }

/* label above a run of smaller entries, e.g. "Other projects" */
.group-title {
  margin-top: 3rem;
  font-size: 1rem;
  font-weight: 500;
  color: var(--muted);
}
.project .meta { color: var(--band); font-weight: 500; font-size: .95rem; margin: .2rem 0 .65rem; }
.project p { max-width: 36rem; }
.project p + p { margin-top: .7rem; }
.project h3 + p,
.project h4 + p { margin-top: .5rem; }   /* entries without a .meta line */
.project .stack { color: var(--muted); font-size: .95rem; margin-top: .65rem; }

.links { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1rem; }
.links a {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  color: var(--ink);
  text-decoration: none;
  font-weight: 500;
  font-size: .95rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: .35rem .9rem;
}
.links a:hover { border-color: var(--band); }

/* Line icons drawn in the sprite, inked with the current text colour. */
.icon {
  width: 1.05rem;
  height: 1.05rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* GitHub's Invertocat ships as a solid black mark, so it is used as an image
   rather than recoloured. On the dark theme it is inverted, which is exactly
   the official white version. */
.icon-github { width: 1.05rem; height: 1.05rem; display: block; filter: invert(1); }
:root[data-theme="light"] .icon-github { filter: none; }

/* ---------- Phones: panels become a bottom sheet ---------- */
@media (max-width: 719px) {
  .panel,
  .panel[data-side="left"] {
    top: 28vh;
    left: 0;
    right: 0;
    width: 100%;
    border: 0;
    border-top: 1px solid var(--rule);
    border-radius: 1.25rem 1.25rem 0 0;
    transform: translateY(100%);
  }
  .panel-body { inset: 1.5rem 0 4.25rem; padding: 0 1.25rem 1.5rem; }

  /* the sheet always rises from the bottom, so it is the bottom corners that go */
  :root[data-panel] .slot.tl,
  :root[data-panel] .slot.tr {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity .35s, visibility 0s;
  }
  :root[data-panel] .slot.bl,
  :root[data-panel] .slot.br {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity .25s, visibility 0s .25s;
  }
  .panel.open,
  .no-js .panel:target { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .panel,
  .panel.open,
  .slot,
  .intro,
  .intro.away { transition: none; }
}
