/* ============================================================
   Samuel Edungbola — blueprint survey route
   Light theme = whiteprint (pale ground, blue ink)
   Dark theme  = cyanotype (Prussian ground, pale ink)
   ============================================================ */

/* ---------- TOKENS ---------- */
:root{
  --bg:#F1F3F2;
  --bg-elevated:#FFFFFF;
  --bar-bg:#FFFFFF;
  --grid:rgba(22,58,86,0.10);
  --grid-strong:rgba(22,58,86,0.18);
  --ink:#173A55;
  --ink-soft:#4A6980;
  /* #7E97A8 sat at 2.74:1 on --bg and failed WCAG AA. This clears it at
     4.74:1 on the page ground and 5.28:1 on card white. */
  --ink-faint:#526F86;
  --accent:#C2401B;
  --accent-soft:rgba(194,64,27,0.12);
  --rule:rgba(23,58,85,0.22);
  --card-bg:rgba(255,255,255,0.55);
  --card-bg-solid:rgba(255,255,255,0.88);

  --font-display:"Big Shoulders Display","Arial Narrow","Helvetica Neue Condensed",sans-serif;
  --font-body:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",Arial,sans-serif;
  --font-mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --font-hand:"Architects Daughter","Bradley Hand",cursive;

  --bar-h:78px;
}

/* The cyanotype palette is declared twice on purpose: once for the system
   preference, once for the explicit data-theme override. CSS can't share a
   declaration block across a media query and a plain selector, and the
   light-dark() function that would collapse them isn't safe on older Safari
   — a bad fallback here means unstyled text, so the duplication stays. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --bg:#0B2A43;
    --bg-elevated:#0F3555;
    --bar-bg:#0F3555;
    --grid:rgba(220,238,248,0.07);
    --grid-strong:rgba(220,238,248,0.13);
    --ink:#E7F1F7;
    --ink-soft:#A9C6D9;
    --ink-faint:#75A6C6;
    --accent:#FF7A50;
    --accent-soft:rgba(255,122,80,0.18);
    --rule:rgba(220,238,248,0.28);
    --card-bg:rgba(15,53,85,0.55);
    --card-bg-solid:rgba(15,53,85,0.90);
  }
}
:root[data-theme="dark"]{
  --bg:#0B2A43;
  --bg-elevated:#0F3555;
  --bar-bg:#0F3555;
  --grid:rgba(220,238,248,0.07);
  --grid-strong:rgba(220,238,248,0.13);
  --ink:#E7F1F7;
  --ink-soft:#A9C6D9;
  --ink-faint:#75A6C6;
  --accent:#FF7A50;
  --accent-soft:rgba(255,122,80,0.18);
  --rule:rgba(220,238,248,0.28);
  --card-bg:rgba(15,53,85,0.55);
  --card-bg-solid:rgba(15,53,85,0.90);
}

/* ---------- BASE ---------- */
*{ box-sizing:border-box; }

html{
  scroll-behavior:smooth;
  /* keeps form controls, scrollbars and the UA's own chrome in the right theme */
  color-scheme:light dark;
}
:root[data-theme="light"]{ color-scheme:light; }
:root[data-theme="dark"]{ color-scheme:dark; }

body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font-body);
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

h1,h2,h3{
  font-family:var(--font-display);
  text-wrap:balance;
  margin:0;
  color:var(--ink);
}
p{ text-wrap:pretty; }
a{ color:var(--accent); }

::selection{ background:var(--accent); color:#fff; }

a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:3px;
  border-radius:2px;
}
/* Both take focus programmatically after an in-page jump (sections from the
   wayfinder, main from the skip link) so screen-reader focus actually moves.
   Neither should draw a ring around a whole screenful of content.
   The [tabindex="-1"] is needed to out-specify [tabindex]:focus-visible above —
   a bare `main:focus-visible` loses to it and the outline still paints. */
main[tabindex="-1"]:focus-visible,
section[tabindex="-1"]:focus-visible{ outline:none; }

.mono{ font-family:var(--font-mono); }

.eyebrow{
  font-family:var(--font-mono);
  font-size:.72rem;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--ink-faint);
  margin:0;
}

.skip-link{
  position:absolute; left:12px; top:-64px; z-index:100;
  background:var(--bg-elevated); color:var(--ink);
  border:1.5px solid var(--accent); border-radius:2px;
  padding:10px 16px; text-decoration:none;
  font-family:var(--font-mono); font-size:.78rem;
  transition:top .18s ease;
}
.skip-link:focus{ top:12px; }

/* ---------- BLUEPRINT GROUND ---------- */
.grid-ground{
  position:fixed; inset:0; z-index:0; pointer-events:none;
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px),
    linear-gradient(var(--grid-strong) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-strong) 1px, transparent 1px);
  background-size:16px 16px, 16px 16px, 96px 96px, 96px 96px;
  background-position:center top;
}
.grid-ground::after{
  content:"";
  position:absolute; inset:0;
  background:radial-gradient(ellipse at 50% 0%, transparent 0%, var(--bg) 78%);
}

.sheet{ position:relative; z-index:1; }

/* ---------- TOP PROGRESS HAIRLINE ---------- */
.progress-rail{
  position:fixed; top:0; left:0; right:0; height:3px; z-index:50;
  background:var(--rule); opacity:.3;
}
.progress-fill{
  height:100%; width:100%;
  background:var(--accent);
  /* scaleX composites; animating width would relayout on every scroll frame */
  transform:scaleX(0);
  transform-origin:left center;
}

/* ============================================================
   WAYFINDER — one nav, two layouts.
   Base styles below 900px: a fixed bottom station bar.
   From 900px up: the vertical left rail.
   ============================================================ */
.wayfinder{
  position:fixed; left:0; right:0; bottom:0; z-index:40;
  background:var(--bar-bg);
  border-top:1.5px solid var(--rule);
  padding:9px 16px calc(9px + env(safe-area-inset-bottom, 0px));
  box-shadow:0 -6px 20px rgba(0,0,0,.06);
}

.wf-readout{
  display:flex; align-items:baseline; gap:9px;
  margin:0 0 7px;
  font-family:var(--font-mono);
  font-size:.68rem; letter-spacing:.14em; text-transform:uppercase;
  line-height:1;
}
.wf-readout-num{ color:var(--accent); font-weight:600; }
.wf-readout-name{ color:var(--ink-soft); }

.wf-track{
  /* the connector geometry below is derived from this count */
  --wf-count:8;
  --wf-progress:0;
  list-style:none; margin:0; padding:0;
  position:relative;
  display:flex;
}
/* full-width connector, drawn from the first dot's centre to the last */
.wf-track::before,
.wf-track::after{
  content:"";
  position:absolute; top:50%;
  height:2px; margin-top:-1px;
  left:calc(100% / var(--wf-count) / 2);
}
.wf-track::before{
  right:calc(100% / var(--wf-count) / 2);
  background:var(--rule); opacity:.55;
}
/* travelled portion, driven by --wf-progress (0–1) from JS */
.wf-track::after{
  width:calc((100% - (100% / var(--wf-count))) * var(--wf-progress));
  background:var(--accent);
  transition:width .35s cubic-bezier(.16,.8,.3,1);
}

.wf-item{ flex:1 1 0; display:flex; }
.wf-stop{
  position:relative; z-index:1;
  flex:1 1 auto;
  display:flex; align-items:center; justify-content:center;
  padding:11px 0;
  text-decoration:none;
  font-family:var(--font-mono);
  -webkit-tap-highlight-color:transparent;
}
.wf-dot{
  width:10px; height:10px; border-radius:50%;
  border:1.5px solid var(--ink-faint);
  background:var(--bar-bg);
  flex:none;
  transition:background-color .25s ease, border-color .25s ease, box-shadow .25s ease;
}
.wf-stop.is-done .wf-dot{
  background:var(--ink-faint);
  border-color:var(--ink-faint);
}
.wf-stop[aria-current] .wf-dot{
  background:var(--accent);
  border-color:var(--accent);
  box-shadow:0 0 0 4px var(--accent-soft);
}
/* the per-stop label is redundant on mobile — .wf-readout names the station —
   but it stays in the accessibility tree as each link's name */
.wf-label{
  position:absolute;
  width:1px; height:1px;
  padding:0; margin:-1px;
  overflow:hidden; clip-path:inset(50%);
  white-space:nowrap; border:0;
}

@media (min-width:900px){
  .wayfinder{
    left:28px; right:auto; bottom:auto; top:50%;
    transform:translateY(-50%);
    background:none; border:none; box-shadow:none; padding:0;
  }
  .wf-readout{ display:none; }

  .wf-track{ flex-direction:column; }
  .wf-track::before,
  .wf-track::after{ content:none; }

  .wf-item{ flex:none; flex-direction:column; align-items:flex-start; }
  /* vertical segment between consecutive stops; 4px centres it under a 10px dot */
  .wf-item + .wf-item::before{
    content:"";
    width:2px; height:22px;
    margin-left:4px;
    background:var(--rule); opacity:.5;
  }

  .wf-stop{
    flex:none;
    justify-content:flex-start;
    gap:10px;
    padding:9px 0;
  }
  .wf-dot{ background:var(--bg); }
  /* stations already passed read as filled, same as the mobile bar — the rail
     shows route travelled, not just current position */
  .wf-stop.is-done .wf-dot{ background:var(--ink-faint); border-color:var(--ink-faint); }

  .wf-label{
    position:static;
    width:auto; height:auto;
    margin:0; overflow:visible; clip-path:none;
    font-size:.66rem; letter-spacing:.1em; text-transform:uppercase;
    color:var(--ink-faint);
    opacity:0; transform:translateX(-4px);
    transition:opacity .2s ease, transform .2s ease;
  }
  /* :focus-visible matters here — a keyboard user tabbing the rail would
     otherwise meet eight unlabelled dots */
  .wf-stop:hover .wf-label,
  .wf-stop:focus-visible .wf-label{ opacity:1; transform:translateX(0); }
  .wf-stop[aria-current] .wf-label{ opacity:1; transform:translateX(0); color:var(--ink); }
}

/* ---------- SHARED LAYOUT ---------- */
.wrap{ max-width:920px; margin:0 auto; padding:0 32px; }
/* 32px of gutter either side of a 20px card inset costs a phone ~100px of
   measure, which was breaking body copy into four- and five-word lines */
@media (max-width:600px){ .wrap{ padding:0 18px; } }
section{ position:relative; padding:min(18vh,150px) 0; }
/* must track the bar's real height, which grows by the home-indicator inset
   on iPhone — headless browsers report that as 0 and hide the difference */
main.sheet{ padding-bottom:calc(var(--bar-h) + env(safe-area-inset-bottom, 0px)); }
@media (min-width:900px){ main.sheet{ padding-bottom:0; } }

.rule{ border:none; border-top:1.5px solid var(--rule); margin:0 0 22px; }

.stationmark{
  display:flex; align-items:baseline; gap:14px;
  margin:0 0 20px;
}
.stationmark .num{
  font-family:var(--font-display); font-weight:900; font-size:2.1rem;
  color:var(--accent); line-height:1;
}

.section-title{ font-size:clamp(1.8rem,4.6vw,2.6rem); font-weight:800; }

/* ---------- HERO ---------- */
.hero{
  min-height:100vh;
  min-height:100svh;
  display:flex; flex-direction:column; justify-content:center;
  padding-top:12vh;
}
.hero .rose{ width:78px; height:78px; margin-bottom:26px; opacity:.9; }
.hero .rose path,
.hero .rose circle,
.hero .rose line{ stroke:var(--ink); }
.hero h1{
  font-size:clamp(2.6rem,7.2vw,5.4rem);
  font-weight:900;
  letter-spacing:-.01em;
  line-height:.96;
}
.hero .role{
  font-family:var(--font-mono);
  font-size:clamp(.85rem,1.6vw,1.05rem);
  letter-spacing:.06em;
  color:var(--accent);
  margin-top:18px;
  text-transform:uppercase;
}
.hero .lede{
  max-width:56ch; margin-top:22px;
  font-size:1.15rem; line-height:1.65;
  color:var(--ink-soft);
}
.hero .coords{ margin-top:14px; font-size:.78rem; color:var(--ink-faint); }

.scrolldown{
  margin-top:64px;
  display:inline-flex; align-items:center; gap:10px;
  font-family:var(--font-mono); font-size:.72rem; letter-spacing:.12em;
  text-transform:uppercase; color:var(--ink-faint);
}
.scrolldown .bar{
  width:2px; height:34px; background:var(--rule);
  position:relative; overflow:hidden; flex:none;
}
.scrolldown .bar i{
  position:absolute; top:-100%; left:0; width:100%; height:100%;
  background:var(--accent);
  animation:runbar 1.8s ease-in-out infinite;
}
@keyframes runbar{
  0%{ top:-100%; } 60%{ top:100%; } 100%{ top:100%; }
}

/* ---------- STATION CARD ---------- */
.station{ perspective:1400px; }
.card{
  background:var(--card-bg-solid);
  border:1.5px solid var(--rule);
  border-radius:2px;
  padding:38px clamp(20px,4vw,48px);
}
/* backdrop-filter is the single most expensive thing on this page: every card
   composites against the fixed gradient ground on each scroll frame. Desktop
   only, where there's headroom; small screens get an opaque card instead. */
@media (min-width:900px){
  .card{
    background:var(--card-bg);
    backdrop-filter:blur(6px);
    -webkit-backdrop-filter:blur(6px);
  }
}

/* Reveal state is gated on .js so a failed or blocked script can never leave
   the page permanently blank. */
.js [data-reveal]{
  opacity:0;
  transform:rotateX(6deg) translateY(26px) scale(.985);
  transform-origin:top center;
  transition:transform .8s cubic-bezier(.16,.8,.3,1), opacity .8s ease;
}
.js [data-reveal].in{
  opacity:1;
  transform:none;
}

.role-title{ font-size:clamp(1.5rem,3.4vw,2rem); font-weight:800; line-height:1.15; }
.subrole-title{ font-size:1.2rem; }
.org{ color:var(--ink-soft); font-weight:500; margin:0; }
.org-lead{ font-size:1.1rem; margin-top:4px; }
.via{ font-size:.8em; color:var(--ink-faint); }

.meta-row{
  display:flex; flex-wrap:wrap; gap:6px 18px;
  margin:10px 0 0;
  font-family:var(--font-mono); font-size:.76rem; color:var(--ink-faint);
  text-transform:uppercase; letter-spacing:.04em;
}

.points{ list-style:none; margin:22px 0 0; padding:0; display:flex; flex-direction:column; gap:12px; }
.points li{
  position:relative; padding-left:22px;
  color:var(--ink); line-height:1.62; font-size:.99rem;
}
.points li::before{
  content:""; position:absolute; left:0; top:.55em;
  width:9px; height:1.5px; background:var(--accent);
}
.points strong{ color:var(--ink); }

.subrole{ margin-top:30px; padding-top:26px; border-top:1px dashed var(--rule); }

.readout{
  display:flex; flex-wrap:wrap; gap:28px;
  margin:22px 0 0; padding-top:20px;
  border-top:1px dashed var(--rule);
}
/* column-reverse keeps the <dt> (label) after the <dd> (value) in the DOM,
   which a definition list requires, while the value still reads on top */
.readout .stat{ display:flex; flex-direction:column-reverse; }
.readout dd{
  margin:0;
  font-family:var(--font-mono); font-size:1.5rem; color:var(--accent);
  font-variant-numeric:tabular-nums; line-height:1.2;
}
.readout dt{
  font-size:.72rem; letter-spacing:.06em; text-transform:uppercase;
  color:var(--ink-faint);
}

.note{
  font-family:var(--font-hand); color:var(--accent);
  font-size:1.02rem; margin-top:22px;
  transform:rotate(-1.2deg); display:inline-block;
}

/* ---------- BUILDS GRID ---------- */
.builds-grid{
  display:grid; grid-template-columns:repeat(2,1fr); gap:22px; margin-top:34px;
}
@media (max-width:720px){ .builds-grid{ grid-template-columns:1fr; } }

.build{
  padding:26px;
  display:flex; flex-direction:column; gap:12px;
}
.build h3{ font-size:1.35rem; font-weight:800; }
.build .stack{
  font-family:var(--font-mono); font-size:.7rem;
  color:var(--ink-faint); letter-spacing:.03em; margin:0;
}
.build p{ font-size:.93rem; line-height:1.58; color:var(--ink-soft); margin:0; }
.build a.link{
  font-family:var(--font-mono); font-size:.75rem;
  margin-top:auto; text-decoration:none;
  overflow-wrap:anywhere;
}
.build a.link:hover{ text-decoration:underline; }

/* ---------- SPEC SHEET ---------- */
.spec{ margin:30px 0 0; border-top:1.5px solid var(--rule); }
.spec-row{
  display:grid; grid-template-columns:180px 1fr; gap:24px; padding:16px 0;
  border-bottom:1px solid var(--rule);
}
@media (max-width:640px){ .spec-row{ grid-template-columns:1fr; gap:6px; } }
.spec-row .k{
  font-family:var(--font-mono); font-size:.74rem; letter-spacing:.06em;
  text-transform:uppercase; color:var(--accent); padding-top:2px;
}
.spec-row .v{ color:var(--ink-soft); font-size:.95rem; line-height:1.6; margin:0; }

/* ---------- CLOSE ---------- */
.close{ text-align:left; }
.close h2{ font-size:clamp(2rem,6vw,3.4rem); font-weight:900; }
.close .lede{
  max-width:52ch; color:var(--ink-soft); margin-top:16px;
  font-size:1.05rem; line-height:1.6;
}
.contact-grid{
  display:flex; flex-wrap:wrap; gap:14px 34px; margin-top:34px;
  font-family:var(--font-mono); font-size:.9rem;
}
.contact-grid a{
  text-decoration:none;
  border-bottom:1px solid transparent;
  overflow-wrap:anywhere;
}
.contact-grid a:hover{ border-bottom-color:var(--accent); }

footer{
  padding:40px 0 60px;
  font-family:var(--font-mono); font-size:.68rem;
  color:var(--ink-faint); letter-spacing:.05em; text-transform:uppercase;
}

/* ============================================================
   REDUCED MOTION — no tilt, no travel, no looping animation.
   Content still reveals, it just fades.
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }

  .js [data-reveal]{
    transform:none;
    transition:opacity .4s ease;
  }
  .js [data-reveal].in{ transform:none; }

  .scrolldown .bar i{ animation:none; top:20%; }

  .wf-track::after{ transition:none; }
  .wf-dot{ transition:none; }
  .skip-link{ transition:none; }
}
