/* ============================================================
   SECTIONS — hero marquee, tickers, about, experience,
              works index, skills list, contact
   ============================================================ */

/* ============================================================
   HERO — stacked full-width rows of single giant words,
   each scrolling as its own marquee track, layered over media.
   ============================================================ */
.section-hero {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: var(--header-h);
  padding-bottom: var(--sp-9);
  overflow: hidden;
}

/* --hero-p: 0 at the top of the page, 1 once the hero has scrolled away.
   Set by js/hero.js. Everything below is derived from it, so the whole
   sequence plays forwards on the way down and backwards on the way up. */
.hero-stage {
  --hero-p: 0;
  --hero-open: calc(1 - var(--hero-p));
  --words-floor: 0.5;
  position: relative;
  display: grid;
  /* minmax(0,1fr), not the default auto: otherwise the grid column sizes to
     the marquee track's max-content (~10,000px) instead of the viewport. */
  grid-template-columns: minmax(0, 1fr);
  min-height: min(78vh, 820px);
  align-items: center;
  overflow: hidden;
}

/* ---- The photo, centred and dominant ---- */
.hero-media {
  position: relative;
  grid-area: 1 / 1;
  z-index: 2;
  justify-self: center;
  width: min(38vw, 460px);
  height: min(72vh, 700px);
  margin: 0;
  overflow: hidden;
  border-radius: 2px;
  /* Fades and pulls back as you scroll down; zooms and fades in coming up. */
  opacity: var(--hero-open);
  transform: scale(calc(0.86 + 0.14 * var(--hero-open)));
  transform-origin: 50% 45%;
  will-change: opacity, transform;
}
.hero-media img,
.hero-media video,
.hero-media .media-placeholder {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
/* Soft vignette so the photo sits in the dark rather than on top of it. */
.hero-media::after {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 45%, transparent 45%, rgb(0 0 0 / 0.5) 100%);
  pointer-events: none;
}

/* ---- The words ---- */
.hero-headline {
  grid-area: 1 / 1;
  z-index: 1;
  position: relative;
  width: 100%;
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  font-family: var(--font-body);
  font-size: clamp(2.5rem, 19vh, 12rem);
  font-weight: 900;
  line-height: 1;
  letter-spacing: var(--tracking-hero);
  text-transform: uppercase;
  /* Follows the theme rather than being locked to white: near-white on the
     dark page, near-black on the light one. Combined with the opacity ramp
     below that reads as soft grey in dark mode and translucent black in
     light mode — legible against either background. */
  color: var(--ink);
  pointer-events: none;
  /* Held back while the photo owns the frame, full strength once it leaves.
     Raise --words-floor to make the resting words stronger, lower it to
     make them fainter. */
  opacity: calc(var(--words-floor, 0.5) + (1 - var(--words-floor, 0.5)) * var(--hero-p));
  will-change: opacity, mask-image;
}

/* Mid-grey carries less contrast on a light page than on a dark one, so the
   light theme needs a slightly stronger floor to feel equally present. */
[data-theme="light"] .hero-stage { --words-floor: 0.62; }

/* The dissolve. A soft ellipse over the photo thins the words down to
   --hole-a instead of erasing them, with a long feathered edge — so each
   word ghosts out as it travels toward the photo and regains its weight
   as it leaves. Both the size and the depth of the fade ease off as
   --hero-p rises, which is what brings the words back to full strength.

   Fading to a low alpha rather than to zero keeps the effect working on
   narrow screens, where the photo covers most of the width and a true
   hole would leave almost no visible text. */
.hero-stage.has-media .hero-headline {
  --hole-x: calc(0.01% + 34% * var(--hero-open));
  --hole-y: calc(0.01% + 52% * var(--hero-open));
  --hole-a: calc(0.14 + 0.86 * var(--hero-p));
  -webkit-mask-image: radial-gradient(ellipse var(--hole-x) var(--hole-y) at 50% 50%,
                      rgb(0 0 0 / var(--hole-a)) 0%, rgb(0 0 0 / var(--hole-a)) 34%, #000 100%);
  mask-image: radial-gradient(ellipse var(--hole-x) var(--hole-y) at 50% 50%,
              rgb(0 0 0 / var(--hole-a)) 0%, rgb(0 0 0 / var(--hole-a)) 34%, #000 100%);
}

.hero-headline .line { display: block; }

.hero-row {
  width: 100%;
  min-width: 0;
  overflow: hidden;
  display: flex;
}
.hero-track {
  display: flex;
  flex: none;
  will-change: transform;
  animation: marquee var(--marquee-duration, 26s) linear infinite;
}
.hero-row:nth-child(even) .hero-track { animation-direction: reverse; }
.hero-track > span { flex: none; padding-inline: 0.28em; }

@keyframes marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* Static and centred when motion is unwelcome. The scroll-linked fade stays
   — it tracks the scrollbar rather than moving on its own — but the
   travelling marquee and the zoom are removed. */
@media (prefers-reduced-motion: reduce) {
  .hero-track { animation: none; justify-content: center; width: 100%; }
  .hero-track > span:not(:first-child) { display: none; }
  .hero-row { justify-content: center; }
  .hero-media { transform: none; }
}

@media (max-width: 900px) {
  .hero-headline { font-size: clamp(2rem, 15vw, 6rem); }
  .hero-media { width: min(62vw, 290px); height: min(54vh, 420px); }
  /* The word block is shorter than the photo here, so the fade has to span
     its full height — and it stays lighter, since there is little room
     either side of the photo for the words to recover in. */
  .hero-stage.has-media .hero-headline {
    --hole-x: calc(0.01% + 46% * var(--hero-open));
    --hole-y: calc(0.01% + 78% * var(--hero-open));
    --hole-a: calc(0.3 + 0.7 * var(--hero-p));
  }
}

.hero-lower {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-6) var(--sp-9);
  align-items: end;
  margin-top: var(--sp-9);
}
@media (max-width: 860px) { .hero-lower { grid-template-columns: 1fr; align-items: start; } }

.hero-statement { font-size: var(--fs-lg); font-weight: 300; color: var(--ink-body); max-width: 54ch; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }

.hero-availability {
  display: inline-flex; align-items: center; gap: 0.6rem;
  margin-bottom: var(--sp-5);
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--ink-muted);
}
.status-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--success);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--success) 24%, transparent);
}

.hero-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--sp-7);
  margin-top: var(--sp-9);
  padding-top: var(--sp-7);
  border-top: 1px solid var(--line);
}
.stat-value {
  font-family: var(--font-display);
  font-size: var(--fs-4xl);
  color: var(--ink);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  margin-bottom: 0.5rem;
}
.stat-label { font-size: var(--fs-xs); color: var(--ink-muted); line-height: 1.5; max-width: 24ch; }

/* ============================================================
   TICKER BAND — currently unused.

   The two scrolling bands (under the hero and above Contact) were
   removed from index.html. The styling is kept so they can be put
   back: re-add the two <div class="ticker" data-mount="ticker-1">
   elements, the ticker() renderer, and the tickerBands field in
   editor/schema.js. Delete this block if you're sure you won't.
   ============================================================ */
.ticker {
  border-block: 3px solid var(--ink);
  overflow: hidden;
  display: flex;
  padding-block: 0.28em;
  font-family: var(--font-body);
  font-size: clamp(1.5rem, 5vw, 3.25rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.15;
  color: var(--ink);
}
.ticker-track {
  display: flex;
  flex: none;
  will-change: transform;
  animation: marquee var(--marquee-duration, 34s) linear infinite;
}
.ticker-reverse .ticker-track { animation-direction: reverse; }
.ticker-track > span { flex: none; display: inline-flex; align-items: center; gap: 0.5em; padding-inline: 0.4em; }
.ticker-track .dot { width: 0.22em; height: 0.22em; border-radius: 50%; background: var(--accent); flex: none; }
.ticker-serif { font-family: var(--font-display); font-weight: 400; font-style: italic; text-transform: none; }

@media (prefers-reduced-motion: reduce) {
  .ticker-track { animation: none; }
}

/* ============================================================
   ABOUT — white, centred, oversized light type with photos
   embedded inline in the running sentence.
   ============================================================ */
/* Deliberately smaller than the section title. Two oversized blocks
   stacked on top of each other just doubles the scrolling. */
.about-statement {
  font-size: clamp(1.15rem, 1.9vw, 1.6rem);
  font-weight: 300;
  line-height: 1.5;
  color: var(--ink-body);
  max-width: 46ch;
  margin-top: calc(var(--sp-8) * -1);
}
.about-statement .accent {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  color: var(--accent-bright);
}

/* An image set inline in the text flow — the reference's signature. */
.img-span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  width: clamp(90px, 11vw, 200px);
  height: clamp(60px, 7vw, 120px);
  margin-inline: 0.18em;
  overflow: hidden;
  border-radius: 2px;
  background: var(--surface-sunk);
  transform: translateY(-0.06em);
}
.img-span img { width: 100%; height: 100%; object-fit: cover; }
.img-span .media-placeholder { position: absolute; inset: 0; }

.about-body {
  margin-top: var(--sp-10);
  display: grid;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 5rem);
  align-items: start;
}
@media (max-width: 900px) { .about-body { grid-template-columns: 1fr; } }

.about-portrait { position: sticky; top: calc(var(--header-h) + var(--sp-7)); }
@media (max-width: 900px) { .about-portrait { position: static; max-width: 300px; } }
.portrait-frame {
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--surface-sunk);
  position: relative;
}
.portrait-frame img { width: 100%; height: 100%; object-fit: cover; }
.portrait-caption { margin-top: var(--sp-4); font-size: var(--fs-xs); color: var(--ink-muted); line-height: 1.5; }

.about-copy { max-width: var(--measure); }
.about-copy p + p { margin-top: var(--sp-5); }
.about-copy p { color: var(--ink-body); font-weight: 300; }
.about-copy .accent { color: var(--accent-bright); font-style: normal; font-weight: 500; }

.principles {
  margin-top: var(--sp-9);
  padding-top: var(--sp-7);
  border-top: 1px solid var(--line);
  display: grid;
  gap: var(--sp-6);
}
.principles-title {
  font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; color: var(--ink-muted);
}
.principle { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 1rem; align-items: start; }
.principle .icon { color: var(--accent-bright); margin-top: 4px; }
.principle-title { font-family: var(--font-display); font-size: var(--fs-xl); color: var(--ink); margin-bottom: 0.2rem; }
.principle-text { font-size: var(--fs-sm); color: var(--ink-muted); line-height: 1.6; }

/* ============================================================
   EXPERIENCE
   ============================================================ */
.timeline { display: grid; }
.role {
  display: grid;
  grid-template-columns: minmax(0, 240px) minmax(0, 1fr);
  gap: clamp(1.25rem, 3vw, 4rem);
  padding-block: var(--sp-10);
  border-top: 1px solid var(--line);
}
.role:first-child { border-top: 0; padding-top: 0; }
.role:last-child { padding-bottom: 0; }
@media (max-width: 820px) { .role { grid-template-columns: 1fr; gap: var(--sp-5); } }

.role-meta { display: grid; gap: 0.5rem; align-content: start; }
.role-period {
  font-size: var(--fs-xs); font-weight: 500;
  text-transform: uppercase; letter-spacing: var(--tracking-label);
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.role-place { display: inline-flex; align-items: center; gap: 0.4rem; font-size: var(--fs-xs); color: var(--ink-muted); }
.role-place .icon { width: 14px; height: 14px; }
.role-current {
  justify-self: start; margin-top: 0.3rem;
  padding: 0.2rem 0.6rem; border-radius: var(--r-pill);
  background: var(--accent-wash); color: var(--accent-bright);
  font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: var(--tracking-label); text-transform: uppercase;
}
.role-title {
  font-family: var(--font-body);
  font-size: var(--fs-3xl);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.1;
  margin-bottom: 0.5rem;
}
.role-org {
  font-size: var(--fs-xs); text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--accent-bright); font-weight: 500; margin-bottom: var(--sp-6);
}
.role-org .org-sep { color: var(--ink-muted); font-weight: 400; letter-spacing: normal; text-transform: none; }
.role-summary { color: var(--ink-body); font-weight: 300; margin-bottom: var(--sp-6); max-width: 58ch; }
.role-points { display: grid; gap: 0.85rem; margin-bottom: var(--sp-6); max-width: 60ch; }
.role-points li {
  position: relative; padding-left: 1.6rem;
  font-size: var(--fs-sm); color: var(--ink-body); font-weight: 300; line-height: 1.65;
}
.role-points li::before {
  content: ""; position: absolute; left: 0; top: 0.7em;
  width: 0.85rem; height: 1px; background: var(--accent-bright);
}
.role-metrics {
  display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-9);
  margin-bottom: var(--sp-6); padding: var(--sp-5) 0;
  border-block: 1px solid var(--line);
}
.role-metric-value {
  font-family: var(--font-display); font-size: var(--fs-2xl);
  color: var(--ink); line-height: 1.1; font-variant-numeric: tabular-nums;
}
.role-metric-label {
  font-size: var(--fs-micro); text-transform: uppercase;
  letter-spacing: var(--tracking-label); color: var(--ink-muted);
}

/* ============================================================
   WORKS — sticky uppercase name index beside big square media
   ============================================================ */
.works {
  display: grid;
  grid-template-columns: minmax(0, 0.7fr) minmax(0, 1.3fr);
  gap: clamp(1.5rem, 5vw, 6rem);
  align-items: start;
}
@media (max-width: 900px) { .works { grid-template-columns: 1fr; } }

.works-index {
  position: sticky;
  top: calc(var(--header-h) + var(--sp-8));
  align-self: start;
  display: grid;
  gap: 0.15rem;
  text-align: right;
}
@media (max-width: 900px) { .works-index { display: none; } }

.works-index li a {
  display: block;
  padding: 0.35rem 0;
  font-size: var(--fs-sm);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-body);
  text-decoration: none;
  /* Dimmed enough to read as inactive, but these are links — anything
     below ~0.65 here drops the effective contrast under AA. */
  opacity: 0.72;
  transition: opacity var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.works-index li a:hover { opacity: 1; color: var(--ink); }
.works-index li a[aria-current="true"] { opacity: 1; color: var(--ink); }

.works-list { display: grid; gap: var(--sp-12); }

.work { display: grid; gap: var(--sp-5); }
.work.is-hidden { display: none; }

.work-media {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--surface-sunk);
}
.work-media img, .work-media .media-placeholder {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--dur-cinematic) var(--ease-out), filter var(--dur-base) var(--ease-out);
}
/* project_darken — the media dims until you engage with it. */
.work-media::after {
  content: "";
  position: absolute; inset: 0;
  background: rgb(0 0 0 / 0.35);
  transition: opacity var(--dur-base) var(--ease-out);
}
.work:hover .work-media::after { opacity: 0; }
.work:hover .work-media img { transform: scale(1.03); }

.work-info { display: grid; gap: 0.3rem; text-align: right; }
.work-title {
  font-size: var(--fs-xl);
  font-family: var(--font-body);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  line-height: 1.3;
}
.work-title a { text-decoration: none; }
.work-title a:hover { color: var(--accent-bright); }
.work-desc { font-size: var(--fs-sm); color: var(--ink-body); opacity: 0.55; }
.work-meta {
  display: flex; flex-wrap: wrap; justify-content: flex-end;
  gap: 0.4rem 1rem;
  font-size: var(--fs-micro); text-transform: uppercase;
  letter-spacing: var(--tracking-label); color: var(--ink-muted);
}
.work-results { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.4rem 1.5rem; }
.work-result { display: inline-flex; align-items: baseline; gap: 0.4rem; font-size: var(--fs-xs); }
.work-result dt { color: var(--ink-muted); text-transform: uppercase; letter-spacing: var(--tracking-label); }
.work-result dd { margin: 0; font-family: var(--font-display); font-size: var(--fs-lg); color: var(--ink); font-variant-numeric: tabular-nums; }
.work .tag-list { justify-content: flex-end; }
.work .link-arrow { justify-self: end; }

.work-empty {
  grid-column: 1 / -1;
  padding: var(--sp-10) var(--sp-6);
  text-align: center;
  border: 1px dashed var(--line-strong);
  color: var(--ink-muted);
}

/* ============================================================
   SKILLS — staggered indented list, sliding in past a rule
   ============================================================ */
.skills-grid { display: grid; gap: var(--sp-11); }

.skill-group {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.75fr);
  gap: clamp(1.5rem, 5vw, 6rem);
  align-items: start;
}
@media (max-width: 860px) { .skill-group { grid-template-columns: 1fr; gap: var(--sp-6); } }

.skill-group-title {
  font-family: var(--font-body);
  font-size: var(--fs-3xl);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.1;
}
.skill-group-note { font-size: var(--fs-sm); color: var(--ink-muted); line-height: 1.6; margin-top: var(--sp-4); max-width: 36ch; }

.skill-list {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-left: 2rem;
  color: var(--accent-warm-text);
  font-weight: 500;
}
/* The vertical rule grows from the top as the group comes into view. */
.skill-list::before {
  content: "";
  position: absolute; left: 0; top: 0;
  width: 3px; height: 100%;
  background: var(--ink);
  transform-origin: top;
  transform: scaleY(0);
  transition: transform 1600ms var(--ease-out) 200ms;
}
.skill-group.is-revealed .skill-list::before { transform: scaleY(1); }

.skill-list li {
  font-size: var(--fs-lg);
  padding: 0.42em 0;
  transform: translate3d(-140%, 0, 0);
  transition: transform 1400ms var(--ease-out) var(--stagger, 0ms);
}
.skill-group.is-revealed .skill-list li { transform: translate3d(0, 0, 0); }
.skill-list li:nth-child(3n + 1) { padding-left: 2em; }
.skill-list li:nth-child(2n + 2) { padding-left: 4em; }
.skill-group:nth-child(even) .skill-list li:nth-child(3n + 2) { padding-left: 3em; }

@media (max-width: 860px) {
  .skill-list li { padding-left: 0 !important; font-size: var(--fs-base); }
}
@media (prefers-reduced-motion: reduce) {
  .skill-list li { transform: none; }
  .skill-list::before { transform: scaleY(1); }
}

.tools-strip { margin-top: var(--sp-11); padding-top: var(--sp-8); border-top: 1px solid var(--line); }
.tools-title {
  font-size: var(--fs-micro); font-weight: 500;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase; color: var(--ink-muted); margin-bottom: var(--sp-5);
}

/* ============================================================
   CONTACT
   ============================================================ */
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(2.5rem, 6vw, 6rem);
  align-items: start;
}
@media (max-width: 940px) { .contact-grid { grid-template-columns: 1fr; } }

.contact-aside .section-title { max-width: 12ch; }
.contact-lead { font-size: var(--fs-lg); font-weight: 300; color: var(--ink-muted); max-width: 44ch; margin-bottom: var(--sp-8); }

.contact-links { display: grid; margin-bottom: var(--sp-8); }
.contact-link {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) 18px;
  align-items: center; gap: 1rem;
  min-height: 66px; padding: 0.9rem 0;
  border-top: 1px solid var(--line);
  text-decoration: none;
  transition: padding-left var(--dur-base) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.contact-link:last-of-type { border-bottom: 1px solid var(--line); }
.contact-link:hover { padding-left: 0.6rem; color: var(--accent-bright); }
.contact-link > .icon { color: var(--accent-bright); }
.contact-link-label {
  display: block; font-size: var(--fs-micro);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--ink-muted); margin-bottom: 0.15rem;
}
.contact-link-value { font-size: var(--fs-lg); color: var(--ink); font-weight: 300; overflow-wrap: anywhere; }
.contact-link:hover .contact-link-value { color: var(--accent-bright); }
.contact-link .icon-external { color: var(--ink-muted); width: 15px; height: 15px; }

.contact-facts { display: grid; gap: var(--sp-5); }
.contact-fact-label {
  font-size: var(--fs-micro); letter-spacing: var(--tracking-label);
  text-transform: uppercase; color: var(--ink-muted); margin-bottom: 0.2rem;
}
.contact-fact-value { font-size: var(--fs-sm); color: var(--ink); font-weight: 300; }

.contact-form-wrap {
  padding: clamp(1.5rem, 3vw, 2.5rem);
  background: var(--bg-alt);
  border: 1px solid var(--line);
}
.contact-form { display: grid; gap: var(--sp-6); }
.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: var(--sp-6);
}
.form-title { font-size: var(--fs-2xl); margin-bottom: 0.35rem; }
.form-sub { font-size: var(--fs-sm); color: var(--ink-muted); font-weight: 300; }
