/* ============================================================
   MODAL — Projects page
   Pipeline view of the AOD Portfolio. Same visual vocabulary
   as the Team page: full-bleed photo hero with deep-green stage,
   sticky hero with the next section sliding up to cover, white
   content sections, tree band → dark grey closing.
   ============================================================ */

.page-projects {
  background: var(--color-white);
  color: var(--color-ink);
  min-height: 100vh;
}

.pj-main {
  position: relative;
  z-index: 1;
}

.pj-wrap {
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 clamp(1.5rem, 5vw, 5rem);
  box-sizing: border-box;
}

/* ============================================================
   SECTION 1 — Hero stage
   200vh tall scroll wrapper around a sticky 100vh hero so the
   first section below can slide up over it via .pj-section--cover.
   Same overlap pattern as About / Team.
   ============================================================ */
.pj-hero-stage {
  position: relative;
  height: 200vh;
  z-index: 0;
}
.pj-hero {
  position: sticky;
  top: 0;
  height: 100vh;
  min-height: 100vh;
  box-sizing: border-box;
  background: var(--color-deep-green);
  color: var(--color-white);
  /* Mirrors .ab-hero: the eyebrow + headline + sub group is centred
     vertically so it sits in the middle of the 100vh hero instead of
     clustering at the top and leaving the lower half empty. Symmetric
     padding clears the fixed nav and gives top/bottom breathing room. */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(6rem, 9vw, 9rem) 0 clamp(5rem, 8vw, 8rem);
  overflow: hidden;
}

/* Hero backdrop layers — solid green underlay, full-bleed aerial
   photo (box-west.jpg), green-tinted vignette so the white type
   reads at the bottom of the hero. */
.pj-hero-bg {
  position: absolute;
  inset: 0;
  background: var(--color-deep-green);
  z-index: 0;
}
.pj-hero-img {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, 100vw);
  height: 100%;
  object-fit: cover;
  z-index: 1;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  opacity: 0.92;
  filter: saturate(1.08) contrast(1.04);
  animation: pj-hero-drift 60s linear infinite alternate;
}
@keyframes pj-hero-drift {
  from { transform: translate(calc(-50% - 14px), -50%) scale(1.02); }
  to   { transform: translate(calc(-50% + 14px), calc(-50% - 6px)) scale(1.05); }
}
.pj-hero-vignette {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    radial-gradient(ellipse 90% 70% at 50% 140%, transparent 0%, rgba(1, 13, 5, 0.0) 55%, rgba(1, 13, 5, 0.28) 85%, rgba(1, 13, 5, 0.50) 100%),
    radial-gradient(ellipse 70% 50% at 50% 18%, rgba(1, 13, 5, 0.08) 0%, transparent 70%),
    linear-gradient(180deg, rgba(1, 13, 5, 0.05) 0%, transparent 50%, rgba(1, 13, 5, 0.20) 100%);
}

/* Mono micro-overlays — fixed to the viewport so they stay visible
   past the hero. Colour flips with body[data-nav-theme] so they
   read white on the dark hero and dark on the white sections. */
.pj-overlay-tl,
.pj-overlay-tr {
  position: fixed;
  top: clamp(1.6rem, 2.2vw, 2.4rem);
  z-index: 30;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(var(--color-white-rgb), 0.62);
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  pointer-events: none;
  transition: color 0.4s ease;
}
body[data-nav-theme="light"] .pj-overlay-tl,
body[data-nav-theme="light"] .pj-overlay-tr {
  color: rgba(var(--color-ink-rgb), 0.55);
}
.pj-overlay-tr .dash {
  transition: background 0.4s ease;
}
body[data-nav-theme="light"] .pj-overlay-tr .dash {
  background: rgba(var(--color-ink-rgb), 0.55);
}
.pj-overlay-tl { left: clamp(1.4rem, 2.5vw, 2.4rem); }
.pj-overlay-tr { right: clamp(1.4rem, 2.5vw, 2.4rem); }
.pj-overlay-tl .dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #1cd07c;
  box-shadow: 0 0 14px rgba(28, 208, 124, 0.85);
  animation: pj-hero-pulse 2.4s ease-in-out infinite;
}
.pj-overlay-tr .dash {
  width: 1.4rem; height: 1px;
  background: rgba(var(--color-white-rgb), 0.6);
}
@keyframes pj-hero-pulse {
  0%, 100% { opacity: 0.55; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.15); }
}

/* Hero content sits above all backdrop layers. */
.pj-hero-inner {
  position: relative;
  z-index: 3;
  /* Match .ab-hero-inner exactly: full-width wrap (no shrink-to-content
     in the centred flex hero) + the same 6rem horizontal padding as
     .ab-wrap, so the Projects hero content lines up with About / Team
     instead of sitting ~16px further left. */
  width: 100%;
  padding-left: clamp(1.5rem, 6vw, 6rem);
  padding-right: clamp(1.5rem, 6vw, 6rem);
}

/* Eyebrow / headline / sub mirror .ab-eyebrow--light / .ab-hero-headline
   / .ab-hero-sub exactly so the Projects hero reads identically to the
   About and Team heroes (same sizes, weights, opacities, rhythm). */
.pj-eyebrow {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: clamp(0.72rem, 0.78vw, 0.82rem);
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(var(--color-white-rgb), 0.85);
  margin: 0 0 var(--space-10) 0;
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
}
.pj-eyebrow::before {
  content: ""; display: inline-block;
  width: 2.2rem; height: 1px; background: rgba(var(--color-white-rgb), 0.85);
}
.pj-headline {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(2.2rem, 4.2vw, 4.4rem);
  line-height: 1.08;
  letter-spacing: -0.022em;
  color: var(--color-white);
  margin: 0 0 clamp(1.5rem, 2.6vw, 2.6rem) 0;
  max-width: 30ch;
  text-wrap: balance;
}
/* "Sydney" stays full white (a single key word should pop, not dim like
   About's secondary italic line). */
.pj-headline em {
  font-style: italic;
  font-weight: 500;
  color: var(--color-white);
}
.pj-sub {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(1rem, 1.15vw, 1.2rem);
  line-height: 1.7;
  color: rgba(var(--color-white-rgb), 0.72);
  margin: 0;
  max-width: 64ch;
}

@media (max-width: 760px) {
  .pj-overlay-tr { display: none; }
  .pj-overlay-tl {
    top: 0.55rem;
    left: 1.1rem;
    font-size: 0.55rem;
    letter-spacing: 0.18em;
  }
}

/* ============================================================
   Generic project section + cover overlap
   ------------------------------------------------------------
   Padding tightened so the five-tile pipeline (Chatswood,
   Haymarket, plus the three grid tiles) reads as one continuous
   chapter rather than five sections separated by empty white
   space. Section borders are removed between consecutive
   .pj-section blocks for the same reason.
   ============================================================ */
.pj-section {
  position: relative;
  padding: clamp(2rem, 3.5vw, 3.5rem) 0;
  background: var(--color-white);
  color: var(--color-ink);
}

/* First section after the hero slides up over it. min-height 100vh
   keeps the cover behaviour intact (the hero is fully obscured the
   moment this section locks at the top). The portfolio intro now
   carries the upper half of the cover, so the previous massive
   30vh padding-top is no longer needed. */
.pj-section--cover {
  position: relative;
  z-index: 2;
  margin-top: -100vh;
  min-height: 100vh;
  box-sizing: border-box;
  padding-top: clamp(7rem, 14vh, 14rem);
  padding-bottom: clamp(2rem, 3.5vw, 3.5rem);
}

/* Portfolio intro — section title sitting above the Chatswood
   bubble inside the cover section. Eyebrow + headline + sub,
   left-aligned to share the wrap of the bubble below. */
.pj-portfolio-intro {
  margin: 0 0 clamp(2.5rem, 4vw, 4rem) 0;
  max-width: 64ch;
}
.pj-portfolio-eyebrow {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: clamp(0.72rem, 0.78vw, 0.82rem);
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--color-ink);
  margin: 0 0 clamp(1rem, 1.6vw, 1.6rem) 0;
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
}
.pj-portfolio-eyebrow::before {
  content: "";
  display: inline-block;
  width: 2.2rem;
  height: 1px;
  background: var(--color-green);
}
.pj-portfolio-headline {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(2.2rem, 4vw, 4rem);
  line-height: 1.04;
  letter-spacing: -0.026em;
  color: var(--color-ink);
  margin: 0 0 clamp(0.85rem, 1.2vw, 1.2rem) 0;
  max-width: 22ch;
  text-wrap: balance;
}
.pj-portfolio-headline em {
  font-style: italic;
  color: var(--color-green);
}
.pj-portfolio-sub {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(0.95rem, 1.05vw, 1.1rem);
  line-height: 1.6;
  color: rgba(var(--color-ink-rgb), 0.72);
  margin: 0;
  max-width: 56ch;
}

/* ============================================================
   Featured project bubbles (Chatswood, Haymarket)
   ------------------------------------------------------------
   Each bubble is one cinematic composition:
     • Full-bleed drone-angle aerial map fills the entire frame.
     • A frosted info card floats over the top-left corner.
     • Brand-green viewfinder brackets pin the four corners.
     • Mono coords + compass overlay the opposite corners.
     • A huge outline-only project number ghosts behind the
       composition for scale and identity.
   The whole thing reads like a satellite-recon dossier card.
   ============================================================ */
.pj-feature .pj-wrap {
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 4vw, 4rem);
  position: relative;
}

.pj-feature-meta {
  position: relative;
  z-index: 2;
  align-self: stretch;
  max-width: 100%;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-card);
  background: var(--color-green);
  box-shadow:
    0 28px 64px rgba(1, 13, 5, 0.22),
    inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  isolation: isolate;
  transition: border-color 0.35s ease, box-shadow 0.35s ease;
}
.pj-feature-meta:hover {
  border-color: rgba(255, 255, 255, 0.45);
  box-shadow:
    0 0 32px rgba(255, 255, 255, 0.10),
    0 28px 64px rgba(1, 13, 5, 0.28),
    inset 0 0 0 1px rgba(255, 255, 255, 0.16);
}

/* Aerial layer — the drone-angle map fills the bubble. Perspective
   + rotateX tilts the satellite tiles back, simulating an oblique
   aerial view from a high drone. transform-origin at the bottom
   so the near edge stays anchored. The map element is scaled up
   to fill the tilted frame; overflow:hidden on the parent crops
   the rotated geometry back to the bubble's rounded rect. */
.pj-feature-meta-art {
  position: relative;
  width: 100%;
  aspect-ratio: 21 / 9;
  background: var(--color-green);
  overflow: hidden;
  z-index: 0;
}
.pj-feature-meta-art .pj-tile-map {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 45%;
  display: block;
  filter: contrast(1.04) saturate(1.06);
}

/* Atmospheric haze — deep-green vignette at the bottom so the
   corner type still reads against a stable canvas, with a light
   darkening from the top so the brand-green bubble doesn't feel
   flat. The aerial fills the centre so the haze only really
   shapes the four edges. */
.pj-feature-haze {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 110% 70% at 50% 100%, rgba(1, 13, 5, 0.55) 0%, rgba(1, 13, 5, 0.18) 55%, rgba(1, 13, 5, 0.0) 80%),
    linear-gradient(180deg, rgba(1, 13, 5, 0.16) 0%, transparent 35%);
}

/* Viewfinder corner brackets — slim white L-shapes pinned to two
   opposite corners of the bubble (top-left + bottom-right), exactly
   matching the grid tiles below. White pops against the brand-green
   stage; built from twin background gradients (horizontal arm +
   vertical arm) per corner. */
.pj-feature-frame {
  position: absolute;
  width: clamp(1.6rem, 2.4vw, 2.4rem);
  height: clamp(1.6rem, 2.4vw, 2.4rem);
  z-index: 3;
  pointer-events: none;
}
.pj-feature-frame--tl {
  top: clamp(0.9rem, 1.6vw, 1.6rem); left:  clamp(0.9rem, 1.6vw, 1.6rem);
  background:
    linear-gradient(var(--color-white), var(--color-white)) left top  / 100% 1.5px no-repeat,
    linear-gradient(var(--color-white), var(--color-white)) left top  / 1.5px 100% no-repeat;
}
.pj-feature-frame--br {
  bottom: clamp(0.9rem, 1.6vw, 1.6rem); right: clamp(0.9rem, 1.6vw, 1.6rem);
  background:
    linear-gradient(var(--color-white), var(--color-white)) right bottom / 100% 1.5px no-repeat,
    linear-gradient(var(--color-white), var(--color-white)) right bottom / 1.5px 100% no-repeat;
}

/* Site index — small mono caps anchored top-right of the aerial,
   identical vocabulary to the grid tile `SITE · 0N`. */
.pj-feature-index {
  position: absolute;
  top: clamp(1.0rem, 1.6vw, 1.6rem);
  right: clamp(3rem, 4vw, 4rem);
  z-index: 4;
  font-family: var(--font-mono);
  font-size: clamp(0.7rem, 0.84vw, 0.84rem);
  letter-spacing: 0.32em;
  color: var(--color-white);
  font-weight: 500;
  pointer-events: none;
  user-select: none;
}
.pj-feature-index::before {
  content: "SITE · ";
  color: rgba(255, 255, 255, 0.65);
}

/* Brand-green meta strip — pinned beneath the aerial, exactly the
   pattern used by the grid tiles' .pj-tile-meta. Slightly larger
   type to reflect the feature bubble's flagship status. */
.pj-feature-meta-text {
  position: relative;
  padding: clamp(1.4rem, 2.2vw, 2.2rem) clamp(1.5rem, 2.6vw, 2.6rem);
  display: flex;
  flex-direction: column;
  gap: clamp(0.45rem, 0.7vw, 0.7rem);
  background: linear-gradient(180deg, rgba(1, 13, 5, 0.0) 0%, rgba(1, 13, 5, 0.32) 100%), var(--color-green);
  color: var(--color-white);
  border-top: 1px solid rgba(255, 255, 255, 0.22);
}
.pj-feature-status {
  font-family: var(--font-mono);
  font-size: clamp(0.7rem, 0.78vw, 0.82rem);
  letter-spacing: 0.30em;
  text-transform: uppercase;
  color: var(--color-white);
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
}
.pj-feature-status::before {
  content: "";
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--color-white);
  box-shadow: 0 0 8px rgba(255, 255, 255, 0.5);
}
.pj-feature-name {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: clamp(2.2rem, 3.6vw, 3.6rem);
  line-height: 1.04;
  letter-spacing: -0.026em;
  color: var(--color-white);
  margin: 0;
  text-wrap: balance;
}
.pj-feature-count {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(0.95rem, 1.1vw, 1.15rem);
  color: rgba(255, 255, 255, 0.78);
  margin: 0;
}
.pj-feature-count span {
  font-weight: 600;
  color: var(--color-white);
  letter-spacing: -0.02em;
}

@media (max-width: 720px) {
  .pj-feature-meta-art { aspect-ratio: 4 / 3; }
  .pj-feature-index { right: clamp(2.4rem, 5vw, 3.2rem); }
}

/* ============================================================
   Project tiles grid (Woollahra, Kingsford, Gordon)
   ============================================================ */
.pj-grid-section {
  background: var(--color-white);
  color: var(--color-ink);
  /* Tightened — sits inside the pipeline cluster directly below
     Chatswood + Haymarket; the wider gap pre-existed because each
     section was treated as its own chapter. */
  padding: clamp(2rem, 3.5vw, 3.5rem) 0 clamp(2.5rem, 4vw, 4rem);
  border-top: 0;
}
.pj-grid-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(var(--color-ink-rgb), 0.55);
  margin: 0 0 clamp(2rem, 3vw, 3rem) 0;
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
}
.pj-grid-eyebrow::before {
  content: ""; display: inline-block;
  width: 2.2rem; height: 1px; background: rgba(var(--color-ink-rgb), 0.55);
}
.pj-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2vw, 1.75rem);
}
/* Grid tiles — same dossier vocabulary as the feature bubbles,
   compressed: drone-angle aerial top, viewfinder corners, ghost
   project number, meta strip pinned beneath — all in the brand-
   green palette so the tiles read as part of the same family as
   the footer. */
.pj-tile {
  position: relative;
  border-radius: var(--radius-card);
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: var(--color-green);
  display: flex;
  flex-direction: column;
  transform-origin: center center;
  isolation: isolate;
  transition:
    border-color 0.3s ease,
    box-shadow   0.3s ease,
    transform    0.4s cubic-bezier(0.2, 0.9, 0.25, 1);
}
.pj-grid-section .pj-tile:hover {
  border-color: rgba(255, 255, 255, 0.45);
  transform: scale(1.04);
  z-index: 5;
  box-shadow:
    0 0 36px rgba(255, 255, 255, 0.14),
    0 26px 56px rgba(1, 13, 5, 0.28);
}

.pj-tile-map-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--color-green);
}
.pj-tile-map {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 45%;
  display: block;
  filter: contrast(1.04) saturate(1.06);
}
.pj-tile-haze {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 110% 70% at 50% 100%, rgba(1, 13, 5, 0.50) 0%, rgba(1, 13, 5, 0.14) 55%, rgba(1, 13, 5, 0) 80%),
    linear-gradient(180deg, rgba(1, 13, 5, 0.14) 0%, transparent 32%);
}

/* Tile corner brackets — same viewfinder vocabulary, smaller. */
.pj-tile-frame {
  position: absolute;
  width: clamp(1.1rem, 1.8vw, 1.6rem);
  height: clamp(1.1rem, 1.8vw, 1.6rem);
  z-index: 3;
  pointer-events: none;
}
.pj-tile-frame--tl {
  top: clamp(0.65rem, 1vw, 1rem); left: clamp(0.65rem, 1vw, 1rem);
  background:
    linear-gradient(var(--color-white), var(--color-white)) left top / 100% 1.5px no-repeat,
    linear-gradient(var(--color-white), var(--color-white)) left top / 1.5px 100% no-repeat;
}
.pj-tile-frame--br {
  bottom: clamp(0.65rem, 1vw, 1rem); right: clamp(0.65rem, 1vw, 1rem);
  background:
    linear-gradient(var(--color-white), var(--color-white)) right bottom / 100% 1.5px no-repeat,
    linear-gradient(var(--color-white), var(--color-white)) right bottom / 1.5px 100% no-repeat;
}

/* Ghost site label — small mono caps anchored top-right of the
   aerial portion. White on the brand-green stage. */
.pj-tile-index {
  position: absolute;
  top: clamp(0.5rem, 1vw, 1rem);
  right: clamp(1.6rem, 2.6vw, 2.4rem);
  z-index: 4;
  font-family: var(--font-mono);
  font-size: clamp(0.65rem, 0.78vw, 0.78rem);
  letter-spacing: 0.32em;
  color: var(--color-white);
  font-weight: 500;
  pointer-events: none;
  user-select: none;
}
.pj-tile-index::before {
  content: "SITE · ";
  color: rgba(255, 255, 255, 0.65);
}

/* Meta strip — sits inside the brand-green well below the aerial.
   Slight deep-green darkening at the bottom for depth; white
   hairline separator joins it to the aerial above. */
.pj-tile-meta {
  position: relative;
  padding: clamp(1.1rem, 1.8vw, 1.6rem) clamp(1.25rem, 2vw, 1.75rem);
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  background: linear-gradient(180deg, rgba(1, 13, 5, 0.0) 0%, rgba(1, 13, 5, 0.32) 100%), var(--color-green);
  color: var(--color-white);
  border-top: 1px solid rgba(255, 255, 255, 0.22);
}
.pj-tile-status {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--color-white);
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
}
.pj-tile-status::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--color-white);
  box-shadow: 0 0 8px rgba(255, 255, 255, 0.5);
}
.pj-tile-name {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: clamp(1.5rem, 2.4vw, 2.2rem);
  line-height: 1.05;
  letter-spacing: -0.022em;
  color: var(--color-white);
  margin: 0;
}
/* Site description — shown on the large stage (an expanded site)
   only, under the name. Hidden on the brand panel, and absent from the
   small marquee cards. Non-disclosing transit/precinct context. */
.pj-stage-context {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(0.95rem, 1.15vw, 1.2rem);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.82);
  margin: 0;
  max-width: 48ch;
  text-wrap: pretty;
}
.pj-tile-count {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(0.9rem, 1.05vw, 1.05rem);
  color: rgba(255, 255, 255, 0.72);
  margin: 0;
}
.pj-tile-count span {
  font-weight: 600;
  color: var(--color-white);
  letter-spacing: -0.02em;
}

/* ============================================================
   Tree band — climbs into the CTA section above with a large
   negative margin so the forest overlaps the link list. Misty
   white top blends with CTA's white bg; green canopy emerges
   around the link rows. line-height: 0 stops a baseline gap
   between the <img> and the green footer below.
   ============================================================ */
.pj-tree-band {
  position: relative;
  margin: clamp(-22rem, -22vw, -8rem) calc(50% - 50vw) 0;
  width: 100vw;
  background: transparent;
  line-height: 0;
  pointer-events: none;
  user-select: none;
  z-index: 0;
}
.pj-tree-band img {
  display: block;
  width: 100%;
  height: auto;
}

/* ============================================================
   Closing block — white stage matching the rest of the page,
   centred. Ink type, brand green on emphasis. The tree-band
   above the footer (placed after this section) carries the
   visual close into the green footer below.
   ============================================================ */
.pj-closing-section {
  position: relative;
  z-index: 1;
  /* Smoothed multi-stop fade so there's no hard knee in the alpha
     curve where the previous two-stop gradient transitioned from
     solid white to a fade — that knee read as a faint horizontal
     banding line where the gradient met the tree band. */
  background:
    linear-gradient(
      to bottom,
      var(--color-white) 0%,
      var(--color-white) 38%,
      rgba(255, 255, 255, 0.95) 50%,
      rgba(255, 255, 255, 0.78) 62%,
      rgba(255, 255, 255, 0.52) 74%,
      rgba(255, 255, 255, 0.25) 86%,
      rgba(255, 255, 255, 0) 100%
    );
  color: var(--color-ink);
  /* Bottom padding capped tighter at ultra-wide so the section
     doesn't grow excessively past the tree-band reveal — keeps the
     closing-to-tree-band rhythm comparable to desktop. */
  padding: clamp(2.5rem, 4.5vw, 4.5rem) 0 clamp(7rem, 9vw, 11rem) 0;
  text-align: center;
  border-top: 0;
}
.pj-closing-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--color-green);
  margin: 0 0 clamp(1.25rem, 2vw, 1.75rem) 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}
.pj-closing-eyebrow::before,
.pj-closing-eyebrow::after {
  content: ""; display: inline-block;
  width: 2.2rem; height: 1px; background: var(--color-green);
}
.pj-closing-headline {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(2rem, 4.4vw, 4.4rem);
  line-height: 1.05;
  letter-spacing: -0.024em;
  color: var(--color-ink);
  margin: 0 0 var(--space-6) 0;
  text-wrap: balance;
}
.pj-closing-headline em {
  font-style: italic;
  color: var(--color-green);
}
.pj-closing-sub {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: clamp(1rem, 1.2vw, 1.2rem);
  line-height: 1.55;
  color: rgba(var(--color-ink-rgb), 0.72);
  margin: 0 auto;
  max-width: 56ch;
}
.pj-closing-sub a {
  color: var(--color-green);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  transition: opacity 0.2s ease;
}
.pj-closing-sub a:hover { opacity: 0.7; }

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 980px) {
  .pj-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .pj-grid { grid-template-columns: 1fr; }
  /* Slightly taller map on narrow screens — the accent is in flow
     above the text on mobile, not overlaying the map. */
  .pj-feature-meta-art .pj-tile-map { aspect-ratio: 16 / 9; }
}

/* ============================================================
   Drive-by truck — runs right→left along the boundary line where
   the hero meets the first white section. Position is fixed to
   the viewport so the truck rides that visual line as the cover
   slides up. js/projects.js sets transform + opacity every frame
   based on scroll progress — stopping the scroll stops the truck.
   ============================================================ */
.pj-truck {
  position: fixed;
  /* Pinned to the bottom of the viewport where the cover section's
     leading edge first appears during the slide-up. */
  bottom: clamp(6vh, 10vh, 14vh);
  left: 0;
  width: clamp(220px, 32vw, 520px);
  height: auto;
  /* z 49 sits the truck above every page element (nav is 50, so
     the menu stays clickable). No fade — the truck reads as a
     real vehicle running on top of everything. */
  z-index: 49;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  /* Start off-screen right. JS overrides transform every frame;
     the inline style is here so the truck isn't visible before
     the first JS update fires. */
  transform: translate3d(120vw, 0, 0);
  filter:
    drop-shadow(0 14px 26px rgba(0, 0, 0, 0.30))
    drop-shadow(0 4px 8px rgba(0, 0, 0, 0.20));
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .pj-truck { display: none; }
}
@media (max-width: 760px) {
  .pj-truck {
    width: clamp(170px, 60vw, 320px);
    bottom: clamp(4vh, 8vh, 10vh);
  }
}

/* ============================================================
   Sydney pipeline showcase — large stage + auto-scrolling strip
   ------------------------------------------------------------
   The large stage sits on top (default = MODAL welcome panel:
   spinning mark left, investor / JV invitation as bullets right).
   Below it, the small widgets run as a right-to-left looping
   marquee (same pattern as the team page banner), showing ~2 cards
   at a time. Click a card to expand it into the stage; the view
   scrolls to centre the stage. Widgets reuse .pj-tile; the stage
   reuses .pj-feature-meta.
   ============================================================ */

/* --- Interactive widgets: pointer + green halo on hover / focus --- */
.pj-widget {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.pj-widget:hover,
.pj-widget:focus-visible {
  outline: none;
  transform: scale(1.04);
  z-index: 6;
  border-color: var(--color-green-bright);
  box-shadow:
    0 0 0 2px var(--color-green-bright),
    0 0 30px 5px rgba(47, 158, 106, 0.55),
    0 24px 52px rgba(1, 13, 5, 0.30);
}
/* Brand widget (small) — green mark on a white panel. */
.pj-widget-spin-wrap {
  display: grid;
  place-items: center;
  background: var(--color-white);
}
.pj-widget--brand { border-color: rgba(var(--color-ink-rgb), 0.14); }
.pj-widget--brand .pj-tile-frame { display: none; }
.pj-widget-spin {
  width: 54%;
  height: auto;
  object-fit: contain;
  animation: pj-spin 60s linear infinite;
  user-select: none;
  -webkit-user-drag: none;
}

/* --- Auto-scrolling widget strip (full-bleed band, below the stage) --- */
.pj-marquee {
  order: 1;                         /* header (0) → stage (0) → marquee */
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  margin-top: clamp(2rem, 4vw, 3.5rem);
}
.pj-marquee-mask {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
}
.pj-marquee-track {
  display: flex;
  list-style: none;
  margin: 0;
  width: max-content;
  gap: clamp(1rem, 2vw, 2rem);
  padding: clamp(1.4rem, 2vw, 2rem) clamp(0.75rem, 2vw, 2rem);
  /* Position is driven by js/marquee.js (auto drift + drag-to-scrub).
     touch-action: pan-y keeps vertical page scroll while horizontal
     drags scrub the strip. */
  cursor: grab;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  will-change: transform;
}
.pj-marquee-track.is-grabbing { cursor: grabbing; }
/* Enlarged cards — about two visible across the band. */
.pj-marquee .pj-widget {
  flex: 0 0 auto;
  width: clamp(280px, 43vw, 580px);
}
.pj-marquee .pj-tile-map-wrap { aspect-ratio: 16 / 9; }
.pj-marquee .pj-tile-meta { padding: clamp(1.1rem, 1.6vw, 1.6rem) clamp(1.25rem, 1.8vw, 1.75rem); }
.pj-marquee .pj-tile-name { font-size: clamp(1.5rem, 2.2vw, 2.4rem); }
.pj-marquee .pj-tile-status { font-size: clamp(0.68rem, 0.82vw, 0.82rem); letter-spacing: 0.26em; }

/* --- Large stage (sits ABOVE the marquee) --- */
.pj-stage {
  margin: 0;
  transition: opacity 0.28s ease, transform 0.28s cubic-bezier(0.2, 0.9, 0.25, 1);
  cursor: default;
}
/* On swap the stage drops + fades, then rises back into place. */
.pj-stage.is-swapping {
  opacity: 0;
  transform: translateY(28px) scale(0.97);
}

/* Brand stage — MODAL welcome panel: spinning mark on the left, the
   investor / JV / government invitation as bullet points on the right.
   White panel so the green mark reads (no green fill behind it). */
.pj-stage--brand { background: var(--color-white); }
.pj-stage--brand .pj-feature-meta-art,
.pj-stage--brand .pj-feature-meta-text,
.pj-stage--brand .pj-feature-frame,
.pj-stage--brand .pj-stage-index { display: none; }
.pj-stage-brand { display: none; }
.pj-stage--brand .pj-stage-brand {
  display: flex;
  align-items: center;
  gap: clamp(1.75rem, 4.5vw, 4.5rem);
  padding: clamp(2.25rem, 4.5vw, 4.25rem) clamp(2rem, 4.5vw, 4.5rem);
}
.pj-stage-brand-mark { flex: 0 0 auto; }
.pj-stage-spin {
  display: block;
  width: clamp(140px, 18vw, 280px);
  height: auto;
  animation: pj-spin 60s linear infinite;
  user-select: none;
  -webkit-user-drag: none;
}
.pj-stage-brand-body { flex: 1 1 auto; color: var(--color-ink); }
.pj-stage-brand-eyebrow {
  font-family: var(--font-mono);
  font-size: clamp(0.78rem, 0.9vw, 0.95rem);
  letter-spacing: 0.30em;
  text-transform: uppercase;
  color: var(--color-green);
  margin: 0 0 clamp(0.8rem, 1.2vw, 1.2rem) 0;
  display: inline-flex; align-items: center; gap: 0.7rem;
}
.pj-stage-brand-eyebrow::before {
  content: ""; display: inline-block;
  width: 2.2rem; height: 1px; background: var(--color-green);
}
.pj-stage-brand-title {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: clamp(2.3rem, 4vw, 4rem);
  line-height: 1.04;
  letter-spacing: -0.028em;
  color: var(--color-ink);
  margin: 0 0 clamp(1.4rem, 2.2vw, 2.2rem) 0;
  text-wrap: balance;
}
.pj-stage-points {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-direction: column;
  gap: clamp(1rem, 1.6vw, 1.5rem);
}
.pj-stage-points li {
  position: relative;
  padding-left: 2rem;
  font-family: var(--font-sans);
  font-size: clamp(1.1rem, 1.4vw, 1.5rem);
  line-height: 1.55;
  color: rgba(var(--color-ink-rgb), 0.80);
}
.pj-stage-points li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.5em;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--color-green);
}
.pj-stage-points li strong { color: var(--color-ink); font-weight: 600; }

@keyframes pj-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .pj-stage-spin,
  .pj-widget-spin { animation: none; }
  /* No looping: wrap the cards so all stay reachable, static. */
  .pj-marquee-track { animation: none; width: auto; flex-wrap: wrap; justify-content: center; }
  .pj-stage { transition: none; }
  .pj-widget:hover,
  .pj-widget:focus-visible { transform: none; }
}

/* Responsive — bigger marquee cards on phones; brand stage stacks. */
@media (max-width: 760px) {
  .pj-marquee .pj-widget { width: clamp(240px, 80vw, 460px); }
  .pj-stage--brand .pj-stage-brand {
    flex-direction: column;
    align-items: flex-start;
    gap: clamp(1.25rem, 4vw, 2rem);
  }
  .pj-stage-brand-mark { align-self: center; }
}
