/* ==========================================================================
   Page layouts: hero, home, projects, case study, about, contact, 404
   ========================================================================== */

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: min(100dvh, 900px);
  display: flex;
  align-items: center;
  padding-top: calc(var(--header-h) + clamp(2rem, 4vw, 4rem));
  padding-bottom: clamp(3rem, 6vw, 6rem);
}

.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.8fr);
  gap: clamp(2rem, 4vw, 5rem);
  align-items: center;
  width: 100%;
}

@media (max-width: 980px) {
  .hero__inner { grid-template-columns: 1fr; }
  /* Headline first when stacked: a full-width portrait would otherwise fill the
     whole first screen on a phone. Capped so it stays a card, not a poster. */
  .hero__aside { width: 100%; max-width: 420px; }
}

/* The h1. Deliberately set as a small tracked label rather than a display
   heading: the name and title need to be the document's h1 for search, but the
   line worth looking at is the h2 underneath. */
.hero__eyebrow {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: var(--space-6);
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.hero__eyebrow::before {
  content: "";
  width: 26px;
  height: 1px;
  flex: none;
  background: var(--hairline-accent);
}

@media (max-width: 560px) {
  .hero__eyebrow { font-size: 0.72rem; letter-spacing: 0.16em; }
  .hero__eyebrow::before { display: none; }
}

.hero__title {
  font-size: var(--step-6);
  font-weight: 300;
  letter-spacing: -0.022em;
  line-height: 1.0;
  margin-bottom: var(--space-6);
}

.hero__title-line { display: block; overflow: hidden; }

/* Each line rises out of its own clipping box on load. */
.hero__title-inner {
  display: block;
  animation: line-rise 1s var(--ease-out) both;
  animation-delay: var(--line-delay, 0ms);
}
@keyframes line-rise {
  from { transform: translateY(102%); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* Rotating word: a fixed-height window with words cycling through it.
   Italic serif carries the emphasis now that there is no gradient. */
.rotator {
  display: inline-grid;
  vertical-align: bottom;
  overflow: hidden;
  height: 1.06em;
}
.rotator__word {
  grid-area: 1 / 1;
  font-style: italic;
  font-variation-settings: "SOFT" 40, "WONK" 1;
  color: var(--stone);
  opacity: 0;
  transform: translateY(100%);
  transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-out);
  white-space: nowrap;
}
.rotator__word.is-active { opacity: 1; transform: none; }
.rotator__word.is-leaving { opacity: 0; transform: translateY(-100%); }

.hero__tagline {
  font-size: var(--step-1);
  color: var(--text-muted);
  max-width: 52ch;
  margin-bottom: var(--space-4);
  animation: fade-up 900ms var(--ease-out) 700ms both;
}

.hero__summary {
  font-size: var(--step-0);
  color: var(--text-faint);
  max-width: 56ch;
  margin-bottom: var(--space-6);
  animation: fade-up 900ms var(--ease-out) 820ms both;
}

.hero__actions { animation: fade-up 900ms var(--ease-out) 940ms both; margin-bottom: var(--space-6); }
.hero__socials { animation: fade-up 900ms var(--ease-out) 1060ms both; }

/*
  On a prerendered load the visitor is already reading the hero before Blazor
  mounts, so replaying the entrance would look like the page loading twice.
  Skip it for that first render only. site.js removes the class once the app is
  up, so client-side navigation back to the home page animates as designed.
*/
.prerendered .hero__title-inner,
.prerendered .hero__tagline,
.prerendered .hero__summary,
.prerendered .hero__actions,
.prerendered .hero__socials,
.prerendered .hero__aside,
.prerendered .scroll-cue {
  animation: none;
  opacity: 1;
  transform: none;
}

@keyframes fade-up {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

/* Portrait / identity panel ------------------------------------------------ */
.hero__aside { position: relative; animation: fade-up 1s var(--ease-out) 480ms both; }

.hero__card {
  position: relative;
  padding: clamp(1.2rem, 1rem + 1vw, 1.6rem);
  border-radius: var(--radius-lg);
}

.hero__portrait {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--hairline);
  display: grid;
  place-items: center;
  margin-bottom: var(--space-5);
}
.hero__portrait img { width: 100%; height: 100%; object-fit: cover; }

/* Colour portrait on hover.
   Deliberately scoped to real pointers. A background-image inside an unmatched
   media query is never requested, so touch visitors skip the download entirely
   rather than paying for an image they can never trigger. */
@media (hover: hover) and (pointer: fine) {
  .hero__portrait::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--portrait-hover, none);
    background-size: cover;
    background-position: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity 560ms var(--ease-out);
  }

  .hero__portrait:hover::after,
  .hero__card:focus-within .hero__portrait::after { opacity: 1; }
}

.hero__monogram {
  font-family: var(--font-display);
  font-size: clamp(3.5rem, 7vw, 5rem);
  font-weight: 300;
  letter-spacing: 0.02em;
  color: var(--text-faint);
}
.hero__portrait-hint {
  position: absolute;
  bottom: 0.75rem; left: 0.75rem; right: 0.75rem;
  font-size: 0.62rem;
  text-align: center;
  color: var(--text-faint);
  font-family: var(--font-mono);
  opacity: 0.7;
}

.hero__facts { display: flex; flex-direction: column; }
.hero__fact {
  display: flex; align-items: center; gap: 0.75rem;
  font-size: 0.83rem; color: var(--text-muted);
  padding-block: 0.65rem;
  border-bottom: 1px solid var(--hairline);
}
.hero__fact:last-child { border-bottom: 0; padding-bottom: 0; }
.hero__fact svg { width: 14px; height: 14px; color: var(--text-faint); flex: none; }
.hero__fact strong { color: var(--text); font-weight: 500; }

/* Scroll cue --------------------------------------------------------------- */
.scroll-cue {
  position: absolute;
  left: 50%; bottom: clamp(1rem, 3vh, 2.25rem);
  translate: -50% 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-body);
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-faint);
  animation: fade-up 1s var(--ease-out) 1300ms both;
}
.scroll-cue__rail {
  width: 1px; height: 40px;
  background: var(--hairline-strong);
  position: relative;
  overflow: hidden;
}
.scroll-cue__rail::after {
  content: "";
  position: absolute; left: 0; top: 0;
  width: 100%; height: 40%;
  background: var(--stone);
  animation: cue-run 2.2s var(--ease-inout) infinite;
}
@keyframes cue-run {
  0%   { transform: translateY(-100%); opacity: 0; }
  40%  { opacity: 1; }
  100% { transform: translateY(250%); opacity: 0; }
}

@media (max-width: 980px) { .scroll-cue { display: none; } }

/* --------------------------------------------------------------------------
   Metrics strip
   -------------------------------------------------------------------------- */

.metrics-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr));
  border-block: 1px solid var(--hairline);
}
.metrics-strip .metric { border-right: 1px solid var(--hairline); }
.metrics-strip .metric:last-child { border-right: 0; }

@media (max-width: 760px) {
  .metrics-strip .metric { border-right: 0; border-bottom: 1px solid var(--hairline); }
  .metrics-strip .metric:last-child { border-bottom: 0; }
}

/* --------------------------------------------------------------------------
   CTA band
   -------------------------------------------------------------------------- */

.cta-band {
  position: relative;
  padding: clamp(2.5rem, 2rem + 4vw, 5.5rem) clamp(1.5rem, 1rem + 3vw, 4rem);
  border-radius: var(--radius-lg);
  text-align: center;
  overflow: hidden;
}
.cta-band__title { font-size: var(--step-4); font-weight: 300; margin-bottom: var(--space-4); }
.cta-band__sub { color: var(--text-muted); font-size: var(--step-1); max-width: 50ch; margin: 0 auto var(--space-6); }

/* --------------------------------------------------------------------------
   Page header (inner pages)
   -------------------------------------------------------------------------- */

.page-head {
  padding-top: calc(var(--header-h) + clamp(3rem, 6vw, 6rem));
  padding-bottom: clamp(2rem, 3vw, 3.5rem);
}
.page-head__title { font-size: var(--step-5); font-weight: 300; margin-bottom: var(--space-5); }
.page-head__sub { font-size: var(--step-1); color: var(--text-muted); max-width: 62ch; }

.breadcrumb {
  display: flex; align-items: center; gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-faint);
  margin-bottom: var(--space-5);
}
.breadcrumb a:hover { color: var(--text); }
.breadcrumb svg { width: 11px; height: 11px; }

/* --------------------------------------------------------------------------
   Case study
   -------------------------------------------------------------------------- */

.case-hero { position: relative; padding-top: calc(var(--header-h) + clamp(2.5rem, 5vw, 5rem)); }

.case-hero__title { font-size: var(--step-5); font-weight: 300; margin-bottom: var(--space-5); }
.case-hero__subtitle {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--step-1);
  color: var(--text-muted);
  max-width: 58ch;
  margin-bottom: var(--space-6);
}

.case-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  padding-block: var(--space-5);
  border-block: 1px solid var(--hairline);
  margin-bottom: var(--space-8);
}
.case-meta__item { min-width: 110px; }
.case-meta__label {
  font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 0.35rem;
}
.case-meta__value { font-size: var(--step--1); font-weight: 500; color: var(--text); }

.case-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 290px);
  gap: clamp(2rem, 4vw, 4.5rem);
  align-items: start;
}
@media (max-width: 940px) { .case-body { grid-template-columns: 1fr; } }

.case-section { margin-bottom: clamp(2.5rem, 2rem + 2vw, 4rem); }

.case-section__label {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: var(--space-5);
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.case-section__label::before {
  content: "";
  width: 24px; height: 1px;
  background: var(--hairline-accent);
}

.case-section p { color: var(--text-muted); font-size: var(--step-0); line-height: 1.78; max-width: var(--measure); }
.case-section p + p { margin-top: var(--space-4); }

/* --------------------------------------------------------------------------
   Case study figures
   Architecture diagrams. A dark-on-dark diagram would vanish into the page, so
   figures sit on a light plate, the same trick as the portrait.
   -------------------------------------------------------------------------- */

.figures { display: flex; flex-direction: column; gap: var(--space-6); }

.figure { margin: 0; }

/* Wide diagrams break out of the text measure, which is usually what a system
   diagram needs. Capped so it never escapes the content column. */
.figure--wide { width: min(100% + 14vw, var(--content-wide)); }
@media (max-width: 1100px) { .figure--wide { width: 100%; } }

.figure__frame {
  position: relative;
  display: block;
  width: 100%;
  padding: clamp(0.75rem, 0.5rem + 1vw, 1.5rem);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--bone);
  cursor: zoom-in;
  transition: border-color var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}
.figure__frame:hover { border-color: var(--hairline-accent); }
.figure__frame img { width: 100%; height: auto; display: block; }

.figure__zoom {
  position: absolute;
  top: 0.6rem; right: 0.6rem;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: rgba(10, 10, 11, 0.72);
  color: var(--bone);
  opacity: 0;
  transition: opacity var(--dur) var(--ease-out);
}
.figure__zoom svg { width: 15px; height: 15px; }
.figure__frame:hover .figure__zoom,
.figure__frame:focus-visible .figure__zoom { opacity: 1; }

.figure__caption {
  margin-top: var(--space-3);
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--text-faint);
  max-width: 62ch;
}

/* Lightbox ----------------------------------------------------------------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  gap: var(--space-4);
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(5, 5, 6, 0.92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  cursor: zoom-out;
  animation: lightbox-in 220ms var(--ease-out);
}
@keyframes lightbox-in { from { opacity: 0; } to { opacity: 1; } }

.lightbox__inner {
  max-width: min(1400px, 100%);
  max-height: 100%;
  cursor: default;
  overflow: auto;
}
.lightbox__inner img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  background: var(--bone);
  padding: clamp(0.75rem, 2vw, 1.75rem);
}
.lightbox__caption {
  margin-top: var(--space-4);
  font-size: 0.85rem;
  color: var(--text-muted);
  text-align: center;
  max-width: 70ch;
  margin-inline: auto;
}

.lightbox__close {
  position: fixed;
  top: clamp(0.75rem, 2vw, 1.5rem);
  right: clamp(0.75rem, 2vw, 1.5rem);
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--hairline-strong);
  background: rgba(15, 15, 17, 0.9);
  color: var(--text-muted);
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.lightbox__close:hover { color: var(--text); border-color: var(--hairline-accent); }
.lightbox__close svg { width: 18px; height: 18px; }

.case-aside { position: sticky; top: calc(var(--header-h) + 1.5rem); display: flex; flex-direction: column; gap: var(--space-4); }
@media (max-width: 940px) { .case-aside { position: static; } }

.case-aside__card { padding: var(--space-5); border-radius: var(--radius-lg); }
.case-aside__title {
  font-size: 0.75rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: var(--space-5);
}

.impact-list { display: flex; flex-direction: column; gap: var(--space-5); }
.impact-list__value {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.015em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.impact-list__label { font-size: 0.8rem; font-weight: 500; margin-top: 0.4rem; }
.impact-list__caption { font-size: 0.72rem; color: var(--text-faint); margin-top: 0.15rem; }

.case-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  justify-content: space-between;
  padding-top: var(--space-7);
  margin-top: var(--space-8);
  border-top: 1px solid var(--hairline);
}
.case-nav__link { display: flex; flex-direction: column; gap: 0.3rem; max-width: 45%; }
.case-nav__link:last-child { text-align: right; align-items: flex-end; }
.case-nav__dir { font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-faint); }
.case-nav__title { font-family: var(--font-display); font-weight: 400; font-size: var(--step-1); }
.case-nav__link:hover .case-nav__title { color: var(--stone); }
@media (max-width: 620px) { .case-nav__link { max-width: 100%; } }

/* --------------------------------------------------------------------------
   About
   -------------------------------------------------------------------------- */

.about-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 330px);
  gap: clamp(2rem, 4vw, 4.5rem);
  align-items: start;
}
@media (max-width: 940px) { .about-grid { grid-template-columns: 1fr; } }

.about-bio p { font-size: var(--step-0); line-height: 1.82; color: var(--text-muted); }
.about-bio p + p { margin-top: var(--space-5); }

/* Lead paragraph set in the display serif. Signals "this is the piece worth
   reading" without a pull-quote or a colour. */
.about-bio p:first-of-type {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 300;
  line-height: 1.48;
  color: var(--text);
}

.about-side { position: sticky; top: calc(var(--header-h) + 1.5rem); display: flex; flex-direction: column; gap: var(--space-4); }
@media (max-width: 940px) { .about-side { position: static; } }

.cert-item {
  display: flex; flex-direction: column; gap: 0.2rem;
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--hairline);
}
.cert-item:last-child { border-bottom: 0; padding-bottom: 0; }
.cert-item__name { font-size: var(--step--1); font-weight: 500; }
.cert-item__issuer { font-size: 0.77rem; color: var(--text-faint); }

/* --------------------------------------------------------------------------
   Contact
   -------------------------------------------------------------------------- */

.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 360px);
  gap: clamp(2rem, 4vw, 4rem);
  align-items: start;
}
@media (max-width: 940px) { .contact-grid { grid-template-columns: 1fr; } }

.contact-card { padding: clamp(1.5rem, 1.2rem + 1.5vw, 2.6rem); border-radius: var(--radius-lg); }

.contact-channel {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--hairline);
  transition: all var(--dur) var(--ease-out);
}
.contact-channel:last-child { border-bottom: 0; }
.contact-channel:hover { padding-left: 0.4rem; }
.contact-channel:hover .contact-channel__value { color: var(--stone); }
.contact-channel__icon {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  border: 1px solid var(--hairline);
  color: var(--text-faint);
}
.contact-channel__icon svg { width: 16px; height: 16px; }
.contact-channel__label { display: block; font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-faint); }
.contact-channel__value { display: block; font-size: var(--step--1); font-weight: 500; word-break: break-word; transition: color var(--dur) var(--ease-out); }

/* --------------------------------------------------------------------------
   404
   -------------------------------------------------------------------------- */

.notfound {
  min-height: 78dvh;
  display: grid;
  place-items: center;
  text-align: center;
  padding-top: var(--header-h);
}
.notfound__code {
  font-family: var(--font-display);
  font-size: clamp(5rem, 18vw, 12rem);
  font-weight: 200;
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--text-faint);
  margin-bottom: var(--space-5);
}

/* --------------------------------------------------------------------------
   Empty / loading states
   -------------------------------------------------------------------------- */

.loading-state {
  display: grid;
  place-items: center;
  gap: var(--space-4);
  min-height: 45dvh;
  color: var(--text-faint);
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.loading-state__ring {
  width: 30px; height: 30px;
  border: 1px solid var(--hairline);
  border-top-color: var(--stone);
  border-radius: 50%;
  animation: spin-slow 800ms linear infinite;
}

.empty-state {
  padding: var(--space-8) var(--space-5);
  text-align: center;
  border: 1px dashed var(--hairline-strong);
  border-radius: var(--radius-sm);
  color: var(--text-faint);
}

.skeleton {
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, rgba(240,236,228,0.025), rgba(240,236,228,0.055), rgba(240,236,228,0.025));
  background-size: 200% 100%;
  animation: shimmer 1.5s linear infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }
