/* ---------- Colours and fonts ---------- */

:root {
  --paper: #f4eee2;       /* cream background */
  --paper-2: #ebe3d2;     /* slightly darker cream for fills */
  --ink: #1d1b18;         /* main text and lines */
  --ink-2: #4c4840;       /* secondary text */
  --pencil: #8b857a;      /* dimensions and construction lines */
  --faint: #b9b2a4;       /* faded names and arrows */
  --accent: var(--ink);   /* links and hover; dark red in the red version */
  --pin: #b42318;         /* map pins (been there) */
  --want: #3f7a3a;        /* map pins (want to go), the only green on the site */
  --tab: #7c3416;         /* hidden section: dark orange-red-brown */
  --tab-text: #fff8ef;

  --mono: "JetBrains Mono", ui-monospace, Menlo, monospace;
  --font: var(--mono);
  --radius: 14px;

  /* Motion: one place for speeds and curves. assets/js reads these too (Site.motion) */
  --slide-time: 0.5s;                         /* experience names and text sliding */
  --slide-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --roll-time: 0.75s;                         /* projects rolling along the curve */
  --roll-follow-time: 0.6s;                   /* the v arrow and section height following them */
  --roll-ease: cubic-bezier(0.55, 0, 0.3, 1);
  --close-time: 0.8s;                         /* loading animation: spread-out text closing back up */
  --close-ease: cubic-bezier(0.65, 0, 0.35, 1);

  --trip-panel-w: 320px;                      /* Trips Map: width of the photo panel */
}


/* ---------- Page ---------- */

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.6;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ink); text-decoration: none; }
a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
a:focus-visible, button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.page {
  max-width: 1000px;
  margin: 0 auto;
  padding: 0 24px;
}

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

.hero {
  position: relative;
  margin-top: 64px;
  padding: 40px 44px 36px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 32px;
}

/* The drawn border and dimensions sit on top of the box */
.sketch {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.sketch .edge { fill: none; stroke: var(--ink); stroke-width: 1.5; stroke-linecap: round; }
.sketch .construction { fill: none; stroke: var(--pencil); stroke-width: 1; stroke-dasharray: none; }
.sketch .dim path, .sketch .dim line, .sketch .dim circle { fill: none; stroke: var(--pencil); stroke-width: 1; }
.sketch .dim .head { fill: var(--pencil); stroke: none; }
.sketch .dim text {
  font-family: var(--mono);
  font-size: 11px;
  fill: var(--pencil);
  paint-order: stroke;
  stroke: var(--paper);
  stroke-width: 4px;
}
.sketch.fine .dim text { font-size: 9px; stroke-width: 3px; } /* smaller numbers, for small text */
.sketch .temp { transition: opacity 0.4s ease; }
.sketch .temp.gone { opacity: 0; }

.name {
  margin: 0;
  font-size: clamp(40px, 7vw, 68px);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
/* Text while the loading animation draws it (assets/js/textdims.js): letters or words in their own
   spans so they can spread out and close back up */
.tx-word { white-space: nowrap; }
.tx-letter, .tx-move {
  display: inline-block;
  transition: transform var(--close-time) var(--close-ease), opacity 0.25s ease;
}
/* --tx-dy: how far down the element's first line has moved, for marks drawn by CSS (a bullet's dash)
   to move with it. tx-still: it jumps there without sliding. */
.tx-still::before { transition: none !important; }

/* Read by screen readers, not shown */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.tagline { margin: 14px 0 0; color: var(--ink-2); }

.links { display: flex; gap: 22px; margin: 14px 0 0; padding: 0; list-style: none; }
.links a { color: var(--ink-2); }

.nav { display: flex; flex-direction: column; gap: 10px; padding-top: 10px; min-width: 260px; }
.nav-row { display: flex; justify-content: space-between; gap: 28px; }
.nav-row:nth-child(2) { justify-content: center; }
.nav a { font-size: 15px; }

/* ---------- Loading animation states ---------- */

/* Before it starts (fonts and content still loading): an empty page */
.waiting .name { visibility: hidden; }
.waiting .sections,
.waiting .footer { opacity: 0; }

/* While it draws: the nav, the tagline, the links and the photos wait, and come in at the end.
   (The resume, the Spotify player and the map come in with the text: assets/js/intro.js.) */
.intro .nav-row,
.intro .tagline,
.intro .links li,
.intro .xphotos { opacity: 0; }

.nav-row, .links li, .tagline, .sections, .footer, .xphotos {
  transition: opacity 0.35s ease, transform 0.35s ease;
}
.intro .nav-row { transform: translateY(-8px); }
.intro .tagline, .intro .links li { transform: translateX(-8px); }

/* "(press r to run animation again)": at the middle of the right edge while the animation draws.
   It fades as everything closes up, before the photos come in. */
.replay-hint {
  position: fixed;
  top: 50%;
  right: 16px;
  z-index: 30;
  margin: 0;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--paper);
  color: var(--ink-2);
  font-size: 13px;
  transform: translateY(-50%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease;
}
.sketching .replay-hint { opacity: 1; }
@media (hover: none) { .replay-hint { display: none; } } /* phones and tablets have no r key */

/* ---------- Sections ---------- */

.section { margin-top: 120px; scroll-margin-top: 32px; }
#experience { margin-top: 76px; } /* first section sits a little closer to the header */
.section-title { margin: 0 0 32px; font-size: 22px; font-weight: 700; }

.bullets { margin: 0; padding: 0; list-style: none; }
.bullets li { position: relative; padding-left: 20px; margin-bottom: 8px; }
.bullets li::before {
  content: "-"; position: absolute; left: 2px; color: var(--ink-2);
  translate: 0 var(--tx-dy, 0px); /* stays beside its line while the loading animation spreads the lines apart */
  transition: translate var(--close-time) var(--close-ease);
}

/* Shake when there's nothing in that direction */
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-4px); }
  40% { transform: translateX(4px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}
.shake { animation: shake 0.35s ease; }

/* ---------- Experience ---------- */

.xrow { margin-bottom: 64px; }
.xrow:last-child { margin-bottom: 0; }

/* Heading:  prev  <  current  >  next   (the sliding is done in assets/js/experience.js) */
.xhead { position: relative; display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; font-size: 20px; }
.xhead button { font: inherit; background: none; border: 0; padding: 0; cursor: pointer; color: inherit; white-space: nowrap; }
.xname { margin: 0; font-size: 20px; line-height: 1.3; transition: color var(--slide-time) var(--slide-ease); }
.xname.current { font-weight: 700; cursor: default !important; }
.xname.side { color: var(--faint); }
.xname.side:hover { color: var(--ink-2); }
.xname.ghost { position: absolute; pointer-events: none; } /* copy of a name sliding out of view */
.xarrow { display: inline-block; padding: 0 2px !important; color: var(--ink) !important; }
.xarrow:hover { color: var(--accent) !important; }
.xarrow[aria-disabled="true"] { color: var(--faint) !important; cursor: default; }

.xstage { position: relative; }
.xstage.moving { overflow-y: clip; } /* while switching, the old text can't spill onto the next row */
.xbody {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 40px;
  padding-top: 18px;
}
.xbody.no-photos { grid-template-columns: minmax(0, 1fr); }
.xbody.leaving { position: absolute; top: 0; left: 0; width: 100%; pointer-events: none; }
.entry-name { margin: 0; font-size: 17px; font-weight: 700; }
.entry-name a { text-decoration: underline; text-decoration-color: var(--faint); text-underline-offset: 4px; }
.entry-name a:hover { text-decoration-color: currentColor; }
.entry-sub { margin: 2px 0 14px; color: var(--ink-2); }

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

.section-title.center { text-align: center; letter-spacing: 0.08em; }

/* Heights and positions are set by assets/js/projects.js */
.wheel {
  position: relative;
  overflow-x: visible;
  overflow-y: clip;   /* projects rolling away disappear at the top/bottom edge */
  min-height: 260px;
  transition: height var(--roll-follow-time) var(--roll-ease); /* grows/shrinks to the project showing */
}

.chev {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  display: block;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  transition: top var(--roll-follow-time) var(--roll-ease), color 0.2s ease;
}
.chev svg { display: block; width: 100%; height: 100%; overflow: visible; }
.chev path { fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.chev::after { content: ""; position: absolute; inset: -10px; } /* bigger click area */
.chev:hover { color: var(--accent); }

.pcard {
  position: absolute;
  left: 0;
  width: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  gap: 40px;
  align-items: start;
  opacity: 0;
  transition: transform var(--roll-time) var(--roll-ease), opacity 0.5s ease;
}
.pcard.on { opacity: 1; transition: transform var(--roll-time) var(--roll-ease), opacity 0.6s ease 0.15s; }
.pcard.no-photos { grid-template-columns: minmax(0, 1fr); }
.ptools { margin: 14px 0 0; font-size: 13px; color: var(--ink-2); }
.plink { display: inline-block; margin-top: 10px; }

/* ---------- Resume ---------- */

.resume-head { display: flex; flex-direction: column; margin-bottom: 12px; }
.resume-head .section-title { margin: 0 0 18px; }
.resume-hint { align-self: center; color: var(--ink-2); font-size: 14px; }

/* A centred box with the page standing in the middle; hovering slowly scrolls down the page */
.resume-box {
  position: relative;
  display: block;
  width: 100%;
  max-width: 680px;
  height: 440px;
  margin: 0 auto;
  overflow: hidden;
  border: 1.5px solid var(--ink);
  border-radius: var(--radius);
  background: var(--paper-2);
}
.resume-box img {
  display: block;
  width: 82%;
  margin: 0 auto;
  border-left: 1.5px solid var(--ink);
  border-right: 1.5px solid var(--ink);
  transition: transform 5s ease-in-out;
}
.resume-box:hover img, .resume-box:focus-visible img { transform: translateY(calc(-100% + 440px)); }
.resume-box:hover { text-decoration: none; }

/* ---------- Top 10 Songs ---------- */

.spotify { display: block; width: 100%; height: 352px; border: 0; border-radius: 12px; }

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

.title-note { font-size: 14px; font-weight: 400; color: var(--ink-2); margin-left: 6px; }

.map-frame {
  border: 1.5px solid var(--ink);
  border-radius: var(--radius);
  padding: 28px 24px;
}
.map-stage { position: relative; }
.world { display: block; width: 100%; height: auto; overflow: visible; }
.world path {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 0.9;
  stroke-linejoin: round;
  transition: fill 0.5s ease;
}
.map-frame.drawn .world path { fill: var(--paper-2); }
.map-frame.resetting, .map-frame.resetting * { transition: none !important; } /* back to blank for a replay (assets/js/map.js) */

.pin {
  position: absolute;
  width: 20px;
  height: 28px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transform: translate(-50%, -100%) translateY(-14px);
  opacity: 0;
  transition: opacity 0.3s ease, transform 0.35s cubic-bezier(0.3, 1.6, 0.6, 1);
  transition-delay: calc(var(--n) * 60ms);
}
.map-frame.drawn .pin { opacity: 1; transform: translate(-50%, -100%); }
.pin svg { display: block; width: 100%; height: 100%; overflow: visible; }
.pin path { fill: var(--pin); stroke: var(--ink); stroke-width: 0.8; }
.pin circle { fill: var(--paper); }
.pin.want path { fill: var(--want); }
.map-frame.drawn .pin:hover, .map-frame.drawn .pin.active { transform: translate(-50%, -100%) scale(1.2); transition-delay: 0s; }

/* Photo panel: closed it has no width; clicking a pin slides it in on the left and the map narrows.
   The inside keeps its full width the whole time, so the text never re-wraps while it slides. */
.map-wrap { display: flex; align-items: flex-start; }
.map-wrap.measuring, .map-wrap.measuring * { transition: none !important; } /* map.js measuring sizes */
.map-wrap.resizing { overflow-y: clip; }   /* while the height eases, nothing spills out */
.map-stage { flex: 1 1 0; min-width: 0; }
.trip-panel {
  flex: 0 0 0px;
  overflow: hidden;
  transition: flex-basis var(--slide-time) var(--slide-ease), margin-right var(--slide-time) var(--slide-ease);
}
.map-wrap.open .trip-panel { flex-basis: var(--trip-panel-w); margin-right: 28px; }
.trip-inner {
  width: var(--trip-panel-w);
  opacity: 0;
  transform: translateX(-24px);
  transition: opacity var(--slide-time) var(--slide-ease), transform var(--slide-time) var(--slide-ease);
}
.map-wrap.open .trip-inner { opacity: 1; transform: none; }
.trip-inner p { margin: 0; }
.trip-name { font-weight: 700; }
.trip-place { color: var(--ink-2); }
.trip-inner .trip-text { margin: 10px 0 14px; }

/* ---------- Photo galleries ---------- */

.gallery {
  position: relative;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--ink);
  border-radius: 10px;
  overflow: hidden;
  background: var(--paper-2);
}
.gallery .slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.gallery .slide.on { opacity: 1; }
.gbtn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  padding: 6px 10px;
  border: 0;
  border-radius: 6px;
  background: rgba(244, 238, 226, 0.88);
  color: var(--ink);
  font: 16px var(--mono);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.gbtn.prev { left: 8px; }
.gbtn.next { right: 8px; }
.gallery:hover .gbtn, .gallery:focus-within .gbtn { opacity: 1; }
@media (hover: none) { .gbtn { opacity: 0.85; } }
.gcount {
  position: absolute;
  right: 8px;
  bottom: 6px;
  padding: 0 6px;
  border-radius: 4px;
  background: rgba(244, 238, 226, 0.88);
  font: 11px var(--mono);
  color: var(--ink-2);
}
.gcount:empty { display: none; }

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

.footer { margin: 60px 0 28px; color: var(--ink-2); font-size: 13px; }

/* ---------- Hidden section (bottom of the page, full window width) ---------- */

.intro .shh { opacity: 0; }
.shh { width: 100%; }

/* The band you pull up: glued to the bottom of the window, full width, 0 tall until pulled.
   assets/js/hidden.js sets its height and moves the page up by the same amount. */
.shh-strip {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  align-items: baseline;
  gap: 2px 14px;
  height: 0;
  padding: 0 12px;
  background: var(--tab);
  color: var(--tab-text);
  overflow: hidden;
  pointer-events: none;
}
.shh-word { line-height: 1.1; white-space: nowrap; }
.shh-strip.settling { transition: height 0.09s ease-out; }
.page.settling { transition: transform 0.09s ease-out; }

/* The panel it opens into: 30% of the window tall, against the far left edge */
.shh-tab {
  position: relative;
  min-height: 30vh;
  padding: 28px 24px 32px;
  background: var(--tab);
  color: var(--tab-text);
  text-align: left;
}
.shh-title { margin: 0 0 18px; font-size: 22px; font-weight: 700; }
.shh-list { margin: 0; padding: 0; list-style: none; font-size: 16px; }
.shh-list li { position: relative; padding-left: 22px; margin-bottom: 10px; }
.shh-list li::before { content: "-"; position: absolute; left: 2px; opacity: 0.7; }

/* ---------- Phones ---------- */

@media (max-width: 720px) {
  .page { padding: 0 16px; }
  .hero { flex-direction: column; gap: 22px; margin-top: 40px; padding: 28px 22px 24px; }
  .nav { min-width: 0; width: 100%; padding-top: 0; }
  .nav-row, .nav-row:nth-child(2) { justify-content: flex-start; }
  .links { gap: 18px; }
  .section { margin-top: 88px; }
  .xbody { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .xhead, .xname { font-size: 18px; }
  .pcard { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .resume-box { height: 300px; }
  .title-note { display: block; margin: 4px 0 0; }
  .map-frame { padding: 16px 10px; }
  .pin { width: 15px; height: 21px; }
  .map-wrap { flex-direction: column-reverse; }   /* the photo panel opens under the map */
  .map-stage { flex: none; width: 100%; }
  .trip-panel {
    flex: none;
    width: 100%;
    max-height: 0;
    transition: max-height var(--slide-time) var(--slide-ease), margin var(--slide-time) var(--slide-ease);
  }
  .map-wrap.open .trip-panel { flex-basis: auto; max-height: 1000px; margin: 20px 0 0; } /* height fits the trip */
  .trip-inner { width: 100%; transform: translateY(-12px); }
  .resume-box:hover img, .resume-box:focus-visible img { transform: translateY(calc(-100% + 300px)); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
