/* ============ START OF MAEZKEV — VANILLA REBUILD ============ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* ============ START OF CORNER SHAPE — SQUIRCLE ============ */
/* corner-shape only does anything where a border-radius is already declared,
   so this bends every existing corner and invents none. It's set from the base
   selector rather than per component, which keeps the shape one decision
   instead of a hundred, and leaves any rule below free to opt out — a plain
   class or id beats the universal selector. Browsers without CSS Borders 4
   drop the line and keep the circular corner, which is the same shape, softer. */
*,
*::before,
*::after {
  corner-shape: var(--corner);
}

/* ============ END OF CORNER SHAPE ============ */

html {
  font-size: 16px;
  scroll-padding-top: var(--header-h);
  scroll-behavior: smooth;
  /* The scrollbar here is a styled one, so it takes real layout width. Holding
     its gutter open means the lightbox can freeze the page by turning overflow
     off without the content jumping sideways to fill it. Not every browser
     reserves the gutter once overflow is hidden, so the viewer measures what
     it actually got and pays back the difference in padding. */
  scrollbar-gutter: stable;
  overflow-x: hidden;
}

/* Scroll lock, held while the lightbox is up. */
html.has-lightbox {
  overflow: hidden;
}

/* When the eased scroller is driving, hand it the scroll offset outright —
   native smooth behaviour would animate every frame it requests. */
html.has-smooth-scroll {
  scroll-behavior: auto;
}

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-white);
  font-family: var(--font);
  font-size: var(--fs-base);
  font-weight: var(--fw-light);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  /* `clip`, not `hidden`: hidden would make body a scroll container and
     break the pinned timeline's position: sticky. */
  overflow-x: clip;
}

/* ============ START OF SCROLLBAR — BLUE HANDLE ON NOTHING ============ */
html {
  scrollbar-color: var(--c-blue) transparent;
  /* Firefox: thumb, track */
  scrollbar-width: thin;
}

::-webkit-scrollbar {
  width: 0.625rem;
  height: 0.625rem;
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-corner {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--c-blue);
  border-radius: 6.1875rem;
  /* A transparent border clipped to the content box insets the handle, so it
     reads as a floating pill rather than filling the gutter edge to edge. */
  border: 0.1875rem solid transparent;
  background-clip: content-box;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--c-blue-hover);
  background-clip: content-box;
}

/* ============ END OF SCROLLBAR — BLUE HANDLE ON NOTHING ============ */

h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0;
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
}

p {
  margin: 0;
}

img,
svg {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
  text-decoration: none;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.container {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip-link {
  position: absolute;
  left: -624.9375rem;
  top: 0;
  z-index: 100;
  padding: var(--space-16) var(--space-24);
  background: var(--c-blue);
  color: var(--c-white);
}

.skip-link:focus {
  left: 0;
}

/* ============ START OF BUTTONS ============ */
.btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* clips the water to the pill */
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  /* Bottom padding runs 2px short of the top: Poppins' baseline sits low in the
     line box, so an even pad reads bottom-heavy. */
  padding: var(--space-16) var(--space-24) calc(var(--space-16) - 2px);
  border: 1px solid var(--c-navy);
  border-radius: 1rem;
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  line-height: var(--lh-none);
  white-space: nowrap;
  cursor: pointer;
  /* The label flips as the water passes it, so it never sits half-legible in a
     blend of the outgoing and incoming colours. */
  transition: color .25s var(--ease) .28s, border-color .5s var(--ease-soft);
}

.btn--sm {
  padding: var(--space-8) var(--space-16) calc(var(--space-8));
  border-radius: 0.75rem;
  font-size: var(--fs-sm);
}

/* Water fill: an oversized panel with a domed top, parked below the button and
   rising on hover. The dome reads as a meniscus while it climbs, and the rise
   overshoots so the curve clears the top and the button ends up fully filled.
   The wobble animates border-radius only, so it never fights the transform. */
.btn::before {
  content: "";
  position: absolute;
  left: -20%;
  bottom: -60%;
  width: 140%;
  height: 160%;
  z-index: 0;
  /* Round, not squircle: this radius draws the meniscus dome itself rather
     than easing a corner, and a superellipse would flatten it into a lid. */
  border-radius: 46% 48% 0 0 / 26% 24% 0 0;
  corner-shape: round;
  transform: translateY(100%);
  transition: transform .7s var(--ease-soft);
}

.btn:hover::before,
.btn:focus-visible::before {
  transform: translateY(-18%);
  animation: waterWobble 3.4s ease-in-out infinite;
}

@keyframes waterWobble {

  0%,
  100% {
    border-radius: 46% 48% 0 0 / 26% 24% 0 0;
  }

  50% {
    border-radius: 49% 44% 0 0 / 21% 29% 0 0;
  }
}

.btn>* {
  position: relative;
  z-index: 1;
}

/* label and icon ride above */
.btn__icon {
  display: flex;
}

/* Primary: green fill, water drains it back to an outline.
   Secondary: blue water fills the outline. */
.btn--primary {
  background: var(--c-green);
  color: var(--c-bg);
}

.btn--primary::before {
  background: var(--c-bg);
}

.btn--primary:hover,
.btn--primary:focus-visible {
  color: var(--c-green);
  border-color: var(--c-green);
}

.btn--secondary {
  background: transparent;
  color: var(--c-blue);
}

.btn--secondary::before {
  background: var(--c-blue);
}

.btn--secondary:hover,
.btn--secondary:focus-visible {
  color: var(--c-bg);
  border-color: var(--c-blue);
}

/* ============ END OF BUTTONS ============ */

/* ============ START OF HEADER ============ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: transparent;
}

/* Progressive blur: four backdrop-filter layers of rising radius, each masked
   to end sooner than the one below it. Where they overlap the blur compounds,
   so it is heaviest at the top and tapers to nothing past the bar. */
.nav-blur {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: calc(var(--header-h) + 4.125rem);
  pointer-events: none;
}

.nav-blur span {
  position: absolute;
  inset: 0;
  display: block;
}

.nav-blur span:nth-child(1) {
  -webkit-backdrop-filter: blur(1px);
  backdrop-filter: blur(1px);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 70%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 70%, transparent 100%);
}

.nav-blur span:nth-child(2) {
  -webkit-backdrop-filter: blur(0.25rem);
  backdrop-filter: blur(0.25rem);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 75%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 75%);
}

.nav-blur span:nth-child(3) {
  -webkit-backdrop-filter: blur(0.625rem);
  backdrop-filter: blur(0.625rem);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 25%, transparent 50%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 25%, transparent 50%);
}

.nav-blur span:nth-child(4) {
  -webkit-backdrop-filter: blur(1.25rem);
  backdrop-filter: blur(1.25rem);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 8%, transparent 28%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 8%, transparent 28%);
}

.header-inner {
  /* Overrides .container's centered 71.25rem wrap: the bar runs closer to the
     viewport edges instead of sitting inside the content measure. */
  max-width: none;
  /* Center the logo and button in the gap between the viewport edges and the main content (71.25rem wide) */
  padding-inline: max(var(--gutter), calc((50vw - 35.625rem) / 2));
  position: relative;
  /* above the blur layers */
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-16);
  min-height: var(--header-h);
}

.brand img {
  width: 3rem;
  height: 3rem;
}


.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  /* 2px bar + 0.3125rem gap = the 0.4375rem pitch the open-state transforms assume, so
     this pair stays literal and stays together. */
  gap: 0.3125rem;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}

.nav-toggle span {
  display: block;
  height: 2px;
  width: 1.5rem;
  margin-inline: auto;
  background: var(--c-white);
  transition: transform .3s var(--ease), opacity .2s linear;
}

.nav-toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(0.4375rem) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-0.4375rem) rotate(-45deg);
}

.mobile-nav {
  position: relative;
  /* above the blur layers */
  z-index: 1;
  border-top: 1px solid var(--c-line);
  padding: var(--space-24) var(--gutter) var(--space-32);
  background: var(--c-bg);
}

.mobile-nav[hidden] {
  display: none;
}

.mobile-nav__actions {
  display: grid;
  gap: var(--space-16);
  justify-items: start;
}

/* ============ END OF HEADER ============ */

/* ============ START OF HERO ============ */
.hero {
  position: relative;
  /* anchors the scroll cue */
  overflow: hidden;
  /* clips the parallax layers as they lag */
  display: flex;
  align-items: stretch;
  min-height: 100vh;
  /* The header is sticky, so it holds 5.25rem of flow above this section. Pull the
     hero back up under it and pad the content down instead — otherwise the top
     of the page is a band of body background rather than the gradient. */
  margin-top: calc(var(--header-h) * -1);
  padding: calc(var(--header-h) + var(--space-48)) var(--gutter) var(--space-64);
}

/* Particle field. pointer-events stay off — the pointer is tracked on the
   section itself, so the canvas never intercepts a click. */
.hero__particles {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* Positioned children paint above the canvas without needing a negative index. */
.hero__left,
.hero__right {
  position: relative;
  z-index: 1;
}

.hero__left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-end;
  flex: 0 0 30%;
  padding-right: var(--space-32);
}

.hero__kicker {
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  /* Stated rather than inherited: this was an h5 and took the heading
     line-height with it. As a paragraph it would fall to the body's 1.6 and
     grow its line box, which shifts the whole centred column beneath it. */
  line-height: var(--lh-heading);
  color: var(--c-white);
}

.hero__status {
  display: flex;
  align-items: center;
  gap: var(--space-16);
}

/* Availability dot — solid core with a halo that swells and fades out. The
   halo starts at opacity 0 so it stays invisible under reduced motion. */
.status-dot {
  position: relative;
  flex: none;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 50%;
  corner-shape: round;
  background: var(--c-green);
}

.status-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  corner-shape: round;
  background: var(--c-green);
  opacity: 0;
  animation: statusPulse 2.4s ease-out infinite;
}

@keyframes statusPulse {
  0% {
    transform: scale(1);
    opacity: .5;
  }

  70% {
    transform: scale(4);
    opacity: 0;
  }

  100% {
    transform: scale(4);
    opacity: 0;
  }
}

.hero__status-text {
  font-size: var(--fs-3xl);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-none);
  color: var(--c-white);
}

.hero__status-text a {
  transition: color .3s var(--ease);
}

.hero__status-text a:hover {
  color: var(--c-green);
}

.hero__right {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-4);
  flex: 1 1 70%;
}

/* The h1 holding the three lines of the name. It stands in for what used to be
   three sibling headings, so it carries the column and the gap they had from
   .hero__right — without it the lines would close up by the gap between them. */
.hero__title {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.hero__name {
  overflow: hidden;
  /* the mask the line rises out of */
  font-size: var(--fs-hero);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
  color: var(--c-white);
}

.hero__name>span {
  display: block;
}

/* Staged entrance. Pure CSS, so it needs no trigger class and cannot leave the
   hero blank if the script fails. `backwards` rather than `both`: it holds the
   from-state through the delay but releases the element once it lands, leaving
   transform and opacity free for the scroll parallax to drive. */
@media (prefers-reduced-motion: no-preference) {
  .hero__name>span {
    animation: heroLine .9s var(--ease-soft) backwards;
  }

  .hero__name:nth-of-type(1)>span {
    animation-delay: .10s;
  }

  .hero__name:nth-of-type(2)>span {
    animation-delay: .20s;
  }

  .hero__name:nth-of-type(3)>span {
    animation-delay: .30s;
  }

  .hero .rotator {
    animation: heroRise .8s var(--ease-soft) .48s backwards;
  }

  .hero__actions {
    animation: heroRise .8s var(--ease-soft) .60s backwards;
  }

  .hero__left {
    animation: heroRise .8s var(--ease-soft) .70s backwards;
  }

  .hero__cue {
    animation: heroCue .8s var(--ease-soft) .95s backwards;
  }
}

@keyframes heroLine {
  from {
    transform: translateY(110%);
  }

  to {
    transform: translateY(0);
  }
}

@keyframes heroRise {
  from {
    opacity: 0;
    transform: translateY(1.125rem);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* Scroll cue — a rail with a light travelling down it. */
.hero__cue {
  position: absolute;
  z-index: 1;
  left: 50%;
  bottom: var(--space-24);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-8);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-caps-wide);
  text-transform: uppercase;
  color: var(--c-muted);
  transition: color .3s var(--ease);
}

.hero__cue:hover,
.hero__cue:focus-visible {
  color: var(--c-blue);
}

.hero__cue-line {
  position: relative;
  width: 1px;
  height: 2.875rem;
  overflow: hidden;
  background: var(--c-line);
}

.hero__cue-line i {
  position: absolute;
  inset: 0 0 auto 0;
  height: 45%;
  background: var(--c-blue);
  animation: cueTravel 2.1s var(--ease) infinite;
}

@keyframes cueTravel {
  0% {
    transform: translateY(-100%);
  }

  100% {
    transform: translateY(222%);
  }
}

@keyframes heroCue {
  from {
    opacity: 0;
    transform: translate(-50%, 1rem);
  }

  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

.rotator {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  /* em, not a spacing token: the word gap has to track the rotator's own
     font-size, which changes at the mobile breakpoint. */
  gap: .4em;
  font-size: var(--fs-2xl);
  font-weight: var(--fw-semibold);
  text-transform: capitalize;
  margin-top: var(--space-8);
}

.rotator__prefix {
  color: var(--c-white);
}

.rotator__slot {
  display: inline-block;
  overflow: hidden;
  height: 1.4em;
  padding: 0 var(--space-8) 0 0;
  color: var(--c-blue);
  vertical-align: bottom;
}

.rotator__inner {
  display: block;
  transition: transform .6s var(--ease);
}

.rotator__inner b {
  display: block;
  height: 1.4em;
  line-height: 1.4em;
  font-weight: var(--fw-semibold);
}

.hero__actions {
  margin-top: var(--space-24);
}

/* ============ END OF HERO ============ */

/* ============ START OF SECTIONS ============ */
.section {
  padding: var(--section-y) 0;
}

/* A label, not a control — it deliberately shares no styling with .btn, so it
   has no hover, no focus ring and nothing to click. */
.section__tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  margin-bottom: var(--space-48);
  padding: var(--space-16) var(--space-24) calc(var(--space-16) - 2px);
  border: 2px solid var(--c-navy);
  border-radius: 1rem;
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  line-height: var(--lh-none);
  white-space: nowrap;
  color: var(--c-white);
}

.section__tag svg {
  flex: none;
}

.section--journey {
  background: radial-gradient(at center right, var(--c-plum) 0%, var(--c-bg) 35%);
}

.section--statement {
  background: radial-gradient(at center center, var(--c-navy) 0%, var(--c-bg) 55%);
}

.section--projects {
  background: radial-gradient(at center center, var(--c-navy) 0%, var(--c-bg) 65%);
}

/* ============ END OF SECTIONS ============ */

/* ============ START OF TIMELINE — PINNED HORIZONTAL SCRUB ============ */
.section--journey {
  padding: 0;
}

.journey-scroll {
  position: relative;
}

/* Base / no-JS / reduced-motion: an ordinary swipeable rail. */
.journey-sticky {
  display: flex;
  flex-direction: column;
  gap: var(--space-32);
  padding-block: var(--section-y);
}

/* Enhanced: JS measured the travel distance and pinned the section. */
.is-pinned .journey-sticky {
  position: sticky;
  top: 0;
  justify-content: center;
  gap: var(--space-48);
  height: 100vh;
  padding-block: calc(var(--header-h) + var(--space-24)) var(--space-48);
  overflow: hidden;
}

.journey-head {
  flex: none;
}

.journey-head .section__tag {
  margin-bottom: 0;
}

/* ============ Track ============ */
.timeline-h {
  position: relative;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.timeline-h::-webkit-scrollbar {
  display: none;
}

/* Height comes from the tallest card rather than the viewport, so the
   block can be centred instead of stranding empty space above it. */
.is-pinned .timeline-h {
  flex: 0 0 auto;
  min-height: 0;
  overflow: hidden;
  scroll-snap-type: none;
}

/* Progressive edge blur — the navbar's technique turned on its side. Three
   layers of rising radius per edge, each masked to end sooner than the one
   below, so cards soften as they approach the edge rather than being cut off
   sharply. Only while pinned: unpinned the container is a real scroller, and
   absolutely positioned children would scroll away with the content. */
.timeline-h__fade {
  position: absolute;
  top: 0;
  /* Stops at the underside of the cards. The track carries a transform, so it
     is its own stacking context and the rail, stems and markers inside it can
     never paint above this layer on z-index alone — the only way to keep the
     progress bar sharp is to end the blur before it. Mirrors the entry stack:
     marker (2.8125rem) + the card's bottom margin + the track's floor. */
  bottom: calc(2.8125rem + var(--space-32) + var(--tl-floor));
  z-index: 1;
  /* Reaches the content start line — the same gutter as .container — with a
     floor so narrower desktops still get a readable ramp. */
  width: max(7.5rem, calc(max(0px, (100% - var(--wrap)) / 2) + var(--gutter)));
  pointer-events: none;
  display: none;
}

.is-pinned .timeline-h__fade {
  display: block;
}

.timeline-h__fade--left {
  left: 0;
}

.timeline-h__fade--right {
  right: 0;
}

.timeline-h__fade>span {
  position: absolute;
  inset: 0;
  display: block;
}

.timeline-h__fade--left>span:nth-child(1),
.timeline-h__fade--right>span:nth-child(1) {
  -webkit-backdrop-filter: blur(1.0.3125rem);
  backdrop-filter: blur(1.0.3125rem);
}

.timeline-h__fade--left>span:nth-child(2),
.timeline-h__fade--right>span:nth-child(2) {
  -webkit-backdrop-filter: blur(0.3125rem);
  backdrop-filter: blur(0.3125rem);
}

.timeline-h__fade--left>span:nth-child(3),
.timeline-h__fade--right>span:nth-child(3) {
  -webkit-backdrop-filter: blur(0.75rem);
  backdrop-filter: blur(0.75rem);
}

.timeline-h__fade--left>span:nth-child(1) {
  -webkit-mask-image: linear-gradient(to left, transparent 0%, #000 65%);
  mask-image: linear-gradient(to left, transparent 0%, #000 65%);
}

.timeline-h__fade--left>span:nth-child(2) {
  -webkit-mask-image: linear-gradient(to left, transparent 30%, #000 80%);
  mask-image: linear-gradient(to left, transparent 30%, #000 80%);
}

.timeline-h__fade--left>span:nth-child(3) {
  -webkit-mask-image: linear-gradient(to left, transparent 58%, #000 96%);
  mask-image: linear-gradient(to left, transparent 58%, #000 96%);
}

.timeline-h__fade--right>span:nth-child(1) {
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 65%);
  mask-image: linear-gradient(to right, transparent 0%, #000 65%);
}

.timeline-h__fade--right>span:nth-child(2) {
  -webkit-mask-image: linear-gradient(to right, transparent 30%, #000 80%);
  mask-image: linear-gradient(to right, transparent 30%, #000 80%);
}

.timeline-h__fade--right>span:nth-child(3) {
  -webkit-mask-image: linear-gradient(to right, transparent 58%, #000 96%);
  mask-image: linear-gradient(to right, transparent 58%, #000 96%);
}

.timeline-h__track {
  position: relative;
  display: flex;
  align-items: stretch;
  gap: var(--space-64);
  width: max-content;
  /* Same gutter as .container, so the first card lines up with the section tag.
     A percentage resolves against the containing block; 100vw would include the
     scrollbar and land ~0.4375rem out. */
  padding-inline: calc(max(0px, (100% - var(--wrap)) / 2) + var(--gutter));
  /* Clearance under the markers. Without it they sit flush against the
     overflow edge and the active state's scale(1.1) gets clipped. */
  padding-bottom: var(--tl-floor);
  will-change: transform;
}

/* The tail matches the gutter too, so travel ends with the last card on the
   container's right edge rather than leaving a long empty run of rail. */
.is-pinned .timeline-h__track {
  padding-right: calc(max(0px, (100% - var(--wrap)) / 2) + var(--gutter));
}

/* The rail runs along the bottom of the track, level with the icon row.
   `bottom` is measured from the padding box, so the floor has to be added
   back in to keep the line through the middle of the markers. */
.timeline-h__rail {
  position: absolute;
  bottom: calc(2.8125rem / 2 + var(--tl-floor));
  left: 0;
  right: 0;
  z-index: 2;
  /* above the cards it runs behind */
  height: 0.25rem;
  transform: translateY(50%);
  background: var(--c-surface);
}

.timeline-h__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--c-blue);
}

/* Entry — date, card, then the marker sitting on the rail. Content is
   bottom-aligned so every card meets its stem at the same height. */
.tl-entry {
  position: relative;
  display: grid;
  grid-template-rows: auto auto auto;
  align-content: end;
  justify-items: center;
  width: 26.25rem;
  flex: none;
}

.tl-label {
  grid-row: 1;
  margin-bottom: var(--space-16);
}

.tl-card {
  grid-row: 2;
  margin-bottom: var(--space-32);
}

.tl-icon {
  grid-row: 3;
}

/* the vertical stem joining a card down to the rail */
.tl-entry::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 2.8125rem;
  width: 2px;
  height: 1.75rem;
  z-index: 2;
  /* stays with the rail, not the card */
  background: var(--c-surface);
  transform: translateX(-50%);
  transition: background-color .2s linear;
}

.tl-entry.is-active::before {
  background: var(--c-blue);
}

.tl-label {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-self: start;
  text-align: left;
  padding: var(--space-4) 0;
}

.tl-label__main {
  color: var(--c-blue);
  font-weight: var(--fw-medium);
}

.tl-label__sub {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.tl-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.8125rem;
  height: 2.8125rem;
  border: 2px solid var(--c-surface);
  border-radius: 50%;
  background: var(--c-bg);
  color: var(--c-white);
  transition: color .2s linear, border-color .2s linear,
    background-color .2s linear, transform .3s var(--ease);
  z-index: 3;
  /* above the rail it sits on */
}

.tl-entry.is-active .tl-icon {
  color: var(--c-blue);
  border-color: var(--c-blue);
  background: var(--c-surface);
  transform: scale(1.1);
}

.tl-card {
  display: flex;
  align-items: flex-start;
  gap: var(--space-16);
  width: 100%;
  padding: var(--space-24);
  border-radius: 1rem;
  background: var(--c-surface);
  box-shadow: var(--shadow-card);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}

/* Cards ahead of the playhead sit back until the scrub reaches them. */
.is-pinned .tl-entry:not(.is-active) .tl-card {
  opacity: .45;
  transform: translateY(0.5rem);
}

.tl-card__media {
  flex: 0 0 2.75rem;
}

.tl-card__media img {
  width: 100%;
  height: auto;
  object-fit: contain;
}

.tl-card__body {
  text-align: left;
  min-width: 0;
}

.tl-card__title {
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  color: var(--c-white);
  margin-bottom: var(--space-8);
}

.tl-card__desc {
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  color: var(--c-muted);
}

/* ============ END OF TIMELINE — PINNED HORIZONTAL SCRUB ============ */

/* ============ START OF STATEMENT ============ */
.statement {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-64) var(--space-24);
  border-radius: 1.5rem;
  background: radial-gradient(circle at var(--mouse-x, 50%) var(--mouse-y, 50%), rgba(255, 255, 255, 0.08) 0%, var(--c-surface-glass) 50%);
  box-shadow: 0 0 80px var(--c-blue-wash);
  border: 1px solid var(--c-hairline);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transition: transform 0.1s;
}

.statement__line {
  max-width: 100%;
}

.statement__line b {
  font-size: var(--fs-statement);
  /* --fw-bold was never defined, so this resolved to nothing and the weight
     fell through to the h3's own 600. Naming the weight it was already
     rendering at changes no pixels, and takes the last claim on Poppins 700
     with it — which is why the font request no longer asks for it. */
  font-weight: var(--fw-semibold);
  text-transform: capitalize;
  background: linear-gradient(135deg, var(--c-white) 20%, var(--c-blue-hover) 50%, var(--c-white) 80%);
  background-size: 200% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  display: inline-block;
  transition: background-position 0.5s var(--ease);
}

.statement:hover .statement__line b {
  background-position: 200% center;
  transition: background-position 2s linear;
}

.clip {
  display: block;
  overflow: hidden;
  padding-bottom: .08em;
}

.clip b {
  display: block;
}

.is-visible .clip b {
  animation: clipIn 1s var(--ease) both;
}

@keyframes clipIn {
  from {
    clip-path: inset(0 100% 0 0);
    transform: translateY(.15em);
  }

  to {
    clip-path: inset(0 0 0 0);
    transform: translateY(0);
  }
}

.statement__line:last-child .clip b {
  animation-delay: .35s;
}

/* ============ END OF STATEMENT ============ */

/* ============ START OF PROJECTS ============ */
.projects {
  display: grid;
  gap: var(--section-y);
}

.project-block {
  display: block;
}

.feature-card {
  display: flex;
  gap: 0;
  border-radius: 1.5rem;
  background: var(--c-surface-glass);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--c-hairline);
  overflow: hidden;
  transition: transform .4s var(--ease), box-shadow .4s var(--ease), border-color .4s var(--ease);
}

.feature-card:hover {
  transform: translateY(-0.375rem);
  box-shadow: 0 16px 40px rgba(10, 132, 255, 0.15), 0 0 20px rgba(10, 132, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.3);
}

.feature-card .quote-box,
.feature-card .meta-row {
  transition: transform 0.4s var(--ease);
}

.feature-card:hover .quote-box,
.feature-card:hover .meta-row {
  transform: translateY(-4px);
}

.feature-card__media {
  flex: 0 0 62%;
  background: var(--c-surface-2);
  overflow: hidden;
  position: relative;
}

.feature-card__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
  transition: transform 0.6s var(--ease);
}

.feature-card:hover .feature-card__media img {
  transform: scale(1.05);
}

.feature-card__aside {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: var(--space-16);
  gap: var(--space-16);
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(0, 0, 0, 0.4) 100%);
  position: relative;
}

.feature-card__aside::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at top left, rgba(255, 255, 255, 0.1), transparent 50%);
  pointer-events: none;
}

.quote-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  padding: var(--space-16);
  border-radius: 1rem;
  background: var(--c-surface-2);
}

.quote-box__mark {
  color: var(--c-line);
}

.quote-box p {
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  color: var(--c-white);
  line-height: var(--lh-snug);
}

.meta-row {
  display: flex;
  gap: var(--space-16);
}

.meta-box {
  flex: 1;
  padding: var(--space-16);
  border-radius: 1rem;
  background: var(--c-surface-2);
}

.meta-box__title {
  font-size: var(--fs-3xl);
  font-weight: var(--fw-semibold);
  color: var(--c-white);
  line-height: var(--lh-heading);
}

.meta-box__sub {
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  color: var(--c-white);
}

/* Image accordion */
.accordion {
  display: flex;
  gap: var(--space-8);
  height: 30rem;
  border-radius: 1.5rem;
  overflow: hidden;
}

.accordion__item {
  position: relative;
  flex: 1;
  background-size: cover;
  background-position: center;
  transition: flex .6s var(--ease);
  cursor: pointer;
  overflow: hidden;
}

.accordion__item.is-active {
  flex: 3;
}

/* The three project stills. They were inline background-image attributes, which
   meant one file had to serve every screen — and the file that suits the 646px
   slot this opens to on a desktop is three times the weight a 353px phone slot
   needs. A background can't take a srcset, so the URLs live here instead and a
   media query hands phones their own cut. These load eagerly whatever else is
   on the page, so on a slow connection they were taking bandwidth the fonts and
   the first paint were waiting on. */
.accordion__item--rupaone {
  background-image: url("../assets/compressed/rupaone.webp");
}

.accordion__item--angop {
  background-image: url("../assets/compressed/angop.webp");
}

.accordion__item--arx-control {
  background-image: url("../assets/compressed/arx-control.webp");
}

@media (max-width: 55rem) {
  .accordion__item--rupaone {
    background-image: url("../assets/compressed/rupaone-800.webp");
  }

  .accordion__item--angop {
    background-image: url("../assets/compressed/angop-800.webp");
  }

  .accordion__item--arx-control {
    background-image: url("../assets/compressed/arx-control-800.webp");
  }
}

.accordion__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-16);
  padding: var(--space-32);
  text-align: center;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.1) 100%);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0.7;
  transition: opacity .6s var(--ease), backdrop-filter .6s var(--ease);
}

.accordion__item.is-active .accordion__overlay {
  opacity: 1;
  backdrop-filter: blur(0px);
  -webkit-backdrop-filter: blur(0px);
}

.accordion__title {
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  color: var(--c-white);
  transform: rotate(-90deg);
  white-space: nowrap;
  transition: all .4s var(--ease);
}

.accordion__item.is-active .accordion__title {
  font-size: var(--fs-5xl);
  transform: rotate(0deg);
  white-space: normal;
}

.accordion__desc {
  max-width: 28.75rem;
  font-size: var(--fs-base);
  color: var(--c-white);
  position: absolute;
  visibility: hidden;
  opacity: 0;
  transform: translateY(1rem);
  transition: all .5s var(--ease);
}

.accordion__item.is-active .accordion__desc {
  position: static;
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition-delay: 0.1s;
}

.accordion__btn {
  margin-top: var(--space-8);
  padding: var(--space-8) var(--space-24);
  border: 1px solid var(--c-white);
  border-radius: 2rem;
  font-size: var(--fs-base);
  position: absolute;
  visibility: hidden;
  overflow: hidden;
  z-index: 1;
  opacity: 0;
  transform: translateY(1rem);
  transition: all .5s var(--ease);
}

.accordion__item.is-active .accordion__btn {
  position: relative;
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition-delay: 0.2s;
}

.accordion__btn::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--c-white);
  z-index: -1;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .3s var(--ease);
}

.accordion__btn:hover {
  color: var(--c-bg);
  box-shadow: 0 0 15px rgba(255, 255, 255, 0.5);
}

.accordion__btn:hover::before {
  transform: scaleX(1);
  transform-origin: left;
}

/* ============ END OF PROJECTS ============ */

/* ============ START OF FOOTER + UTILITIES ============ */
.site-footer {
  padding: var(--space-48) 0;
  background: var(--c-bg);
  text-align: center;
  font-size: var(--fs-sm);
  color: var(--c-muted);
}

.to-top {
  position: fixed;
  right: var(--space-24);
  bottom: var(--space-24);
  z-index: 40;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 1px solid var(--c-navy);
  border-radius: 1rem;
  background: var(--c-surface);
  color: var(--c-white);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.625rem);
  transition: opacity .3s var(--ease), transform .3s var(--ease), visibility .3s, border-color .5s var(--ease-soft);

  /* Water animation requirements */
  overflow: hidden;
  isolation: isolate;
}

.to-top>* {
  position: relative;
  z-index: 1;
}

.to-top::before {
  content: "";
  position: absolute;
  left: -20%;
  bottom: -60%;
  width: 140%;
  height: 160%;
  z-index: 0;
  /* Round, not squircle: this radius draws the meniscus dome itself rather
     than easing a corner, and a superellipse would flatten it into a lid. */
  border-radius: 46% 48% 0 0 / 26% 24% 0 0;
  corner-shape: round;
  transform: translateY(100%);
  transition: transform .7s var(--ease-soft);
  background: var(--c-surface-2);
}

.to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.to-top:hover::before,
.to-top:focus-visible::before {
  transform: translateY(-18%);
  animation: waterWobble 3.4s ease-in-out infinite;
}

.to-top:hover,
.to-top:focus-visible {
  border-color: var(--c-surface-2);
}

/* Scroll reveal.

   An animation rather than a transition, and with no fill mode. A transition
   here would replace whatever `transition` the element already declares — the
   feature card's hover lift, the accordion's flex easing — and a fill mode
   would pin `transform` afterwards, outranking those same hovers. Without one,
   the element hands control straight back once it has landed. */
.reveal {
  opacity: 0;
}

.reveal.is-visible {
  opacity: 1;
  animation: revealUp .8s var(--ease-soft) var(--reveal-delay, 0s);
}

@keyframes revealUp {
  from {
    opacity: 0;
    transform: translateY(2.5rem);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* Custom cursor. The one thing on the site that stays a true circle: the dot
   and the ring read as a pointer, not as a piece of the interface, so they sit
   outside the squircle theme. */
#cursor,
#follower {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  pointer-events: none;
  border-radius: 50%;
  corner-shape: round;
  opacity: 0;
  transition: opacity .3s linear;
}

#cursor {
  width: 0.5rem;
  height: 0.5rem;
  background: var(--c-blue);
}

#follower {
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--c-blue);
  transition: opacity .3s linear, width .25s var(--ease), height .25s var(--ease),
    background-color .25s var(--ease);
}

body.has-cursor #cursor,
body.has-cursor #follower {
  opacity: 1;
}

/* The lightbox keeps the site's cursor. It is the only pointer these pages
   have — `cursor: none` is set on everything above — so standing it down over
   the viewer left the controls with nothing under the pointer at all. What the
   native zoom-in and grab cursors were saying, the ring now says itself. */

/* Over something interactive the ring takes over on its own: the dot drops
   out and a faint wash of the accent fills the circle in its place. The
   circle keeps its size — only the fill marks the change. */
body.has-cursor #cursor.is-hover {
  opacity: 0;
}

#follower.is-hover {
  background: var(--c-blue-wash);
}

/* Pressing is the one thing that resizes the ring. */
#follower.is-down {
  width: 1.625rem;
  height: 1.625rem;
}

#follower.is-hover.is-down {
  background: var(--c-blue-wash-strong);
}

/* The custom cursor replaces the native one outright. `has-cursor` is only
   set once the pointer has actually moved, so the arrow is never hidden
   before its stand-in exists. */
@media (hover: hover) and (pointer: fine) {

  body.has-cursor,
  body.has-cursor * {
    cursor: none;
  }
}

/* ============ END OF FOOTER + UTILITIES ============ */

/* ============ START OF CONTEXT MENU ============ */
.ctx-menu {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9000;
  min-width: 14.5rem;
  padding: var(--space-8);
  border: 1px solid var(--c-navy);
  border-radius: 0.875rem;
  background: var(--c-menu-bg);
  -webkit-backdrop-filter: blur(0.875rem);
  backdrop-filter: blur(0.875rem);
  box-shadow: var(--shadow-menu);
  transform-origin: top left;
  animation: ctxIn .14s var(--ease) both;
}

.ctx-menu[hidden] {
  display: none;
}

@keyframes ctxIn {
  from {
    opacity: 0;
    transform: scale(.96);
  }

  to {
    opacity: 1;
    transform: scale(1);
  }
}

.ctx-menu__group[hidden] {
  display: none;
}

/* `:not([hidden])` matters: `+` matches on DOM order, so without it the link
   group still draws a separator above the next group while it is display:none,
   leaving a stray line across the top of the menu. */
.ctx-menu__group:not([hidden])+.ctx-menu__group {
  margin-top: var(--space-8);
  padding-top: var(--space-8);
  border-top: 1px solid var(--c-hairline);
}

.ctx-menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  width: 100%;
  padding: var(--space-8) var(--space-16);
  border: 0;
  border-radius: 0.5625rem;
  background: none;
  color: var(--c-white);
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
  line-height: var(--lh-none);
  text-align: left;
  cursor: pointer;
  transition: background-color .15s var(--ease), color .15s var(--ease);
}

.ctx-menu__item:hover,
.ctx-menu__item:focus-visible {
  background: var(--c-navy);
  color: var(--c-blue);
  outline: none;
}

.ctx-menu__item svg {
  flex: none;
  opacity: .6;
}

.ctx-menu__item:hover svg,
.ctx-menu__item:focus-visible svg {
  opacity: 1;
}

.ctx-menu__item.is-done {
  color: var(--c-green);
}

.ctx-menu__item.is-done svg {
  opacity: 1;
}

.ctx-menu__ext {
  margin-left: auto;
  font-size: var(--fs-2xs);
  opacity: .5;
}

/* ============ END OF CONTEXT MENU ============ */

/* ============ START OF RESPONSIVE ============ */
@media (max-width: 64rem) {
  .feature-card {
    flex-direction: column;
  }

  .feature-card__media {
    flex: none;
  }

  .feature-card__media img {
    position: static;
    height: auto;
  }
}

@media (max-width: 55rem) {
  :root {
    --header-h: 4.25rem;
  }

  /* padding-inline is inherited as var(--gutter) to align with container */

  .header-inner>.btn {
    padding: 0.6rem 0.8rem;
    border-radius: 0.6rem;
    font-size: 0.7rem;
  }

  .header-inner>.btn svg {
    width: 11px;
    height: 11px;
  }

  /* Hamburger menu and its related display overrides have been removed to show the Work With Me button instead. */

  .hero {
    flex-direction: column;
    justify-content: center;
    gap: var(--space-32);
    padding-top: calc(var(--header-h) + var(--space-24));
  }

  .hero__left {
    order: 2;
    align-items: flex-start;
    flex: none;
    padding-right: 0;
  }

  .hero__right {
    order: 1;
    flex: none;
  }

  .hero__name {
    font-size: var(--fs-4xl);
    line-height: var(--lh-tight);
  }

  /* Viewport-relative on purpose: the address has to shrink to fit one line on
     a 20rem screen, which no fixed step on the scale can promise. */
  .hero__status-text {
    font-size: 5vw;
  }

  .rotator {
    font-size: var(--fs-lg);
  }

  .hero__actions {
    display: none;
  }

  .hero__cue {
    display: none;
  }

  .section {
    padding: var(--section-y-sm) 0;
  }

  /* Timeline: never pinned here — swipe the rail sideways instead.
     The row layout is unchanged; entries stretch to the tallest card so
     every marker still lands on the rail. */
  .journey-sticky {
    gap: var(--space-24);
    padding-block: var(--section-y-sm);
  }

  .timeline-h {
    scroll-snap-type: x mandatory;
  }

  .timeline-h__track {
    gap: var(--space-24);
  }

  .tl-entry {
    width: min(18.75rem, 78vw);
    scroll-snap-align: center;
  }

  .tl-card {
    flex-direction: column;
    align-items: center;
    text-align: center;
  }

  .tl-card__media {
    flex: none;
    width: 3.125rem;
  }

  .tl-card__body {
    text-align: center;
  }

  .tl-card__title {
    font-size: var(--fs-lg);
  }

  .tl-card__desc {
    font-size: var(--fs-sm);
  }

  .statement {
    align-items: center;
  }

  .meta-row {
    flex-direction: column;
  }

  .accordion {
    flex-direction: column;
    height: auto;
  }

  .accordion__item {
    flex: none;
    min-height: 16.25rem;
  }

  .accordion__item.is-active {
    flex: none;
  }

  .accordion__overlay {
    opacity: 1;
    position: static;
    background: var(--c-overlay-soft);
  }

  .accordion__item .accordion__overlay {
    min-height: 16.25rem;
  }

  .accordion__title {
    transform: none;
    white-space: normal;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }
}

/* ============ END OF RESPONSIVE ============ */

/* ============ END OF MAEZKEV — VANILLA REBUILD ============ */