:root {
  --ink: #0b0f1a;
  --ink-soft: #3c4456;
  --bg: #dfe8f4;
  --accent: #ff5a5a;
}

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

html { scroll-behavior: auto; }

body {
  font-family: "Inter", system-ui, sans-serif;
  color: var(--ink);
  background: var(--bg);
  overflow-x: hidden;
}

#scene {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
}

/* ---------- Nav ---------- */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 22px 36px;
  z-index: 30;
}
.nav-left { display: flex; gap: 36px; }
.nav-left a {
  color: var(--ink);
  text-decoration: none;
  font-size: 13px;
  letter-spacing: 0.08em;
  font-weight: 500;
}
.nav-logo {
  font-family: "Archivo", sans-serif;
  font-weight: 800;
  font-size: 22px;
  letter-spacing: 0.18em;
}
.nav-right { display: flex; gap: 12px; justify-content: flex-end; }
.btn {
  display: inline-block;
  text-decoration: none;
  font-size: 13px;
  letter-spacing: 0.06em;
  font-weight: 600;
  padding: 14px 26px;
  border-radius: 999px;
  transition: transform 0.2s ease;
}
.btn:hover { transform: scale(1.04); }
.btn-light { background: #c9d4e4; color: var(--ink); }
.btn-dark { background: var(--ink); color: #fff; }
.btn-big { font-size: 15px; padding: 18px 40px; }

/* ---------- Hero ----------
   Title-card layout: no panel, no blur. The type is anchored to the bottom
   left of the frame so the sky and the tower tops stay unobstructed, and
   legibility comes from the scrim below rather than from a box. */
.hero {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  text-align: left;
  /* bottom padding has to clear the centred scroll cue (bottom: 4vh) */
  padding: 0 clamp(22px, 6vw, 104px) clamp(104px, 15vh, 180px);
  z-index: 10;
  pointer-events: none;
}

/* Readability without a panel: one soft ground-up gradient. It reads as
   haze over the city rather than as a UI element, and it only covers the
   lower half so the skyline above stays fully visible. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgba(219, 230, 244, 0.94) 0%,
    rgba(219, 230, 244, 0.74) 24%,
    rgba(219, 230, 244, 0.3) 48%,
    rgba(219, 230, 244, 0) 70%
  );
}

/* a rule, then the label — sets the editorial tone before the big line lands */
.hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 2.4vh;
  font-size: clamp(10.5px, 0.95vw, 13px);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.hero-eyebrow::before {
  content: "";
  width: clamp(26px, 3.4vw, 62px);
  height: 1.5px;
  background: currentColor;
  opacity: 0.55;
}

.hero h1 {
  font-family: "Archivo", sans-serif;
  font-weight: 800;
  /* with no box to fit inside, the line can run much larger */
  font-size: clamp(54px, 11.5vw, 168px);
  line-height: 0.96;
  letter-spacing: -0.045em;
}
.hero-sub {
  margin-top: 3vh;
  font-size: clamp(15px, 1.35vw, 19px);
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: 46ch;
}

.hero-cta {
  margin-top: 3.4vh;
  display: flex;
  gap: 14px;
  justify-content: flex-start;
  flex-wrap: wrap;
}
.hero-hint {
  margin-top: 2.2vh;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}
.hero-hint-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  background: linear-gradient(135deg, #ff5a5a 0%, #5a8cff 100%);
  box-shadow: 0 0 7px rgba(255, 90, 90, 0.5);
}

.scroll-cue {
  position: fixed;
  bottom: 4vh;
  left: 50%;
  transform: translateX(-50%);
  font-family: inherit;
  color: var(--ink);
  border: 0;
  cursor: pointer;
  font-size: 13px;
  letter-spacing: 0.12em;
  border-bottom: 1.5px solid var(--ink);
  padding-bottom: 8px;
  z-index: 10;
}

/* ---------- Skip the tour ---------- */
.skip-tour {
  position: fixed;
  right: 96px;
  bottom: 32px;
  z-index: 90;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  background: rgba(238, 244, 252, 0.75);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1.5px solid rgba(255, 255, 255, 0.6);
  border-radius: 999px;
  padding: 12px 20px;
  cursor: pointer;
  box-shadow: 0 10px 28px rgba(20, 35, 70, 0.18);
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s;
}
.skip-tour.show { opacity: 1; visibility: visible; transform: translateY(0); }
.skip-tour:hover { background: rgba(238, 244, 252, 0.95); }
body.night .skip-tour {
  background: rgba(28, 38, 64, 0.72);
  border-color: rgba(255, 255, 255, 0.16);
}
body.night .skip-tour:hover { background: rgba(34, 46, 78, 0.92); }

/* ---------- Steps panel ---------- */
.steps {
  position: fixed;
  left: 4vw;
  bottom: 5vh;
  z-index: 20;
  max-width: 560px;
  opacity: 0;
  visibility: hidden;
  /* the panel is a matte, not a target — clicks pass through to the city.
     Only the step links opt back in (see .step-link). */
  pointer-events: none;
}
.step { margin-bottom: 18px; }
.step-row { display: flex; align-items: center; gap: 26px; }
.step-num {
  font-size: 14px;
  font-weight: 600;
  width: 50px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  flex-shrink: 0;
  transition: background 0.4s, box-shadow 0.4s;
}
.step.active .step-num {
  background: #fff;
  box-shadow: 0 8px 24px rgba(20, 35, 70, 0.12);
}
.step-title {
  font-family: "Archivo", sans-serif;
  font-weight: 600;
  font-size: 17px;
  letter-spacing: -0.01em;
  transition: font-size 0.35s ease;
}
.step.active .step-title { font-size: clamp(24px, 2.4vw, 34px); }
.step-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.45s ease;
  overflow: hidden;
  margin-left: 76px;
}
.step.active .step-body { grid-template-rows: 1fr; }
.step-body > div, .step-body > p { min-height: 0; }
.step-body p {
  overflow: hidden;
  padding-top: 16px;
  font-size: 16.5px;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 470px;
}
.step-body { position: relative; }
.step-bar {
  position: absolute;
  left: -26px;
  top: 18px;
  bottom: 6px;
  width: 2px;
  background: rgba(11, 15, 26, 0.12);
}
.step-bar span {
  display: block;
  width: 2px;
  height: 0%;
  background: var(--ink);
}
/* wrapper so the collapsing 0fr→1fr grid still has exactly one row
   now that each step carries a link under its paragraph */
.step-inner { overflow: hidden; }
.step-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  pointer-events: auto;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  padding-bottom: 3px;
  border-bottom: 1.5px solid rgba(11, 15, 26, 0.25);
  transition: border-color 0.25s ease, gap 0.25s ease;
}
.step-link:hover { border-bottom-color: var(--ink); gap: 13px; }
.step-link span { transition: transform 0.25s ease; }
.step-link:hover span { transform: translateX(2px); }
body.night .step-link { border-bottom-color: rgba(238, 242, 250, 0.3); }

/* ---------- Outro ---------- */
.outro {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5vh;
  text-align: center;
  z-index: 10;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.outro h2 {
  font-family: "Archivo", sans-serif;
  font-weight: 700;
  font-size: clamp(40px, 6.4vw, 92px);
  line-height: 1.04;
  letter-spacing: -0.03em;
}
.outro.visible { pointer-events: auto; }

/* ---------- Scroll driver ----------
   Length of the whole camera flight. Four steps span p=0.06→0.88, so this
   works out to roughly one screen of scroll per step — 1000vh made it about
   two, which is a long way to travel for one paragraph. */
.scroll-space { height: 560vh; }

/* ---------- Mobile nav ---------- */
.nav-burger {
  display: none;
  background: none;
  border: 0;
  width: 44px;
  height: 44px;
  cursor: pointer;
  z-index: 60;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.nav-burger span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--ink);
  transition: transform 0.3s, opacity 0.3s;
}
.mobile-menu {
  position: fixed;
  inset: 0;
  background: rgba(223, 232, 244, 0.97);
  backdrop-filter: blur(12px);
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8vh;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease;
}
.mobile-menu.open { opacity: 1; pointer-events: auto; }
.mobile-menu a {
  font-family: "Archivo", sans-serif;
  font-weight: 700;
  font-size: clamp(28px, 8vw, 44px);
  color: var(--ink);
  text-decoration: none;
  letter-spacing: -0.02em;
}
body.menu-open .nav-burger span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
body.menu-open .nav-burger span:nth-child(2) { opacity: 0; }
body.menu-open .nav-burger span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

/* ---------- Content pages ---------- */
.page {
  position: relative;
  z-index: 5;
  max-width: 1100px;
  margin: 0 auto;
  padding: 140px 6vw 60px;
}
.page-kicker {
  font-size: 13px;
  letter-spacing: 0.14em;
  font-weight: 600;
  color: var(--ink-soft);
  text-transform: uppercase;
}
.page h1 {
  font-family: "Archivo", sans-serif;
  font-weight: 700;
  font-size: clamp(42px, 7vw, 84px);
  letter-spacing: -0.03em;
  line-height: 1.02;
  margin: 14px 0 22px;
}
.page-lede {
  font-size: clamp(16px, 1.5vw, 19px);
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 640px;
}
.section-title {
  font-family: "Archivo", sans-serif;
  font-weight: 700;
  font-size: clamp(26px, 3.4vw, 40px);
  letter-spacing: -0.02em;
  margin: 90px 0 30px;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 24px;
}
.card {
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(8px);
  border-radius: 20px;
  padding: 28px;
  box-shadow: 0 10px 36px rgba(20, 35, 70, 0.08);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
  transform: translateY(-6px);
  box-shadow: 0 22px 48px rgba(20, 35, 70, 0.14);
}
.card h3 {
  font-family: "Archivo", sans-serif;
  font-size: 20px;
  margin-bottom: 10px;
}
.card p { font-size: 15px; line-height: 1.6; color: var(--ink-soft); }
.card .emoji { font-size: 30px; display: block; margin-bottom: 14px; }

/* Stats */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 18px;
  margin-top: 40px;
}
.stat {
  background: rgba(255, 255, 255, 0.72);
  border-radius: 18px;
  padding: 24px;
  text-align: center;
  box-shadow: 0 10px 30px rgba(20, 35, 70, 0.07);
}
.stat b {
  display: block;
  font-family: "Archivo", sans-serif;
  font-size: clamp(30px, 4vw, 44px);
  letter-spacing: -0.02em;
}
.stat span {
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--ink-soft);
  text-transform: uppercase;
}

/* Tags */
.tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.tag {
  font-size: 12px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 999px;
  background: #e6edf8;
  color: var(--ink-soft);
}

/* Project cards */
.project-card { overflow: hidden; padding: 0; display: flex; flex-direction: column; }
.project-card .thumb {
  aspect-ratio: 16 / 9;
  background: #eef3fa center / cover no-repeat;
}
.project-card .body { padding: 24px 26px 28px; flex: 1; display: flex; flex-direction: column; }
.project-card .links { margin-top: auto; padding-top: 18px; display: flex; gap: 16px; }
.project-card .links a {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1.5px solid var(--ink);
  padding-bottom: 2px;
}

/* Skill bars */
.skill-row { margin-bottom: 22px; }
.skill-row .label {
  display: flex;
  justify-content: space-between;
  font-size: 14.5px;
  font-weight: 600;
  margin-bottom: 8px;
}
.skill-row .bar {
  height: 8px;
  border-radius: 999px;
  background: rgba(11, 15, 26, 0.08);
  overflow: hidden;
}
.skill-row .bar span {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, #ff5a5a, #5a8cff);
}

/* ---------- Skill transit map (metro lines) ---------- */
.metro-intro { margin-bottom: 6px; }
.xchg-note { color: var(--ink); font-weight: 600; border-bottom: 1.5px dashed currentColor; }

.metro-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  margin-top: 18px;
}
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
}
.legend-item i {
  width: 16px;
  height: 6px;
  border-radius: 999px;
  background: var(--c, var(--ink));
}
.legend-x i {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--ink);
}

.metro-map {
  display: grid;
  grid-template-columns: 1fr;          /* mobile-first: one line per row */
  gap: 18px;
  margin-top: 32px;
}

.line {
  --c: #ff5a5a;
  position: relative;
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(8px);
  border-radius: 20px;
  border-top: 4px solid var(--c);
  padding: 22px 22px 24px;
  box-shadow: 0 10px 36px rgba(20, 35, 70, 0.08);
}
.line-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: "Archivo", sans-serif;
  font-weight: 700;
  font-size: 12.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #fff;
  background: var(--c);
  padding: 7px 15px;
  border-radius: 999px;
  margin-bottom: 20px;
}
.line-badge::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #fff;
}

.stations {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 4px 0;
}
.track {
  position: absolute;
  left: 13px;
  top: 18px;
  bottom: 18px;
  width: 4px;
  border-radius: 999px;
  background: var(--c);
  opacity: 0.32;
  transform-origin: top center;
}
.station {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 4px 9px 38px;
  min-height: 44px;                     /* comfortable mobile tap height */
}
.station .dot {
  position: absolute;
  left: 7px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  border: 4px solid var(--c);
  box-shadow: 0 1px 4px rgba(20, 35, 70, 0.18);
}
.station.core .dot {
  background: var(--c);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.85), 0 1px 5px rgba(20, 35, 70, 0.22);
}
.station.xchg .dot {
  width: 18px;
  height: 18px;
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.85), 0 1px 5px rgba(20, 35, 70, 0.22);
}
.st-name { font-weight: 600; font-size: 15.5px; }
.st-lvl {
  margin-left: auto;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
}
.station.xchg .st-lvl { color: var(--c); }

@media (min-width: 820px) {
  .metro-map { grid-template-columns: repeat(3, 1fr); align-items: start; }
}

/* Cert cards */
.cert-card { display: flex; gap: 18px; align-items: flex-start; }
.cert-card img { width: 72px; height: 72px; object-fit: contain; flex-shrink: 0; }
.cert-card .meta { font-size: 12px; letter-spacing: 0.08em; color: var(--ink-soft); }
.cert-card a {
  display: inline-block;
  margin-top: 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}

/* Contact */
.contact-grid {
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  gap: 40px;
  margin-top: 50px;
}
.contact-form { display: flex; flex-direction: column; gap: 14px; }
.contact-form input, .contact-form textarea {
  font: inherit;
  padding: 16px 18px;
  border-radius: 14px;
  border: 1.5px solid rgba(11, 15, 26, 0.12);
  background: rgba(255, 255, 255, 0.8);
  outline: none;
  transition: border-color 0.2s;
}
.contact-form input:focus, .contact-form textarea:focus { border-color: var(--ink); }
.contact-form textarea { min-height: 160px; resize: vertical; }
.contact-form button {
  font: inherit;
  font-weight: 600;
  border: 0;
  cursor: pointer;
}
.info-line { display: flex; gap: 14px; margin-bottom: 22px; font-size: 15.5px; }
.info-line b { display: block; font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; }
.info-line a { color: var(--ink); }

/* Footer */
.site-footer {
  position: relative;
  z-index: 5;
  margin-top: 100px;
  padding: 50px 6vw 40px;
  border-top: 1.5px solid rgba(11, 15, 26, 0.1);
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  justify-content: space-between;
  align-items: center;
  font-size: 14px;
  color: var(--ink-soft);
}
.site-footer .social { display: flex; gap: 20px; }
.site-footer a { color: var(--ink); text-decoration: none; font-weight: 600; }

/* Live visit badge. Stays hidden until analytics.js has real numbers in
   hand, so a blocked or offline Firestore leaves no dangling placeholder. */
.visit-count {
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  opacity: 0.75;
}
.visit-count[hidden] { display: none; }
.visit-count span {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--ink);
}

/* Reveal animation hook — only hidden once JS confirms GSAP is running,
   so content stays visible if scripts fail to load. */
body.js-anim .reveal { opacity: 0; transform: translateY(36px); }

/* Page-mode body: normal scroll, soft gradient bg */
body.subpage {
  background: linear-gradient(180deg, #e7eefa 0%, #dfe8f4 40%, #dce6f3 100%);
}
body.subpage #scene { opacity: 0.55; }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .contact-grid { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .nav { padding: 16px 20px; grid-template-columns: auto 1fr auto; }
  .nav-left, .nav-right { display: none; }
  .nav-logo { justify-self: start; font-size: 18px; }
  .nav-burger { display: flex; justify-self: end; grid-column: 3; }
  /* phone: the display line still runs edge to edge, just at phone scale */
  .hero { padding: 0 22px clamp(92px, 13vh, 116px); }
  .hero h1 { font-size: clamp(40px, 14vw, 72px); letter-spacing: -0.04em; }
  .hero-eyebrow { font-size: 10px; letter-spacing: 0.2em; margin-bottom: 1.8vh; }
  .hero-sub { font-size: 14px; margin-top: 2.4vh; max-width: 34ch; }
  .hero-cta { margin-top: 2.8vh; gap: 10px; }
  .hero-cta .btn { font-size: 12px; padding: 12px 20px; }
  .hero-hint { margin-top: 2.4vh; font-size: 12px; text-align: left; }

  /* sits beside the toggle under the nav — the bottom edge belongs to the
     steps card and the scroll cue */
  .skip-tour {
    top: 90px;
    right: 64px;
    bottom: auto;
    font-size: 10.5px;
    letter-spacing: 0.08em;
    padding: 10px 14px;
    gap: 6px;
  }

  /* a shorter journey on a phone — less of a marathon */
  .scroll-space { height: 420vh; }

  .step-link { font-size: 11.5px; margin-top: 10px; }

  /* compact scroll cue: short label + a gently bobbing chevron
     (the long "…EXPLORE MY WORLD" pill looked clumsy on a narrow screen) */
  .scroll-cue {
    font-size: 11.5px;
    letter-spacing: 0.16em;
    bottom: 3.2vh;
    padding: 9px 15px;
    gap: 9px;
  }
  .scroll-cue .sc-full { display: none; }
  .scroll-cue .sc-mini { display: inline; }
  .scroll-cue .sc-arrow {
    display: inline-block;
    width: 7px; height: 7px;
    border-right: 2px solid var(--ink);
    border-bottom: 2px solid var(--ink);
    transform: rotate(45deg);
    animation: scBob 1.4s ease-in-out infinite;
  }

  /* steps: a slim bottom card showing only the CURRENT section, so the
     city stays visible instead of being buried under four stacked rows */
  .steps {
    left: 10px; right: 10px; bottom: 10px;
    max-width: none;
    padding: 14px 16px;
    border-radius: 18px;
  }
  .steps .step { display: none; margin-bottom: 0; }
  /* only the current section shows — and it shuffles in instead of popping */
  .steps .step.active { display: block; animation: stepIn 0.5s var(--lg-elastic) both; }
  .steps .step.active .step-num { animation: stepNumPop 0.55s var(--lg-elastic) both 0.06s; }
  .step-row { gap: 12px; }
  .step-num { width: 34px; height: 34px; border-radius: 9px; }
  .step-title { font-size: 15px; }
  .step-body { margin-left: 46px; }
  .step-body p { font-size: 13.5px; padding-top: 10px; }
  .step.active .step-title { font-size: 18px; }

  .outro h2 { font-size: clamp(30px, 9vw, 44px); padding: 0 6vw; }
  .page { padding-top: 110px; }
}

/* ============================================================
   Subpage "awwwards" layer
   ============================================================ */

/* full-strength scene behind content */
body.subpage #scene { opacity: 1; }
body.subpage .page { padding-top: 20vh; }

/* word-split headline reveal */
.w { display: inline-block; overflow: hidden; vertical-align: bottom; }
.wi { display: inline-block; transform: translateY(115%); }

/* outlined accent word in big headlines */
.accent {
  font-style: normal;
  color: transparent;
  -webkit-text-stroke: 2px var(--ink);
}

/* kicker chip */
.page-kicker {
  display: inline-block;
  background: rgba(255, 255, 255, 0.75);
  border: 1.5px solid rgba(11, 15, 26, 0.1);
  padding: 9px 18px;
  border-radius: 999px;
  backdrop-filter: blur(6px);
}

/* ---------- developer at the desk (about page) ----------
   Same flat, chunky miniature language as the 3D scenes: pale stock, one warm
   accent, no gradients. Every colour is a single fill below, so the hair, skin
   and shirt are one-line changes. */
.about-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(240px, 360px);
  gap: 48px;
  align-items: center;
}
.dev-scene svg {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 320 / 300;
  overflow: visible;
}
.dv-shadow { fill: rgba(11, 15, 26, 0.09); }
.dv-desk { fill: #dbe5f4; stroke: rgba(11, 15, 26, 0.16); stroke-width: 1.2; }
.dv-desk-leg { fill: #cfdcee; }
.dv-pale { fill: #f3f7fd; stroke: rgba(11, 15, 26, 0.16); stroke-width: 1.2; }
.dv-chair { fill: #9fb6d2; }
.dv-shirt { fill: #7fb8b0; }
.dv-skin { fill: #f0c9a8; }
.dv-hair { fill: #2c2f3d; }
.dv-eye { fill: #2c2f3d; }
.dv-specs rect { fill: none; stroke: #2c2f3d; stroke-width: 2; }
.dv-specs path { stroke: #2c2f3d; stroke-width: 2; fill: none; }
.dv-smile { fill: none; stroke: #2c2f3d; stroke-width: 2; stroke-linecap: round; }
.dv-arm {
  fill: none;
  stroke: #7fb8b0;
  stroke-width: 14;
  stroke-linecap: round;
}
.dv-mug { fill: #c8554a; }
.dv-mug-handle { fill: none; stroke: #c8554a; stroke-width: 3.5; }
.dv-steam { fill: none; stroke: rgba(11, 15, 26, 0.22); stroke-width: 2.4; stroke-linecap: round; }
.dv-pot { fill: #d9906e; }
.dv-leaf { fill: #9ec98e; }
/* the screen is the one thing that never goes dark — it is the light source */
.dv-screen { fill: #222c45; }
.dv-ln-a { fill: #7fd0a8; }
.dv-ln-b { fill: #8fb3d9; }
.dv-ln-c { fill: #e9c47e; }
.dv-ln-d { fill: #ff8f8f; }
.dv-caret { fill: #eef3fb; }

/* motion: hands tapping, the last line still being typed, steam drifting */
.js-anim .dv-hand-l { animation: dvTap 0.62s ease-in-out infinite; }
.js-anim .dv-hand-r { animation: dvTap 0.62s ease-in-out infinite 0.31s; }
.js-anim .dv-caret { animation: dvBlink 1.05s steps(1) infinite; }
.js-anim .dv-steam { animation: dvSteam 3s ease-in-out infinite; }
.js-anim .dv-steam-2 { animation-delay: 1.1s; }
@keyframes dvTap {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-2.5px); }
}
@keyframes dvBlink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }
@keyframes dvSteam {
  0% { opacity: 0; transform: translateY(4px); }
  35% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-8px); }
}

body.night .dv-desk { fill: #232e49; stroke: rgba(238, 242, 250, 0.2); }
body.night .dv-desk-leg { fill: #1b2540; }
body.night .dv-pale { fill: #27314c; stroke: rgba(238, 242, 250, 0.2); }
body.night .dv-chair { fill: #3a4c6e; }
body.night .dv-shirt { fill: #5e9a92; }
body.night .dv-arm { stroke: #5e9a92; }
body.night .dv-skin { fill: #d8ab89; }
body.night .dv-shadow { fill: rgba(0, 0, 0, 0.28); }
body.night .dv-steam { stroke: rgba(238, 242, 250, 0.3); }
body.night .dv-hair, body.night .dv-eye { fill: #1a1c26; }

/* ---------- mini landmark beside each section heading ----------
   page.js wraps every .section-title in a .section-head and drops the stage in
   beside it, so the heading margins have to live on the wrapper now — the ones
   on .section-title are zeroed out below. */
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 28px;
  margin: 90px 0 30px;
}
.section-head .section-title { margin: 0; }
/* Block layout, not flex: as a flex item an SVG sized `width:100%;height:auto`
   has to resolve its height from a parent whose height depends on the SVG, and
   Chrome breaks the loop by collapsing it. The explicit aspect-ratio (matching
   the viewBox) makes the height fall out of the width instead. */
.mini-bldg {
  flex: 0 0 auto;
  width: 96px;
}
.mini-bldg svg {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 120 / 123;
}
.mb-name {
  display: block;
  margin-top: 7px;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-soft);
  text-align: center;
  line-height: 1.3;
}
/* miniature palette — the same pale-stock-and-gold city as the 3D scenes */
.mb-pale { fill: #f3f7fd; stroke: rgba(11, 15, 26, 0.18); stroke-width: 0.8; }
.mb-glass { fill: #9fb6d2; stroke: rgba(11, 15, 26, 0.18); stroke-width: 0.8; }
.mb-pod { fill: #eae2d0; stroke: rgba(11, 15, 26, 0.18); stroke-width: 0.8; }
.mb-base { fill: #dbe5f4; stroke: rgba(11, 15, 26, 0.14); stroke-width: 0.8; }
.mb-gold { fill: #e9c47e; }
.mb-ground { fill: rgba(11, 15, 26, 0.16); }
/* floors this heading has not reached yet: a dashed plan, not a building */
.mb-part.is-ghost { opacity: 0.34; }
.mb-part.is-ghost * {
  fill: none;
  stroke: rgba(11, 15, 26, 0.55);
  stroke-width: 1;
  stroke-dasharray: 3 2.5;
}

/* ghost section numbers */
.section-title { position: relative; }
.section-title::before {
  content: attr(data-num);
  position: absolute;
  left: -0.12em;
  top: -0.85em;
  font-size: 2.6em;
  font-weight: 800;
  color: transparent;
  -webkit-text-stroke: 1.5px rgba(11, 15, 26, 0.14);
  pointer-events: none;
}

/* glowing scroll-progress line (echoes the homepage path) */
.scroll-line {
  position: fixed;
  top: 0;
  left: max(12px, 2.2vw);
  width: 3px;
  height: 100vh;
  border-radius: 999px;
  background: linear-gradient(180deg, #ff5a5a, #e9c47e, #55aaff);
  box-shadow: 0 0 14px rgba(90, 140, 255, 0.55);
  transform: scaleY(0);
  transform-origin: top;
  z-index: 25;
  pointer-events: none;
}

/* ---------- custom cursor ----------
   Centred with negative margins rather than `translate: -50% -50%`, because
   the individual `translate` property composes *outside* `transform` — any
   scale there would multiply the pointer coordinates and throw the ring off
   the pointer. Margins are laid out once and never fight the transform.
   Size changes are done with scale in the transform (compositor only); the
   old width/height transition relaid out the element on every hover. */
.cursor-dot, .cursor-ring {
  position: fixed;
  top: 0; left: 0;
  border-radius: 50%;
  pointer-events: none;
  z-index: 200;
  opacity: 0;
  will-change: transform;
  transition: opacity 0.18s ease;
}
body.cursor-on .cursor-dot,
body.cursor-on .cursor-ring { opacity: 1; }

.cursor-dot {
  width: 7px; height: 7px;
  margin: -3.5px 0 0 -3.5px;
  background: var(--ink);
}
.cursor-ring {
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
  border: 1.5px solid rgba(11, 15, 26, 0.4);
  transition: opacity 0.18s ease, border-color 0.2s ease, background-color 0.2s ease;
}
/* over something clickable the ring takes over and the dot steps aside */
body.cursor-hot .cursor-ring {
  border-color: rgba(255, 90, 90, 0.85);
  background-color: rgba(255, 90, 90, 0.09);
}
body.cursor-on.cursor-hot .cursor-dot { opacity: 0; }
/* over text the native I-beam is more useful than a decorative ring */
body.cursor-on.cursor-text .cursor-dot,
body.cursor-on.cursor-text .cursor-ring { opacity: 0; }

/* Hide the native cursor only while the custom one is actually running.
   Previously this keyed off body.subpage, so anyone with reduced motion —
   who never gets the custom cursor — was left with no cursor at all. */
@media (pointer: fine) {
  body.cursor-custom,
  body.cursor-custom a,
  body.cursor-custom button { cursor: none; }
  body.cursor-custom input,
  body.cursor-custom textarea,
  body.cursor-custom [contenteditable] { cursor: text; }
}

/* marquee strip */
.marquee {
  overflow: hidden;
  margin: 11vh calc(-6vw) 0;
  padding: 18px 0;
  border-top: 1.5px solid rgba(11, 15, 26, 0.1);
  border-bottom: 1.5px solid rgba(11, 15, 26, 0.1);
  background: rgba(255, 255, 255, 0.4);
}
.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee 28s linear infinite;
}
.marquee-track span {
  font-family: "Archivo", sans-serif;
  font-weight: 800;
  font-size: clamp(22px, 3vw, 38px);
  letter-spacing: 0.02em;
  white-space: nowrap;
  padding-right: 24px;
  color: transparent;
  -webkit-text-stroke: 1.5px rgba(11, 15, 26, 0.5);
}
.marquee-track span b { color: var(--accent); -webkit-text-stroke: 0; font-weight: 800; }
@keyframes marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* colourful tags (scene palette) */
.tags .tag:nth-child(4n+1) { background: #f8e3dc; color: #a2553e; }
.tags .tag:nth-child(4n+2) { background: #ddeee9; color: #3c7a6e; }
.tags .tag:nth-child(4n+3) { background: #f6ecd4; color: #97742c; }
.tags .tag:nth-child(4n+4) { background: #e2eaf8; color: #4a6c9b; }

/* project thumbs zoom on hover */
.project-card .thumb { transition: transform 0.6s cubic-bezier(0.2, 0.6, 0.2, 1); }
.project-card:hover .thumb { transform: scale(1.06); }
.project-card:hover h3 { color: #a2553e; }
.card h3 { transition: color 0.3s; }

/* cards: slightly glassier */
.card {
  border: 1.5px solid rgba(255, 255, 255, 0.8);
  will-change: transform;
}

/* mini outro CTA on content pages */
.mini-outro {
  text-align: center;
  padding: 18vh 0 6vh;
}
.mini-outro h2 {
  font-family: "Archivo", sans-serif;
  font-weight: 700;
  font-size: clamp(34px, 5.4vw, 72px);
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin-bottom: 5vh;
}

@media (max-width: 760px) {
  .scroll-line { display: none; }
  .marquee { margin: 9vh calc(-6vw) 0; }
  body.subpage .page { margin-top: 9vh; padding-top: 4vh; border-radius: 22px; }
}

/* ============================================================
   Readability mattes, preloader, day/night, landmark labels
   ============================================================ */

/* --- soft matte panels behind text (landscape stays visible) --- */
/* No longer a card — just the lockup. Kept as a hook so the hero contents
   stay clickable inside the pointer-events:none hero layer. */
.hero-card {
  max-width: min(1180px, 100%);
  pointer-events: auto;
}

/* on short laptop viewports the display line has to come down or it eats
   the whole frame and collides with the nav */
@media (max-height: 800px) {
  .hero h1 { font-size: clamp(44px, 8.4vw, 108px); }
  .hero-sub { font-size: clamp(14px, 1.2vw, 17px); margin-top: 2.4vh; }
  .hero { padding-bottom: clamp(88px, 13vh, 132px); }
}
.steps {
  background: rgba(238, 244, 252, 0.55);
  backdrop-filter: blur(9px);
  -webkit-backdrop-filter: blur(9px);
  border: 1.5px solid rgba(255, 255, 255, 0.55);
  border-radius: 26px;
  padding: 24px 28px;
}
.outro h2 {
  background: rgba(238, 244, 252, 0.5);
  backdrop-filter: blur(9px);
  -webkit-backdrop-filter: blur(9px);
  border: 1.5px solid rgba(255, 255, 255, 0.55);
  border-radius: 28px;
  padding: 4vh 5vw;
}
body.subpage .page {
  background: rgba(236, 242, 250, 0.45);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  border-radius: 34px;
  margin-top: 14vh;
  padding-top: 7vh;
  padding-left: 5vw;
  padding-right: 5vw;
}
body.subpage .page { max-width: 1180px; }
.scroll-cue {
  background: rgba(238, 244, 252, 0.6);
  backdrop-filter: blur(6px);
  padding: 10px 18px 12px;
  border-radius: 999px;
  border-bottom: none;
  box-shadow: inset 0 -1.5px 0 var(--ink);
}

/* --- preloader --- */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: #dfe8f4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  transition: opacity 0.55s ease;
}
.preloader.done { opacity: 0; pointer-events: none; }
.preloader svg { width: 120px; height: 120px; position: relative; }
.preloader .ringwrap { position: relative; width: 120px; height: 120px; }
.preloader .pl-logo {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Archivo", sans-serif;
  font-weight: 800;
  font-size: 30px;
  letter-spacing: 0.1em;
  color: var(--ink);
}
.preloader circle {
  fill: none;
  stroke-width: 3.5;
  transform: rotate(-90deg);
  transform-origin: center;
}
.preloader .bgc { stroke: rgba(11, 15, 26, 0.12); }
.preloader .fgc {
  stroke: url(#plgrad);
  stroke-linecap: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
}
.preloader .pl-num {
  font-size: 13px;
  letter-spacing: 0.18em;
  font-weight: 600;
  color: var(--ink-soft);
}
.preloader.exit { opacity: 1; transition: opacity 0.4s ease; }
body.night .preloader { background: #141b2e; }

/* --- landmark hover label --- */
.lm-label {
  position: fixed;
  z-index: 120;
  border-radius: 22px;
  padding: 12px 18px 12px 14px;
  pointer-events: none;
  transform: translate(-50%, calc(-100% - 12px));
  opacity: 0;
  transition: opacity 0.22s ease, transform 0.22s ease;
  box-shadow: 0 14px 38px rgba(20, 35, 70, 0.2), 0 2px 8px rgba(20, 35, 70, 0.1);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 11px;
}
.lm-label.show {
  opacity: 1;
  transform: translate(-50%, calc(-100% - 18px));
}
/* downward caret (uses ::before so ::after is free for the glass rim) */
.lm-label::before {
  content: "";
  position: absolute;
  bottom: -8px;
  left: 50%;
  transform: translateX(-50%);
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 8px solid rgba(255, 255, 255, 0.72);
  z-index: 3;
  pointer-events: none;
}
body.night .lm-label::before { border-top-color: rgba(30, 42, 74, 0.82); }
/* accent dot */
.lm-label-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  background: linear-gradient(135deg, #ff5a5a 0%, #5a8cff 100%);
  box-shadow: 0 0 7px rgba(255, 90, 90, 0.5);
}
.lm-label b {
  display: block;
  font-family: "Archivo", sans-serif;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.lm-label span {
  display: block;
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 500;
  margin-top: 1px;
}
.lm-label-text { flex: 1; }
.lm-label-arrow {
  font-size: 14px;
  opacity: 0.38;
  margin-left: 4px;
  align-self: flex-end;
  margin-bottom: 1px;
}

/* --- day/night toggle --- */
.mode-toggle {
  position: fixed;
  right: 26px;
  bottom: 26px;
  z-index: 90;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.6);
  background: rgba(238, 244, 252, 0.75);
  backdrop-filter: blur(8px);
  cursor: pointer;
  box-shadow: 0 10px 28px rgba(20, 35, 70, 0.18);
  transition: transform 0.25s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink, #10172a);
}
.mode-toggle:hover { transform: scale(1.1); }
.mode-toggle svg {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  transition: opacity 0.25s ease, transform 0.35s ease;
}
.mode-toggle .icon-sun { opacity: 1; transform: rotate(0deg) scale(1); }
.mode-toggle .icon-moon { opacity: 0; transform: rotate(-40deg) scale(0.6); }
.mode-toggle.is-night .icon-sun { opacity: 0; transform: rotate(40deg) scale(0.6); }
.mode-toggle.is-night .icon-moon { opacity: 1; transform: rotate(0deg) scale(1); }

/* --- night theme --- */
body.night {
  --ink: #eef2fa;
  --ink-soft: #aab6cf;
  background: #141b2e;
}
body.night.subpage { background: linear-gradient(180deg, #18203a 0%, #141b2e 60%); }
body.night .btn-light { background: #2a3552; color: #eef2fa; }
body.night .btn-dark { background: #eef2fa; color: #10172a; }
body.night .steps,
body.night .outro h2,
body.night .scroll-cue,
body.night.subpage .page {
  background: rgba(16, 23, 42, 0.55);
  border-color: rgba(255, 255, 255, 0.12);
}
body.night .scroll-cue { box-shadow: inset 0 -1.5px 0 var(--ink); }

/* same haze, tuned to the night sky */
body.night .hero::before {
  background: linear-gradient(
    to top,
    rgba(14, 20, 36, 0.94) 0%,
    rgba(14, 20, 36, 0.76) 24%,
    rgba(14, 20, 36, 0.32) 48%,
    rgba(14, 20, 36, 0) 70%
  );
}
body.night .card, body.night .stat {
  background: rgba(22, 30, 52, 0.72);
  border-color: rgba(255, 255, 255, 0.1);
  box-shadow: 0 10px 36px rgba(0, 0, 0, 0.35);
}
body.night .step.active .step-num { background: #232e4e; }
body.night .step-bar { background: rgba(238, 242, 250, 0.18); }
body.night .step-bar span { background: var(--ink); }
body.night .mobile-menu { background: rgba(16, 23, 42, 0.96); }
body.night .nav-burger span { background: var(--ink); }
body.night .mode-toggle {
  background: rgba(22, 30, 52, 0.8);
  border-color: rgba(255, 255, 255, 0.15);
}
body.night .marquee { background: rgba(20, 28, 50, 0.5); border-color: rgba(255,255,255,0.1); }
body.night .marquee-track span { -webkit-text-stroke-color: rgba(238, 242, 250, 0.45); }
body.night .section-title::before { -webkit-text-stroke-color: rgba(238, 242, 250, 0.16); }

/* the miniature after dark: stock goes navy, gold stays lit — the same trick
   the 3D scenes use, where only the crown and spire keep their colour */
body.night .mb-pale { fill: #27314c; stroke: rgba(238, 242, 250, 0.22); }
body.night .mb-glass { fill: #35496b; stroke: rgba(238, 242, 250, 0.22); }
body.night .mb-pod { fill: #d8c8a6; stroke: rgba(238, 242, 250, 0.22); }
body.night .mb-base { fill: #1d2640; stroke: rgba(238, 242, 250, 0.18); }
body.night .mb-ground { fill: rgba(238, 242, 250, 0.18); }
body.night .mb-part.is-ghost * { stroke: rgba(238, 242, 250, 0.55); }
body.night .mb-name { color: rgba(238, 242, 250, 0.62); }
body.night .accent { -webkit-text-stroke-color: var(--ink); }
body.night .page-kicker { background: rgba(22, 30, 52, 0.75); border-color: rgba(255,255,255,0.12); }
body.night .contact-form input, body.night .contact-form textarea {
  background: rgba(22, 30, 52, 0.8);
  border-color: rgba(255, 255, 255, 0.14);
  color: var(--ink);
}
body.night .cursor-dot { background: var(--ink); }
body.night .cursor-ring { border-color: rgba(238, 242, 250, 0.5); }
body.night .lm-label { background: rgba(22, 30, 52, 0.92); border-color: rgba(255,255,255,0.14); }
body.night .lm-label-dot { box-shadow: 0 0 7px rgba(90, 140, 255, 0.5); }
body.night .site-footer { border-color: rgba(255, 255, 255, 0.12); }
body.night .site-footer a, body.night .info-line a { color: var(--ink); }
body.night .tags .tag { filter: brightness(0.92) saturate(1.1); }

@media (max-width: 760px) {
  /* tuck the toggle under the nav so it never sits on the bottom steps card */
  .mode-toggle { top: 84px; right: 12px; bottom: auto; width: 44px; height: 44px; }
  .mode-toggle svg { width: 19px; height: 19px; }
}

/* ============================================================
   Substance layer: case studies, working form, résumé, proof
   ============================================================ */

/* project card → case-study affordances */
.project-card .thumb { display: block; }
.project-card h3 a { color: inherit; text-decoration: none; }
.project-card:hover h3 a { color: #a2553e; }
.links .case-link { color: var(--accent) !important; border-bottom-color: var(--accent) !important; }

/* "trusted to build for" strip (truthful — real client names) */
.builtfor {
  margin-top: 64px;
  padding: 30px 34px;
  border-radius: 22px;
  background: rgba(255, 255, 255, 0.5);
  border: 1.5px solid rgba(255, 255, 255, 0.6);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 30px;
}
.builtfor-label {
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-soft);
}
.builtfor-names { display: flex; flex-wrap: wrap; gap: 14px 28px; }
.builtfor-names a {
  font-family: "Archivo", sans-serif;
  font-weight: 700;
  font-size: clamp(18px, 2.2vw, 26px);
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  opacity: 0.85;
  transition: opacity 0.25s;
}
.builtfor-names a:hover { opacity: 1; }

/* ---------- case study page ---------- */
.case-back {
  display: inline-block;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  text-decoration: none;
  margin-bottom: 18px;
}
.case-back:hover { color: var(--ink); }
.case-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
/* Frame, not a window: the height follows the screenshot rather than the
   screenshot being cut to fit a fixed box. The small padding turns the frame
   into a mount around the image instead of a hard edge against it. */
.case-hero-img {
  margin-top: 40px;
  padding: 12px;
  border-radius: 24px;
  background: #eef3fa;
  border: 1.5px solid rgba(255, 255, 255, 0.6);
  box-shadow: 0 22px 60px rgba(20, 35, 70, 0.16);
}
.case-hero-img img {
  display: block;
  width: 100%;
  height: auto;
  /* Safety valve so a very tall screenshot cannot swallow the first screen.
     In px, not vh: a vh cap changes with the window, so the same case study
     letterboxes on a short laptop and not on a tall monitor. */
  max-height: 640px;
  object-fit: contain;
  border-radius: 14px;
}
.case-cols {
  display: grid;
  grid-template-columns: 1fr 300px;
  gap: 48px;
  margin-top: 40px;
}
.case-features {
  list-style: none;
  margin: 22px 0 0;
  display: grid;
  gap: 12px;
}
.case-features li {
  position: relative;
  padding-left: 30px;
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink-soft);
}
.case-features li::before {
  content: "→";
  position: absolute;
  left: 0;
  color: var(--accent);
  font-weight: 700;
}
.case-note {
  margin-top: 36px;
  padding: 22px 26px;
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.55);
  border: 1.5px solid rgba(255, 255, 255, 0.6);
  border-left: 3px solid var(--accent);
}
.case-note span {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--ink-soft);
}
.case-note p { margin-top: 8px; font-size: 15.5px; line-height: 1.6; color: var(--ink); }
.case-aside { position: sticky; top: 110px; align-self: start; }
/* spec-sheet list: label left, value right, one full-width row each — so longer
   values like "Custom domain" never wrap unevenly against shorter ones */
.case-stats { display: flex; flex-direction: column; gap: 10px; }
.case-stats .stat {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 15px 18px;
  text-align: left;
}
.case-stats .stat span {
  order: -1;            /* label sits on the left */
  flex-shrink: 0;
  padding-top: 1px;
}
.case-stats .stat b {
  font-size: clamp(15px, 1.6vw, 18px);
  font-weight: 700;
  text-align: right;
  line-height: 1.3;
}

.case-nav {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  margin-top: 80px;
  padding-top: 30px;
  border-top: 1.5px solid rgba(11, 15, 26, 0.12);
}
.case-nav-item {
  text-decoration: none;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.case-nav-item.right { text-align: right; }
.case-nav-item span { font-size: 12px; letter-spacing: 0.08em; color: var(--ink-soft); }
.case-nav-item b {
  font-family: "Archivo", sans-serif;
  font-size: clamp(18px, 2.2vw, 24px);
  letter-spacing: -0.01em;
  color: var(--ink);
  transition: color 0.25s;
}
.case-nav-item:hover b { color: var(--accent); }

/* ---------- working contact form states ---------- */
.cf-hp { position: absolute; left: -9999px; opacity: 0; height: 0; width: 0; }
.form-status { font-size: 14.5px; line-height: 1.5; min-height: 1em; }
.form-status.ok { color: #2e8b6f; font-weight: 600; }
.form-status.err { color: #c8554a; font-weight: 600; }
.contact-form button[disabled] { opacity: 0.6; cursor: progress; }
.form-status a { color: var(--ink); font-weight: 600; }
/* a button that has to read as part of the sentence it sits in */
.linkish {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--ink);
  font-weight: 600;
  cursor: pointer;
  border-bottom: 1.5px solid rgba(11, 15, 26, 0.3);
}
.linkish:hover { border-bottom-color: var(--ink); }
body.night .form-status a, body.night .linkish { color: #eef2fa; }
body.night .linkish { border-bottom-color: rgba(238, 242, 250, 0.35); }

/* the two no-JS-required ways to reach me, beside the form */
.contact-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 8px;
}
.contact-actions .btn { cursor: pointer; }

/* ---------- night-mode variants for new pieces ---------- */
body.night .builtfor,
body.night .case-note,
body.night .case-hero-img { background: rgba(22, 30, 52, 0.6); border-color: rgba(255,255,255,0.12); }
body.night .case-nav { border-color: rgba(255,255,255,0.14); }
body.night .form-status.ok { color: #6fd3ad; }

/* ---------- responsive ---------- */
@media (max-width: 860px) {
  .case-cols { grid-template-columns: 1fr; gap: 30px; }
  .case-aside { position: static; }
}
@media (max-width: 760px) {
  .builtfor { flex-direction: column; align-items: flex-start; gap: 12px; }
  .case-nav-item b { font-size: 17px; }
}



.resume-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 24px;
  margin: 30px 0 0 30px;
  background: #f0f2f5;
  border-radius: 12px;
  font-size: 14px;
  position: sticky;
  top: 0;
  z-index: 10;
}

body.resume-body {
  background: #fdfdfd;
  color: #333;
  font-family: "Inter", system-ui, sans-serif;
}

.resume-container {
  display: grid;
  grid-template-columns: 320px 1fr;
  max-width: 1000px;
  margin: 0 auto 60px;
  background: #fff;
  box-shadow: 0 0 40px rgba(0,0,0,0.05);
  min-height: 297mm; /* A4 height approximation */
}

.resume-sidebar {
  background: #f7f9fc;
  border-right: 1px solid #eee;
  padding: 40px 30px;
  display: flex;
  flex-direction: column;
  gap: 30px;
}

.resume-profile-pic {
  width: 180px;
  height: 180px;
  margin: 0 auto 20px;
  border-radius: 50%;
  overflow: hidden;
  border: 6px solid #fff;
  box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.resume-profile-pic img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.resume-side-section {
  margin-bottom: 10px;
}
.resume-side-title {
  font-family: "Archivo", sans-serif;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: #444;
  background: #eef2f7;
  padding: 8px 12px;
  margin: 0 0 15px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.resume-side-title::before {
  content: "";
  width: 10px;
  height: 10px;
  background: #8da9c4;
  display: inline-block;
}

.resume-side-content {
  font-size: 13px;
  line-height: 1.6;
  color: #666;
}

.contact-item {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}
.contact-icon {
  width: 20px;
  text-align: center;
  color: #888;
}
.contact-item a {
  color: #555;
  text-decoration: none;
  transition: color 0.2s;
}
.contact-item a:hover { color: #000; }

.cert-badges {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 20px;
}
.cert-badges img {
  width: 100%;
  height: auto;
  border-radius: 4px;
}

.skill-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.skill-list li {
  margin-bottom: 8px;
  position: relative;
  padding-left: 15px;
}
.skill-list li::before {
  content: "•";
  position: absolute;
  left: 0;
  color: #aaa;
}

.resume-main {
  padding: 60px 50px;
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.resume-main-header {
  text-align: center;
  border-bottom: 2px solid #333;
  padding-bottom: 30px;
  margin-bottom: 20px;
}
.resume-main-header h1 {
  font-family: "Archivo", sans-serif;
  font-size: 42px;
  font-weight: 800;
  letter-spacing: 0.2em;
  margin: 0;
}
.resume-main-title {
  font-size: 14px;
  letter-spacing: 0.3em;
  color: #777;
  margin-top: 10px;
  font-weight: 500;
}

.resume-main-section {
  display: flex;
  flex-direction: column;
  gap: 15px;
}
.resume-main-title-block {
  font-family: "Archivo", sans-serif;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: #444;
  background: #eef2f7;
  padding: 8px 12px;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 10px;
}
.resume-main-title-block::before {
  content: "";
  width: 10px;
  height: 10px;
  background: #8da9c4;
  display: inline-block;
}

.resume-main-section p {
  font-size: 14px;
  line-height: 1.6;
  color: #555;
}

.experience-item, .education-item, .project-item {
  margin-bottom: 20px;
}
.experience-head, .education-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 4px;
}
.experience-head b, .education-head b {
  font-size: 16px;
  font-weight: 700;
}
.experience-head span, .education-head span {
  font-size: 13px;
  color: #888;
}
.experience-company, .education-company {
  font-size: 14px;
  color: #666;
  margin-bottom: 8px;
  font-style: italic;
}
.experience-details, .education-details, .project-details {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 13.5px;
  color: #555;
  line-height: 1.6;
}
.experience-details li, .education-details li, .project-details li {
  position: relative;
  padding-left: 15px;
  margin-bottom: 4px;
}
.experience-details li::before, .education-details li::before, .project-details li::before {
  content: "•";
  position: absolute;
  left: 0;
  color: #aaa;
}

.project-head {
  font-size: 16px;
  font-weight: 700;
  margin-bottom: 8px;
}
.project-details a {
  color: #4a6c9b;
  text-decoration: none;
}
.project-details a:hover { text-decoration: underline; }

@media print {
  .resume-toolbar { display: none; }
  body.resume-body { background: #fff; }
  .resume-container {
    box-shadow: none;
    margin: 0;
    width: 100%;
    max-width: none;
  }
}

@media (max-width: 800px) {
  .resume-container {
    grid-template-columns: 1fr;
  }
  .resume-sidebar {
    border-right: 0;
    border-bottom: 1px solid #eee;
  }
}

@media (max-width: 720px) {
  .resume-cols { grid-template-columns: 1fr; gap: 10px; }
  .resume-contact { text-align: left; }
  .resume-head { align-items: flex-start; }
}

@media print {
  .resume-toolbar { display: none; }
  body.resume-page { background: #fff; }
  .resume { box-shadow: none; margin: 0; max-width: none; border-radius: 0; padding: 0; }
  .resume-section { break-inside: avoid; }
  .resume-item { break-inside: avoid; }
  a { color: var(--ink) !important; }
}

/* ============================================================
   LIQUID GLASS — translucent floating panels, refractive rims,
   specular sheen, water-drop depth, elastic hovers.
   (Appended last so it supersedes the earlier matte treatment.)
   ============================================================ */
:root {
  --lg-blur: 18px;
  --lg-sat: 180%;
  --lg-bg: linear-gradient(140deg, rgba(255,255,255,0.26), rgba(255,255,255,0.09));
  --lg-bg-strong: linear-gradient(140deg, rgba(255,255,255,0.52), rgba(255,255,255,0.24));
  --lg-border: rgba(255,255,255,0.6);
  --lg-shadow: 0 16px 44px rgba(20,35,70,0.16), 0 3px 10px rgba(20,35,70,0.07);
  --lg-inset: inset 0 1px 1px rgba(255,255,255,0.85), inset 0 2px 22px rgba(255,255,255,0.18), inset 0 -12px 28px rgba(255,255,255,0.05);
  /* iridescent refractive rim (light bends warm↔cool at the edges) */
  --lg-rim: linear-gradient(140deg, rgba(255,255,255,0.95) 0%, rgba(186,214,255,0.20) 28%, rgba(255,255,255,0.04) 50%, rgba(255,214,232,0.14) 72%, rgba(255,255,255,0.62) 100%);
  /* top-left specular highlight (the gloss on a drop of water) */
  --lg-sheen: radial-gradient(135% 100% at 16% -12%, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0.14) 26%, rgba(255,255,255,0) 52%);
  --lg-elastic: cubic-bezier(0.34, 1.56, 0.64, 1);
}
body.night {
  --lg-bg: linear-gradient(140deg, rgba(48,62,98,0.5), rgba(20,28,48,0.34));
  --lg-bg-strong: linear-gradient(140deg, rgba(42,56,92,0.82), rgba(22,30,52,0.64));
  --lg-border: rgba(255,255,255,0.16);
  --lg-shadow: 0 18px 48px rgba(0,0,0,0.44), 0 3px 12px rgba(0,0,0,0.3);
  --lg-inset: inset 0 1px 1px rgba(255,255,255,0.32), inset 0 2px 22px rgba(255,255,255,0.05);
  --lg-rim: linear-gradient(140deg, rgba(255,255,255,0.5) 0%, rgba(150,190,255,0.14) 30%, rgba(255,255,255,0.02) 52%, rgba(255,255,255,0.06) 72%, rgba(255,255,255,0.3) 100%);
  --lg-sheen: radial-gradient(135% 100% at 16% -12%, rgba(180,205,255,0.26) 0%, rgba(180,205,255,0.06) 28%, rgba(255,255,255,0) 52%);
}

/* ---- shared glass surface ---- */
/* .hero-card is deliberately absent — the hero is a bare title card now */
.steps, .outro h2, .scroll-cue, .page-kicker,
.mode-toggle, .lm-label, .card, .stat, .builtfor, .case-note,
body.subpage .page {
  background: var(--lg-sheen), var(--lg-bg);
  -webkit-backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-sat));
  backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-sat));
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-shadow), var(--lg-inset);
}
/* give static panels a containing block for the rim ::after */
.page-kicker, .card, .stat, .builtfor, .case-note,
.outro h2, .case-hero-img, .project-card .thumb, .btn { position: relative; }

/* ---- refractive rim (edge-only, never covers content) ---- */
.steps::after, .outro h2::after, .scroll-cue::after,
.page-kicker::after, .mode-toggle::after, .lm-label::after, .card::after,
.stat::after, .builtfor::after, .case-note::after, body.subpage .page::after,
.nav::after, .case-hero-img::after, .project-card .thumb::after,
.btn-light::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: var(--lg-rim);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
  z-index: 2;
}

/* ---- floating glass nav island ---- */
.nav {
  top: 14px;
  left: 14px;
  right: 14px;
  width: auto;
  padding: 12px 24px;
  border-radius: 24px;
  background: var(--lg-sheen), var(--lg-bg-strong);
  -webkit-backdrop-filter: blur(22px) saturate(185%);
  backdrop-filter: blur(22px) saturate(185%);
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-shadow), var(--lg-inset);
}

/* ---- glass form fields ---- */
.contact-form input, .contact-form textarea {
  background: var(--lg-sheen), var(--lg-bg);
  -webkit-backdrop-filter: blur(12px) saturate(160%);
  backdrop-filter: blur(12px) saturate(160%);
  border: 1px solid var(--lg-border);
  box-shadow: inset 0 1px 1px rgba(255,255,255,0.6), 0 6px 18px rgba(20,35,70,0.07);
}
.contact-form input:focus, .contact-form textarea:focus {
  border-color: rgba(255,255,255,0.9);
  box-shadow: inset 0 1px 1px rgba(255,255,255,0.7), 0 0 0 3px rgba(120,170,255,0.28);
}

/* ---- marquee strip: glass without side overflow ---- */
.marquee {
  background: var(--lg-bg);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  border-top: 1px solid var(--lg-border);
  border-bottom: 1px solid var(--lg-border);
}

/* ---- image panels: keep the picture, add a glass rim + depth ---- */
.case-hero-img, .project-card .thumb {
  border: 1px solid var(--lg-border);
  box-shadow: 0 16px 44px rgba(20,35,70,0.18), inset 0 1px 1px rgba(255,255,255,0.4);
}

/* ---- buttons as liquid glass ---- */
.btn-light {
  background: var(--lg-sheen), var(--lg-bg-strong);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  backdrop-filter: blur(14px) saturate(170%);
  border: 1px solid var(--lg-border);
  box-shadow: 0 8px 22px rgba(20,35,70,0.14), inset 0 1px 1px rgba(255,255,255,0.8);
  color: var(--ink);
}
.btn-dark {
  background: linear-gradient(140deg, #20283d, #0a0e19);
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 10px 26px rgba(11,15,26,0.34), inset 0 1px 1px rgba(255,255,255,0.22), inset 0 -8px 18px rgba(0,0,0,0.25);
  color: #fff;
}

/* ---- elastic spring hovers ---- */
.btn { transition: transform 0.5s var(--lg-elastic), box-shadow 0.35s ease, background 0.35s ease; }
.btn:hover { transform: translateY(-2px) scale(1.05); }
.btn-light:hover { box-shadow: 0 16px 34px rgba(20,35,70,0.2), inset 0 1px 1px rgba(255,255,255,0.9); }
.btn-dark:hover { box-shadow: 0 18px 38px rgba(11,15,26,0.42), inset 0 1px 1px rgba(255,255,255,0.28); }

.card, .stat, .builtfor {
  transition: transform 0.55s var(--lg-elastic), box-shadow 0.4s ease, background 0.4s ease;
}
.card:hover, .stat:hover {
  transform: translateY(-9px) scale(1.02);
  box-shadow: 0 30px 64px rgba(20,35,70,0.22), var(--lg-inset);
}
.mode-toggle {
  transition: transform 0.5s var(--lg-elastic), box-shadow 0.3s ease, background 0.4s ease;
}
.mode-toggle:hover { transform: scale(1.14) translateY(-2px); }
.project-card .thumb { transition: transform 0.6s var(--lg-elastic); }

/* ---- mobile menu: dense frosted glass (stays legible over the scene) ---- */
.mobile-menu {
  background: var(--lg-sheen), var(--lg-bg-strong);
  -webkit-backdrop-filter: blur(30px) saturate(180%);
  backdrop-filter: blur(30px) saturate(180%);
}

/* ---- night-mode glass (reuse selectors so source-order wins) ---- */
body.night .steps, body.night .outro h2,
body.night .scroll-cue, body.night.subpage .page, body.night .card,
body.night .stat, body.night .builtfor, body.night .case-note,
body.night .page-kicker, body.night .mode-toggle, body.night .lm-label,
body.night .line {
  background: var(--lg-sheen), var(--lg-bg);
  border-color: var(--lg-border);
  box-shadow: var(--lg-shadow), var(--lg-inset);
}
body.night .line { border-top: 4px solid var(--c); }
body.night .station .dot { box-shadow: 0 0 0 3px rgba(22, 30, 52, 0.85), 0 1px 5px rgba(0, 0, 0, 0.4); }
body.night .station.core .dot,
body.night .station.xchg .dot { box-shadow: 0 0 0 3px rgba(22, 30, 52, 0.9), 0 1px 5px rgba(0, 0, 0, 0.4); }
body.night .legend-x i { background: #1a2238; }
body.night .nav, body.night .mobile-menu, body.night .btn-light {
  background: var(--lg-sheen), var(--lg-bg-strong);
  border-color: var(--lg-border);
}
body.night .marquee { background: var(--lg-bg); border-color: var(--lg-border); }
body.night .contact-form input, body.night .contact-form textarea {
  background: var(--lg-sheen), var(--lg-bg);
  border-color: var(--lg-border);
  color: var(--ink);
}
body.night .btn-dark { background: linear-gradient(140deg, #f4f7ff, #d9e2f3); color: #10172a; }

/* ---- outro headline: clearer, less frosted glass frame ---- */
.outro h2 {
  background: var(--lg-sheen), linear-gradient(140deg, rgba(255,255,255,0.12), rgba(255,255,255,0.04));
  -webkit-backdrop-filter: blur(5px) saturate(135%);
  backdrop-filter: blur(5px) saturate(135%);
}
body.night .outro h2 {
  background: var(--lg-sheen), linear-gradient(140deg, rgba(48,62,98,0.26), rgba(20,28,48,0.16));
}

/* ---- responsive: keep the nav island tidy on phones ---- */
@media (max-width: 760px) {
  .nav { top: 10px; left: 10px; right: 10px; padding: 10px 16px; border-radius: 18px; }
}

/* ============================================================
   Scroll cue + bottom-card motion (homepage)
   ============================================================ */
/* lay the cue out as label + chevron; the compact label and the chevron
   are mobile-only (hidden here so desktop keeps the full pill unchanged) */
.scroll-cue { display: inline-flex; align-items: center; }
.scroll-cue .sc-mini, .scroll-cue .sc-arrow { display: none; }

@keyframes scBob {
  0%, 100% { transform: translateY(0) rotate(45deg); opacity: 0.55; }
  50%      { transform: translateY(4px) rotate(45deg); opacity: 1; }
}

/* the bottom step cards deal in with a small springy slide + badge pop */
@keyframes stepIn {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes stepNumPop {
  from { opacity: 0; transform: scale(0.7); }
  to   { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue .sc-arrow,
  .steps .step.active,
  .steps .step.active .step-num,
  .dv-hand, .dv-caret, .dv-steam { animation: none !important; }
}

/* ============================================================
   Mobile — about · projects · skills · contact
   ============================================================ */
@media (max-width: 760px) {

  /* --- spacing tightening --- */
  .section-title { margin-top: 56px; margin-bottom: 18px; }
  /* one column: the scene drops under the lede rather than squeezing beside it */
  .about-intro { grid-template-columns: 1fr; gap: 28px; }
  .dev-scene { max-width: 300px; margin: 0 auto; }
  /* the wrapper owns the margins once page.js has built the section heads */
  .section-head { margin: 56px 0 18px; gap: 16px; }
  /* a heading at 26px next to a 96px stage leaves no room for the words */
  .mini-bldg { width: 56px; }
  .mb-name { display: none; }
  .page-lede { font-size: 15px; }
  .mini-outro { padding: 8vh 0 3vh; }
  .mini-outro h2 { font-size: clamp(24px, 7vw, 36px); margin-bottom: 2.5vh; }

  /* --- stats: 2×2 grid on phones --- */
  .stats { grid-template-columns: 1fr 1fr; gap: 14px; }
  .stat { padding: 18px 14px; }

  /* --- cards: tighter gaps and padding --- */
  .card-grid { gap: 16px; }
  .card { padding: 22px 20px; }

  /* --- language cards: 2 col so 4 langs fit in 2 rows --- */
  .lang-grid { grid-template-columns: 1fr 1fr; }

  /* --- project card links: pill buttons for reliable tapping --- */
  .project-card .links { flex-wrap: wrap; gap: 8px; padding-top: 14px; }
  .project-card .links a {
    padding: 7px 14px;
    border-radius: 999px;
    border: 1.5px solid rgba(11, 15, 26, 0.18) !important;
    border-bottom: 1.5px solid rgba(11, 15, 26, 0.18) !important;
    background: rgba(255, 255, 255, 0.55);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    font-size: 12px;
    min-height: 36px;
    display: inline-flex;
    align-items: center;
  }
  .links .case-link {
    color: var(--accent) !important;
    border-color: rgba(255, 90, 90, 0.45) !important;
    background: rgba(255, 90, 90, 0.08) !important;
  }

  /* night mode: dark pills */
  body.night .project-card .links a {
    background: rgba(22, 30, 52, 0.6) !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
  }
  body.night .links .case-link {
    border-color: rgba(255, 90, 90, 0.45) !important;
    background: rgba(255, 90, 90, 0.12) !important;
  }

  /* --- builtfor strip: compact --- */
  .builtfor { padding: 18px 20px; margin-top: 40px; }
  .builtfor-names a { font-size: clamp(16px, 4.5vw, 22px); }

  /* --- cert cards: smaller badge --- */
  .cert-card { gap: 14px; }
  .cert-card img { width: 60px; height: 60px; }

  /* --- skill bars: tighter --- */
  .skill-row { margin-bottom: 18px; }

  /* --- contact: prevent iOS input zoom, full-width button --- */
  .contact-form input,
  .contact-form textarea { font-size: 16px; padding: 14px 16px; }
  .contact-form textarea { min-height: 130px; }
  #cf-submit { width: 100%; text-align: center; }

  /* --- info lines --- */
  .info-line { margin-bottom: 20px; font-size: 15px; }
  .info-line > span { font-size: 20px; padding-top: 2px; flex-shrink: 0; }

  /* --- contact CTAs: stack full-width rather than crowd onto one line --- */
  .contact-grid > div > .btn,
  .contact-actions .btn { width: 100%; text-align: center; display: block; box-sizing: border-box; }
  .contact-actions { flex-direction: column; }
}

/* Very narrow phones (≤420 px) */
@media (max-width: 420px) {
  .cert-card { flex-direction: column; gap: 10px; }
  .cert-card img { width: 52px; height: 52px; }
  .card { padding: 18px 16px; }
  .section-title { margin-top: 44px; }
  .section-head { margin-top: 44px; gap: 12px; }
  .mini-bldg { width: 44px; }
  .contact-grid { gap: 24px; margin-top: 36px; }
  .stats { gap: 10px; }
}

/* ============================================================
   No-scene fallback (home page)
   ------------------------------------------------------------
   The hero, steps and outro are fixed-position overlays whose opacity is
   driven entirely by the ScrollTrigger in main.js. If the 3D scene can't run
   — no WebGL, a blocked CDN, a throw in main.js — nothing ever reveals them
   and the visitor gets a hero over ten screens of nothing.

   index.html sets .has-scene on <html> only when WebGL is available, and
   page.js clears it again if the scene never paints. Without that flag the
   overlays drop back into normal document flow as a plain, readable page.
   ============================================================ */
html:not(.has-scene) #scene,
html:not(.has-scene) .scroll-space,
html:not(.has-scene) .scroll-cue { display: none; }

html:not(.has-scene) body {
  background: linear-gradient(180deg, #e7eefa 0%, #dfe8f4 40%, #dce6f3 100%);
}
html:not(.has-scene) main {
  max-width: 1000px;
  margin: 0 auto;
  padding: 148px 6vw 12vh;
  display: flex;
  flex-direction: column;
  gap: 9vh;
}
html:not(.has-scene) .hero,
html:not(.has-scene) .steps,
html:not(.has-scene) .outro {
  position: static;
  inset: auto;
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  max-width: none;
  transform: none;
}
/* no scene to read the type against, so the haze has nothing to do — and
   with .hero static its inset:0 would resolve against the viewport and
   wash the whole document */
html:not(.has-scene) .hero { padding: 0; }
html:not(.has-scene) .hero::before { display: none; }
html:not(.has-scene) .outro { gap: 4vh; }

/* every step is expanded and "current" — there is no scroll position to track */
html:not(.has-scene) .step { margin-bottom: 40px; }
html:not(.has-scene) .step-body { grid-template-rows: 1fr; }
html:not(.has-scene) .step-title { font-size: clamp(24px, 2.4vw, 34px); }
html:not(.has-scene) .step-num {
  background: #fff;
  box-shadow: 0 8px 24px rgba(20, 35, 70, 0.12);
}
html:not(.has-scene) .step-bar span { height: 100%; }
html:not(.has-scene) body.night .step-num { background: #232e4e; }

@media (max-width: 760px) {
  html:not(.has-scene) main { padding-top: 110px; gap: 6vh; }
  /* the mobile rule collapses all but the active step; without a scroll
     position nothing is active, so show them all */
  html:not(.has-scene) .steps .step { display: block; }
}

/* the skip control and scroll cue only mean something while the flight exists */
html:not(.has-scene) .skip-tour { display: none; }

/* ============================================================
   Reduced motion
   ------------------------------------------------------------
   The camera flight is the whole point of the page, so it isn't removed —
   but it is cut to a fraction of the travel, and main.js drops the scrub
   smoothing and pins the skip control open so there is always a way out.
   This block sits last so it beats both the desktop and mobile lengths.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .scroll-space { height: 240vh; }
  .scroll-cue .sc-arrow { animation: none; }
  .skip-tour { transition: none; }
}
