/* ===========================================================================
   Wild — Craft, Engineered.
   Implemented from Figma (fileKey Ef7ULPmEOmffnS1gzSvvY1, node 31020:2834).
   Vanilla CSS, no build step. Assembled from per-section builds under
   .figma-build/ (kept out of the repo; see git history if needed).
   =========================================================================== */

:root{
  --nav-h: 56px;
}
*,*::before,*::after{box-sizing:border-box;}
html{-webkit-text-size-adjust:100%; scroll-behavior:smooth;}
body{
  margin:0;
  color:#0a0a0a;
  font-family:'Sneak','Helvetica Neue',Arial,sans-serif;
  padding-top: var(--nav-h);
  /* Site-wide: never leave a single word dangling alone on the last
     line of a wrapped block — the browser's own line-breaking
     algorithm rebalances earlier line breaks so the last line always
     picks up at least one more word from the line above it, but only
     when the paragraph actually has enough words to redistribute
     (a genuinely single trailing word, or one long unbreakable word,
     stays as-is — there's nothing to rebalance against). Inherited,
     so this covers every block of text on the site by default rather
     than needing a class on each one; a component can still opt back
     into plain wrapping with text-wrap: wrap if a specific spot needs
     it. Unsupported browsers just fall back to normal wrapping. */
  text-wrap: pretty;
  /* faint graph-paper grid, visible through every section below since
     their own backgrounds are transparent */
  background-color:#fff;
  background-image:
    linear-gradient(to right, rgba(10,10,10,0.06) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(10,10,10,0.06) 1px, transparent 1px);
  background-size: 32px 32px;
}
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
}
/* Anchor targets for .site-nav's links — keeps a jump (native hash or
   the brand's own click handlers elsewhere) from landing exactly
   under the fixed bar. */
#practices, #approach, #about, #contact,
#consulting, #engineering, #design, #growth{
  scroll-margin-top: var(--nav-h);
}
img{max-width:100%;}
a{color:inherit;}

/* Visually hidden but still announced — used to keep a heading's real
   trailing period in the accessible text while .heading-dot below
   shows a pixel-square stand-in for it visually. */
.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;
}

/* A section heading's closing period, drawn as a small pixel square
   instead of a dot — sized in em so it scales with whatever heading
   it sits in. */
.heading-dot{
  display: inline-block;
  width: 0.26em;
  height: 0.26em;
  margin-left: 0.16em;
  background: #1264f5;
  vertical-align: 0.02em;
}
/* Native cursor stays visible everywhere — the reference site
   (craft.wild.as) never hides or replaces it. What reads as an
   "animated cursor" there is a fixed full-page canvas sitting behind
   all content that deposits fading heat wherever the pointer goes,
   plus an idle wander animation; see assets/js/cursor-field.js (site-
   wide) and assets/js/squares.js (the header's own world map, which
   layers a second, scoped heat effect on top). */

/* Site-wide reactive pixel field (assets/js/cursor-field.js). Fixed to
   the viewport and negative z-index so it paints behind every section
   without needing to touch #main's own positioning — sections here
   are already transparent (see the body background above), so the
   field shows through everywhere, exactly like the reference. */
#cursorField{
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
  display: block;
}
@media (prefers-reduced-motion: reduce){
  #cursorField{ display: none; }
}
/* Any footer-game instance reaching 'play' adds this to <body> (see
   footer-game.js's startGame()/endGame()) — the reactive trail/idle
   Snake would otherwise drift across the game board itself while
   you're trying to actually play, so it's hidden for the duration. */
body.fg-playing #cursorField{ display: none; }

/* ==========================================================================
   Site nav — layout copied from mistral.ai's own fixed header (inspected
   live in a browser, since it's client-rendered): a full-bleed bar,
   divided into bordered cells, pinned through the whole page with no
   hide-on-scroll. Colour/type use this site's own brand rather than
   their dark navy — see assets/js/site-nav.js for the mobile toggle.
   ========================================================================== */
.site-nav{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: var(--nav-h);
  z-index: 1000;
  background: #fff;
  border-bottom: 1px solid rgba(10, 10, 10, 0.12);
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
}
.site-nav__inner{
  display: flex;
  align-items: stretch;
  height: 100%;
}
.site-nav__brand{
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  padding: 0 22px;
  border-right: 1px solid rgba(10, 10, 10, 0.12);
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: #0a0a0a;
  text-decoration: none;
  white-space: nowrap;
}
/* The "Squares Part" mark — two overlapping squares with a fixed
   third-tone intersection; the same 3-tier blue already drawn by
   squares.js/cursor-field.js's own 5-tier ladder. Hovering the brand
   link parts the two outer squares around the shared core, same
   interaction picked out of the logo-concepts round; pressing it
   dips slightly, same convention every button on the site already
   uses. */
.site-nav__mark{
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  overflow: visible;
  transition: transform 0.15s ease;
}
.site-nav__mark .m-a{ fill: #0d3fc0; transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1); transform-box: fill-box; transform-origin: top left; }
.site-nav__mark .m-b{ fill: #1264f5; transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1); transform-box: fill-box; transform-origin: bottom right; }
.site-nav__mark .m-join{ fill: #cfe0fb; }
.site-nav__brand:hover .site-nav__mark .m-a{ transform: translate(-3px, -3px); }
.site-nav__brand:hover .site-nav__mark .m-b{ transform: translate(3px, 3px); }
.site-nav__brand:active .site-nav__mark{ transform: scale(0.9); }
@media (prefers-reduced-motion: reduce){
  .site-nav__mark, .site-nav__mark .m-a, .site-nav__mark .m-b{
    transition: none !important;
    transform: none !important;
  }
}
.site-nav__links{
  display: flex;
  align-items: center;
  gap: 32px;
  margin: 0;
  padding: 0 28px;
  list-style: none;
}
.site-nav__links a{
  display: inline-flex;
  align-items: center;
  font-size: 15px;
  font-weight: 400;
  color: #5a5a5a;
  text-decoration: none;
  transition: color 0.15s ease;
}
.site-nav__links a:hover{
  color: #0a0a0a;
}
.site-nav__contact{
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: auto;
  padding: 0 28px;
  border-left: 1px solid rgba(10, 10, 10, 0.12);
  background: #1264f5;
  font-size: 15px;
  font-weight: 500;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.3s ease;
}
.site-nav__contact:hover{
  background: #0a0a0a;
}
.site-nav__toggle{
  display: none;
  position: relative;
  align-items: center;
  justify-content: center;
  width: var(--nav-h);
  flex-shrink: 0;
  margin-left: auto;
  border: 0;
  border-left: 1px solid rgba(10, 10, 10, 0.12);
  background: none;
  padding: 0;
  cursor: pointer;
}
/* Same pixelarticons pack as every other icon on the site — this used
   to be two plain CSS bars rotating into an X, which worked but broke
   the site-wide "icons only come from the pixel pack" rule. Both
   icons sit stacked in the same spot; toggling just crossfades +
   scales between them instead of morphing lines. */
.site-nav__toggle-icon{
  position: absolute;
  width: 20px;
  height: 20px;
  color: #0a0a0a;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.site-nav__toggle-icon--close{
  opacity: 0;
  transform: scale(0.5) rotate(-45deg);
}
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-icon--menu{
  opacity: 0;
  transform: scale(0.5) rotate(45deg);
}
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-icon--close{
  opacity: 1;
  transform: scale(1) rotate(0deg);
}
.site-nav__mobile{
  display: none;
  flex-direction: column;
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  background: #fff;
  border-bottom: 1px solid rgba(10, 10, 10, 0.12);
}
.site-nav__mobile.is-open{
  display: flex;
}
.site-nav__mobile a{
  padding: 16px 22px;
  border-top: 1px solid rgba(10, 10, 10, 0.12);
  font-size: 16px;
  color: #0a0a0a;
  text-decoration: none;
}
a.site-nav__mobile-contact{
  background: #1264f5;
  color: #fff;
  font-weight: 500;
}

@media (max-width: 720px){
  .site-nav__links,
  .site-nav__contact{
    display: none;
  }
  .site-nav__toggle{
    display: flex;
  }
}

/* Reveal-on-scroll (assets/js/reveal.js) — opacity only, no movement,
   matching the reference (fixaplan.com). */
.reveal {
  opacity: 0;
  transition: opacity 0.7s ease;
}
.reveal.is-visible {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .reveal {
    transition: none;
    opacity: 1;
  }
}

/* ==========================================================================
   Pixel-notched shape — reusable "stepped corner" silhouette (sampled from
   reference screenshots of a badge and a button) applied to every button
   and number badge on the page, in place of plain rounded rectangles.
   --notch controls the step size in px; 3 steps are cut from each corner.
   ========================================================================== */

.pixel-notched {
  --notch: 6px;
  clip-path: polygon(
    calc(var(--notch) * 3) 0,
    calc(100% - var(--notch) * 3) 0,
    calc(100% - var(--notch) * 3) var(--notch),
    calc(100% - var(--notch) * 2) var(--notch),
    calc(100% - var(--notch) * 2) calc(var(--notch) * 2),
    calc(100% - var(--notch)) calc(var(--notch) * 2),
    calc(100% - var(--notch)) calc(var(--notch) * 3),
    100% calc(var(--notch) * 3),
    100% calc(100% - var(--notch) * 3),
    calc(100% - var(--notch)) calc(100% - var(--notch) * 3),
    calc(100% - var(--notch)) calc(100% - var(--notch) * 2),
    calc(100% - var(--notch) * 2) calc(100% - var(--notch) * 2),
    calc(100% - var(--notch) * 2) calc(100% - var(--notch)),
    calc(100% - var(--notch) * 3) calc(100% - var(--notch)),
    calc(100% - var(--notch) * 3) 100%,
    calc(var(--notch) * 3) 100%,
    calc(var(--notch) * 3) calc(100% - var(--notch)),
    calc(var(--notch) * 2) calc(100% - var(--notch)),
    calc(var(--notch) * 2) calc(100% - var(--notch) * 2),
    var(--notch) calc(100% - var(--notch) * 2),
    var(--notch) calc(100% - var(--notch) * 3),
    0 calc(100% - var(--notch) * 3),
    0 calc(var(--notch) * 3),
    var(--notch) calc(var(--notch) * 3),
    var(--notch) calc(var(--notch) * 2),
    calc(var(--notch) * 2) calc(var(--notch) * 2),
    calc(var(--notch) * 2) var(--notch),
    calc(var(--notch) * 3) var(--notch)
  );
}

.pixel-notched--sm { --notch: 2px; }
.pixel-notched--md { --notch: 4px; }

/* ==========================================================================
   01-header-hero
   Figma: fileKey Ef7ULPmEOmffnS1gzSvvY1
   Node 31020:2840 -> .hh-header (top band / hero heading)
   Node 31020:3801 -> .hh-strip  (clipped teaser-text strip below hero)
   Font seen in Figma: "Sneak" (Regular) - not a system/Google font, no file
   was exported by Figma, so a sans-serif fallback stack is used. See notes.md.
   ========================================================================== */

.hh-header,
.hh-strip {
  box-sizing: border-box;
}

.hh-header *,
.hh-strip * {
  box-sizing: border-box;
}

/* ---- header / hero band -------------------------------------------------- */

.hh-header {
  width: 100%;
  background: transparent;
}

.hh-header__band {
  width: 100%;
  padding: 0 56px;
  /* Opaque on purpose: the site-wide cursor-field canvas sits behind
     every section (see #cursorField), but this text band needs solid
     footing under it — unlike the world map just below, which is
     meant to let that field's glow bleed through its ocean gaps. */
  background: #fff;
}

.hh-header__container {
  max-width: 1288px; /* 1176px content + 2 x 56px side gutters, matches Figma's inner margin container */
  margin: 0 auto;
}

.hh-header__grid {
  display: grid;
  grid-template-columns: 697.84px 436.16px;
  column-gap: 42px;
  max-width: 1176px;
  margin: 0 auto;
  padding: 28px 0 30px;
}

.hh-header__heading {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.hh-header__title {
  margin: 0;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 400;
  font-style: normal;
  font-size: 76.44px;
  line-height: 70.325px;
  letter-spacing: -2.6754px;
  text-transform: uppercase;
  color: #0a0a0a;
}

.hh-header__title-line {
  display: block;
}

.hh-header__ctas {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-top: 28px;
}

.hh-header__textlink {
  display: inline-flex;
  align-items: center;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 500;
  font-size: 15px;
  color: #0a0a0a;
  text-decoration: none;
}

.hh-header__textlink .flip-label {
  text-decoration: underline;
  text-decoration-color: rgba(10, 10, 10, 0.3);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.2s ease;
}

.hh-header__textlink:hover .flip-label {
  text-decoration-color: #0a0a0a;
}

.hh-header__side {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-left: 42px;
  min-height: 140.64px;
}

.hh-header__side-divider {
  position: absolute;
  top: -0.18px;
  left: 0;
  width: 1px;
  height: 197px;
  background: rgba(10, 10, 10, 0.12);
}

.hh-header__tagline {
  margin: 0;
  max-width: 394.156px;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 400;
  font-size: 20px;
  line-height: 23.6px;
  letter-spacing: -0.2px;
  text-transform: uppercase;
  text-align: justify;
  color: #0a0a0a;
}

.hh-header__sep {
  display: inline-block;
  width: 5px;
  height: 5px;
  margin: 0 1px;
  background: currentColor;
  vertical-align: middle;
}

.hh-header__desc {
  margin: 24px 0 0;
  max-width: 394.156px;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 400;
  font-size: 13px;
  line-height: 18.85px;
  text-align: left;
  color: #0a0a0a;
}

/* Scroll colour-scrub (assets/js/hero-text-scrub.js): each character is its
   own span so JS can sweep it from grey to ink individually. The word
   wrapper stays a plain inline box — only line-wrapping needs it, nothing
   is styled on it directly. The short transition just smooths between
   scroll-tick updates; the sweep itself is driven by scroll position, not
   by this transition's timing. */
.htr-word {
  display: inline;
}

.htr-active .htr-char {
  color: #8b8b8b;
  transition: color 120ms linear;
}

.hh-header__rule {
  width: 100%;
  height: 1px;
  background: rgba(10, 10, 10, 0.12);
}

/* Interactive pixel-grid canvas, reproducing Figma node 31020:17698 —
   sits right below the hero text, matching that node's own 1470:707
   aspect ratio (183 x 88 real cells) at rest. Squares are drawn/
   animated in assets/js/squares.js; see squares-grid-data.js for the
   sampled source data (colors sampled directly from the real Figma
   export). No aspect-ratio/width:100% on the canvas here any more —
   squares.js now sizes it in pixels itself (floors cell size on
   narrow screens so the map doesn't shrink into illegible noise),
   so this just needs to center + crop whatever width that comes out
   to; display:flex + overflow:hidden do that without CSS needing to
   know the canvas's actual size. */
.squares-wrap {
  width: 100%;
  display: flex;
  justify-content: center;
  overflow: hidden;
}

#squaresCanvas {
  display: block;
  cursor: pointer;
}

/* ---- small screens: relax fixed widths so nothing overflows the viewport */
@media (max-width: 1280px) {
  .hh-header__grid {
    grid-template-columns: 1fr;
    row-gap: 32px;
  }

  .hh-header__side-divider {
    display: none;
  }

  .hh-header__side {
    padding-left: 0;
  }
}

@media (max-width: 640px) {
  .hh-header__band {
    padding: 0 24px;
  }

  .hh-header__title {
    font-size: 48px;
    line-height: 46px;
    letter-spacing: -1.6px;
  }

  .hh-header__spacer {
    height: 200px;
  }

  /* The pixel-notched button's label wraps to two lines at this width,
     which left "What we do" sitting beside it lopsided and cramped
     rather than actually side by side — stack them instead. Same
     align-items: stretch technique as .pf-form__footer's own submit
     button, so "Start a conversation" fills the full width like every
     other primary CTA does on mobile, not just this one hero.
     .hh-header__ctas needs its own explicit 100% too: its parent
     (.hh-header__heading) is itself a column flexbox with
     align-items: flex-start, so without that, .hh-header__ctas would
     just shrink-wrap to its own widest child instead of actually
     reaching the heading's full width for align-items: stretch below
     to stretch the button against. */
  .hh-header__ctas {
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
  }

  .hh-header__ctas .ec-btn {
    width: 100%;
  }

  /* Stretched full-width by align-items: stretch above (a bigger tap
     target), but its own content still defaulted to the left edge of
     that box instead of actually sitting in the middle of the row. */
  .hh-header__textlink {
    justify-content: center;
  }
}
/* ============================================================
   02-intro-cases — intro paragraph + case-study card carousel
   Prefix: ic-  (scoped to avoid collisions with other sections)
   Fonts:  'Sneak' (Regular / Medium) — custom typeface referenced
           in Figma as Sneak:Regular / Sneak:Medium. Font files were
           not available from the Figma export; a system fallback
           stack is used. See notes.md.
   ============================================================ */

.ic-section {
  width: 100%;
  background: transparent;
  padding: 98px 56px 42px;
  box-sizing: border-box;
  overflow: hidden;
}

/* ---------- Intro paragraph ---------- */

.ic-intro {
  display: flex;
  justify-content: center;
  width: 100%;
  margin: 0 auto 42px;
}

.ic-intro__text {
  margin: 0;
  max-width: 1176px;
  width: 100%;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 400;
  font-size: 46px;
  line-height: 48.76px;
  letter-spacing: -0.92px;
  color: #0a0a0a;
}

/* ---------- Cards grid ----------
   Structure taken directly from integratedbio.com's own usp-cards block
   (read its actual HTML/CSS, not guessed): a plain grid, gap:0 so the
   cards sit flush against each other, each one a full-bleed block in
   its own colour rather than a neutral box with a coloured icon. Always
   exactly 4 practices, so a hardcoded 2x2 desktop grid stands in for
   their count-driven :has() rules (which handle a variable number of
   cards — not needed here). */

.ic-cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 0;
  width: 100%;
  /* Same column cap as .ic-intro__text above it — without this the
     full-bleed cards (see note above: no gap, edge-to-edge colour by
     design) just kept growing with the viewport, turning into vast
     slabs of flat colour on an ultrawide monitor instead of reading
     as a grid of four cards. */
  max-width: 1176px;
  margin: 0 auto;
}

@media (max-width: 900px) {
  .ic-cards {
    grid-template-columns: 1fr;
    grid-template-rows: none;
  }
}

.ic-card {
  position: relative;
}

.ic-card {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  gap: 32px;
  min-height: 360px;
  padding: 36px;
  background: var(--ic);
  color: var(--ic-ink);
  text-decoration: none;
  overflow: hidden;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.ic-card:hover {
  transform: scale(1.035);
  /* Cards sit flush (grid gap:0) — scaling up would tuck this card's
     far edge under its neighbour's near edge without this. */
  z-index: 6;
}

/* Border "snake", hover only, in --ic-ink so it reads on any of the
   four card colours. A conic-gradient tried first reads as a beam
   sweeping from the centre, not a segment travelling the edge itself —
   correct at the flat sides but visibly wrong right at each 90° corner
   (a diagonal cut through it), since a conic sweep has nothing to do
   with the rectangle's actual path. Traced on an actual <rect> (SVG,
   markup in index.html) and animated via stroke-dashoffset instead: a
   real path, so it turns the corners properly, the way a marching-ants
   selection does. */
.ic-card__ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.ic-card__ring rect {
  x: 1.5px;
  y: 1.5px;
  width: calc(100% - 3px);
  height: calc(100% - 3px);
  fill: none;
  stroke: var(--ic-ink);
  stroke-width: 3px;
  /* 120px lit segment, then enough bare path that only one segment is
     ever visible at once on a card this size — a single snake circling
     the border, not repeating "marching ants". */
  stroke-dasharray: 120 1900;
}

.ic-card:hover .ic-card__ring {
  opacity: 1;
}

.ic-card:hover .ic-card__ring rect {
  animation: ic-ring-crawl 3s linear infinite;
}

@keyframes ic-ring-crawl {
  to {
    stroke-dashoffset: -2020;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ic-card {
    transition: none;
  }
  .ic-card:hover {
    transform: none;
  }
  .ic-card:hover .ic-card__ring rect {
    animation: none;
  }
}

.ic-card__media {
  position: relative;
  width: 100%;
  height: 350px;
  /* neutral, NOT accent-tinted — every icon colour (including pale
     gold) needs the same reliable contrast to pop against it */
  background: #f4f4f2;
  border: 1px solid rgba(10, 10, 10, 0.08);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.25s ease, background 0.25s ease;
}

.ic-card__media::before {
  /* faint accent wash on hover, in the card's own colour */
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ic, transparent);
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
}

.ic-card__media:hover {
  border-color: var(--ic, rgba(10, 10, 10, 0.3));
  background: #eeeeec;
}
.ic-card__media:hover::before {
  opacity: 0.1;
}

/* Flat cards (no photo, no hover-reveal link) — used where a practice or
   focus area has no real case study to show; a custom animated icon in
   the card's own accent colour stands in instead of a photo. */
.ic-card--flat {
  cursor: default;
}

.ic-card__media--navy { --ic: #1c2541; }
.ic-card__media--blue { --ic: #3b5bd9; }
.ic-card__media--gold { --ic: #f5c518; }
.ic-card__media--red { --ic: #e0492a; }

/* Each practice card is now its own full-bleed colour (--ic, same
   tokens as above) rather than a neutral box with a coloured icon —
   --ic-ink is the contrast colour for the icon glyph, index number and
   text on top of it, picked per card for actual contrast rather than a
   fixed light/dark rule. */
.ic-card--navy { --ic: #1c2541; --ic-ink: #ffffff; }
.ic-card--blue { --ic: #3b5bd9; --ic-ink: #ffffff; }
.ic-card--gold { --ic: #f5c518; --ic-ink: #0a0a0a; }
.ic-card--red { --ic: #e0492a; --ic-ink: #ffffff; }

.ic-card__index {
  position: absolute;
  top: 24px;
  right: 24px;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-size: 13px;
  letter-spacing: -0.13px;
  color: var(--ic-ink);
  opacity: 0.7;
}

.ic-card__content {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* ==========================================================================
   Practice icons — custom square pixel glyphs, each coloured with the
   card's own accent (--ic, set above) and each with its own idle
   animation plus a distinct hover response. Squares and steps only (no
   circles, no smooth diagonals), matching the site's pixel-notch/
   pixel-icon language used elsewhere.
   ========================================================================== */

.picon {
  position: relative;
  width: 132px;
  height: 132px;
  flex-shrink: 0;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.picon::after {
  /* soft colour halo behind the glyph — ties it to the card's accent
     without competing with the icon itself for contrast. --ic-ink
     falls back to --ic: .ic-card sets --ic-ink (its own background IS
     --ic now, so the halo needs the contrast colour instead); other
     .picon users that never set --ic-ink keep the original
     accent-coloured halo on their own neutral box. */
  content: "";
  position: absolute;
  inset: -34%;
  background: radial-gradient(circle, var(--ic-ink, var(--ic)) 0%, transparent 72%);
  opacity: 0.16;
  z-index: -1;
  transition: opacity 0.25s ease, transform 0.3s ease;
}
.ic-card:hover .picon::after {
  opacity: 0.26;
  transform: scale(1.15);
}

/* The halo reads as a soft glow on a neutral grey box, but on
   .ic-card's own full-colour background (same hue as the halo would
   be, before falling back through --ic-ink) it just looks like stray
   light behind the icon — dropped for .ic-card specifically, idle and
   hover alike. content:none removes the pseudo-element outright rather
   than just hiding it, so the now-pointless hover rule above has
   nothing left to animate. */
.ic-card .picon::after {
  content: none;
}

.ic-card:hover .picon {
  transform: scale(1.08);
}
.ic-card:active .picon {
  transform: scale(0.94);
  transition-duration: 0.12s;
}

/* ---- Real icons, sourced from pixelarticons.com (briefcase, code,
   brush, trending-up, store, smartphone, refresh, shopping-cart —
   paths copied as-is from that library's own SVGs, never redrawn)
   instead of the hand-built square glyphs this card set used before.
   Each keeps its own idle motion plus a faster version on hover,
   matching the site's existing "idle -> livelier on hover" language;
   .picon and .picon::after above already provide the halo + outer
   scale response generically, so only the glyph itself needs styling
   here. ---- */

.picon__glyph {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 72px;
  height: 72px;
  /* --ic-ink falls back to --ic — see .picon::after above for why. */
  fill: var(--ic-ink, var(--ic));
  transform: translate(-50%, -50%);
}

/* Technology Consulting — briefcase, carried with a gentle bob. */
.picon--consulting .picon__glyph {
  animation: picon-bob 2.6s ease-in-out infinite;
}
.ic-card:hover .picon--consulting .picon__glyph {
  animation-duration: 1s;
}

/* Software & Product Development — code, a hard on/off blink like a
   cursor waiting to type. */
.picon--dev .picon__glyph {
  animation: picon-blink 1.1s steps(1, end) infinite;
}
.ic-card:hover .picon--dev .picon__glyph {
  animation-duration: 0.5s;
}

/* Design — brush, a light wiggle. */
.picon--design .picon__glyph {
  animation: picon-wiggle 3s ease-in-out infinite;
}
.ic-card:hover .picon--design .picon__glyph {
  animation-duration: 1s;
}

/* Growth & Operations — trending-up, a scale pulse (the chart itself
   "growing"). */
.picon--growth .picon__glyph {
  animation: picon-grow 1.6s ease-in-out infinite;
}
.ic-card:hover .picon--growth .picon__glyph {
  animation-duration: 0.7s;
}

/* Ownership (the "What we will not do" stat pair) — key, a light
   wiggle as if turning in a lock. */
.picon--ownership .picon__glyph {
  animation: picon-wiggle 3s ease-in-out infinite;
}
.va-stat:hover .picon--ownership .picon__glyph {
  animation-duration: 1s;
}

/* NDA — lock, breathing gently as if actively holding something secure. */
.picon--nda .picon__glyph {
  animation: picon-pulse 2s ease-in-out infinite;
}
.va-stat:hover .picon--nda .picon__glyph {
  animation-duration: 0.8s;
}

@keyframes picon-bob {
  0%, 100% { transform: translate(-50%, -50%) translateY(0); }
  50% { transform: translate(-50%, -50%) translateY(-6px); }
}
@keyframes picon-blink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0.25; }
}
@keyframes picon-wiggle {
  0%, 100% { transform: translate(-50%, -50%) rotate(0deg); }
  25% { transform: translate(-50%, -50%) rotate(-8deg); }
  75% { transform: translate(-50%, -50%) rotate(8deg); }
}
@keyframes picon-grow {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50% { transform: translate(-50%, -50%) scale(1.15); }
}
@keyframes picon-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}
@keyframes picon-buzz {
  0%, 60%, 100% { transform: translate(-50%, -50%); }
  63%, 69%, 75% { transform: translate(calc(-50% - 2px), -50%); }
  66%, 72% { transform: translate(calc(-50% + 2px), -50%); }
}
@keyframes picon-spin {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to { transform: translate(-50%, -50%) rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  /* .picon .picon__glyph (not just .picon__glyph) to match the
     per-variant rules' own specificity (.picon--cycle .picon__glyph
     etc.) — otherwise this loses the cascade and e.g. the cycle icon
     keeps spinning under reduced motion despite this rule "matching". */
  .picon .picon__glyph {
    animation: none;
    transition: none;
    /* translate(-50%,-50%) is load-bearing centring, not just part of
       the animation — keep it, only the animation itself stops. */
    transform: translate(-50%, -50%);
  }
}

@media (max-width: 900px) {
  .picon { width: 96px; height: 96px; }
  .picon__glyph { width: 52px; height: 52px; }
}

/* ---- Click delight: confetti burst (assets/js/picon-fx.js) ---- */

.picon-confetti {
  position: absolute;
  width: var(--sz);
  height: var(--sz);
  margin: calc(var(--sz) * -0.5) 0 0 calc(var(--sz) * -0.5);
  pointer-events: none;
  animation: picon-confetti-burst 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes picon-confetti-burst {
  0% { transform: translate(0, 0) scale(1) rotate(0deg); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(0.3) rotate(90deg); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .picon-confetti {
    display: none;
  }
}

/* ==========================================================================
   Pixel dissolve/materialise reveal (assets/js/pixel-reveal.js) — a
   shuffled grid of small squares covers each card and shrinks away with
   a staggered delay as it scrolls into view, then grows back to cover
   it on the way back out (either edge), instead of a plain fade.
   ========================================================================== */

.ic-card__pixelmask {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(5, 1fr);
  pointer-events: none;
}

.ic-card__pixelmask span {
  background: #fff;
  transform: scale(1);
  opacity: 1;
  transition: transform 0.5s cubic-bezier(0.65, 0, 0.35, 1), opacity 0.5s ease;
}

.ic-card.is-assembled .ic-card__pixelmask span {
  transform: scale(0);
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .ic-card__pixelmask span {
    transition: none;
  }
}

.ic-card__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

/* .ic-card__media::after and .ic-card__cta ("View case study" hover
   reveal) used to live here — dead now that every practice card is
   flat (--flat) and full-bleed coloured rather than a neutral photo
   box; removed along with the carousel's next button below. */

.ic-card__title {
  margin: 0;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 500;
  font-size: 26px;
  line-height: 1.15;
  letter-spacing: -0.5px;
  color: var(--ic-ink);
}

.ic-card__desc {
  margin: 0;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 400;
  font-size: 14.5px;
  line-height: 21.75px;
  color: var(--ic-ink);
  opacity: 0.8;
}

@media (max-width: 900px) {
  .ic-section {
    padding: 64px 24px 32px;
  }

  .ic-intro__text {
    font-size: 30px;
    line-height: 34px;
    letter-spacing: -0.4px;
    white-space: normal;
  }

  .ic-card__title {
    font-size: 22px;
    line-height: 30px;
  }
}
/* ==========================================================================
   Section: "Born in Vienna" + "AI is good at everything except the last
   10 percent" — two stacked two-column blocks, heading+eyebrow on the
   left, justified body copy (and, in the second block, a two-up stat
   pair with pixel-glyph icons) on the right.

   Classes are scoped with a `va-` (Vienna / AI) prefix to avoid colliding
   with other implemented sections.
   ========================================================================== */

.va-section {
  --va-ink: #0a0a0a;
  --va-body-ink: #2a2a2a;
  --va-muted: #8b8b8b;

  /* 'Sneak' is the family named in the Figma file. No web-font file or
     CDN reference ships with the export, so it falls back to a neutral
     geometric-grotesk sans that matches the design screenshot. Swap in
     the real font file/stack once one is provided. */
  --va-font-sans: 'Sneak', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --va-font-mono: 'SFMono-Regular', ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;

  background: transparent;
  color: var(--va-body-ink);
}

.va-inner {
  max-width: 1176px;
  margin: 0 auto;
  padding: 126px 56px;
}

.va-grid {
  display: grid;
  grid-template-columns: minmax(0, 448px) minmax(0, 1fr);
  column-gap: 84px;
  align-items: start;
}

/* ---- Left column: heading + eyebrow -------------------------------- */

.va-heading-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.va-heading {
  margin: 0;
  /* +0.5em over the usual 448px cap — room for the trailing
     .heading-dot so it doesn't wrap onto its own line. */
  max-width: calc(448px + 0.5em);
  font-family: var(--va-font-sans);
  font-weight: 400;
  font-size: 46px;
  line-height: 48.76px;
  letter-spacing: -0.92px;
  color: var(--va-ink);
}

.va-eyebrow {
  margin: 14px 0 0;
  max-width: 297px;
  font-family: var(--va-font-mono);
  font-weight: 400;
  font-size: 10px;
  line-height: 16.2px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--va-muted);
}

/* ---- Right column: body copy --------------------------------------- */

.va-body-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.va-body-col > * {
  margin: 17.75px 0 0;
  width: 100%;
}

.va-body-col > *:first-child {
  margin-top: 0;
}

.va-body {
  font-family: var(--va-font-sans);
  font-weight: 400;
  font-size: 16.905px;
  line-height: 27.386px;
  text-align: justify;
  color: var(--va-body-ink);
}

.va-note {
  font-family: var(--va-font-sans);
  font-weight: 400;
  font-size: 14px;
  line-height: 22.68px;
  text-align: justify;
  color: var(--va-muted);
}

/* ---- Stat pair (second block only) ---------------------------------- */

.va-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 28px;
  margin-top: 49px;
}

.va-stats + .va-body {
  margin-top: 49px;
}

.va-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.va-stat__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 128px;
  height: 128px;
}

/* Real icons, sourced from pixelarticons.com (key, lock), reusing the
   same .picon system as the practice cards above instead of the
   abstract pixel-grid glyphs this pair used before — each with its
   own idle motion, a faster version plus a scale response on hover of
   the whole stat, and a press-in on click, matching how .picon
   already behaves everywhere else on the page. No colour halo here,
   though (unlike the practice cards) — against this plain white
   section it just read as a smudge behind the glyph. */
.va-stat__icon .picon {
  width: 96px;
  height: 96px;
}
.va-stat__icon .picon__glyph {
  width: 52px;
  height: 52px;
}
.va-stat__icon .picon::after {
  display: none;
}

.va-stat:hover .picon {
  transform: scale(1.08);
}
.va-stat:active .picon {
  transform: scale(0.94);
  transition-duration: 0.12s;
}

.va-stat__label {
  margin: 18px 0 0;
  font-family: var(--va-font-mono);
  font-weight: 400;
  font-size: 11px;
  line-height: 16.5px;
  letter-spacing: 1.98px;
  text-transform: uppercase;
  color: var(--va-muted);
}

.va-stat__desc {
  margin: 7px 0 0;
  max-width: 309px;
  font-family: var(--va-font-sans);
  font-weight: 400;
  font-size: 14px;
  line-height: 22.68px;
  text-align: center;
  color: var(--va-body-ink);
}

/* ---- Responsive ------------------------------------------------------ */

@media (max-width: 900px) {
  .va-inner {
    padding: 80px 32px;
  }

  .va-grid {
    grid-template-columns: 1fr;
    row-gap: 32px;
  }

  .va-heading {
    font-size: clamp(30px, 6vw + 12px, 46px);
    line-height: 1.06;
  }

  .va-heading-col,
  .va-body-col {
    max-width: none;
  }

  .va-body-col > * {
    max-width: none;
  }
}

@media (max-width: 560px) {
  .va-inner {
    padding: 56px 20px;
  }

  .va-stats {
    grid-template-columns: 1fr;
    row-gap: 32px;
  }

  .va-body,
  .va-note {
    text-align: left;
  }
}

@media (prefers-reduced-motion: reduce) {
  .va-section * {
    scroll-behavior: auto;
  }
}
/* ==========================================================================
   04 — Explore/Generate/Refine/Scale + Brand Context Protocol
   Figma fileKey Ef7ULPmEOmffnS1gzSvvY1
   nodes: 31020:3213, 31020:3214
   Classes scoped with `ec-` prefix. See notes.md for fonts/colors/decisions.
   ========================================================================== */

.ec-section {
  --ec-ink: #0a0a0a;
  --ec-body: #2a2a2a;
  --ec-muted: #8b8b8b;
  --ec-badge-bg: #1c2541;
  --ec-white: #ffffff;

  /* Figma layer reports "Sneak" (Regular/Medium) — a custom typeface not
     available as a webfont; fall back to a clean neo-grotesque stack. */
  --ec-font-sans: "Sneak", -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --ec-font-mono: "SFMono-Regular", ui-monospace, "SF Mono", "Roboto Mono", Menlo, Consolas, monospace;

  box-sizing: border-box;
  background: transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

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

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

.ec-section p {
  margin: 0;
}

/* --------------------------------------------------------------------- */
/* Section 1 — Explore. Generate. Refine. Scale.                          */
/* --------------------------------------------------------------------- */

.ec-explore {
  padding: 98px 56px;
}

.ec-container {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  max-width: 1176px;
}

.ec-intro {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 28px;
  width: 100%;
}

.ec-heading {
  font-family: var(--ec-font-sans);
  font-weight: 400;
  font-size: 46px;
  line-height: 47.84px;
  letter-spacing: -0.92px;
  color: var(--ec-ink);
  margin: 0;
}

.ec-intro__text {
  font-family: var(--ec-font-sans);
  font-weight: 400;
  font-size: 16.905px;
  line-height: 27.386px;
  color: var(--ec-body);
  max-width: 503px;
}

.ec-chart {
  width: 100%;
  padding-top: 42px;
}

.ec-chart__img {
  display: block;
  width: 100%;
  height: auto;
  max-width: 1176px;
  /* The evolution silhouette (explore-chart-data.js) is a 160x59 cell
     grid, each of its 4 figures now centred in its own quarter to match
     .ec-legend's 4 columns below, instead of the raw source image's
     uneven spacing. */
  aspect-ratio: 1176 / 434;
  cursor: pointer;
}

.ec-legend {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}

/* `.ec-section ul` resets padding to 0 (it's a stronger 0-1-1 selector —
   one class plus the ul tag — beating plain `.ec-legend` at 0-1-0), which
   is why bumping the padding-top above quietly did nothing. Scoped to
   .ec-explore for 0-2-0 so it actually wins. */
.ec-explore .ec-legend {
  /* Feet-to-caption gap: was 17px, still read as stuck together at 44px
     too — the figures need real air above the "01 Frame" row. */
  padding-top: 108px;
}

.ec-legend__item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 13px;
  padding-bottom: 17px;
}

/* Per-item quarter of the same march-of-progress chart above (see
   explore-chart.js's header comment) — hidden by default since the
   4-column desktop grid already sits directly under the one wide
   .ec-chart canvas in matching quarters. Only shown once .ec-legend
   stops being 4 columns, below, at which point .ec-chart itself hides
   instead: it no longer lines up with anything once the items reflow
   into fewer columns (or one), so every item gets its own figure
   directly above its own heading instead. */
.ec-legend__figure {
  display: none;
  width: 100%;
  max-width: 200px;
}

.ec-legend__figure-canvas {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 294 / 434;
  cursor: pointer;
}

.ec-legend__head {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 24px;
  padding-top: 2px;
}

.ec-legend__num {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  background: var(--ec-badge-bg);
  color: var(--ec-white);
  font-family: var(--ec-font-mono);
  font-weight: 400;
  font-size: 9px;
  line-height: 11.25px;
  letter-spacing: 0.36px;
}

.ec-legend__label {
  font-family: var(--ec-font-sans);
  font-weight: 500;
  font-size: 15px;
  line-height: 18.75px;
  color: var(--ec-ink);
}

.ec-legend__text {
  font-family: var(--ec-font-sans);
  font-weight: 400;
  font-size: 13.5px;
  line-height: 20.25px;
  color: var(--ec-body);
  max-width: 284px;
}

/* --------------------------------------------------------------------- */
/* Section 2 — The Brand Context Protocol.                                */
/* --------------------------------------------------------------------- */

.ec-protocol {
  padding: 126px 56px 35px;
}

.ec-protocol__grid {
  display: grid;
  grid-template-columns: 447.72fr 644.28fr;
  gap: 0 84px;
  width: 100%;
  max-width: 1176px;
}

/* Heading-only instance (no right column of body copy) — center it
   instead of leaving the right track empty. */
.ec-protocol__grid--solo {
  grid-template-columns: 1fr;
  text-align: center;
}

.ec-protocol__grid--solo .ec-protocol__col-left {
  align-items: center;
  margin: 0 auto;
}

.ec-protocol__col-left {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.ec-heading--protocol {
  /* +0.5em over the usual 448px cap — room for the trailing
     .heading-dot so it doesn't wrap onto its own line. */
  max-width: calc(448px + 0.5em);
  width: 100%;
  line-height: 48.76px;
}

.ec-eyebrow {
  padding-top: 14px;
  max-width: 296.719px;
  font-family: var(--ec-font-mono);
  font-weight: 400;
  font-size: 10px;
  line-height: 16.2px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--ec-muted);
  margin: 0;
}

.ec-protocol__col-right {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.ec-protocol__text {
  font-family: var(--ec-font-sans);
  font-weight: 400;
  font-size: 16.905px;
  line-height: 27.386px;
  color: var(--ec-body);
  padding-bottom: 17.75px;
}

.ec-protocol__lead {
  font-weight: 500;
  color: var(--ec-ink);
}

.ec-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* fallbacks matter here: this class is also used inside .hh-header,
     which never defines --ec-ink/--ec-white (those live on .ec-section),
     so without a fallback the button rendered with a transparent bg */
  background: var(--ec-ink, #0a0a0a);
  color: var(--ec-white, #ffffff);
  text-decoration: none;
  font-family: var(--ec-font-sans, 'Sneak', -apple-system, 'Helvetica Neue', Arial, sans-serif);
  font-weight: 500;
  font-size: 17.64px;
  line-height: 26.46px;
  letter-spacing: -0.1764px;
  padding: 16px 36px;
  border: none;
  appearance: none; /* a <button>-tag .ec-btn (e.g. 404.html's "Play a game") otherwise keeps the UA's own bezel, invisible on the dark fill everything else here uses but visible as a stray line on this one's white/ghost background */
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.ec-btn:hover {
  background: #1264f5;
}

/* --------------------------------------------------------------------- */
/* Responsive                                                             */
/* --------------------------------------------------------------------- */

@media (max-width: 900px) {
  .ec-explore {
    padding: 64px 24px;
  }

  .ec-protocol {
    padding: 64px 24px 40px;
  }

  .ec-heading,
  .ec-heading--protocol {
    font-size: 34px;
    line-height: 1.08;
  }

  .ec-intro__text,
  .ec-protocol__text {
    max-width: 100%;
  }

  .ec-legend {
    grid-template-columns: repeat(2, 1fr);
    row-gap: 24px;
  }

  .ec-legend__text {
    max-width: 100%;
  }

  /* .ec-legend is no longer 4 columns past this point, so the one wide
     .ec-chart canvas above it can't promise its quarters line up with
     anything any more — swap to the per-item figures instead (see
     .ec-legend__figure above). */
  .ec-chart {
    display: none;
  }

  .ec-legend__figure {
    display: block;
  }

  /* .ec-explore .ec-legend's 108px padding-top (above) is sized for a
     completely different junction: it's the desktop chart's own feet
     -to-caption gap, sitting between .ec-chart's bottom edge and the
     "01 Frame" row right under it. With .ec-chart hidden here, that
     padding just becomes dead air between the intro copy and the
     first item's own figure — dropped entirely. */
  .ec-explore .ec-legend {
    padding-top: 0;
  }

  .ec-protocol__grid {
    grid-template-columns: 1fr;
    gap: 32px 0;
  }

  .ec-eyebrow {
    max-width: 100%;
  }
}

@media (max-width: 520px) {
  .ec-legend {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ec-btn {
    transition: none;
  }
}
/* ==========================================================================
   Figma build — 05-chart2-ai-levels
   Section 1 (31020:3467): dot-cloud chart + 4-item legend, no heading.
   Section 2 (31020:3468): "Move your organisation up the levels of AI."
   heading + body copy + 3-item level list.

   Fonts referenced in the Figma file: "Sneak" (Regular/Medium) for headings,
   body and legend copy, and "SFMono-Regular" for the small mono labels
   (badge numbers, eyebrow, L1/L3/L5 tags). "Sneak" is not a redistributable
   web font available to this build, so it falls back to a neutral grotesk
   sans that matches its x-height/weight in the screenshot. See notes.md.
   ========================================================================== */

.al-chart-section,
.al-levels-section {
  --al-ink: #0a0a0a;
  --al-body: #2a2a2a;
  --al-muted: #8b8b8b;
  --al-badge-bg: #1c2541;
  --al-badge-fg: #ffffff;
  --al-rule: rgba(10, 10, 10, 0.12);
  --al-wrap: 1176px;

  --al-font-display: 'Sneak', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
  --al-font-mono: 'SFMono-Regular', 'SF Mono', 'IBM Plex Mono', 'Roboto Mono', ui-monospace, Menlo, Consolas, monospace;

  box-sizing: border-box;
  background: transparent;
}

.al-chart-section *,
.al-levels-section * {
  box-sizing: border-box;
}

/* ---- Section 1: chart + legend ------------------------------------------ */

.al-chart-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 14px 56px 98px;
}

.al-chart-section__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  max-width: var(--al-wrap);
}

.al-chart {
  width: 100%;
  margin: 0;
}

.al-chart__image {
  display: block;
  width: 100%;
  height: auto;
}

.al-legend {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  width: 100%;
  margin: 17px 0 0;
  padding: 0;
  list-style: none;
}

/* FAQ instance: 5 items read better across 3 columns than 4. */
.al-legend--faq {
  grid-template-columns: repeat(3, 1fr);
  margin-top: 0;
}

.al-legend__item {
  display: flex;
  flex-direction: column;
  gap: 13px;
  padding-bottom: 17px;
}

.al-legend__head {
  display: flex;
  align-items: center;
  gap: 9px;
}

.al-legend__index {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  background: var(--al-badge-bg);
  color: var(--al-badge-fg);
  font-family: var(--al-font-mono);
  font-size: 9px;
  line-height: 1;
  letter-spacing: 0.04em;
}

.al-legend__title {
  font-family: var(--al-font-display);
  font-weight: 500;
  font-size: 15px;
  line-height: 1.25;
  color: var(--al-ink);
}

.al-legend__desc {
  margin: 0;
  font-family: var(--al-font-display);
  font-weight: 400;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--al-body);
}

/* ---- Section 2: heading + body + level list ------------------------------ */

.al-levels-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 126px 56px;
}

.al-levels-section__inner {
  display: grid;
  grid-template-columns: 447.72fr 644.28fr;
  gap: 0 84px;
  width: 100%;
  max-width: var(--al-wrap);
  align-items: start;
}

.al-levels__heading-col {
  display: flex;
  flex-direction: column;
  padding-top: 18px;
}

.al-levels__heading {
  margin: 0;
  font-family: var(--al-font-display);
  font-weight: 400;
  font-size: 46px;
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--al-ink);
  max-width: 30ch;
}

.al-levels__eyebrow {
  margin: 14px 0 0;
  max-width: 22ch;
  font-family: var(--al-font-mono);
  font-size: 10px;
  line-height: 1.62;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--al-muted);
  text-align: justify;
}

.al-levels__desc {
  margin: 14px 0 0;
  max-width: 34ch;
  font-family: var(--al-font-display);
  font-size: 14px;
  line-height: 1.55;
  color: var(--al-muted);
}

.al-levels__body-col {
  display: flex;
  flex-direction: column;
  padding-top: 18px;
}

.al-levels__para {
  margin: 0;
  font-family: var(--al-font-display);
  font-weight: 400;
  font-size: 16.9px;
  line-height: 1.62;
  color: var(--al-body);
  text-align: justify;
}

.al-levels__para + .al-levels__para {
  margin-top: 17.75px;
}

.al-levels__list {
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
}

.al-levels__list + .al-levels__para {
  margin-top: 28px;
}

.al-levels__item {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 20px;
  padding: 24px 0;
}

/* A row of small square ticks instead of a plain solid/native-dashed
   rule — the same pixel language as .pixel-notched and the picon
   grids, not a generic border-style. */
.al-levels__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background-image: repeating-linear-gradient(to right, var(--al-rule) 0 4px, transparent 4px 9px);
}

/* No divider above the first item or below the last — the section's
   own edges already frame the list, so those two would just be a
   redundant extra line right next to the surrounding whitespace. */
.al-levels__item:first-child::before {
  content: none;
}

.al-levels__item:last-child {
  padding-bottom: 25px;
}

.al-levels__tag {
  flex-shrink: 0;
  font-family: var(--al-font-mono);
  font-size: 40px;
  letter-spacing: 0;
  color: var(--al-muted);
}

.al-levels__item-body {
  flex: 1;
  min-width: 0;
}

.al-levels__item-title {
  margin: 0 0 8px;
  font-family: var(--al-font-display);
  font-weight: 500;
  font-size: 40px;
  line-height: 1.1;
  color: var(--al-ink);
}

.al-levels__item-text {
  margin: 0;
  font-family: var(--al-font-display);
  font-size: 15px;
  line-height: 1.5;
  color: var(--al-body);
}

/* Light-blue tile with a primary-blue glyph and primary-blue pixel
   corner brackets — four small L-shaped ticks (built from stacked
   background-image layers, not a border) instead of a plain dashed
   outline, echoing the site's own notched/pixel-corner language. */
.al-levels__item-icon {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  background-color: #cfe0fb;
  background-repeat: no-repeat;
  background-image:
    linear-gradient(#1264f5, #1264f5), linear-gradient(#1264f5, #1264f5),
    linear-gradient(#1264f5, #1264f5), linear-gradient(#1264f5, #1264f5),
    linear-gradient(#1264f5, #1264f5), linear-gradient(#1264f5, #1264f5),
    linear-gradient(#1264f5, #1264f5), linear-gradient(#1264f5, #1264f5);
  background-size:
    9px 2px, 2px 9px,
    9px 2px, 2px 9px,
    9px 2px, 2px 9px,
    9px 2px, 2px 9px;
  background-position:
    left top, left top,
    right top, right top,
    left bottom, left bottom,
    right bottom, right bottom;
}

.al-levels__item-icon svg {
  width: 20px;
  height: 20px;
  color: #1264f5;
}

/* ---- Responsive ----------------------------------------------------------- */

@media (max-width: 900px) {
  .al-legend {
    grid-template-columns: repeat(2, 1fr);
  }

  .al-levels-section__inner {
    grid-template-columns: 1fr;
    gap: 40px 0;
  }

  .al-levels__heading {
    font-size: clamp(2rem, 1.5rem + 2vw, 2.875rem);
  }
}

@media (max-width: 560px) {
  .al-chart-section {
    padding: 14px 24px 64px;
  }

  .al-levels-section {
    padding: 72px 24px;
  }

  .al-legend {
    grid-template-columns: 1fr;
  }

  .al-levels__para,
  .al-levels__eyebrow {
    text-align: left;
  }

  .al-levels__item {
    gap: 12px;
  }

  .al-levels__tag,
  .al-levels__item-title {
    font-size: 24px;
  }

  .al-levels__item-icon {
    width: 36px;
    height: 36px;
  }

  .al-levels__item-icon svg {
    width: 16px;
    height: 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .al-chart-section,
  .al-levels-section {
    scroll-behavior: auto;
  }
}
/* ==========================================================================
   06 — Projects / CTA / Footer
   Fonts: 'Sneak' (headings & body — not a web-safe/Google font, see notes.md)
          'SF Mono' (tag pill labels, system monospace)
   Colors: see notes.md for full token list
   ========================================================================== */

.pf-projects,
.pf-cta {
  --pf-black: #0a0a0a;
  --pf-body: #2a2a2a;
  --pf-muted: #8b8b8b;
  --pf-max: 1176px;
  --pf-pad: 56px;
  box-sizing: border-box;
}

.pf-projects *,
.pf-cta * {
  box-sizing: border-box;
}

.pf-projects {
  padding: 98px var(--pf-pad);
  background: transparent;
  font-family: 'Sneak', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
}

.pf-projects__intro {
  max-width: var(--pf-max);
  margin: 0 auto;
}

.pf-projects__heading {
  margin: 0;
  /* +0.5em over the usual 535px cap — just enough room for the
     trailing .heading-dot so it doesn't wrap onto its own line. */
  max-width: calc(535px + 0.5em);
  font-size: clamp(2rem, 1.4rem + 1.8vw, 2.875rem);
  line-height: 1.06;
  letter-spacing: -0.02em;
  font-weight: 400;
  color: var(--pf-black);
}

.pf-projects__body {
  margin: 21px 0 0;
  max-width: 678px;
  font-size: 1.057rem;
  line-height: 1.62;
  color: var(--pf-body);
}

/* ---- Cards grid — structure read directly from mistral.ai's own
   "Deploy frontier AI..." three-column service block (its real HTML,
   not guessed from a screenshot): a full-bleed strip with a border
   top and bottom, a bordered grid inside (border-left on the row,
   border-right on each cell so the columns divide like a table), a
   small icon + title anchored to the top of each cell and the
   description pushed to the bottom via justify-content:space-between.
   Ported here in this site's own light theme and blue accent instead
   of mistral's dark one — the request was for the structure, not
   their colours. ---- */

.pf-cards-grid {
  margin: 47px calc(var(--pf-pad) * -1) 0;
  border-top: 1px solid rgba(10, 10, 10, 0.12);
  border-bottom: 1px solid rgba(10, 10, 10, 0.12);
}

.pf-cards-grid__row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  /* Cell content sits 32px further in than this padding (its own
     left/right padding below) — subtract that so the first cell's
     icon/title lines up flush with .pf-projects__intro above it. */
  padding: 0 calc(max(var(--pf-pad), (100% - var(--pf-max)) / 2) - 32px);
  border-left: 1px solid rgba(10, 10, 10, 0.12);
}

.pf-cards-grid__cell {
  display: flex;
  flex-direction: column;
  /* space-between used to sit here, anchoring the icon to the top and
     the text group to the bottom — but with only two children, that
     stretches to fill the whole 280px min-height, so the declared gap
     below was never the actual gap on screen. flex-start lets that
     24px be the real, visible icon-to-text distance; the leftover
     space now just sits below the description instead. */
  justify-content: flex-start;
  gap: 24px;
  min-height: 280px;
  padding: 40px 32px;
  border-right: 1px solid rgba(10, 10, 10, 0.12);
  transition: background 0.2s ease, backdrop-filter 0.2s ease;
}

/* The row's own border-left is the only outer edge on that side —
   the last cell's border-right would otherwise draw a second, unmatched
   outer edge on this side alone. */
.pf-cards-grid__cell:last-child {
  border-right: none;
}

.pf-cards-grid__cell:hover {
  /* Translucent, not solid — the fixed cursor-heat canvas
     (assets/js/cursor-field.js) sits behind every section, and an
     opaque hover fill was hard-clipping the trail right at the cell's
     edge. A blur reads as "the pointer glow is still there, just
     behind frosted glass" instead of it vanishing outright. */
  background: rgba(247, 249, 254, 0.55);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* Title + description grouped with a tight gap — proximity: they're
   one unit of related copy and read as closer to each other than
   either is to the icon above (which .pf-cards-grid__cell's own
   space-between otherwise pushes toward opposite ends of the cell). */
.pf-cards-grid__text {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.pf-cards-grid__icon {
  display: block;
  width: 24px;
  height: 24px;
  color: #1264f5;
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.pf-cards-grid__cell:hover .pf-cards-grid__icon {
  transform: scale(1.15);
}

.pf-cards-grid__icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.pf-cards-grid__title {
  margin: 0;
  /* Reserves 2 lines' worth of height even when a title only needs
     one, so every card's description starts at the same row instead
     of whichever card wraps to two lines pulling its own text down
     past its neighbours. */
  min-height: 2.6em;
  font-size: 1.375rem;
  line-height: 1.3;
  letter-spacing: -0.01em;
  font-weight: 500;
  color: var(--pf-black);
}

.pf-cards-grid__desc {
  margin: 0;
  font-size: 0.906rem;
  line-height: 1.5;
  color: var(--pf-body);
}

/* ==========================================================================
   CTA
   ========================================================================== */

.pf-cta {
  padding: 168px var(--pf-pad);
  background: transparent;
  font-family: 'Sneak', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
}

.pf-cta__inner {
  max-width: var(--pf-max);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.pf-cta__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 170px;
  padding: 16px 36px;
  background: var(--pf-black);
  color: #ffffff;
  font-size: 1.1025rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  text-decoration: none;
  white-space: nowrap;
}

.pf-cta__button:hover {
  background: #1a1a1a;
}

.pf-cta__text {
  max-width: 524px;
  margin: 30px 0 0;
  font-size: 1.1025rem;
  line-height: 1.6;
  color: var(--pf-muted);
}

.pf-cta__text + .pf-cta__text {
  margin-top: 16px;
}

.pf-cta__list {
  margin: 24px 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.95rem;
  line-height: 1.7;
  color: var(--pf-muted);
}

.pf-cta__contact {
  margin: 30px 0 0;
  font-size: 1.1025rem;
  line-height: 1.6;
}

.pf-cta__email {
  color: var(--pf-black);
  text-decoration: none;
}

.pf-cta__email:hover {
  text-decoration: underline;
}

.pf-cta__address {
  color: var(--pf-muted);
}

.pf-cta__heading {
  margin: 0;
  max-width: 620px;
  font-size: clamp(1.8rem, 1.3rem + 1.6vw, 2.5rem);
  line-height: 1.12;
  letter-spacing: -0.02em;
  font-weight: 400;
  color: var(--pf-black);
}

/* ==========================================================================
   Contact form — the site's own pixel language applied to a real form:
   pixel-notched fields, a consent checkbox that "materialises" like the
   cards do, and a decorative cursor by the message label that blinks
   faster while you're actually typing.
   ========================================================================== */

.pf-form {
  width: 100%;
  max-width: 620px;
  margin: 56px 0 0;
  text-align: left;
}

.pf-form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

.pf-field {
  margin: 20px 0 0;
  display: flex;
  flex-direction: column;
}
.pf-form__row .pf-field {
  margin-top: 0;
}
.pf-form__row {
  margin-top: 20px;
}
.pf-form > .pf-field:first-child {
  margin-top: 0;
}

.pf-field label {
  font-family: 'SFMono-Regular', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pf-muted);
  margin: 0 0 8px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.pf-field label abbr {
  color: #1264f5;
  text-decoration: none;
  margin-left: 2px;
}

.pf-field input,
.pf-field select,
.pf-field textarea {
  width: 100%;
  height: 52px;
  padding: 0 18px;
  background: #f4f4f2;
  border: 1px solid rgba(10, 10, 10, 0.1);
  font-family: 'Sneak', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
  font-size: 15px;
  color: var(--pf-black);
  transition: border-color 0.2s ease, background 0.2s ease;
}

.pf-field textarea {
  height: auto;
  padding: 14px 18px;
  resize: vertical;
  line-height: 1.5;
}

.pf-field select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--pf-black) 50%),
    linear-gradient(135deg, var(--pf-black) 50%, transparent 50%);
  background-position: calc(100% - 22px) center, calc(100% - 16px) center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 40px;
}

.pf-field input:hover,
.pf-field select:hover,
.pf-field textarea:hover {
  border-color: rgba(10, 10, 10, 0.25);
}

.pf-field input:focus,
.pf-field select:focus,
.pf-field textarea:focus {
  outline: none;
  border-color: #1264f5;
  background-color: #ffffff; /* not the `background` shorthand — it would reset select's arrow background-image to none */
  box-shadow: 0 0 0 3px rgba(18, 100, 245, 0.14);
}

.pf-field input[aria-invalid="true"],
.pf-field textarea[aria-invalid="true"] {
  border-color: #e0492a;
}

.pf-field__error {
  margin: 6px 0 0;
  font-size: 12.5px;
  color: #e0492a;
}

.pf-field--honeypot {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

/* Decorative blinking cursor by the message label — speeds up while
   the field actually has focus, like a line being typed. */
.pf-form__cursor {
  display: inline-block;
  width: 6px;
  height: 12px;
  background: #1264f5;
  animation: picon-blink 1.1s steps(1, end) infinite;
}
.pf-field.is-typing .pf-form__cursor {
  animation-duration: 0.4s;
}

/* ---- Custom consent checkbox: materialises from pixels when checked,
   same idiom as the cards, rather than a borrowed checkmark glyph ---- */

.pf-check {
  margin: 28px 0 0;
  display: flex;
  align-items: flex-start;
  gap: 14px;
  cursor: pointer;
}

.pf-check__input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.pf-check__box {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  margin-top: 2px;
  background: #f4f4f2;
  border: 1px solid rgba(10, 10, 10, 0.18);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 2px;
  padding: 4px;
  transition: border-color 0.2s ease;
}

.pf-check__box span {
  background: #1264f5;
  opacity: 0;
  transform: scale(0);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease;
}

.pf-check__box span:nth-child(1) { transition-delay: 0ms; }
.pf-check__box span:nth-child(2) { transition-delay: 30ms; }
.pf-check__box span:nth-child(3) { transition-delay: 60ms; }
.pf-check__box span:nth-child(4) { transition-delay: 20ms; }
.pf-check__box span:nth-child(5) { transition-delay: 50ms; }
.pf-check__box span:nth-child(6) { transition-delay: 80ms; }
.pf-check__box span:nth-child(7) { transition-delay: 40ms; }
.pf-check__box span:nth-child(8) { transition-delay: 70ms; }
.pf-check__box span:nth-child(9) { transition-delay: 100ms; }

.pf-check__input:checked ~ .pf-check__box {
  border-color: #1264f5;
}
.pf-check__input:checked ~ .pf-check__box span {
  opacity: 1;
  transform: scale(1);
}
.pf-check__input:focus-visible ~ .pf-check__box {
  box-shadow: 0 0 0 3px rgba(18, 100, 245, 0.25);
}

.pf-check__label {
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--pf-body);
}
.pf-check__label a {
  color: var(--pf-black);
  text-decoration: underline;
}

.pf-form__footer {
  margin: 32px 0 0;
  display: flex;
  align-items: center;
  gap: 20px;
}

.pf-form__submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 52px;
  padding: 0 32px;
  background: var(--pf-black);
  color: #fff;
  border: none;
  font-family: 'Sneak', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.pf-form__submit:hover {
  background: #1264f5;
}
.pf-form__submit:disabled {
  opacity: 0.6;
  cursor: default;
}

.pf-form__note {
  font-size: 13px;
  color: var(--pf-muted);
}

.pf-form__status {
  margin: 18px 0 0;
  font-size: 13.5px;
}
.pf-form__status[data-state="ok"] { color: #1264f5; }
.pf-form__status[data-state="error"] { color: #e0492a; }

@media (prefers-reduced-motion: reduce) {
  .pf-form__cursor,
  .pf-check__box span,
  .pf-form__submit {
    transition: none;
    animation: none;
  }
}

@media (max-width: 640px) {
  .pf-form__row {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .pf-form__row .pf-field {
    margin-top: 20px;
  }
  .pf-form__row .pf-field:first-child {
    margin-top: 0;
  }
  .pf-form__footer {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 768px) {
  .pf-projects {
    padding: 64px 24px;
  }

  .pf-cta {
    padding: 96px 24px;
  }

  .pf-cards-grid {
    margin: 32px -24px 0;
  }

  .pf-cards-grid__row {
    grid-template-columns: repeat(2, 1fr);
    padding: 0;
  }

  .pf-cards-grid__cell {
    padding: 40px 24px;
  }

  .pf-cards-grid__cell:nth-child(2n) {
    border-right: none;
  }

  .pf-projects__body {
    font-size: 1rem;
  }
}

@media (max-width: 560px) {
  .pf-cards-grid__row {
    grid-template-columns: 1fr;
  }

  .pf-cards-grid__cell {
    border-right: none;
    border-bottom: 1px solid rgba(10, 10, 10, 0.12);
  }

  .pf-cards-grid__cell:last-child {
    border-bottom: none;
  }
}

/* ==========================================================================
   Marquee — scrolling pixel-text between the contact form and the footer.
   Same technique as craft.wild.as's own bottom marquee (assets/js/
   marquee-text.js has the full breakdown); the canvas is transparent so
   the page's own graph-paper grid (body background-image, see top of
   this file) shows through behind the letters, matching the reference.
   ========================================================================== */

.mq-marquee {
  width: 100%;
  /* Not symmetric on purpose: .pf-cta right above already ends in its
     own 168px bottom padding, so a plain 56px/56px here left the text
     sitting only 56px from the footer but 168+56=224px from the form's
     last visible line — closer to the footer than centred between the
     two. Zero top padding (the form's own padding already provides the
     gap above) and 168px bottom (matching .pf-cta's own padding, so the
     gap below matches the gap above) centres it for real. */
  padding: 0 0 168px;
  overflow: hidden;
}

.mq-marquee__canvas {
  display: block;
  width: 100%;
  height: 220px;
}

.mq-marquee__sr-text {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .mq-marquee {
    padding: 48px 24px;
  }
  .mq-marquee__canvas {
    display: none;
  }
  .mq-marquee__sr-text {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip: auto;
    white-space: normal;
    display: block;
    max-width: 760px;
    margin: 0 auto;
    text-align: center;
    font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
    font-size: 28px;
    line-height: 1.3;
    color: #0a0a0a;
  }
}

@media (max-width: 768px) {
  .mq-marquee {
    /* .pf-cta drops to 96px bottom padding at this width (see its own
       768px rule) — match it so the two sides stay balanced. */
    padding-bottom: 96px;
  }
  .mq-marquee__canvas {
    height: 130px;
  }
}

/* Footer — colophon (Videtexy legal/company block, replaces the
   Figma node 31020:3803 "play" button, which had no equivalent
   text content once the page became Videtexy's real copy). */

/* Footer — structure copied from mistral.ai's own real footer (found
   by scrolling all the way to document.body.scrollHeight and reading
   the actual last <footer>, not guessed): a full-bleed row of link
   columns divided by vertical rules — no brand there at all — then a
   divider, a row for brand-adjacent content, another divider, then a
   plain bottom bar with copyright on the left and a big graphic
   moment centred. Colour/type are this site's own light theme
   (Sneak, primary blue) rather than their dark navy; the "social
   icons | app badges" and "language selector" rows have no honest
   equivalent for this site, so that structural slot instead carries
   real Videtexy content (brand+description, registered-office facts)
   rather than inventing accounts or an app that don't exist. Every
   link is a real anchor to a section already on the page, an
   existing legal page, or the cookie-settings action — never a dead
   "#". */

.ft-footer {
  width: 100%;
  box-sizing: border-box;
  background: #fff;
  border-top: 1px solid rgba(10, 10, 10, 0.12);
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
}

/* ---- Row 1: divided link columns, full-bleed like the nav bar ---- */

.ft-links {
  display: flex;
  max-width: 1176px;
  margin: 0 auto;
  padding: 0 56px;
}

.ft-links__col {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 48px 32px 40px 32px;
  border-left: 1px solid rgba(10, 10, 10, 0.12);
}

.ft-links__col:first-child {
  border-left: none;
  padding-left: 0;
}

.ft-links__label {
  margin: 0 0 4px;
  font-size: 13px;
  font-weight: 500;
  color: #8b8b8b;
}

.ft-links__col a,
.ft-links__col > span,
.ft-links__linklike {
  font-size: 14px;
  line-height: 1.4;
  color: #2a2a2a;
  text-decoration: none;
  transition: color 0.15s ease;
}

.ft-links__col a,
.ft-links__linklike {
  display: inline-flex;
  align-items: center;
  position: relative;
  padding-right: 24px; /* constant space for the icon below, so its reveal never changes where long labels wrap */
}

/* The icon overlays instead of sitting in flow — on a wrapping label
   (e.g. "Software & Product Development") growing its width in flow
   would shrink the text's own available width on hover, changing
   where it wraps and jumping the whole column's layout. Same rule for
   .ft-links__linklike (the "Cookie settings" button) — it isn't an
   <a>, so it never matched this selector before and sat with its icon
   crammed in-flow right after the text instead of pinned to the edge
   like every real link in this column. */
.ft-links__col a .btn-icon,
.ft-links__linklike .btn-icon {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  margin-left: 0;
}
.ft-links__col a.flip-btn:hover .btn-icon,
.ft-links__linklike:hover .btn-icon {
  margin-left: 0;
}

.ft-links__col a:hover,
.ft-links__linklike:hover {
  color: #1264f5;
}

.ft-links__linklike {
  display: inline-flex;
  align-items: center;
  background: none;
  border: none;
  padding: 0 24px 0 0; /* right space kept for the icon — see .ft-links__col a, .ft-links__linklike above */
  margin: 0;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}

/* ---- Row 2: brand + description (left), registered-office facts
   (right) — this site's own stand-in for the reference's social
   icons / app-store badges row, which has no honest equivalent here ---- */

.ft-brand {
  display: flex;
  justify-content: space-between;
  gap: 40px;
  max-width: 1176px;
  margin: 0 auto;
  padding: 32px 56px;
  border-top: 1px solid rgba(10, 10, 10, 0.12);
}

.ft-colophon__brand {
  margin: 0 0 10px;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: #0a0a0a;
}

.ft-colophon__desc {
  margin: 0;
  max-width: 420px;
  font-size: 14px;
  line-height: 1.6;
  color: #5a5a5a;
}

.ft-brand__legal {
  margin: 0;
  max-width: 320px;
  font-size: 12.5px;
  line-height: 1.7;
  color: #8b8b8b;
  text-align: right;
}

/* ---- Row 3: plain bottom bar — copyright only. Used to also carry a
   static 7x7 pixel accent, echoing the reference's giant logo moment
   there — removed on request, kept just the copyright line. ---- */

.ft-bottom {
  display: flex;
  align-items: center;
  max-width: 1176px;
  margin: 0 auto;
  padding: 20px 56px 32px;
}

.ft-bottom__copy {
  margin: 0;
  font-size: 12.5px;
  color: #8b8b8b;
}

@media (max-width: 900px) {
  .ft-links {
    flex-wrap: wrap;
    padding: 0 24px;
  }
  .ft-links__col {
    flex: 1 1 45%;
    padding: 32px 16px 24px 16px;
  }
  .ft-links__col:nth-child(odd) {
    border-left: none;
    padding-left: 0;
  }
  .ft-brand {
    flex-direction: column;
    padding: 32px 24px;
  }
  .ft-brand__legal {
    text-align: left;
  }
  .ft-bottom {
    padding: 16px 24px 32px;
  }
}

/* ---- Row 4: the footer game (assets/js/footer-game.js) — ported from
   craft.wild.as's own footer-tetris.js after reading its source
   directly: a thin strip drifts small shapes forever; click it and
   it expands into a real playable game on the same wide board. Same
   mechanism there, but the game itself is a Galaga-style meteor
   shoot-'em-up instead of Tetris, and it uses only this site's own
   primary blue and its tints instead of the reference's five-hue
   palette. ---- */

.fg-strip {
  position: relative;
  width: 100%;
  height: 81px; /* 9 rows * 9px cell, matches the reference's own idle strip height */
  overflow: hidden;
  border-top: 1px solid rgba(10, 10, 10, 0.12);
  cursor: pointer;
  transition: height 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}

.fg-strip.is-playing {
  height: min(52vh, 420px);
  cursor: crosshair;
}

#footcity {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

.fg-teaser {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  border: 0;
  margin: 0;
  padding: 10px 18px;
  background: #0a0a0a;
  color: #fff;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-size: 13px;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: opacity 0.35s ease, transform 0.35s ease, background 0.15s ease;
}

.fg-teaser:hover {
  background: #1264f5;
}

.fg-strip.is-playing .fg-teaser {
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0.9);
}

#fgHud {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: none;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  pointer-events: none;
}

.fg-strip.is-playing #fgHud {
  display: block;
}

#fgHud .fg-score {
  position: absolute;
  top: 12px;
  left: 16px;
  padding: 4px 10px;
  background: rgba(255, 255, 255, 0.88);
  font-size: clamp(14px, 2vw, 20px);
  letter-spacing: 0.06em;
  color: #0a0a0a;
  font-variant-numeric: tabular-nums;
}

#fgHud .fg-hint {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  margin: 0;
  font-size: 11px;
  color: #8b8b8b;
  text-align: center;
  white-space: nowrap;
  transition: opacity 0.4s ease;
}

/* Only there to explain the controls to a first-time player — fades
   out (assets/js/footer-game.js's dismissHint()) the moment they
   actually move or shoot, instead of sitting over the board the
   whole run. */
#fgHud .fg-hint.is-dismissed {
  opacity: 0;
}

#fgHud .fg-pad {
  position: absolute;
  right: 18px;
  bottom: 18px;
  display: flex;
  gap: 6px;
  pointer-events: auto;
}

/* On a touch device the board itself is already the control: drag
   the ship, tap to shoot (see footer-game.js's mouseX/click wiring).
   The D-pad would just be redundant buttons eating space on an
   already-tight strip, so it only renders for a real mouse. */
@media (hover: none) and (pointer: coarse) {
  #fgHud .fg-pad {
    display: none;
  }
}

#fgHud .fg-pad button {
  border: 0;
  margin: 0;
  padding: 0;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  background: #fff;
  color: #0a0a0a;
  box-shadow: 0 2px 10px rgba(10, 10, 10, 0.14);
  cursor: pointer;
  pointer-events: auto;
  transition: background 0.15s ease, color 0.15s ease;
}

#fgHud .fg-pad button svg {
  width: 16px;
  height: 16px;
}

#fgHud .fg-pad button:hover {
  background: #1264f5;
  color: #fff;
}

/* Same shape + hover language as every other button on the site:
   pixel-notched, a flip-label that rolls over, an icon that slides in
   on the right — not a bespoke plain square. */
#fgHud .fg-close {
  position: absolute;
  top: 14px;
  right: 18px;
  z-index: 6;
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 14px;
  border: 0;
  margin: 0;
  background: #fff;
  color: #0a0a0a;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-size: 13px;
  font-weight: 500;
  box-shadow: 0 2px 10px rgba(10, 10, 10, 0.14);
  cursor: pointer;
  pointer-events: auto;
  transition: background 0.15s ease, color 0.15s ease;
}

#fgHud .fg-close:hover {
  background: #1264f5;
  color: #fff;
}

#fgHud .fg-over {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(3px);
}

#fgHud.is-over .fg-over {
  display: flex;
}

#fgHud .fg-over__title {
  font-size: clamp(18px, 2.6vw, 26px);
  color: #0a0a0a;
  letter-spacing: 0.01em;
}

#fgHud .fg-over__score {
  margin: 0;
  font-size: 13px;
  color: #5a5a5a;
  font-variant-numeric: tabular-nums;
}

/* Same shape + hover language as every other button on the site:
   pixel-notched, a flip-label that rolls over, an icon that slides in
   on the right — not a bespoke plain-background button. */
#fgHud .fg-over__again {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  border: 0;
  margin: 0;
  padding: 10px 22px;
  background: #1264f5;
  color: #fff;
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: background 0.15s ease;
}

#fgHud .fg-over__again:hover {
  background: #0a0a0a;
}

@media (prefers-reduced-motion: reduce) {
  .fg-strip,
  .fg-strip.is-playing .fg-teaser,
  #fgHud .fg-hint {
    transition: none;
  }
}

/* ==========================================================================
   More life — small touches spread across the page rather than one big
   effect: a pixel scroll progress bar, a bouncing back-to-top button,
   every numbered badge popping on hover, a CTA arrow that slides in,
   and a quiet "always on" pulse by the footer wordmark.
   ========================================================================== */

/* ---- Pixel scroll progress bar (assets/js/liveliness.js) ---- */

#scrollProgress {
  position: fixed;
  top: var(--nav-h); /* sits right under .site-nav, which would otherwise hide it (z-index 1000) */
  left: 0;
  width: 100%;
  height: 4px;
  z-index: 500;
  background: rgba(10, 10, 10, 0.06);
  pointer-events: none;
}

#scrollProgressFill {
  height: 100%;
  width: 0%;
  background: #1264f5;
  background-image: repeating-linear-gradient(
    to right,
    rgba(255, 255, 255, 0.55) 0,
    rgba(255, 255, 255, 0.55) 1px,
    transparent 1px,
    transparent 8px
  );
  transition: width 0.1s linear;
}

@media (prefers-reduced-motion: reduce) {
  #scrollProgressFill {
    transition: none;
  }
}

/* ---- Back to top ---- */

#toTop {
  position: fixed;
  right: 28px;
  bottom: 28px;
  z-index: 500;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0a0a0a;
  border: none;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.25s ease, transform 0.25s ease, background 0.2s ease;
  animation: totop-bounce 2.6s ease-in-out infinite;
}

#toTop.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* the footer game's D-pad sits in the same bottom-right corner —
   hidden while playing so the two never overlap (see fg-strip below) */
body.fg-playing #toTop {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

#toTop .flip-label,
#toTop .flip-label__inner {
  height: 16px;
}

#toTop img {
  display: block;
  width: 16px;
  height: 16px;
  transform: rotate(-90deg);
}

#toTop:hover {
  background: #1264f5;
}

@keyframes totop-bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-5px); }
}

#toTop.is-visible {
  animation-play-state: running;
}
#toTop:not(.is-visible) {
  animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
  #toTop {
    animation: none;
    transition: opacity 0.25s ease;
    transform: none;
  }
}

/* ---- Numbered badge + its label grow together on hover, and the
   label text flips — one simple move instead of the badge scaling
   and rotating on its own while the text next to it sat still.
   Same treatment everywhere a small pixel-notched badge sits beside
   a title (.ec-legend, .al-legend, .al-levels). ---- */

.ec-legend__item,
.al-legend__item,
.al-levels__item {
  transition: transform 0.2s ease;
}

.ec-legend__head,
.al-legend__head {
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.ec-legend__item:hover .ec-legend__head,
.al-legend__item:hover .al-legend__head {
  transform: scale(1.08);
}

.ec-legend__num,
.al-legend__index {
  transition: background 0.2s ease;
}

.ec-legend__item:hover .ec-legend__num,
.al-legend__item:hover .al-legend__index {
  background: #1264f5;
}

.al-levels__tag {
  display: inline-block;
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.2s ease;
}

.al-levels__item-title {
  display: inline-block;
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.al-levels__item:hover .al-levels__tag {
  transform: scale(1.15);
  color: #1264f5;
}

.al-levels__item:hover .al-levels__item-title {
  transform: scale(1.08);
}

/* The label/title itself rolls over — the same .flip-label mechanic
   every CTA button already uses, just triggered by hovering the row
   instead of a .flip-btn. */
.ec-legend__item:hover .flip-label__inner,
.al-legend__item:hover .flip-label__inner,
.al-levels__item:hover .flip-label__inner {
  transform: translateY(-100%);
}

@media (prefers-reduced-motion: reduce) {
  .ec-legend__head,
  .al-legend__head,
  .ec-legend__num,
  .al-legend__index,
  .al-levels__tag,
  .al-levels__item-title {
    transition: none;
  }
  .ec-legend__item:hover .ec-legend__head,
  .al-legend__item:hover .al-legend__head,
  .al-levels__item:hover .al-levels__tag,
  .al-levels__item:hover .al-levels__item-title {
    transform: none;
  }
}

/* ---- Shared hover mechanic for every actionable text button on the
   site (hero CTA, nav CTA, header secondary link, form submit, footer
   "Cookie settings", cookie-bar accept/decline): the label rolls up
   and is replaced by an identical copy rolling in from below, and a
   contextual icon pops in on the right with a bouncy entrance, then
   keeps a small idle bob for as long as it's hovered. One system
   (`.flip-btn` + `.flip-label` + `.btn-icon`) instead of one-off CSS
   per button, so adding it anywhere just means adding the classes.
   Icons are real pixelarticons.com glyphs, never invented. ---- */

.ec-btn {
  gap: 0;
}

.flip-label {
  position: relative;
  display: inline-block;
  overflow: hidden;
}
.flip-label__inner {
  display: block;
  transition: transform 0.35s cubic-bezier(0.65, 0, 0.35, 1);
}
.flip-label__inner + .flip-label__inner {
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
}
.flip-btn:hover .flip-label__inner {
  transform: translateY(-100%);
}

.btn-icon {
  display: inline-flex;
  align-items: center;
  width: 0;
  margin-left: 0;
  opacity: 0;
  overflow: hidden;
  transition: width 0.25s ease, margin-left 0.25s ease, opacity 0.25s ease;
}
.btn-icon__glyph {
  width: 1em; /* scales with each button's own font-size instead of a fixed px per variant */
  height: 1em;
  flex-shrink: 0;
  display: block;
}
.flip-btn:hover .btn-icon {
  width: 1em;
  margin-left: 8px;
  opacity: 1;
}
.flip-btn:hover .btn-icon__glyph {
  animation: btn-icon-pop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) both,
    btn-icon-bob 1.1s ease-in-out 0.45s infinite;
}
@keyframes btn-icon-pop {
  0% { transform: scale(0.2) rotate(-35deg); }
  55% { transform: scale(1.3) rotate(10deg); }
  75% { transform: scale(0.9) rotate(-6deg); }
  100% { transform: scale(1) rotate(0deg); }
}
@keyframes btn-icon-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-2px); }
}

@media (prefers-reduced-motion: reduce) {
  .flip-label__inner,
  .btn-icon {
    transition: none;
  }
  /* Matching the hover rule's own specificity (.flip-btn:hover
     .btn-icon__glyph) — a bare .btn-icon__glyph here would lose the
     cascade to it and keep animating, the same specificity mistake
     already caught this session on .picon__glyph. */
  .flip-btn:hover .btn-icon__glyph {
    animation: none;
  }
}

/* ---- Submit button lifts slightly on hover, on top of its colour swap ---- */

.pf-form__submit:hover {
  transform: translateY(-2px);
}

/* ---- CTA press "wow": a snappy squash-and-overshoot bounce plus a
   burst of small pixel squares from the press point, in this site's
   own blue tiers — the same pixel-grid language as squares.js and the
   footer game, not a generic ripple. Triggered via JS
   (assets/js/cta-press.js) on pointerdown/keydown rather than a plain
   CSS :active rule, so the full animation always plays out even on
   the fastest possible click or tap, instead of being cut short by
   however long the real press happens to last. Scoped to the site's
   three primary CTAs (hero, nav, form submit) via .cta-burst. ---- */

.cta-burst.is-punching {
  animation: cta-punch 0.42s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes cta-punch {
  0% { transform: scale(1); }
  35% { transform: scale(0.9); }
  65% { transform: scale(1.05); }
  100% { transform: scale(1); }
}

.cta-burst__piece {
  position: fixed;
  left: var(--ox);
  top: var(--oy);
  width: var(--sz);
  height: var(--sz);
  background: var(--pc);
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  animation: cta-burst-fly 0.55s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes cta-burst-fly {
  0% { transform: translate(-50%, -50%) translate(0, 0) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -50%) translate(var(--dx), var(--dy)) scale(0.3); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  /* Belt-and-suspenders: cta-press.js already skips spawning pieces
     and adding .is-punching under reduced motion, matching this
     project's own double-safety convention elsewhere. */
  .cta-burst.is-punching {
    animation: none;
  }
}

/* ---- Footer brand mark — same "Squares Part" mark as the nav, no
   interaction here since this line is plain text, not a link. The
   plain blinking dot this used to be is gone along with it. ---- */

.ft-colophon__brand {
  display: flex;
  align-items: center;
  gap: 8px;
}

.ft-colophon__mark {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

/* ==========================================================================
   Cookie bar (assets/js/cookie-consent.js) — bottom-left, deliberately
   not full-width or right-anchored so it never collides with #toTop.
   ========================================================================== */

.cookie-bar {
  position: fixed;
  left: 20px;
  bottom: 20px;
  z-index: 900;
  width: min(400px, calc(100vw - 40px));
  background: #fff;
  border: 1px solid rgba(10, 10, 10, 0.14);
  box-shadow: 0 16px 40px rgba(10, 10, 10, 0.16);
  padding: 20px;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
}
.cookie-bar[hidden] {
  display: none;
}
.cookie-bar__inner {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.cookie-bar__text {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: #3a3a3a;
}
.cookie-bar__text a {
  color: #1264f5;
  text-decoration: underline;
}
.cookie-bar__actions {
  display: flex;
  align-items: center;
  gap: 16px;
}
.cookie-bar__btn {
  display: inline-flex;
  align-items: center;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  border: none;
  transition: background-color 0.2s ease, color 0.2s ease;
}
.cookie-bar__btn--quiet {
  background: none;
  padding: 0;
  color: #5a5a5a;
  text-decoration: none;
}
.cookie-bar__btn--quiet .flip-label {
  text-decoration: underline;
}
.cookie-bar__btn--quiet:hover {
  color: #0a0a0a;
}
.cookie-bar__btn:not(.cookie-bar__btn--quiet) {
  background: #0a0a0a;
  color: #fff;
  padding: 10px 20px;
}
.cookie-bar__btn:not(.cookie-bar__btn--quiet):hover {
  background: #1264f5;
}

@media (prefers-reduced-motion: reduce) {
  .cookie-bar__btn {
    transition: none;
  }
}

/* ==========================================================================
   Legal pages (privacy.html, terms.html, cookies.html) — same nav,
   footer and cursor field as index.html, a plain reading layout for
   the page itself.
   ========================================================================== */

.lg-pagehead {
  max-width: 1176px;
  margin: 0 auto;
  padding: 64px 56px 40px;
}
.lg-pagehead__crumbs {
  margin: 0 0 20px;
  font-size: 13px;
  color: #8b8b8b;
}
.lg-pagehead__crumbs a {
  color: #8b8b8b;
  text-decoration: underline;
}
.lg-pagehead__crumbs a:hover {
  color: #0a0a0a;
}
.lg-pagehead__title {
  margin: 0 0 20px;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
  font-size: 44px;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  color: #0a0a0a;
}
.lg-pagehead__lede {
  max-width: 720px;
  margin: 0 0 12px;
  font-size: 16px;
  line-height: 1.6;
  color: #2a2a2a;
}

/* 404.html only — a CTA back to the homepage, sitting with the page
   heading rather than in .lg-prose (that block's own `a` styling —
   blue, underlined — is meant for legal-text links, and would win
   over .ec-btn's white/no-underline on specificity, same class count
   plus the element selector). */
.lg-pagehead__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin: 32px 0 0;
}

/* Secondary CTA next to "Back to home" (404.html's "Play a game") —
   .ec-btn's own solid dark fill is reserved for the one primary action
   in a group; this is the same shape and hover language, just outlined
   instead of filled so the two don't compete. */
.ec-btn--ghost {
  background: #fff;
  color: var(--ec-ink, #0a0a0a);
  border: 1px solid rgba(10, 10, 10, 0.3);
}
.ec-btn--ghost:hover {
  background: #1264f5;
  color: #fff;
  border-color: #1264f5;
}

/* 404.html only — the whole hero doubles as a live preview of the
   footer's own game (assets/js/footer-game.js): .fg-strip's canvas
   sits full-bleed behind the copy instead of in a callout further
   down the page, so the entire above-the-fold view is the "preview"
   rather than something only a scroll-all-the-way-down visitor would
   ever find. #footcity has to stay a singleton, so the footer's own
   copy is removed on this page (see the HTML comment there). Only the
   explicit "Play a game" button starts it here (see footer-game.js's
   clickToStart) — the background itself isn't a click target, since
   on this page it's the whole hero rather than a dedicated widget.
   Once playing, the error copy fades out below (its own
   .lg-pagehead__inner rule) so the game board isn't fighting a "This
   page does not exist" heading for attention. */
.lg-pagehead--play {
  position: relative;
  max-width: none;
  margin: 0;
  padding: 0;
  min-height: calc(100vh - var(--nav-h));
  overflow: hidden;
}

.lg-pagehead__game {
  position: absolute;
  inset: 0;
  height: auto; /* inset:0 alone already stretches it to fill the hero */
  border-top: 0;
}

.lg-pagehead__game.is-playing {
  height: auto; /* keep filling the hero instead of shrinking to the footer strip's own min(52vh, 420px) */
}

.lg-pagehead__inner {
  position: relative;
  z-index: 2;
  max-width: 1176px;
  margin: 0 auto;
  padding: 64px 56px 40px;
  transition: opacity 0.3s ease;
}

/* #fgHud's own z-index (3) is set on a descendant that isn't inside a
   stacking context of its own (.fg-strip has no z-index, so it never
   becomes one) — it ends up compared against .lg-pagehead__inner's
   z-index (2) at whatever real stacking context sits above both, and
   wins. So while playing, the HUD already paints over this copy
   rather than the other way around; fading the copy out here (instead
   of trying to fix the stacking order) also removes the "This page
   does not exist" heading from view entirely, which is the actual
   goal — a distraction-free board, not just a correctly-ordered one. */
.lg-pagehead__game.is-playing ~ .lg-pagehead__inner {
  opacity: 0;
  pointer-events: none;
}

@media (max-width: 640px) {
  .lg-pagehead--play {
    min-height: 480px; /* 100vh reads too tall once the on-screen keyboard/browser chrome eats into it */
  }
}
.lg-pagehead__meta {
  margin: 0;
  font-size: 13px;
  color: #8b8b8b;
}

/* Same box as .lg-pagehead (max-width:1176px, padding-left:56px) so
   this section's left edge lines up with the title/lede above it —
   .lg-prose used to be its own narrower (776px) centered column,
   which kept its own left edge but shifted it right of everything
   above, reading as center-aligned body copy under a left-aligned
   heading. The 720px reading-width cap now lives on the headings/
   paragraphs themselves instead, so lines still don't run too wide,
   but nothing is centered any more. */
.lg-prose {
  max-width: 1176px;
  margin: 0 auto;
  padding: 0 56px 96px;
  font-family: 'Sneak', 'Helvetica Neue', Arial, sans-serif;
}
.lg-prose h2 {
  max-width: 720px;
  margin: 40px 0 12px;
  font-size: 19px;
  font-weight: 600;
  color: #0a0a0a;
}
.lg-prose h2:first-child {
  margin-top: 0;
}
.lg-prose p {
  max-width: 720px;
  margin: 0 0 16px;
  font-size: 15px;
  line-height: 1.7;
  color: #2a2a2a;
}
.lg-prose a {
  color: #1264f5;
  text-decoration: underline;
}

@media (max-width: 640px) {
  /* .lg-pagehead__inner (404.html's merged hero) never had a mobile
     override of its own — it kept the desktop 64px/56px padding at
     every width, so on a 375px phone the actual text column was only
     ~260px wide (375 - 56*2), squeezed and wrapping hard, instead of
     matching every other page's same 24px side padding below. */
  .lg-pagehead,
  .lg-pagehead__inner {
    padding: 40px 24px 32px;
  }
  .lg-pagehead__title {
    font-size: 32px;
  }
  .lg-prose {
    padding: 0 24px 64px;
  }
  /* Same full-width treatment as .hh-header__ctas's own CTAs — stack
     "Back to home" and "Play a game" and let each fill the row. */
  .lg-pagehead__actions {
    flex-direction: column;
    align-items: stretch;
  }
  .lg-pagehead__actions .ec-btn {
    width: 100%;
  }
}
