/* Back-to-home link, replacing the logo in the header on project pages */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-main);
  font-weight: 400;
  font-size: var(--fs-nav-link);
  color: var(--color-text);
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
  transition: color 0.25s ease;
}

.back-link:hover,
.back-link:focus-visible {
  color: var(--color-accent);
}

.back-link__icon {
  width: 14px;
  height: auto;
  transform: scaleX(-1);
  transition: transform 0.25s ease;
}

.back-link:hover .back-link__icon,
.back-link:focus-visible .back-link__icon {
  transform: scaleX(-1) translateX(4px);
}

.project-hero {
  position: relative;
  background: var(--color-text-light);
  padding-block: clamp(40px, 6.09vw, 78px);
  overflow: hidden;
}

/* Soft background circles + two sparkle stars tucked by her head, tuned
   to this page's own single theme color (var(--color-accent) and its
   tint/dark) instead of all four project colors - this page is about
   one project, not a preview of all of them. Matches the simplified
   Figma reference, replacing the old icon-cushion + scatter treatment.
   Sits behind the grid content (z-index 0 vs. the inner's 1).

   Constrained to a centered, 1502px-max box - the exact width of the
   Figma frame the positions below were measured from - rather than the
   full, unbounded .project-hero width, so the circles/stars stay
   correctly centered on the page (same center as .project-hero__inner's
   own 1280px box) instead of drifting outward on very wide viewports. */
.project-hero__doodles {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 100%;
  max-width: 1502px;
  transform: translateX(-50%);
  z-index: 0;
  pointer-events: none;
  display: none;
}

.project-hero__blob {
  position: absolute;
  border-radius: 50%;
  aspect-ratio: 1;
}

.project-hero__star {
  position: absolute;
  aspect-ratio: 1;
}

/* left/top mark each piece's CENTER (translate(-50%,-50%)), not its
   top-left corner.
   blob--a/c are plain page-relative washes (a big one bleeding off the
   top, a small one down by the line), so they mirror cleanly as a
   plain 100%-minus-left for --reversed below. */
.project-hero__blob--a { left: 38.15%; top: 0.49%; width: clamp(140px, 21.57%, 324px); background: var(--color-accent-tint); transform: translate(-50%, -50%); }
.project-hero__blob--c { left: 51.5%; top: 72.67%; width: clamp(24px, 3.40%, 51px); background: var(--color-accent-tint-soft); transform: translate(-50%, -50%); }

/* blob--b (centered behind the character) and both stars (right by her
   head) do NOT mirror the same way: .project-hero__character is always
   inset `right: 21%` of its own line-row, i.e. anchored to the END of
   the line regardless of layout direction - so she sits near the
   page's outer edge when --reversed puts her column on the right, but
   near the page's center (bordering the graphic) in the default
   layout. Mirroring blob--b/stars' --reversed position with a plain
   100%-minus-left therefore put them nowhere near her in the default
   layout (confirmed by measuring .project-hero__character's own
   rendered center in both layouts - it isn't a mirror). Each set below
   is measured directly against her actual position in its own layout. */
.project-hero__blob--b { left: 38.58%; top: 67.94%; width: clamp(60px, 10.05%, 151px); background: var(--color-accent-tint-soft); transform: translate(-50%, -50%); }
/* Both stars' own boxes sit fully above the character's bounding box
   (not just offset left/right) - she is positioned close enough here
   that anything landing inside her box is painted over by her artwork
   (.project-hero__content stacks above .project-hero__doodles), which
   silently hid the stars entirely when they were placed left-of-center
   instead of strictly above. */
.project-hero__star--a { left: 37.55%; top: 47.6%; width: clamp(18px, 2.33%, 35px); color: var(--color-accent); transform: translate(-50%, -50%); }
.project-hero__star--b { left: 39.57%; top: 45.16%; width: clamp(11px, 1.33%, 20px); color: var(--color-accent-dark); transform: translate(-50%, -50%); }

.project-hero--reversed .project-hero__blob--a { left: 61.85%; }
.project-hero--reversed .project-hero__blob--c { left: 48.5%; }
/* blob--b/stars split further still, between --reversed and the
   --framed variant of it (AegisCore): --framed's wider graphic column
   leaves less headroom above her, measured independently rather than
   reused from the plain --reversed numbers, which put the stars low
   enough to land inside her box here too (same silent-hide bug as the
   default layout above, just on the other variant). */
.project-hero--reversed:not(.project-hero--framed) .project-hero__blob--b { left: 77.2%; top: 68.5%; }
.project-hero--reversed:not(.project-hero--framed) .project-hero__star--a { left: 74.73%; top: 51.34%; }
.project-hero--reversed:not(.project-hero--framed) .project-hero__star--b { left: 76.53%; top: 50.31%; }

.project-hero--framed .project-hero__blob--b { left: 77.86%; top: 65%; }
.project-hero--framed .project-hero__star--a { left: 75.39%; top: 46.34%; }
.project-hero--framed .project-hero__star--b { left: 77.19%; top: 45.31%; }

@media (min-width: 1240px) {
  .project-hero__doodles {
    display: block;
  }
}

.project-hero__inner {
  position: relative;
  z-index: 1;
  max-width: 1280px;
  margin-inline: auto;
  padding-left: clamp(20px, 7.5vw, 96px);
  padding-right: clamp(0px, 1vw, 12px);
  display: grid;
  /* minmax(0, 1fr), not bare 1fr: a bare 1fr track's implicit automatic
     minimum is "auto", which lets it refuse to shrink below the
     graphic's preferred width (its `width` clamp) and blow out the
     grid's total width past the container on narrower viewports. */
  grid-template-columns: clamp(300px, 43.2vw, 553px) minmax(0, 1fr);
  /* ONE row, not two: "content" (text-block + line-row stacked inside
     their own wrapper) sits beside "graphic" in a single grid row, so
     the row's height is simply max(content's natural height, graphic's
     height) - plain CSS grid row sizing, no multi-row-span distribution
     quirks. */
  grid-template-areas: "content graphic";
  /* Content (text+line) is vertically centered against the graphic,
     not pinned to its top - when the graphic is taller, the shorter
     content column floats centered within that row instead of
     hugging its top edge. */
  align-items: center;
  column-gap: clamp(16px, 2.4vw, 31px);
}

.project-hero__content {
  grid-area: content;
  display: flex;
  flex-direction: column;
  /* 0px between the subtitle and the line-row, per Figma - the heading-
     to-subtitle 90px gap lives inside .project-hero__text-block's own
     `gap` instead, so it's unaffected by this. */
  gap: 0;
}

/* Mirrored variant: graphic on the left, text on the right. Scoped to a
   modifier class so other project pages keep the default text-left
   layout. */
.project-hero--reversed .project-hero__inner {
  grid-template-columns: minmax(0, 1fr) clamp(300px, 43.2vw, 553px);
  grid-template-areas: "graphic content";
  padding-left: clamp(0px, 1vw, 12px);
  padding-right: clamp(20px, 7.5vw, 96px);
}

.project-hero__text-block {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: clamp(40px, 7vw, 90px);
}

.project-hero__heading {
  display: flex;
  flex-direction: column;
  gap: clamp(14px, 2.34vw, 30px);
}

.project-hero__eyebrow {
  text-align: left;
  color: var(--color-accent);
}

.project-hero__title {
  text-transform: uppercase;
  letter-spacing: -0.1em;
}

.project-hero__subtitle {
  text-align: left;
}

.project-hero__graphic {
  grid-area: graphic;
  position: relative;
  /* Centers the (now-shrunk) image within the box's full original
     footprint, so the box itself keeps reserving the same row height
     it always did - only the visible image gets smaller, leaving real
     margin around it for the glow to spread into without the section's
     overflow:hidden clipping it. */
  display: flex;
  align-items: center;
  justify-content: center;
  /* This is wider than its own 1fr grid track BY DESIGN - confirmed
     straight from Figma's node coordinates: at the 1280px reference
     frame, the laptop (701px) bleeds 91px past even the frame's own
     left edge, well past its ~610px track. Matching that ratio means
     letting it overflow the track; the section's overflow:hidden keeps
     that overflow from ever becoming a page-level horizontal scrollbar,
     it only ever clips visually, and only on viewports narrow enough
     that there's no spare margin outside the 1280px inner container to
     bleed into (reproducible on the Indicators page too - this is the
     same tension that already existed there). */
  width: clamp(200px, 54.38vw, 696px);
  aspect-ratio: 1449 / 933;
  flex-shrink: 1;
  min-width: 0;
}

/* Some projects' hero graphic is a bordered screenshot frame rather
   than the laptop mockup - visibly a different (taller) shape, so
   object-fit:contain inside the laptop's aspect-ratio box would
   letterbox it. Scoped per-project since the laptop ratio is still
   correct for the others. Width is also its own value (not the shared
   54.38vw/696px): at the 1280px reference this graphic is 839px wide
   (65.56vw) - a noticeably bigger share of the hero than the laptop
   mockup gets in the other projects' heroes. */
.project-hero--framed .project-hero__graphic {
  width: clamp(200px, 65.56vw, 839px);
  aspect-ratio: 2408 / 1320;
}

/* This hero's own column-gap: at the 1280px reference, Figma has the
   graphic's visible right edge at x=580 and the text column starting
   at x=640 - a 60px gap (4.69vw), not the shared 31px (2.4vw) the
   laptop-mockup heroes use. The bigger, bleeding graphic above means
   less of that 60px is "inside" the grid track to begin with, so
   reusing the smaller shared gap read as the text crowding the image. */
.project-hero--framed .project-hero__inner {
  column-gap: clamp(20px, 4.69vw, 60px);
  /* Figma's text column right-edge sits 87px (6.8vw) from the frame
     edge here, not the shared 96px (7.5vw). */
  padding-right: clamp(20px, 6.8vw, 87px);
}

/* Mirrored variant has graphic in the FIRST column, so an end-aligned
   overflow would bleed rightward into the text column instead of the
   outer edge. justify-self: end flips which side absorbs the bleed,
   matching the default template's own text-right/graphic-left bleed
   direction (toward the page's outer edge, not the text). */
.project-hero--reversed .project-hero__graphic {
  justify-self: end;
}

/* box-shadow, not filter: drop-shadow - deliberately. A drop-shadow
   filter on (or wrapping) the actual <img> clips its own blur at the
   bottom edge only, in this rendering engine, once the image is scaled
   down enough from its native resolution (confirmed with a plain div
   standing in for the img: identical filter, identical position, full
   symmetric bleed on every side - it's specifically about a replaced
   element being involved). box-shadow on this wrapper sidesteps it
   entirely and reads the same visually for a plain rectangular image. */
.project-hero__graphic-shadow {
  display: block;
  width: 85%;
  height: 85%;
  position: relative;
  z-index: 2;
  /* Soft glow in the page's own theme color (var(--color-accent)
     already resolves per-project - teal/blue/olive/mauve) instead of a
     generic neutral drop shadow. */
  box-shadow: 0 14px 38px color-mix(in srgb, var(--color-accent) 22%, transparent);
}

.project-hero__graphic-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}


/* Sized to fully contain the character (not just the thin line), so her
   height is reserved in the layout's own rhythm instead of floating
   outside it as absolute-positioned overflow. */
.project-hero__line-row {
  position: relative;
  width: clamp(220px, 43.2vw, 553px);
  height: clamp(86px, 12.45vw, 160px);
}

.project-hero__character {
  position: absolute;
  right: 21%;
  bottom: 0;
  width: clamp(55px, 7.97vw, 102px);
  height: auto;
  z-index: 2;
}

.project-hero__decor-line {
  display: block;
  position: absolute;
  left: 0;
  bottom: 28.2%;
  width: 100%;
  height: auto;
}

/* Mobile has its own character placement (sitting at the same height as
   the subtitle text, overlapping down onto the laptop below) - this
   second instance stays hidden until the mobile breakpoint, while the
   line-sitting instance above is hidden there instead. Position is
   computed from the Figma mobile reference: she sits beside/below the
   subtitle line, not attached to the laptop. */
.project-hero__character--mobile {
  display: none;
}

@media (max-width: 760px) {
  /* Equal top/bottom, not a shorter section: keeps the section's total
     height matching the home hero's own mobile height (same 210px of
     combined top+bottom padding the old 68px/142px split added up to -
     see the git history for that derivation), just redistributed
     evenly instead of mostly dumped under the content. The old
     asymmetric split was sized for a bottom-anchored character that's
     hidden on mobile, so it read as the text+graphic block sitting
     high in the section with a dead gap underneath; a plain 68px/68px
     fixed that but shrank the section itself. 105px/105px keeps the
     section just as tall while actually centering the content in it. */
  .project-hero {
    padding-top: 105px;
    padding-bottom: 105px;
  }

  /* Now that the graphic is widened to match the text column above
     (see the width rule below), its own side margin is only ~28px -
     too little room for a big blur radius to fade out in before
     hitting .project-hero's overflow:hidden edge, reading as a flat
     colored block rather than a shadow. Smaller radius, lower opacity,
     more vertical offset: reads as a shadow sitting under the image. */
  .project-hero__graphic-shadow {
    box-shadow: 0 10px 18px color-mix(in srgb, var(--color-accent) 18%, transparent);
  }

  /* Locked to Figma's 375px mobile reference frame, in fixed px - not
     vw/clamp. The reference design was never fluid across this whole
     range in the first place (it's one fixed frame), so scaling it
     continuously just drifted the laptop/text/character out of the
     relationship Figma actually specifies. Pinning it to the 375px
     numbers holds correctly for the realistic phone range (~320-430px)
     and simply stays put (doesn't grow/shrink) outside it. */
  .project-hero__inner,
  .project-hero--reversed .project-hero__inner {
    grid-template-columns: 1fr;
    grid-template-areas:
      "content"
      "graphic";
    justify-items: center;
    text-align: center;
    padding-inline: 0;
    /* text row -> graphic row: Figma has the subtitle's box bottom at
       y=201 and the laptop's own top (not the taller character+laptop
       group bounding it) at y=239 - a 38px gap. */
    row-gap: 38px;
  }

  .project-hero__text-block {
    /* Wider than Figma's 263px reference: that number worked for the old
       smaller title size, but the bigger mobile title (above) needs more
       room so a long single word like "Integrations" doesn't wrap
       mid-word. Capped against the viewport so it still never touches
       the section's side edges on the narrowest phones. */
    width: min(320px, calc(100vw - 48px));
    /* height: auto, not a fixed box - a fixed height here only ever
       existed to anchor the (now-removed) mobile character; forcing it
       risked clipping the subtitle's second line since real font
       metrics render a hair taller than Figma's own 162px box. */
    margin-inline: auto;
  }

  .project-hero__heading {
    /* Venus -> title: Figma's box gap here is 20px, not the shared
       clamp(14px, 2.34vw, 30px) (which bottoms out at 14px at this
       width - that's the "not correct" spacing). */
    gap: 20px;
  }

  /* The project name is the page's main heading - it needs to read as
     bigger than the section titles below it ("Overview", "Research"...),
     which bottom out at 32px (--fs-section-title's own clamp floor).
     --fs-display-title's floor (26px) undershoots that, so this page's
     own h1 gets a mobile floor of its own, same as the home page's
     hero title gets in hero.css. */
  .project-hero__title {
    font-size: 44px;
  }

  .project-hero__eyebrow,
  .project-hero__subtitle {
    text-align: center;
  }

  .project-hero__graphic,
  .project-hero--reversed .project-hero__graphic {
    /* !important: each project page sets its own inline width (a
       clamp tuned to that image's native resolution) directly on this
       element, which otherwise beats any external class rule
       regardless of media query - this is the one way to still force
       a shared mobile width across all of them. Matches the text
       block's own width exactly, so the image's edges line up with
       the text column above it instead of sitting narrower (or, with
       only a thin margin around it, making its drop-shadow read as a
       solid colored block rather than a shadow with room to fade). */
    width: min(320px, calc(100vw - 48px)) !important;
    /* Figma's own 37px/19px margins were asymmetric to leave room for
       the character bleeding off its right edge. With her removed
       there's no longer a reason for that lopsided offset, so this
       centers true (justify-self default handles it) instead of
       reproducing a skew that no longer serves a purpose. */
    justify-self: center;
    /* The mobile laptop asset's own ratio (319 x 195.7 in Figma) is
       visibly squatter than the desktop graphic's 1449/933 - reusing
       that stretched this taller than Figma's reference and threw off
       the gap below it. */
    aspect-ratio: 319 / 195.7;
  }

  /* The framed-screenshot hero graphic (see the desktop rule above)
     keeps its own real ratio on mobile too, instead of the laptop
     mobile asset's 319/195.7. */
  .project-hero--framed .project-hero__graphic {
    aspect-ratio: 2408 / 1320;
  }

  .project-hero__line-row {
    display: none;
  }

  /* Hidden on mobile: her bounding box can be placed at the exact spot
     Figma specifies (confirmed pixel-for-pixel against the reference),
     but our character artwork is a different pose - sitting cross-
     legged, mid-air - than the reference's character, who dangles her
     legs over an edge. Box position matching isn't enough to read as
     "sitting on" the laptop when the pose itself isn't built to rest on
     anything; it just looks like she's floating next to it. Omitting
     her avoids that, rather than chasing a fix no position value can
     actually deliver. */
  .project-hero__character--mobile {
    display: none;
  }

  /* Mobile has its own dedicated Figma reference (a 375px-wide frame),
     not just a scaled-down crop of the desktop one: all three circles
     plus both stars appear there, positioned with fixed px straight off
     that frame - same spot regardless of layout direction (mobile
     centers both --default and --reversed the same way). The stars
     aren't tied to the character here (she's hidden on mobile - see
     .project-hero__character--mobile above); in the reference they just
     sit near the title/top circle as free-floating sparkles. */
  .project-hero__doodles,
  .project-hero--reversed .project-hero__doodles {
    display: block;
  }

  /* Desktop anchors every piece by its center (translate(-50%,-50%));
     mobile's fixed-px values below were measured as plain top-left
     corners straight off the Figma frame, so transform is cleared. */
  .project-hero__blob--a,
  .project-hero--reversed .project-hero__blob--a,
  .project-hero__blob--b,
  .project-hero--reversed .project-hero__blob--b,
  .project-hero__blob--c,
  .project-hero--reversed .project-hero__blob--c,
  .project-hero__star--a,
  .project-hero--reversed .project-hero__star--a,
  .project-hero__star--b,
  .project-hero--reversed .project-hero__star--b {
    transform: none;
  }

  .project-hero__blob--a,
  .project-hero--reversed .project-hero__blob--a {
    left: 31px;
    top: -44px;
    width: 303px;
  }

  /* blob--b and both stars need a higher-specificity selector here than
     the other two: the desktop rules that split them further between
     --reversed and --reversed--framed (above) are 3 classes deep, which
     would otherwise outrank a plain ".project-hero--reversed .x" mobile
     override at 2 - ".project-hero__doodles" as a third qualifier just
     matches that specificity so the mobile value (later in the
     file) wins as intended. */
  .project-hero__blob--b,
  .project-hero--reversed .project-hero__doodles .project-hero__blob--b {
    left: 246px;
    top: 296px;
    width: 151px;
  }

  .project-hero__blob--c,
  .project-hero--reversed .project-hero__blob--c {
    left: 0;
    top: 466px;
    width: 104px;
  }

  /* Raised from the Figma reference's own 118px/93px: the reference's
     title sits lower in its frame than ours does on the no-eyebrow
     pages (Copilot Chat, AegisCore - a single "POLICIES"/"CHAT COPILOT"
     line starts right under the subtitle with no "Venus" line above
     it), so those two stars' boxes land on top of the title text there.
     65px/40px clears the title on every page (checked against the
     shortest, title-top case) while keeping the same ~25px gap between
     the two stars themselves. */
  .project-hero__star--a,
  .project-hero--reversed .project-hero__doodles .project-hero__star--a {
    left: 242px;
    top: 65px;
    width: 35px;
  }

  .project-hero__star--b,
  .project-hero--reversed .project-hero__doodles .project-hero__star--b {
    left: 280px;
    top: 40px;
    width: 20px;
  }
}
