:root {
  --bg: #121212;
  --fg: #e8e8e8;
  --muted: #8a8a8a;
  --faint: #4a4a4a;
  --line: #2e2e2e;
  --font: "Roboto Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* timeline geometry */
  --date-w: 120px;   /* left column holding the sticky date */
  --gap: 104px;      /* space between date column and content; spine sits in the middle */
  --spine-x: calc(var(--date-w) + var(--gap) / 2);

  /* dotted lines, drawn with repeating dots so they look the same in every browser */
  --dots-v: radial-gradient(circle, var(--faint) 1px, transparent 1.4px) center top / 3px 8px repeat-y;
  --dots-v-lit: radial-gradient(circle, var(--fg) 1px, transparent 1.4px) center top / 3px 8px repeat-y;
  --dots-h: radial-gradient(circle, var(--faint) 1px, transparent 1.4px) left center / 8px 3px repeat-x;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
img, video { display: block; max-width: 100%; }

/* ---------- Header ---------- */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 28px;
  z-index: 10;
  background: linear-gradient(var(--bg) 60%, transparent);
}

.logo-mark {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 36px;
  border: 1.5px solid var(--fg);
  font-weight: 400;
  font-size: 14px;
  letter-spacing: 1px;
}

.site-nav { display: flex; gap: 28px; font-size: 13px; }
.site-nav a { position: relative; }
.site-nav a::after {
  content: "";
  position: absolute;
  left: 0; bottom: -4px;
  width: 0; height: 1px;
  background: var(--fg);
  transition: width .25s ease;
}
.site-nav a:hover::after { width: 100%; }

/* ---------- Scroll progress (left) ---------- */
.progress {
  position: fixed;
  top: 48px;
  left: 13vw;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 5;
}
.progress-value {
  color: var(--muted);
  font-size: 18px;
  padding-left: 10px;
}
.progress-track {
  position: absolute;
  left: 0; top: 0;
  width: 1px;
  height: 80px;
  background: var(--line);
}
.progress-bar {
  display: block;
  width: 1px;
  height: 0;
  background: var(--fg);
  transition: height .1s linear;
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 16px;
  border-bottom: 1px solid var(--line);
  margin: 0 10vw;
}

.typewriter {
  font-weight: 200;
  text-align: center;
  margin-top: -18vh;
}
.type-line {
  display: block;
  min-height: 1.3em;
  font-size: clamp(24px, 3.4vw, 40px);
}
.type-line--sub {
  margin-top: 14px;
  font-size: clamp(15px, 1.8vw, 22px);
  color: var(--muted);
}

/* blinking cursor on whichever line is active */
.type-line.typing::after {
  content: "";
  display: inline-block;
  width: 1.5px;
  height: 1.1em;
  margin-left: 6px;
  vertical-align: -0.15em;
  background: var(--fg);
  animation: blink 1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

.scroll-down {
  position: absolute;
  bottom: 28vh;
  color: var(--muted);
  animation: bob 2s ease-in-out infinite;
}
@keyframes bob { 50% { transform: translateY(6px); } }

.ping {
  position: absolute;
  bottom: 24px;
  right: 0;
  font-size: 12px;
  color: var(--muted);
}
.ping a, .timeline-end a { color: var(--fg); border-bottom: 1px solid transparent; }
.ping a:hover, .timeline-end a:hover { border-color: var(--fg); }

/* =========================================================
   Timeline
   ========================================================= */
.timeline {
  max-width: 1060px;
  margin: 0 auto;
  padding: 140px 28px 80px;
}

.timeline-intro {
  padding-left: calc(var(--date-w) + var(--gap));
  margin-bottom: 96px;
}
.timeline-intro h2 { font-weight: 200; font-size: clamp(26px, 3vw, 36px); }
.timeline-intro p { color: var(--muted); font-size: 13px; margin-top: 10px; }

.timeline-track { position: relative; }

/* the vertical dotted spine; the lit part grows as you scroll */
.spine {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--spine-x);
  width: 3px;
  transform: translateX(-50%);
  background: var(--dots-v);
  -webkit-mask-image: linear-gradient(transparent, #000 40px, #000 calc(100% - 160px), transparent);
          mask-image: linear-gradient(transparent, #000 40px, #000 calc(100% - 160px), transparent);
}
.spine-fill {
  position: absolute;
  inset: 0 0 auto 0;
  height: 0;
  background: var(--dots-v-lit);
}

/* one project = one entry */
.entry {
  position: relative;
  display: grid;
  grid-template-columns: var(--date-w) var(--gap) minmax(0, 1fr);
  padding: 24px 0 180px;
}

.entry:last-child { padding-bottom: 96px; }

.entry-date {
  grid-column: 1;
  position: sticky;
  top: 45vh;
  align-self: start;
  padding-top: 23px;
  text-align: right;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
  text-transform: lowercase;
  letter-spacing: .08em;
  transition: color .4s ease;
}
.entry.reached .entry-date { color: var(--fg); }

.entry-body { grid-column: 3; min-width: 0; }

/* big node on the spine for each project */
.node {
  position: absolute;
  left: var(--spine-x);
  top: 57px;
  width: 13px;
  height: 13px;
  border: 1px solid var(--muted);
  border-radius: 50%;
  background: var(--bg);
  transform: translate(-50%, -50%);
  transition: background .4s ease, border-color .4s ease, box-shadow .4s ease;
  z-index: 1;
}
.entry.reached .node {
  background: var(--fg);
  border-color: var(--fg);
  box-shadow: 0 0 0 6px var(--bg), 0 0 0 7px var(--faint);
}

.entry-head { position: relative; padding-top: 24px; }
/* dotted connector: node -> title */
.entry-head::before {
  content: "";
  position: absolute;
  top: 33px; /* lines up with .node: 57px - the entry's 24px top padding */
  right: calc(100% + 14px);
  width: calc(var(--gap) / 2 - 24px);
  height: 3px;
  margin-top: -1.5px;
  background: var(--dots-h);
  transform-origin: left center;
}

.meta {
  font-size: 12px;
  color: var(--muted);
  letter-spacing: .06em;
  text-transform: lowercase;
}
.meta-date { display: none; }
.badge {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  border: 1px solid var(--fg);
  border-radius: 20px;
  color: var(--fg);
  font-size: 11px;
}

.entry-body h3 {
  font-weight: 200;
  font-size: clamp(26px, 3.2vw, 38px);
  margin-top: 6px;
  line-height: 1.2;
}

.lede {
  margin-top: 20px;
  max-width: 62ch;
  font-size: 15px;
  line-height: 1.75;
  color: #cfcfcf;
}

/* sub-steps inside a project, each branching off the spine */
.step {
  position: relative;
  margin-top: 64px;
}
.step::before { /* dotted branch from the spine */
  content: "";
  position: absolute;
  top: 9px;
  right: calc(100% + 12px);
  width: calc(var(--gap) / 2 - 12px);
  height: 3px;
  margin-top: -1.5px;
  background: var(--dots-h);
  transform-origin: left center;
}
.step::after { /* small dot where the branch meets the spine */
  content: "";
  position: absolute;
  top: 9px;
  left: calc(var(--gap) / -2);
  width: 7px;
  height: 7px;
  border: 1px solid var(--faint);
  border-radius: 50%;
  background: var(--bg);
  transform: translate(-50%, -50%);
  transition: background .4s ease, border-color .4s ease;
}
.step.reached::after { background: var(--fg); border-color: var(--fg); }

.step-title {
  font-weight: 300;
  font-size: 16px;
  line-height: 18px;
  margin-bottom: 16px;
}
.step-title span { color: var(--muted); margin-right: 8px; font-size: 12px; }

.step p, .notes li {
  max-width: 64ch;
  font-size: 14px;
  line-height: 1.75;
  color: #c4c4c4;
}
.step p + p { margin-top: 12px; }
.step .flow + p, .step .example + p { margin-top: 0; }
.step strong, .notes b { font-weight: 400; color: var(--fg); }
code { font-family: inherit; font-size: .92em; color: var(--fg); }
var { font-style: italic; }

/* expandable technical notes */
.notes { margin-top: 18px; max-width: 70ch; }
.notes summary {
  display: inline-block;
  cursor: pointer;
  list-style: none;
  font-size: 12px;
  color: var(--muted);
  padding-bottom: 4px;
  background: var(--dots-h);
  background-position: left bottom;
  transition: color .2s ease;
}
.notes summary::-webkit-details-marker { display: none; }
.notes summary::after { content: " +"; }
.notes[open] summary::after { content: " −"; }
.notes summary:hover, .notes[open] summary { color: var(--fg); }
.notes ul { list-style: none; margin-top: 16px; }
.notes li {
  position: relative;
  padding-left: 22px;
  margin-bottom: 12px;
  font-size: 13px;
}
.notes li::before {
  content: "";
  position: absolute;
  left: 2px; top: .8em;
  width: 14px; height: 3px;
  background: var(--dots-h);
}
.notes-sub {
  margin-top: 20px;
  font-size: 11px !important;
  letter-spacing: .1em;
  color: var(--muted) !important;
}

/* signal-flow diagrams */
.flow {
  display: flex;
  align-items: center;
  margin: 8px 0 26px;
  padding-top: 18px;
}
.flow-node {
  flex: 0 0 auto;
  border: 1px solid var(--faint);
  padding: 10px 12px;
  font-size: 12px;
  text-align: center;
  white-space: nowrap;
}
.flow-node small { display: block; margin-top: 4px; font-size: 10px; color: var(--muted); }
.flow-link {
  position: relative;
  flex: 1 1 0;
  min-width: 36px;
  height: 3px;
  background: var(--dots-h);
}
.flow-link span {
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 10px;
  color: var(--muted);
}
/* a dot of "signal" travelling along each link */
.flow-link::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 5px; height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: var(--fg);
  animation: travel-x 2.4s linear infinite;
}
.flow-link:nth-of-type(4)::after { animation-delay: .6s; }
.flow-link:nth-of-type(6)::after { animation-delay: 1.2s; }
.flow-link:nth-of-type(8)::after { animation-delay: 1.8s; }
@keyframes travel-x {
  0% { left: 0; opacity: 0; }
  10%, 90% { opacity: 1; }
  100% { left: 100%; opacity: 0; }
}
@keyframes travel-y {
  0% { top: 0; opacity: 0; }
  10%, 90% { opacity: 1; }
  100% { top: 100%; opacity: 0; }
}

/* photos */
.gallery {
  columns: 2;
  column-gap: 14px;
  margin-top: 20px;
}
.gallery--three { columns: 3; }
.gallery--single { columns: 1; max-width: 560px; }
.gallery figure {
  break-inside: avoid;
  margin-bottom: 18px;
}
.gallery img {
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  cursor: zoom-in;
  opacity: .88;
  transition: opacity .3s ease, border-color .3s ease;
}
.gallery img:hover { opacity: 1; border-color: var(--faint); }
figcaption {
  margin-top: 8px;
  font-size: 11px;
  color: var(--muted);
}

.gallery--phones { max-width: 520px; }

.video-frame { max-width: 640px; }

.step-date {
  margin-left: 10px;
  padding-left: 10px;
  border-left: 1px solid var(--faint);
  font-size: 12px;
  color: var(--muted);
  letter-spacing: .06em;
}

/* example command, terminal-style */
.example {
  position: relative;
  max-width: 100%;
  margin: 4px 0 8px;
  padding: 26px 16px 14px;
  border: 1px dashed var(--faint);
  font-family: inherit;
  font-size: 12px;
  line-height: 1.9;
  color: var(--fg);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.example .dim { color: var(--muted); }
.example-label {
  position: absolute;
  top: 6px; left: 16px;
  font-size: 10px;
  letter-spacing: .1em;
  color: var(--muted);
}
.video-frame video { width: 100%; border: 1px solid var(--line); background: #000; }

/* VISI: the last node pulses, work in progress */
.entry--now .node { border-style: dashed; }
.entry--now.reached .node { animation: pulse 2.4s ease-out infinite; }
@keyframes pulse {
  0%   { box-shadow: 0 0 0 6px var(--bg), 0 0 0 7px var(--faint); }
  70%  { box-shadow: 0 0 0 16px var(--bg), 0 0 0 17px transparent; }
  100% { box-shadow: 0 0 0 6px var(--bg), 0 0 0 7px transparent; }
}
.banner { max-width: 420px; }
.banner img { width: 100%; height: auto; border-radius: 18px; }
.coming-soon {
  margin-top: 22px;
  font-size: 18px !important;
  font-weight: 200;
  color: var(--fg) !important;
}
.coming-soon::after { /* same blinking cursor as the hero */
  content: "";
  display: inline-block;
  width: 1.5px;
  height: 1.1em;
  margin-left: 6px;
  vertical-align: -0.15em;
  background: var(--fg);
  animation: blink 1s steps(1) infinite;
}

.timeline-end {
  padding-left: calc(var(--date-w) + var(--gap));
  font-size: 12px;
  color: var(--muted);
}

.site-footer {
  text-align: center;
  padding: 48px 16px 32px;
  color: var(--muted);
  font-size: 12px;
}

/* ---------- Scroll reveal ---------- */
.js .reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .8s ease, transform .8s cubic-bezier(.2, .7, .2, 1);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* dotted branches "draw" outward when their step appears */
.js .reveal.step::before,
.js .reveal.entry-head::before {
  transform: scaleX(0);
  transition: transform .7s ease .25s;
}
.js .reveal.is-visible.step::before,
.js .reveal.is-visible.entry-head::before { transform: scaleX(1); }

/* ---------- Lightbox ---------- */
.lightbox {
  margin: auto;
  max-width: min(94vw, 1200px);
  padding: 0;
  border: 1px solid var(--faint);
  background: var(--bg);
  color: var(--fg);
  cursor: zoom-out;
}
.lightbox::backdrop { background: rgba(0, 0, 0, .88); }
.lightbox img { max-height: 84vh; width: auto; margin: 0 auto; }
.lightbox-caption { padding: 10px 14px; font-size: 12px; color: var(--muted); }

/* ---------- Tablet: vertical flow diagrams ---------- */
@media (max-width: 900px) {
  :root { --date-w: 72px; --gap: 72px; }

  .flow { flex-direction: column; align-items: flex-start; padding-top: 0; }
  .flow-node { min-width: 150px; text-align: left; }
  .flow-link {
    flex: 0 0 auto;
    width: 3px;
    min-width: 0;
    height: 34px;
    margin-left: 24px;
    background: var(--dots-v);
  }
  .flow-link span { bottom: auto; top: 50%; left: 14px; transform: translateY(-50%); }
  .flow-link::after {
    top: 0; left: 50%;
    margin: -2.5px 0 0 -2.5px;
    animation-name: travel-y;
  }
  .gallery--three { columns: 2; }
}

/* ---------- Phone: spine on the left, dates inline ---------- */
@media (max-width: 640px) {
  :root { --date-w: 0px; --gap: 56px; }

  .site-header { padding: 14px 16px; }
  .site-nav { gap: 14px; font-size: 11px; }
  /* keep the counter clear of the timeline spine */
  .progress { top: auto; left: auto; bottom: 16px; right: 16px; }
  .progress-track { display: none; }
  .progress-value { padding: 0; font-size: 13px; }
  .hero { margin: 0 16px; }
  .ping { right: auto; text-align: center; width: 100%; }

  .timeline { padding: 110px 16px 64px 4px; }
  .entry { grid-template-columns: 0 var(--gap) minmax(0, 1fr); padding-bottom: 120px; }
  .entry-date { display: none; }
  .meta-date { display: inline; color: var(--fg); }
  .entry-head::before { width: calc(var(--gap) / 2 - 18px); right: calc(100% + 8px); }
  .step { margin-top: 48px; }
  .step::before { width: calc(var(--gap) / 2 - 10px); right: calc(100% + 6px); }
  .lede { font-size: 14px; }
  .gallery, .gallery--three { column-gap: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .scroll-down, .flow-link::after, .entry--now.reached .node, .coming-soon::after { animation: none; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .js .reveal.step::before, .js .reveal.entry-head::before { transform: none; transition: none; }
}
