/* =========================================================
   SECTIONS — per-section layout only.
========================================================= */

/* ---------- floating dock nav ----------
   A pill that hovers just above the bottom edge, holding all primary
   navigation. Replaces the old sticky top header entirely. */
.dock{
  position:fixed;
  left:50%;
  bottom:var(--sp-5);
  z-index:100;
  transform:translateX(-50%);
  max-width:calc(100vw - var(--sp-5) * 2);
  padding:var(--sp-2);
  background:color-mix(in srgb, var(--c-surface-hi) 76%, transparent);
  border:1px solid var(--c-border);
  border-radius:var(--radius-pill);
  backdrop-filter:var(--blur-glass);
  -webkit-backdrop-filter:var(--blur-glass);
  box-shadow:var(--shadow-lg);
}

.dock__list{
  display:flex;
  align-items:center;
  gap:var(--sp-1);
  /* narrow screens scroll the pill rather than wrapping or clipping */
  overflow-x:auto;
  scrollbar-width:none;
  -ms-overflow-style:none;
}
.dock__list::-webkit-scrollbar{ display:none; }

.dock__list a{
  display:block;
  padding:var(--sp-2) var(--sp-4);
  border-radius:var(--radius-pill);
  font-size:var(--fs-sm);
  font-weight:500;
  white-space:nowrap;
  color:var(--c-text-muted);
  transition:color var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out);
}
.dock__list a:hover{
  color:var(--c-text);
  background:var(--c-surface);
}
.dock__list a.is-active{
  color:var(--c-on-accent);
  background:var(--c-accent);
  box-shadow:0 2px 14px rgba(74,143,255,.45);
}

@media (max-width: 720px){
  .dock{
    bottom:var(--sp-3);
    max-width:calc(100vw - var(--sp-4) * 2);
  }
  .dock__list a{
    padding:var(--sp-2) var(--sp-3);
    font-size:var(--fs-xs);
  }
}


/* ---------- hero + about: the pinned zoom scene ----------
   A tall scroller whose sticky child holds the viewport. The monitor
   screen in the photograph is the pivot: the scene dollies toward it
   while the About panel grows out of it.

   Transforms are set from js/modules/zoom.js, which measures the
   screen's real position each resize. Everything here is the static
   scaffolding plus the no-JS / reduced-motion / small-screen fallback. */
.zoom{
  position:relative;
  /* scroll distance for the whole move; tuned so the zoom feels
     deliberate rather than twitchy */
  height:300vh;
}
.zoom__pin{
  position:sticky;
  top:0;
  height:100vh;
  overflow:hidden;
}

/* the photograph */
.zoom__scene{
  position:absolute;
  inset:0;
  z-index:0;
  will-change:transform, opacity;
}
.zoom__scene picture{ display:block; height:100%; }
.zoom__bg{
  width:100%;
  height:100%;
  object-fit:cover;
  /* the source image is very dark already; this keeps the slogan
     legible over the brighter glow at the bottom */
  filter:brightness(.92);
}

/* slogan layer */
.zoom__intro{
  position:absolute;
  inset:0;
  z-index:2;
  display:grid;
  align-content:start;
  padding-top:16vh;
  text-align:center;
  will-change:transform, opacity;
  pointer-events:none;
}
.zoom__intro-inner{ pointer-events:auto; }
.zoom__intro .eyebrow{ display:block; margin-bottom:var(--sp-4); }
.zoom__slogan{
  margin-bottom:var(--sp-4);
  font-size:var(--fs-3xl);
  text-shadow:0 2px 40px rgba(0,0,0,.85);
}
.zoom__lede{
  max-width:46ch;
  margin-inline:auto;
  color:var(--c-text-muted);
  text-shadow:0 2px 20px rgba(0,0,0,.9);
}
.zoom__cue{
  /* sits well below the lede, nearer the lower third of the scene */
  margin-top:22vh;
  font-family:var(--font-mono);
  font-size:var(--fs-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--c-text-faint);
}
.zoom__cue::after{
  content:"";
  display:block;
  width:1px;
  height:34px;
  margin:var(--sp-3) auto 0;
  background:linear-gradient(var(--c-accent), transparent);
  animation:zoomCue 1.9s ease-in-out infinite;
}
@keyframes zoomCue{
  0%{ transform:scaleY(0); transform-origin:top; }
  50%{ transform:scaleY(1); transform-origin:top; }
  51%{ transform-origin:bottom; }
  100%{ transform:scaleY(0); transform-origin:bottom; }
}

/* the panel that grows out of the screen */
.zoom__portal{
  position:absolute;
  inset:0;
  z-index:3;
  display:grid;
  place-items:center;
  pointer-events:none;
  will-change:transform, opacity;
  /* Visible by default. If zoom.js never runs, the panel must still be
     readable rather than a permanently invisible About section — the
     same failure mode guarded against in reveal.js. */
  opacity:1;
}
/* zoom.js adds this to <html> and immediately writes an inline opacity,
   so there is no flash of the panel before the effect takes over. */
html.zoom-ready .zoom__portal{ opacity:0; }
.zoom__portal.is-open{ pointer-events:auto; }

.panel{
  width:100%;
  height:100%;
  overflow:hidden;
  background:
    radial-gradient(ellipse 90% 60% at 50% -10%, rgba(79,140,255,.10), transparent 70%),
    var(--c-surface);
  border:1px solid var(--c-border-strong);
  box-shadow:0 0 120px rgba(79,140,255,.18);
}
/* content scrolls inside the panel if a short viewport can't hold it,
   so nothing is ever clipped away */
.panel__scroll{
  height:100%;
  overflow-y:auto;
  padding:var(--sp-8) var(--sp-7);
}
.panel__scroll > *{ max-width:var(--shell-max); margin-inline:auto; }
.panel__head{ margin-bottom:var(--sp-5); }
.about__actions{
  display:flex;
  flex-wrap:wrap;
  gap:var(--sp-3);
  margin-top:var(--sp-6);
}
.about .stat-row{
  margin-top:var(--sp-6);
  padding-top:var(--sp-5);
  border-top:1px solid var(--c-border);
}

/* ---- fallback: no JS, reduced motion, or a small screen ----
   The pin collapses and the two parts become ordinary stacked
   sections, so the content is fully reachable without the effect. */
@media (max-width: 900px), (prefers-reduced-motion: reduce){
  .zoom{ height:auto; }
  .zoom__pin{ position:static; height:auto; overflow:visible; }

  .zoom__scene{
    position:relative;
    height:62vh;
    transform:none !important;
    opacity:1 !important;
  }

  .zoom__intro{
    position:absolute;
    inset:0;
    padding-top:14vh;
    transform:none !important;
    opacity:1 !important;
  }

  .zoom__portal{
    position:relative;
    inset:auto;
    opacity:1 !important;
    transform:none !important;
    pointer-events:auto;
    padding:var(--sp-8) 0 0;
  }
  .panel{
    height:auto;
    background:none;
    border:0;
    box-shadow:none;
  }
  .panel__scroll{
    height:auto;
    overflow:visible;
    max-width:var(--shell-max);
    margin-inline:auto;
    padding:0 var(--shell-pad);
  }
}

/* no-JS: the transforms never run, so make sure nothing starts hidden */
html:not(.js) .zoom__portal{ opacity:1 !important; pointer-events:auto; }

/* ---------- generic section ---------- */
.section{ padding-block:var(--sp-9); }
.section > .shell{ max-width:var(--shell-max); }

.section__head{
  margin-bottom:var(--sp-8);
  max-width:var(--measure);
}
.section__index{
  display:inline-flex;
  align-items:center;
  gap:var(--sp-3);
  margin-bottom:var(--sp-4);
  font-family:var(--font-mono);
  font-size:var(--fs-xs);
  letter-spacing:var(--tracking-wide);
  color:var(--c-accent);
}
/* a short rule of light trailing the section number */
.section__index::after{
  content:"";
  width:56px;
  height:1px;
  background:linear-gradient(90deg, var(--c-accent), transparent);
}
.section__title{ font-size:var(--fs-2xl); }
.section__sub{
  margin-top:var(--sp-4);
  color:var(--c-text-muted);
  font-size:var(--fs-md);
}

/* Each section gets its own accent so the palette is used as signal
   rather than sprayed everywhere. Blue stays the default voice. */
#projects   .section__index{ color:var(--c-cyan); }
#projects   .section__index::after{ background:linear-gradient(90deg, var(--c-cyan), transparent); }
#services   .section__index{ color:var(--c-purple); }
#services   .section__index::after{ background:linear-gradient(90deg, var(--c-purple), transparent); }
#volunteer  .section__index{ color:var(--c-green); }
#volunteer  .section__index::after{ background:linear-gradient(90deg, var(--c-green), transparent); }
#contact    .section__index{ color:var(--c-orange); }
#contact    .section__index::after{ background:linear-gradient(90deg, var(--c-orange), transparent); }

/* ---------- about ---------- */
.about{
  display:grid;
  grid-template-columns:1.2fr .8fr;
  gap:var(--sp-7);
  align-items:start;
}
.about__copy{ color:var(--c-text-muted); }
.about__aside{
  display:flex;
  flex-direction:column;
  gap:var(--sp-5);
}
.cat-figure figcaption{
  margin-top:var(--sp-3);
  text-align:center;
  font-size:var(--fs-xs);
  color:var(--c-text-faint);
}

/* ---------- case studies ---------- */
.case-list{
  display:flex;
  flex-direction:column;
  gap:var(--sp-7);
}
.case{
  display:grid;
  grid-template-columns:220px 1fr;
  gap:var(--sp-6);
  padding-top:var(--sp-6);
  border-top:1px solid var(--c-border);
}
.case__tag{
  font-family:var(--font-mono);
  font-size:var(--fs-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--c-text-faint);
}
.case__role{
  margin-top:var(--sp-2);
  font-size:var(--fs-sm);
  color:var(--c-text-muted);
}
.case__title{
  margin-bottom:var(--sp-5);
  font-size:var(--fs-xl);
}
.case__block + .case__block{ margin-top:var(--sp-4); }
.case__block h4{
  margin-bottom:var(--sp-1);
  font-size:var(--fs-xs);
  font-weight:600;
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--c-text-faint);
}
.case__block p{ color:var(--c-text-muted); font-size:var(--fs-sm); }
.case .tag-list{ margin-top:var(--sp-5); }

/* ---------- timeline (experience + volunteer) ---------- */
.timeline{
  display:flex;
  flex-direction:column;
}
.role{
  display:grid;
  grid-template-columns:200px 1fr;
  gap:var(--sp-6);
  padding-block:var(--sp-6);
  border-top:1px solid var(--c-border);
}
.role:last-child{ border-bottom:1px solid var(--c-border); }
.role__dates{
  font-family:var(--font-mono);
  font-size:var(--fs-xs);
  color:var(--c-text-faint);
}
.role__title{ font-size:var(--fs-lg); }
.role__org{
  margin-bottom:var(--sp-4);
  font-size:var(--fs-sm);
  color:var(--c-accent);
}

/* ---------- services ---------- */
.service-list{
  display:grid;
  grid-template-columns:repeat(2,1fr);
  gap:var(--sp-5);
}
.service{ padding:var(--sp-5); }
.service__title{
  margin-bottom:var(--sp-3);
  font-size:var(--fs-lg);
}
.service p{ color:var(--c-text-muted); font-size:var(--fs-sm); }

/* ---------- skills ---------- */
.skill-groups{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:var(--sp-6);
}
.skill-group__title{
  margin-bottom:var(--sp-4);
  font-size:var(--fs-base);
}

/* ---------- testimonials ---------- */
.quote-list{
  display:grid;
  grid-template-columns:repeat(2,1fr);
  gap:var(--sp-5);
}

/* ---------- education ---------- */
.education{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:var(--sp-6);
  align-items:start;
}
.degree{ padding:var(--sp-5); }
.degree__org{ margin-top:var(--sp-2); color:var(--c-text-muted); font-size:var(--fs-sm); }
.degree__meta{ margin-top:var(--sp-1); color:var(--c-text-faint); font-size:var(--fs-xs); }

.cert-heading{ margin-bottom:var(--sp-4); font-size:var(--fs-base); }
.cert-list{
  display:flex;
  flex-direction:column;
  gap:var(--sp-3);
}
.cert-list li{
  position:relative;
  padding-left:var(--sp-5);
  font-size:var(--fs-sm);
  color:var(--c-text-muted);
}
.cert-list li::before{
  content:"";
  position:absolute;
  left:0; top:.55em;
  width:9px; height:9px;
  border:2px solid var(--c-accent);
  border-radius:50%;
}

/* ---------- contact ---------- */
.contact{
  display:grid;
  grid-template-columns:1.1fr .9fr;
  gap:var(--sp-6);
  align-items:start;
}
.contact__form{
  display:flex;
  flex-direction:column;
  gap:var(--sp-4);
}
.contact__links{
  display:flex;
  flex-direction:column;
}
.contact__links a{
  display:flex;
  justify-content:space-between;
  gap:var(--sp-4);
  padding:var(--sp-4) 0;
  border-bottom:1px solid var(--c-border);
  font-size:var(--fs-sm);
  transition:color var(--dur-fast) var(--ease-out);
}
.contact__links li:first-child a{ border-top:1px solid var(--c-border); }
.contact__links a:hover{ color:var(--c-accent); }
.contact__key{ color:var(--c-text-faint); }

/* ---------- footer ---------- */
.site-footer{
  /* extra bottom room so the floating dock never covers the footer text */
  padding-block:var(--sp-6) calc(var(--dock-h) + var(--sp-6));
  border-top:1px solid var(--c-border);
}
.site-footer__inner{
  display:flex;
  justify-content:space-between;
  flex-wrap:wrap;
  gap:var(--sp-3);
  font-size:var(--fs-sm);
  color:var(--c-text-faint);
}

/* =========================================================
   RESPONSIVE
========================================================= */
@media (max-width: 900px){
  .about,
  .education,
  .contact{ grid-template-columns:1fr; }

  .service-list,
  .quote-list{ grid-template-columns:1fr; }

  .skill-groups{ grid-template-columns:repeat(2,1fr); }

  .case,
  .role{ grid-template-columns:1fr; gap:var(--sp-4); }

  .section{ padding-block:var(--sp-8); }
}

@media (max-width: 720px){
  .skill-groups{ grid-template-columns:1fr; }
  .stat-row{ gap:var(--sp-5); }
}
