/*
  FILE: csa-website.css
  PURPOSE: Styles specific to the CSA Website project page only, not
  reused by any other project (see project.css for the shared header/
  footer/nav patterns every project page uses, linked before this
  file). Covers the 3-stage identity check gate: its full-bleed navy
  background, dashed prompt cards, the "checking"/"denied" popup cards,
  and every button state.
*/

/* ---- Gate section: full-bleed navy background, same 100vw + negative
   margin technique already used by csa-game.css's .project-final-
   designs, so it breaks out of .project-page's max width regardless of
   viewport. ---- */
.csa-gate {
  width: 100vw;
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  background: var(--color-csa-mobile-bg);
}

/* The gate itself gets hidden (not removed) once the case study is
   revealed. .csa-gate__inner's own display:flex below would otherwise
   beat the browser's default [hidden]{display:none} rule (author
   styles always win over the UA stylesheet), so this override is
   needed. */
.csa-gate[hidden] {
  display: none;
}

/* Stays inside the normal 1200px max width (like every other section),
   1px blue side strokes plus the same soft grid pattern as CSA Mobile's
   Final designs section (csa-game.css's .project-final-designs__inner),
   reused at identical values (100px repeat unit, 20% opacity) so both
   CSA pages' dark sections match. */
.csa-gate__inner {
  max-width: 1200px;
  margin: 0 auto;
  box-sizing: border-box;
  padding: 40px 40px; /* .csa-gate__stage below now supplies most of the section's height */
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  border-left: 1px solid var(--color-csa-mobile-accent);
  border-right: 1px solid var(--color-csa-mobile-accent);
  font-family: var(--font-mono);
  background-image:
    repeating-linear-gradient(
      to right,
      rgba(15, 84, 248, 0.2) 0,
      rgba(15, 84, 248, 0.2) 1px,
      transparent 1px,
      transparent 100px
    ),
    repeating-linear-gradient(
      to bottom,
      rgba(15, 84, 248, 0.2) 0,
      rgba(15, 84, 248, 0.2) 1px,
      transparent 1px,
      transparent 100px
    );
}

/* Visually-hidden but still screen-reader-visible, standard clip
   technique. Used for #csa-gate-announcer, see index.html's comment on
   why the visible prompt itself isn't the live region. */
.csa-gate__sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* The "text and button" area: fixed 700px on desktop (100dvh, the full
   viewport, on mobile, see the media query below), vertically centres
   whichever [prompt, active panel] pair is currently showing. height
   (not max-height) on purpose: content that ever needs more room (long
   zoomed text, say) pushes this box taller instead of clipping. The
   skip link stays outside this box, it isn't part of "the text and
   button". */
.csa-gate__stage {
  box-sizing: border-box;
  width: 100%;
  height: 700px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 80px;
}

/* Only one panel visible at a time, toggled by csa-website.js adding/
   removing "is-active". Fades and pops in rather than just appearing,
   see the transition comment in index.html: this only happens once the
   prompt above has finished retyping. */
.csa-gate__panel {
  display: none;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 600px;
}

.csa-gate__panel.is-active {
  display: flex;
  animation: csa-gate-pop-in 0.25s ease;
}

@keyframes csa-gate-pop-in {
  from {
    opacity: 0;
    transform: scale(0.95);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Outgoing panel: added by csa-website.js at the same moment the
   prompt starts erasing its old text, so the old button/card visibly
   leaves as the old text disappears, instead of just vanishing once
   the new stage is ready. "forwards" holds the faded-out end state
   until csa-website.js removes this class right as it swaps which
   panel is active. */
.csa-gate__panel.is-exiting {
  animation: csa-gate-fade-out 0.25s ease forwards;
}

@keyframes csa-gate-fade-out {
  from {
    opacity: 1;
    transform: scale(1);
  }
  to {
    opacity: 0;
    transform: scale(0.85);
  }
}

@media (prefers-reduced-motion: reduce) {
  .csa-gate__panel.is-active,
  .csa-gate__panel.is-exiting {
    animation: none;
  }
}

/* Dashed prompt box, reusing the same visual language as csa-game.css's
   .project-final-designs__callout (dashed border, solid navy fill,
   rounded corners), as its own page-scoped class rather than editing
   the shared one. tabindex="-1" (set in the HTML) lets JS focus this
   after a stage change, so screen readers land on the new prompt
   instead of losing their place; outline removed only for that
   programmatic focus, real keyboard focus never lands here since it's
   not otherwise interactive. One persistent element shared across all
   3 stages now (see index.html), csa-website.js scrambles its text in
   and updates its data-stage attribute on every transition.

   height is set inline by lockPromptHeight() in csa-website.js, fixed
   once from the longest of the 3 prompts rather than left to grow/
   shrink with whichever stage is currently showing, per Lucrecia's
   request. display:flex + align-items:center here is what vertically
   centres a shorter prompt within that fixed height -- scrambleText()
   in the JS wraps every stage's characters in one single inner <span>
   specifically so this flex centring only ever positions that one
   child as a whole, the individual character spans inside it still
   wrap across multiple lines exactly like normal paragraph text,
   flex's own layout rules never apply to them directly. */
.csa-gate__prompt {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  width: 100%;
  max-width: 800px;
  margin: 0;
  padding: 24px 32px;
  border: 1px dashed var(--color-csa-mobile-accent);
  border-radius: 12px;
  background: var(--color-csa-mobile-bg); /* solid fill, 100% opacity, #010131 */
  font-size: var(--font-size-h2); /* same size on all 3 stages */
  line-height: 1.5;
  color: var(--color-csa-mobile-text);
}

/* The sole flex item inside .csa-gate__prompt while its characters are
   scrambling in (see scrambleText() in csa-website.js) -- block +
   full-width so its own text still wraps across multiple lines exactly
   like normal paragraph content would, .csa-gate__prompt's own
   align-items:center then only has to vertically centre this one
   full-width block as a whole, never touching the individual character
   spans' own layout. */
.csa-gate__prompt-inner {
  display: block;
  width: 100%;
}

.csa-gate__prompt:focus {
  outline: none;
}

/* Popup card (stages 2 and 3): csa-web-checkpoint-bckg.png as the
   background image (the flat navy fill is now just a fallback in case
   the image is slow/fails to load), same 1px side-only red stroke +
   red glow on both cards now (previously a different colour per state,
   superseded, see the removed --checking/--denied modifiers). */
.csa-gate__card {
  box-sizing: border-box;
  width: 100%;
  max-width: 420px;
  padding: 40px 32px;
  border-radius: 10px;
  background-color: #0B1B4D;
  background-image: url('../../assets/projects/csa-website/csa-web-checkpoint-bckg.png');
  background-size: cover;
  background-position: center;
  border-left: 1px solid #F53A44;
  border-right: 1px solid #F53A44;
  box-shadow: 0 0 10px #F53A44;
}

.csa-gate__card-eyebrow {
  margin: 0 0 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-weight: 700;
  font-size: var(--font-size-h2); /* matches .csa-gate__card-title, per the "same size" request */
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--color-csa-mobile-text);
}

.csa-gate__card-eyebrow--danger {
  color: var(--color-csa-web-red);
}

.csa-gate__card-title {
  margin: 0 0 16px;
  font-size: var(--font-size-h2);
  font-weight: 700;
  text-transform: uppercase;
  color: var(--color-csa-mobile-text);
}

.csa-gate__card-title--danger {
  color: var(--color-csa-web-red);
}

.csa-gate__card-question {
  margin: 0 0 24px;
  font-family: var(--font-body);
  font-size: var(--font-size-project-body);
  color: var(--color-csa-mobile-text);
}

.csa-gate__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
}

/* ---- Buttons: real <button> elements throughout, explicit hover/
   focus/active states on all of them. The reference press animation
   lives on a URL this environment can't reach, so this is a reasonable
   original build (colour shift + lift on hover, scale-down on press),
   not a pixel match, flag if it should be adjusted once compared
   live. ---- */

.csa-gate__button {
  border: none;
  cursor: pointer;
  font-family: var(--font-mono);
  transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease, background 0.15s ease;
}

.csa-gate__button:focus-visible {
  outline: 3px solid var(--color-csa-mobile-text);
  outline-offset: 3px;
}

/* Stage 1's button, built from Lucrecia's Figma spec: two concentric
   circles. .csa-gate__button-base is the decorative outer "base"
   (272px, dark red fill, 3px border, wide soft glow behind
   everything), just a positioning wrapper, not interactive. The real
   <button> is the inner 212px circle, centred inside it. */
.csa-gate__button-base {
  position: relative;
  width: 272px;
  height: 272px;
  border-radius: 50%;
  box-sizing: border-box;
  background: #500007;
  border: 3px solid #CE071D;
  box-shadow: 0 0 100px rgba(249, 22, 42, 0.51);
  display: flex;
  align-items: center;
  justify-content: center;
}

.csa-gate__button--start {
  box-sizing: border-box;
  width: 212px;
  height: 212px;
  padding: 0 20px;
  border-radius: 50%;
  background: #F9162A;
  border: 9px solid #CE071D;
  box-shadow: 0 0 9px rgba(0, 0, 0, 0.49);
  display: flex;
  align-items: center;
  justify-content: center;
}

.csa-gate__button-label {
  max-width: 150px;
  color: var(--color-csa-mobile-text);
  font-weight: 700;
  font-size: 32px;
  line-height: 1.2;
  text-transform: uppercase;
}

/* Hover: darker fill + a bigger, stronger drop shadow than the resting
   state's, so it reads clearly (not specified in the Figma spec, this
   particular treatment is a judgement call, flag if something different
   was wanted). Press state matches the spec: slightly smaller, fill
   switches to the darker red already used for the stroke. .is-pressed
   is the same look as :active, added by csa-website.js so the pressed
   state can be held and released on a timer (letting people actually
   see it) instead of only lasting as long as the mouse is physically
   down, which for a quick click is barely visible. */
.csa-gate__button--start:hover {
  background: #E01326;
  box-shadow: 0 0 22px rgba(0, 0, 0, 0.65);
}

.csa-gate__button--start:active,
.csa-gate__button--start.is-pressed {
  transform: scale(0.96);
  background: #CE071D;
}

/* Stages 2 and 3's rectangular pill CTAs. */
.csa-gate__button--accept,
.csa-gate__button--reject,
.csa-gate__button--retry {
  padding: 14px 28px;
  border-radius: 999px;
  font-weight: 700;
  font-size: var(--font-size-body);
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.csa-gate__button--accept {
  background: var(--color-csa-web-green);
  color: var(--color-csa-mobile-bg);
}

.csa-gate__button--reject {
  background: var(--color-csa-web-red);
  color: var(--color-csa-mobile-text);
}

.csa-gate__button--retry {
  background: transparent;
  border: 2px solid var(--color-csa-mobile-accent);
  color: var(--color-csa-mobile-text);
}

.csa-gate__button--accept:hover,
.csa-gate__button--reject:hover,
.csa-gate__button--retry:hover {
  filter: brightness(1.1);
  transform: translateY(-2px);
}

.csa-gate__button--accept:active,
.csa-gate__button--reject:active,
.csa-gate__button--retry:active,
.csa-gate__button--reject.is-pressed,
.csa-gate__button--retry.is-pressed {
  transform: scale(0.96);
  filter: brightness(0.95);
}

/* ---- Skip link: sits at the bottom of the gate on every stage, small
   and muted so it doesn't compete with the game itself, underline
   appears only on hover/focus. Muted colour still meets WCAG AA
   against the navy background (4.5:1+ for this size text). ---- */
.csa-gate__skip {
  margin-top: 40px;
  font-family: var(--font-body);
  font-size: var(--font-size-small);
  color: var(--color-csa-mobile-text-muted);
  text-decoration: none;
}

.csa-gate__skip:hover,
.csa-gate__skip:focus-visible {
  text-decoration: underline;
  color: var(--color-csa-mobile-text);
}

/* ---- Case study wrapper: no padding of its own, every section inside
   it (Final designs, Role, Collaborators, Similar projects) manages its
   own, same as every other project page. ---- */
.csa-gate__case-study {
  /* Explains the "blue line around the whole page" Lucrecia reported in
     Safari: revealCaseStudy() in csa-website.js calls .focus() on this
     element on purpose, so screen reader users land on the new content
     the moment the gate is passed, not the outdated diagnosis (100vw
     breakout math) tried first. Safari draws its native focus ring for
     ANY focused element by default, including one focused entirely by
     script, not just by tabbing to it -- Chrome is more conservative
     here and mostly reserves it for real keyboard interaction, which is
     why this never showed up there. Safe to switch off just the ring:
     screen readers move focus off the FOCUS EVENT firing, not off this
     visible outline, and this element is never meant to be tabbed to
     directly by a sighted keyboard user (only reached via .focus()
     right after the gate/skip-link), so there's no real keyboard user
     losing a focus indicator they'd otherwise rely on here. */
  outline: none;
}

/* ---- Final designs: full-bleed navy background + 1px blue side
   strokes + soft 100px blue grid, same technique as .csa-gate above
   (itself copied from csa-game.css's .project-final-designs__inner),
   duplicated here rather than shared since this section lives in a
   different part of the DOM. ---- */
.csa-final {
  width: 100vw;
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  background: var(--color-csa-mobile-bg);
}

.csa-final__inner {
  max-width: 1200px;
  margin: 0 auto;
  box-sizing: border-box;
  padding: 50px 40px;
  /* Bug fix: with padding-bottom zeroed out on desktop (see the
     override below) and no bottom border, the last divider's own 50px
     margin-bottom had nothing to stop it collapsing straight through
     this element AND .csa-final around it -- it was landing as a
     stray 50px gap of the page's light background between .csa-final
     and the outro section, instead of as dark space inside the
     section like every other divider's clearance. flow-root makes
     this a block formatting context, which contains that margin
     inside .csa-final__inner where it belongs. */
  display: flow-root;
  border-left: 1px solid var(--color-csa-mobile-accent);
  border-right: 1px solid var(--color-csa-mobile-accent);
  font-family: var(--font-mono);
  background-image:
    repeating-linear-gradient(
      to right,
      rgba(15, 84, 248, 0.2) 0,
      rgba(15, 84, 248, 0.2) 1px,
      transparent 1px,
      transparent 100px
    ),
    repeating-linear-gradient(
      to bottom,
      rgba(15, 84, 248, 0.2) 0,
      rgba(15, 84, 248, 0.2) 1px,
      transparent 1px,
      transparent 100px
    );
}

/* Per Lucrecia: the section should end flush with the last divider's
   own line, not leave a further stretch of empty navy (with its own
   trailing, lineless grid cell) below it. Reverted an earlier attempt
   at this that shifted the WHOLE background grid's phase to anchor a
   line to the bottom edge instead -- that re-aligned the last line
   correctly but silently shifted every other divider's line out of
   sync with the grid too, since dividers 1-6 each have their own
   margin-top hand-measured against the grid's original top-anchored
   position (see .csa-final__divider's own comment above). Zeroing just
   the LAST divider's margin-bottom instead leaves that grid untouched:
   the section's bottom edge now sits exactly at this divider's own
   line, satisfying the same request without moving anything else. */
.csa-final__inner > .csa-final__divider:last-child {
  margin-bottom: 0;
}

/* Plain block on mobile (wasn't asked to change). Desktop: 400px tall
   normally, heading vertically centred inside it. min-height (not a
   hard height) so that if the heading ever wraps to more lines than
   usual at a narrow desktop width, the box grows to fit instead of
   the text overflowing its bounds. */
.csa-final__intro {
  display: flex;
  align-items: center;
  justify-content: center;
}

@media (min-width: 769px) {
  .csa-final__intro {
    min-height: 400px; /* 4 rows of the 100px background grid */
    box-sizing: border-box;
  }
}

.csa-final__heading {
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
  font-size: var(--font-size-h2);
  font-weight: 700;
  text-transform: uppercase;
  color: var(--color-csa-mobile-text);
}

/* Desktop: Open Sans (matches the rest of the Final Designs text now,
   see the row callouts and callout--plain/--overlay below) and a
   fluid size instead of the fixed --font-size-h2, same clamp()
   technique as .csa-final__callout--overlay (2vw scaling, floor and
   ceiling), scaled up proportionally for this element's larger base
   size: floor 20px (h2's 30px * the same ~0.67 floor ratio used
   there), ceiling 30px (h2's own size) reached at the 1200px
   .csa-final__inner max-width via 2.5vw. Mobile untouched, still the
   plain fixed --font-size-h2 above. */
@media (min-width: 769px) {
  .csa-final__heading {
    font-family: var(--font-body);
    font-size: clamp(20px, 2.5vw, 30px);
  }
}

/* Solid rule, same placement rule as csa-game.css's own dividers: at
   least 50px clear above/below, snapped to the next 100px background
   grid line down from whatever's directly above it. margin-bottom is
   the fixed "50px clear after" half, shared by every divider. The
   margin-top values below are the ORIGINAL mobile-measured ones
   (mobile wasn't asked to change this round); desktop overrides them
   with its own freshly-measured values further down, since the
   desktop layout changed enough that almost none of them still line
   up with the mobile numbers. */
.csa-final__divider {
  width: 100%;
  margin-bottom: 50px;
  border: none;
  border-top: 1px solid var(--color-csa-mobile-accent);
}

/* 38px, not the eyeballed 80px this originally had: measured against
   the intro heading's real height, the background grid's nearest line
   above the divider's old position sits at 200px from
   .csa-final__inner's own top, which this margin-top lands on exactly
   (introBottom 162 + 38 = 200) -- Lucrecia flagged the mismatch with a
   screenshot. */
.csa-final__divider--1 { margin-top: 38px; }
.csa-final__divider--2 { margin-top: 51px; }
/* 0, same reasoning as desktop's own divider--3 (see the desktop
   override below): section 3's padding-bottom is what supplies this
   divider's clearance now (a solid fill, not the plain grid), so it
   needs no margin of its own on top of that. This value now applies
   at every width -- both the mobile and desktop overrides below also
   land on 0, kept explicit in both places rather than removed, so
   each breakpoint's reasoning stays documented where a reader would
   look for it. */
.csa-final__divider--3 { margin-top: 0; }
.csa-final__divider--4 { margin-top: 51px; }
.csa-final__divider--5 { margin-top: 51px; }
.csa-final__divider--6 { margin-top: 51px; }
/* Mobile: 0, not a positive margin -- .csa-final__feature--final's own
   height now supplies the clearance above this divider (see that
   rule's comment), same "container supplies the gap" pattern used on
   desktop elsewhere in this file. Was a flat 149px before, which left
   a lot of empty space below the image (Lucrecia's report) once the
   feature's own height stopped matching its content exactly. Desktop
   keeps its own separate override below, untouched. */
.csa-final__divider--7 { margin-top: 0; }

/* Desktop-specific positions, computed the same way as the mobile
   ones above (render + measure + snap to the next grid line). --2,
   --6 and --7 each sit one grid line higher than the plain "next
   available line" rule would otherwise give, per Lucrecia's explicit
   calls -- recomputed fresh against the current render each round
   rather than stacked as a running total, since content height keeps
   shifting round to round (font-size cuts, tightened sections) and a
   historical pixel offset from a much taller page stops meaning
   anything once the page is shorter. --3 is 0: the section above it
   (global network) now has its own padding-bottom:50px feeding the
   solid fill all the way up to this divider, so the clearance is
   already built into that padding, this divider needs no margin of
   its own on top of it. --2's margin-bottom is 0 for the mirror-image
   reason: the section AFTER it (global network) has its own
   padding-top:50px now, so the clearance from --2 down to that
   section's title is already solid fill from the padding, not this
   divider's own margin (previously it still had margin-bottom:50px
   here, which put that 50px on the OUTSIDE of the fill and left the
   grid pattern visible in that gap, even after the fill's own
   internal padding got fixed). */
@media (min-width: 769px) {
  .csa-final__divider--1 { margin-top: 50px; }
  .csa-final__divider--2 { margin-top: 49px; margin-bottom: 0; }
  .csa-final__divider--3 { margin-top: 0; }
  .csa-final__divider--4 { margin-top: 111px; }
  .csa-final__divider--5 { margin-top: 64px; }
  .csa-final__divider--6 { margin-top: 49px; }
  .csa-final__divider--7 { margin-top: 49px; }
}

/* Desktop: on the standard 1200px inner column, the divider should
   span the full width between the two blue side strokes -- already
   true by default (.csa-final__divider is width:100% of its 1120px
   content column, but .csa-final__inner itself has 40px side padding,
   so "full width" here means cancelling that padding for the divider
   specifically, same negative-margin technique used for the bleed
   sections below). */
@media (min-width: 769px) {
  .csa-final__divider {
    width: calc(100% + 80px);
    margin-left: -40px;
  }
}

/* Desktop: divider--7 is the last thing inside .csa-final__inner now,
   its own 50px margin-bottom is the only clearance before the navy
   background ends -- .csa-final__inner's own bottom padding (50px,
   shared with the top/sides) would otherwise add extra navy space
   after it, so it's zeroed here, desktop only. */
@media (min-width: 769px) {
  .csa-final__inner {
    padding-bottom: 0;
  }
}

.csa-final__feature {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
}

/* Dashed callout, same visual language as .csa-gate__prompt (dashed
   blue border, navy fill, rounded corners). */
.csa-final__callout {
  box-sizing: border-box;
  width: 100%;
  max-width: 800px;
  margin: 0;
  padding: 24px 32px;
  border: 1px dashed var(--color-csa-mobile-accent);
  border-radius: 12px;
  background: var(--color-csa-mobile-bg);
  font-size: var(--font-size-project-body);
  line-height: 1.5;
  color: var(--color-csa-mobile-text);
}

/* Desktop only: text left, image right (DOM order already puts the
   callout first), row-reverse not needed. The callout's own 30px
   margin-top pushes it down from the row's shared top edge, so it
   sits 30px below the image's own top, per the brief; flex:1 lets it
   fill whatever space the image doesn't use. Open Sans per Lucrecia's
   request (the page's body font token, see tokens.css), overriding
   the monospace font .csa-final__inner sets for everything else. */
@media (min-width: 769px) {
  .csa-final__feature--row {
    flex-direction: row;
    align-items: flex-start;
    gap: 30px;
  }

  .csa-final__feature--row .csa-final__callout {
    flex: 1 1 auto;
    min-width: 0;
    margin-top: 30px;
    /* Same fluid clamp() as .csa-final__callout--overlay, per
       Lucrecia's request to use that same resize behaviour across
       the rest of the Final Designs text, not just section 4. */
    font-size: clamp(16px, 2vw, 24px);
    font-family: var(--font-body);
  }

  /* flex-shrink:0 keeps the image at its intended max-height:600
     size whenever there's room (this had briefly regressed to
     max-width:50%, which shrank it even on wide viewports where
     there was plenty of space -- Lucrecia caught this). The max-width
     here is a safety cap, not a proactive resize: at the full 1120px
     row width it's larger than the image's natural size so it does
     nothing, it only kicks in once the row gets narrow enough that
     the image alone would otherwise leave no room for the text
     (reserves at least 250px for the callout, preventing the overflow
     bug from two rounds ago without shrinking the image needlessly). */
  .csa-final__feature--row .csa-final__image {
    flex-shrink: 0;
    max-width: calc(100% - 250px);
    margin: 0;
  }
}

/* Desktop only: full-bleed width, solid background (the grid pattern
   doesn't show through here). Both padding-top and padding-bottom are
   what the solid fill stretches to cover: padding-top pairs with
   divider--2's margin-bottom:0 (see above) so the fill reaches all
   the way UP to that divider, and padding-bottom pairs with
   divider--3's margin-top:0 so it reaches all the way DOWN to that
   one too -- the section is solid fill from divider to divider, no
   grid pattern visible anywhere in between (an earlier attempt at
   this removed padding-top entirely instead, which did make the
   section shorter as asked, but left the OUTSIDE gap above the box,
   governed by --2's own margin, still showing the grid -- Lucrecia
   caught this). The callout and gif themselves only care about this
   padding for their own spacing (callout inset via its own
   max-width:800px + auto margins, not container padding; gif reaches
   the true bled edges left/right, no side padding on this container
   at all). */
@media (min-width: 769px) {
  .csa-final__feature--bleed600 {
    width: calc(100% + 80px);
    margin-left: -40px;
    margin-right: -40px;
    box-sizing: border-box;
    padding-top: 50px;
    padding-bottom: 50px;
    background: #02052B;
  }
}

/* Desktop only: no dashed box, plain centred text. Open Sans and the
   same fluid clamp() sizing as the rest of the Final Designs text now
   (see .csa-final__heading's comment for how the floor/ceiling here
   were derived from --font-size-h2's 30px). */
@media (min-width: 769px) {
  .csa-final__callout--plain {
    border: none;
    background: none;
    padding: 0;
    text-align: center;
    font-family: var(--font-body);
    font-size: clamp(20px, 2.5vw, 30px);
  }
}

.csa-final__highlight {
  text-transform: uppercase;
  color: #D90B25;
  background: #000000;
  padding: 0 6px;
}

/* Desktop only: image bleeds full width/no padding, callout is
   absolutely positioned on top of it. */
@media (min-width: 769px) {
  .csa-final__feature--overlay {
    position: relative;
    width: calc(100% + 80px);
    margin-left: -40px;
    margin-right: -40px;
    display: block;
  }

  /* right:50% (not left:40px) so the box's own RIGHT edge sits at the
     horizontal centre of the page, per Lucrecia's request -- moved,
     not resized, width/max-width untouched. This container is bled
     symmetrically (40px wider on each side than .csa-final__inner), so
     its own 50% midpoint lines up with .csa-final__inner's midpoint
     too. */
  .csa-final__callout--overlay {
    position: absolute;
    top: 40px;
    right: 50%;
    z-index: 1;
    width: auto;
    /* calc(50% - 40px) is the width that makes the box's LEFT edge
       land exactly at the section's normal 40px inset, given its
       RIGHT edge is pinned to 50%. min() with 500px caps it there at
       wide viewports (so it doesn't grow past its original intended
       size) while still shrinking below 500px at narrower ones,
       always respecting that 40px left padding by construction
       instead of the previous 55%-based figure, which didn't account
       for the 40px inset and let the box's left edge drift past it
       (even into negative/overflowing territory) as the window
       narrowed -- Lucrecia caught this. */
    max-width: min(500px, calc(50% - 40px));
    /* Shrinks gradually with the viewport (2vw), floored at 16px and
       capped at 24px, so the text stays comfortable as the box above
       narrows instead of overflowing or wrapping awkwardly. */
    font-size: clamp(16px, 2vw, 24px);
    font-family: var(--font-body);
  }
}

/* Desktop only: the whole INTEL composite as one full-width, unmasked
   image (transparent PNG, height simply follows its own aspect
   ratio). Shown only on desktop, see .csa-final__desktop-only /
   .csa-final__mobile-only below for the 3-crop mobile equivalent. */
@media (min-width: 769px) {
  .csa-final__feature--full {
    width: calc(100% + 80px);
    margin-left: -40px;
    margin-right: -40px;
    display: block;
  }
}

@media (min-width: 769px) {
  .csa-final__desktop-only {
    display: block;
  }

  .csa-final__mobile-only {
    display: none;
  }
}

@media (max-width: 768px) {
  .csa-final__desktop-only {
    display: none;
  }
}

/* Capped by height first (keeps very tall screenshots, e.g. the Hedi
   chat screen, from towering over everything else), width: auto keeps
   its own aspect ratio, max-width: 100% is the safety net for wide
   images (e.g. the gif) so that constraint takes over instead once
   height stops being the limiting side. */
.csa-final__image {
  display: block;
  height: auto;
  max-height: 600px;
  width: auto;
  max-width: 100%;
  margin: 0 auto;
  border-radius: var(--radius-image);
}

/* Used within the bleed/overlay/full desktop treatments above: image
   fills its container's full width, no height cap, nothing masked.
   Comes AFTER .csa-final__image on purpose (equal specificity, later
   rule wins) so it actually overrides the height cap above rather
   than losing to it. */
.csa-final__image--bleed {
  width: 100%;
  max-width: none;
  height: auto;
  max-height: none;
  margin: 0;
  border-radius: 0;
}

/* Needed wherever a feature uses <picture> for a mobile crop (see
   index.html), same fix used elsewhere on the site (e.g. mateset.css):
   without this, the browser's default picture/source layout breaks
   .csa-final__feature's flex centering. */
.csa-final__feature picture {
  display: contents;
}

.csa-final__feature picture source {
  display: none;
}

/* Outro: lives in its own section OUTSIDE .csa-final now (back on the
   page's normal light background), fixed 340px tall on mobile
   (unchanged, wasn't asked to move this round), text capped at 900px
   and centred, H2 typography (matches .project-copy__title in
   project.css: same font, size, weight, colour). */
.csa-final-outro {
  height: 340px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Desktop: 300px tall instead. min-height (not a hard height) so that
   if the outro text ever wraps to more lines than usual at a narrow
   desktop width, the box grows to fit instead of the text overflowing
   its bounds. */
@media (min-width: 769px) {
  .csa-final-outro {
    height: auto;
    min-height: 300px;
  }
}

.csa-final-outro__text {
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
  font-family: var(--font-heading);
  font-size: var(--font-size-h2);
  font-weight: var(--weight-medium);
  /* Explicit line-height instead of the default "normal": "normal"
     derives its spacing from the loaded font's own ascent/descent
     metrics, which differ per font/browser and can make a perfectly
     flex-centred block look off-centre (more space above the text
     than below, or vice versa) purely from where the font places its
     own leading -- Lucrecia measured this asymmetry in her browser
     even though .csa-final-outro's flex centring itself is correct
     (confirmed again: the line box itself measures dead centre, 108px
     above and below, in Chromium testing here). A fixed value removes
     most of that font-dependent variable, but line-height still
     leaves room ABOVE the cap-height and BELOW the baseline for
     descenders, and browsers don't distribute that room identically,
     which is what's still showing up specifically in Safari. */
  line-height: 1.4;
  /* Trims that remaining leading down to the font's own cap-height/
     baseline instead of its full ascent/descent box, which is exactly
     what's inconsistent across browsers -- should remove the last of
     the asymmetry where it's supported. Still a very new CSS property
     (shipped late 2024/2025), so this is a progressive enhancement:
     harmless no-op in anything that doesn't recognise it yet, falls
     back to the line-height-based centring above. Couldn't verify
     this directly against Safari myself (no Safari available in this
     environment), please check there once this is live and flag if
     it's still off. */
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
  color: var(--color-text-dark);
}

/* Divider right after the outro, closing it off before Role starts.
   Sits on the light background outside the blue Final Designs section,
   so it uses the site's normal dark text colour, not the blue accent
   colour used for every divider inside .csa-final. Simple, fixed
   placement only, none of the grid-snap logic used above applies here.
   Shown at every width now (was desktop-only at first, Lucrecia asked
   for it on mobile too) -- width/spacing differ per breakpoint below. */
.csa-final-outro__divider {
  display: block;
  border: none;
  border-top: 1px solid var(--color-text-dark);
}

@media (min-width: 769px) {
  .csa-final-outro__divider {
    max-width: 1200px;
    margin: 0 auto;
  }
}

/* Mobile: full width (no max-width needed, .project-page is already
   narrower than the 1200px cap at these sizes), 40px clear above and
   below so it doesn't crowd the outro text or Role section right next
   to it. */
@media (max-width: 768px) {
  .csa-final-outro__divider {
    margin: 40px 0;
  }
}

@media (max-width: 768px) {
  .csa-gate__inner {
    padding: 20px 20px; /* .csa-gate__stage fills the viewport itself below */
  }

  /* Per Lucrecia's follow-up: desktop's fixed 700px doesn't apply here,
     the stage instead fills the viewport so everything is visible on
     one screen without scrolling. 100vh first as a fallback for
     browsers without dvh support, 100dvh after to override it where
     supported (dvh accounts for mobile browser toolbars showing/
     hiding, so the box isn't taller than what's actually visible). */
  .csa-gate__stage {
    height: 100vh;
    height: 100dvh;
  }

  .csa-gate__prompt {
    padding: 20px 24px;
  }

  /* Scaled down from the desktop sizes (272px base / 212px button),
     same ratio between the two, not specified in the Figma spec (only
     the desktop numbers were given), flag if different mobile sizing
     was wanted. */
  .csa-gate__button-base {
    width: 210px;
    height: 210px;
  }

  .csa-gate__button--start {
    width: 164px;
    height: 164px;
    border-width: 7px;
  }

  .csa-gate__button-label {
    font-size: 22px;
    max-width: 110px;
  }

  .csa-gate__card {
    padding: 30px 20px;
  }

  .csa-gate__actions {
    flex-direction: column;
    width: 100%;
  }

  .csa-gate__button--accept,
  .csa-gate__button--reject {
    width: 100%;
  }

  .csa-final__inner {
    padding: 50px 20px;
  }

  /* Zeroed separately from the padding shorthand above (same technique
     as desktop's own .csa-final__inner override): the navy background
     should end right after the last divider, not trail an extra 50px
     of empty navy past it. */
  .csa-final__inner {
    padding-bottom: 0;
  }

  .csa-final__callout {
    padding: 20px 24px;
    /* Per Lucrecia: every text container centred on mobile now,
       matching the plain heading above (already centred) instead of
       the default left alignment. */
    text-align: center;
    font-family: var(--font-body);
  }

  .csa-final__image {
    max-height: none; /* height-capping matters less once width is already the constraint at this size */
  }

  .csa-final__heading {
    font-size: 24px;
  }

  /* Extra clearance above the heading, mobile only: landing here comes
     from revealCaseStudy() in csa-website.js scrolling this section's
     top flush with the viewport top, right where the fixed floating
     nav sits (89px tall including its own top offset, see float-nav.css)
     -- the intro's own 50px top padding on .csa-final__inner wasn't
     enough clearance, so the nav was covering the first bit of the
     heading text. Bumped again per Lucrecia's follow-up request for
     more breathing room (was 50px), and matched with an equal
     padding-bottom so the heading sits centred in its own box instead
     of just being pushed down (was 0 bottom padding here, relying on
     divider--1's own margin-top for space after). */
  .csa-final__intro {
    padding: 70px 0;
  }

  /* Dividers reach the true edges of the viewport (not just
     .csa-final__inner's own padded content area), same bleed
     technique as the desktop dividers: cancel the 20px side padding
     with an equal negative margin. .csa-final__inner already spans
     the full viewport width at mobile sizes (max-width:1200px never
     kicks in below that), so this reaches the screen edges directly. */
  .csa-final__divider {
    width: calc(100% + 40px);
    margin-left: -20px;
  }

  /* Section 3 (global network): same solid fill as desktop, no side
     padding on the container itself so the gif can bleed to the true
     edges -- the callout stays inset via its own padding (above), same
     pattern as desktop's max-width:800px + auto-margins equivalent. No
     padding-bottom restored: removing it last round did shrink the
     section as asked, but it also meant the gap between the gif and
     divider--3 fell OUTSIDE this box, back on the plain grid
     background -- same class of bug as the top gap below, just on the
     other end (Lucrecia caught this too). padding-bottom pairs with
     divider--3's own margin-top:0 (see its rule) the same way
     padding-top pairs with divider--2's margin-bottom:0, so the fill
     now runs solid all the way from divider--2 to divider--3, no gap
     left uncovered on either side -- matches desktop's own version of
     this section exactly now. */
  .csa-final__feature--bleed600 {
    width: calc(100% + 40px);
    margin-left: -20px;
    margin-right: -20px;
    box-sizing: border-box;
    padding-top: 50px;
    padding-bottom: 50px;
    background: #02052B;
  }

  .csa-final__callout--plain {
    border: none;
    background: none;
  }

  /* Mirrors desktop's own fix for the same bug: divider--2's standard
     50px margin-bottom put that clearance OUTSIDE this section's own
     box, on the plain grid background, so the grid pattern was still
     visible right above the title even though the box's own internal
     padding-top was already solid fill. Zeroing it here means the
     fill (which starts as soon as the box begins) now reaches all the
     way up to divider--2 itself, no gap left uncovered. divider--3
     gets the equivalent fix (margin-top:0) up with the rest of the
     mobile divider values above, for the gap on the other side of
     this section. */
  .csa-final__divider--2 {
    margin-bottom: 0;
  }

  /* Masks the gif to a fixed 240px band (object-fit:cover crops
     rather than squishing it) instead of letting it run its full
     natural height, which was making this section very tall on
     mobile. */
  .csa-final__feature--bleed600 .csa-final__image {
    height: 240px;
    max-height: 240px;
    object-fit: cover;
  }

  /* Section 4 (speed test): only the image bleeds to the viewport
     edges, the callout keeps the section's normal 20px side padding
     (via its own width:100% of the still-unbled feature container) --
     unlike section 3, the whole feature isn't bled here, just this one
     child, so the text doesn't inherit the same edge-to-edge width. */
  .csa-final__feature--overlay .csa-final__image {
    width: calc(100% + 40px);
    max-width: none;
    margin-left: -20px;
    margin-right: -20px;
  }

  /* Section 9 (final block, mobile-6 crop): the previous round moved
     divider--7 up one grid line to close up excess empty space, but
     that overshot -- centred in a 427px slot, the ~430px image left
     only a couple of negative/near-zero px on each side, no real
     clearance at all. Lucrecia asked for a minimum 50px below the
     image, kept centred, which needs slot height >= image height +
     100px (50 both sides). The plain next-available-line target
     (5000, giving ~97px split two ways, just under 50 each) still
     wasn't quite enough, so this now uses the next grid line up after
     that (5100) instead -- exactly "an entire extra grid row" as
     Lucrecia predicted this might take. 627px is that target minus
     .csa-final__feature--final's own top position (4473), landing
     divider--7 (margin-top:0, see above) precisely at 5100. */
  .csa-final__feature--final {
    height: 627px;
    box-sizing: border-box;
    justify-content: center;
  }

  /* Outro: side padding so the text doesn't run to the true screen
     edges (it previously had none, relying only on its own
     max-width:900px, which never actually constrains anything at
     mobile widths), and the same 24px size as the Final Designs intro
     heading above, per Lucrecia's request. */
  .csa-final-outro {
    padding: 0 20px;
    box-sizing: border-box;
  }

  .csa-final-outro__text {
    font-size: 24px;
  }
}

/* ---- Role image: 5px corner radius, per Lucrecia's request ---- */
.project-role__image {
  border-radius: 5px;
}
