    /* ════════════════════════════════════════════════════
       GLOBAL FOOTER
       1. Final CTA + logo marquee
       2. Link columns + bottom bar
       3. Dark scroll-up reveal end-piece
    ════════════════════════════════════════════════════ */

    /* ── Overscroll canvas — Ben's source set `html { background-color:
       var(--color-bg-primary) }` here for the top rubber-band bounce.
       Deliberately dropped in the port: it would tint every LEGACY page's
       root canvas from white to cloud (#F4F4F4). Top bounce shows white
       instead; the BOTTOM bounce stays dark because the fixed reveal
       layer bleeds 300px below the viewport (see .footer-reveal). ── */

    /* ── Reveal cover — wraps ALL page content (see integration note).
       Solid background so nothing bleeds through to the fixed dark layer
       pinned behind the page. Port note: white, not var(--color-bg-primary)
       — legacy pages assume a white body canvas, and redesign pages paint
       their own cloud canvas via their `.tc` page wrapper (as does the
       footer via its own .tc scope), so nothing here shows through. ── */
    .footer-reveal-cover {
      position: relative;
      z-index: 1;
      background: #fff;
    }

    /* ────────────────────────────────────────────────────
       1. FINAL CTA + MARQUEE
    ──────────────────────────────────────────────────── */
    .footer-cta {
      position: relative;
      /* A step more breathing room than the standard section rhythm — the
         marquee needs air above and below the content. Mobile gets extra
         height so the outer marquee rows sit clear of the content. */
      padding: calc(var(--spacing-section) + var(--spacing-2xl)) 0;
      text-align: center;
      overflow: hidden;
    }
    @media (min-width: 768px) {
      .footer-cta { padding: calc(var(--spacing-section) + var(--spacing-lg)) 0; }
    }

    /* Marquee — full window width, behind the content, on the same
       vertical level. Fades into the window edges via the mask. */
    .footer-cta-marquee {
      position: absolute;
      inset: 0;
      padding: var(--spacing-2xl) 0;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      pointer-events: none;
      -webkit-mask-image: linear-gradient(to right, transparent 0%, black 12%, black 88%, transparent 100%);
              mask-image: linear-gradient(to right, transparent 0%, black 12%, black 88%, transparent 100%);
    }
    .footer-cta-row { overflow: hidden; }
    .footer-cta-track {
      display: flex;
      align-items: center;
      gap: var(--spacing-2xl);
      width: max-content;
      /* Duration per row is a scoped decorative value (same basis as the
         home hero reel's 46s). Slight variation keeps the rows organic. */
      animation: footer-cta-scroll 64s linear infinite;
    }
    .footer-cta-row:nth-child(2) .footer-cta-track {
      animation-duration: 76s;
      animation-direction: reverse;
    }
    .footer-cta-row:nth-child(3) .footer-cta-track { animation-duration: 70s; }
    @keyframes footer-cta-scroll {
      to { transform: translateX(-50%); }
    }
    /* Same contain-fit bounding box + ink-normalise treatment as the home
       hero reel (120×34 box, brightness(0) → graphite, muted). Kept a step
       quieter than the hero reel so copy stays comfortably readable. */
    .footer-cta-track img {
      width: 120px;
      height: 34px;
      object-fit: contain;
      flex: none;
      filter: brightness(0);
      opacity: 0.3;
    }
    @media (max-width: 767px) {
      .footer-cta-track img { width: 108px; height: 31px; }
    }
    @media (prefers-reduced-motion: reduce) {
      .footer-cta-track { animation: none; }
    }

    /* Scrim — fades the marquee out behind the heading/CTAs. Canvas-coloured
       radial bloom, so it reads as the logos dissolving under the content. */
    .footer-cta-scrim {
      position: absolute;
      inset: 0;
      pointer-events: none;
      /* Tight, strong core: fully opaque across the text/CTA footprint,
         then a fast falloff so the logos read clearly just beyond it.
         Mobile: the content spans most of the narrow viewport, so the
         ellipse runs wider and shorter than the desktop shape. */
      background: radial-gradient(ellipse 70% 40% at 50% 50%,
        var(--color-bg-primary) 38%,
        color-mix(in srgb, var(--color-bg-primary) 78%, transparent) 60%,
        transparent 80%);
    }
    @media (min-width: 768px) {
      .footer-cta-scrim {
        background: radial-gradient(ellipse 34% 64% at 50% 50%,
          var(--color-bg-primary) 38%,
          color-mix(in srgb, var(--color-bg-primary) 78%, transparent) 60%,
          transparent 80%);
      }
    }

    .footer-cta .tc-container {
      position: relative;
      z-index: 1;
    }
    .footer-cta h2 {
      max-width: 880px;
      margin: 0 auto var(--spacing-xl);
    }

    /* ────────────────────────────────────────────────────
       2. MAIN FOOTER — link columns + bottom bar
    ──────────────────────────────────────────────────── */
    .footer-main {
      position: relative;
      padding-top: var(--spacing-2xl);
    }
    /* Faded-end hairline separators (same treatment as the home hero sep). */
    .footer-main::before,
    .footer-bar::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: var(--border-thin);
      background: linear-gradient(to right, transparent, var(--color-bg-stroke) 12%, var(--color-bg-stroke) 88%, transparent);
    }

    /* Mobile: two flowing text columns (multicol) — the desktop column
       wrappers dissolve via display:contents so each link GROUP packs
       into the columns independently, avoiding the tall-row gaps a grid
       creates. Desktop (≥1024px): the 5-column grid. */
    .footer-cols {
      column-count: 2;
      column-gap: var(--gap-cards);
      padding-bottom: var(--spacing-2xl);
    }
    .footer-cols > div:not(.footer-brand-col) { display: contents; }
    .footer-group {
      break-inside: avoid;
      margin-bottom: var(--spacing-xl);
    }
    @media (min-width: 1024px) {
      .footer-cols {
        display: grid;
        grid-template-columns: 1.2fr 1fr 1fr 1fr 1fr;
        gap: var(--spacing-xl) var(--gap-cards);
      }
      .footer-cols > div:not(.footer-brand-col) { display: block; }
      .footer-group { margin-bottom: 0; }
    }

    /* Column 1 — brand. Spans the full width on mobile. */
    .footer-brand-col {
      column-span: all;
      margin-bottom: var(--spacing-xl);
      position: relative;
    }
    /* A small brand-wash bloom peaking just below-left of the lockup —
       the rainbow masked into a soft radial glow, per the DS's ambient
       wash guidance. Geometry/opacity are scoped decorative values. */
    .footer-brand-col::before {
      content: '';
      position: absolute;
      z-index: -1;
      width: 480px;
      height: 480px;
      left: -280px;   /* centre sits ~40px past the content column's left edge */
      top: -150px;
      pointer-events: none;
      background: var(--color-brand-wash);
      -webkit-mask: radial-gradient(circle closest-side at 50% 50%, #000 8%, transparent 75%);
              mask: radial-gradient(circle closest-side at 50% 50%, #000 8%, transparent 75%);
      opacity: 0.1;
    }
    @media (min-width: 1024px) {
      .footer-brand-col {
        column-span: none;
        margin-bottom: 0;
      }
    }
    .footer-brand { display: inline-flex; }
    .footer-brand img {
      height: 40px;   /* matches the final-cta logo's desktop size */
      width: auto;
    }

    /* Desktop stacked groups (e.g. Solutions → Services) separate via
       margin-top; on mobile the groups' own margin-bottom handles it
       (margin-top would double up at column breaks). */
    @media (min-width: 1024px) {
      .footer-group + .footer-group { margin-top: var(--spacing-xl); }
    }
    /* Column headings render two steps down the scale (body) — the h4
       tag stays for structure, the footer runs small overall. */
    .footer-group h4 {
      font-size: var(--font-size-body);
      margin-bottom: 12px;   /* same 12px basis as the button gap exception */
    }

    .footer-list {
      list-style: none;
      display: flex;
      flex-direction: column;
      gap: 6px;   /* sub-8px micro-adjustment */
    }
    .footer-sublist {
      list-style: none;
      display: flex;
      flex-direction: column;
      gap: 6px;   /* sub-8px micro-adjustment */
      margin-top: 6px;
    }

    /* Link tiers. Tier 1: small body, semibold, slate → graphite on hover.
       Tier 2: tiny, fog → slate on hover. Both gain the CTA arrow,
       fading in while drifting away from the text. */
    .footer-link,
    .footer-sublink {
      display: inline-flex;
      align-items: center;
      transition: color var(--transition-fast), transform var(--transition-base);
    }
    /* All links share one resting colour (fog) and lift TWO palette steps
       to graphite on hover, drifting 2px in the arrow's direction so
       colour + motion + arrow read as one gesture. Tier hierarchy is
       carried by size alone. */
    .footer-link {
      font-size: var(--font-size-body-sm);
      color: var(--color-text-muted);
    }
    .footer-sublink {
      font-size: var(--font-size-body-sm);
      color: var(--color-text-muted);
    }
    .footer-link:hover,
    .footer-sublink:hover {
      color: var(--color-text-primary);
      transform: translateX(2px);
    }

    /* "New" pill — micro label after a link's text, status green.
       10px sits a step below --font-size-tiny (micro-label exception);
       2/6px padding keeps the pill tight. */
    .footer-new-tag {
      font-size: 11px;
      line-height: 1;
      letter-spacing: var(--letter-spacing-normal);
      font-weight: var(--font-weight-semibold);
      color: var(--color-text-primary);
      background: color-mix(in srgb, var(--color-success) 18%, transparent);
      border-radius: var(--radius-full);
      padding: 2px 6px;
      margin-left: 6px;
    }

    /* Hover arrow — Lucide arrow-right as a CSS mask so it takes
       currentColor. (SVG-in-CSS data URI: documented exception.) */
    .footer-link::after,
    .footer-sublink::after {
      content: '';
      width: 0.8em;
      height: 0.8em;
      margin-left: var(--spacing-xs);
      flex: none;
      background: currentColor;
      -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
              mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
      opacity: 0;
      transform: translateX(-4px);
      transition: opacity var(--transition-base), transform var(--transition-base);
    }
    .footer-link:hover::after,
    .footer-sublink:hover::after {
      opacity: 1;
      transform: translateX(0);
    }

    /* ── Bottom bar — 50px tall: 16px padding + ~17px content line. ── */
    .footer-bar {
      position: relative;
      padding: var(--spacing-sm) 0;
    }
    .footer-bar-inner {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: var(--spacing-sm);
      text-align: center;
    }
    @media (min-width: 1024px) {
      .footer-bar-inner {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        align-items: center;
        text-align: left;
      }
      .footer-bar-social { justify-self: start; }
      .footer-bar-status { justify-self: center; }
      .footer-bar-legal  { justify-self: end; }
    }

    .footer-bar-legal {
      font-size: var(--font-size-tiny);
      color: var(--color-text-muted);
    }

    .footer-bar-social {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
    }
    .footer-bar-social-label {
      font-size: var(--font-size-tiny);
      color: var(--color-text-muted);
    }
    .footer-social-links {
      display: flex;
      align-items: center;
      gap: var(--spacing-sm);
    }
    /* Standalone social glyphs — muted ink, lifting to graphite on hover. */
    .footer-social-links a {
      color: var(--color-text-muted);
      display: inline-flex;
      transition: color var(--transition-fast);
    }
    .footer-social-links a:hover { color: var(--color-text-primary); }
    .footer-social-links svg {
      width: var(--spacing-sm);
      height: var(--spacing-sm);
      display: block;
    }

    .footer-bar-status {
      display: inline-flex;
      align-items: center;
      gap: var(--spacing-xs);
      font-size: var(--font-size-tiny);
      color: var(--color-text-muted);
      transition: color var(--transition-fast);
    }
    .footer-bar-status:hover { color: var(--color-text-secondary); }
    .footer-status-orb {
      width: var(--spacing-xs);
      height: var(--spacing-xs);
      border-radius: var(--radius-full);
      background: var(--color-success);
      box-shadow: 0 0 6px color-mix(in srgb, var(--color-success) 70%, transparent);
      animation: footer-status-pulse 3s ease-in-out infinite;
    }
    @keyframes footer-status-pulse {
      0%, 100% { box-shadow: 0 0 4px color-mix(in srgb, var(--color-success) 50%, transparent); }
      50%      { box-shadow: 0 0 9px color-mix(in srgb, var(--color-success) 85%, transparent); }
    }
    @media (prefers-reduced-motion: reduce) {
      .footer-status-orb { animation: none; }
    }

    /* ────────────────────────────────────────────────────
       3. SCROLL-UP REVEAL END-PIECE
       Ported from the approved footer-reveal design reference —
       high-fidelity values (dark bg, wash ramp, masks, opacities,
       60/36px spacing) are approved hard-coded exceptions and are
       intentionally outside the token system. The page scrolls up
       off this fixed layer; the spacer provides the extra runway.
    ──────────────────────────────────────────────────── */
    .footer-reveal,
    .footer-reveal-spacer {
      /* 60px above / 36px below the logo — approved end-piece spacing —
         plus 30px extra dark runway ABOVE the logo (more scroll distance;
         the logo's resting position is unchanged). */
      --fr-above: calc(60px + 30px);
      --fr-below: 36px;
      /* Logo column = the 1280px container minus its 40px gutters. */
      --fr-logo-w: min(
        calc(var(--container-max) - var(--container-padding-tablet) * 2),
        calc(100vw - var(--container-padding-tablet) * 2)
      );
    }

    .footer-reveal {
      position: fixed;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: 0;
      background: #0E0E0E;   /* approved end-piece black — deeper than graphite */
      overflow: hidden;
      padding: var(--fr-above) 0 var(--fr-below);
      /* Bleed below the viewport so the bottom rubber-band bounce shows
         dark, not the canvas behind; the extra padding puts the logo's
         resting position back where it was. */
      bottom: -300px;
      padding-bottom: calc(var(--fr-below) + 300px);
      /* Hidden dark headroom above the end-piece (border-top isn't clipped
         by overflow:hidden and doesn't move the content). At rest it sits
         behind the page; on overscroll rubber-band the page lifts past the
         end-piece's top and the bounce reveals dark, not bare canvas.
         CAPPED at 120px (was 40vh): taller headroom made the fixed layer
         exceed short viewports, so the dark showed through at the TOP
         bounce behind the nav. 120px covers any realistic rubber-band. */
      border-top: 120px solid #0E0E0E;
      display: flex;
      justify-content: center;
      pointer-events: none;
    }

    /* Muted brand wash climbing 34% up from the bottom edge. Ramp colours
       are the approved muted brand stops (no yellow) — exact per spec. */
    .footer-reveal-wash {
      position: absolute;
      /* Stop above the layer's 300px overscroll bleed so the wash ramp
         stays within the visible end-piece (inset:0 pushed its strong
         zone below the viewport). */
      inset: 0 0 300px 0;
      pointer-events: none;
      background: linear-gradient(90deg, #14454A 0%, #1F3F63 26%, #3D3169 52%, #4E2848 76%, #5C3A24 100%);
      -webkit-mask: linear-gradient(180deg, transparent 56%, #000 100%);
              mask: linear-gradient(180deg, transparent 56%, #000 100%);
      opacity: 0.5;
    }

    /* Giant ghost lockup — two stacked copies of the same PNG so the icon
       and wordmark fade out over their own (different) vertical spans.
       Mask stops are luminance values, not design colours. */
    .footer-reveal-logo {
      position: relative;
      width: var(--fr-logo-w);
      /* Pin the logo box to the lockup SVG's intrinsic ratio (viewBox
         158×48) so the end-piece's height ALWAYS matches the spacer's
         ghost, even if the asset fails to load. */
      aspect-ratio: 158 / 48;
    }
    .footer-reveal-logo img {
      display: block;
      width: 100%;
      height: auto;
      filter: invert(1);   /* black mono lockup → white */
      opacity: 0.12;
    }
    /* Icon layer — left 18% of the lockup; fades over the full height,
       reaching zero only at the very bottom (never hard-clips the mark). */
    .footer-reveal-logo img.footer-reveal-icon {
      clip-path: inset(0 82% 0 0);
      -webkit-mask: linear-gradient(180deg, #000 0%, #000 12%, rgba(0,0,0,0.45) 55%, rgba(0,0,0,0.12) 85%, transparent 100%);
              mask: linear-gradient(180deg, #000 0%, #000 12%, rgba(0,0,0,0.45) 55%, rgba(0,0,0,0.12) 85%, transparent 100%);
    }
    /* Wordmark layer — the text spans ~y30–72% of the lockup, so its fade
       is compressed to that band. */
    .footer-reveal-logo img.footer-reveal-wordmark {
      position: absolute;
      inset: 0;
      clip-path: inset(0 0 0 18%);
      -webkit-mask: linear-gradient(180deg, #000 30%, rgba(0,0,0,0.5) 48%, rgba(0,0,0,0.14) 64%, transparent 74%);
              mask: linear-gradient(180deg, #000 30%, rgba(0,0,0,0.5) 48%, rgba(0,0,0,0.14) 64%, transparent 74%);
    }

    /* Film grain over the whole end-piece. */
    .footer-reveal-grain {
      position: absolute;
      inset: 0;
      pointer-events: none;
      mix-blend-mode: overlay;
      opacity: 0.5;
      background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="120" height="120"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2"/></filter><rect width="100%25" height="100%25" filter="url(%23n)" opacity="0.5"/></svg>');
    }

    /* Spacer — identical intrinsic height to .footer-reveal, purely to give
       the page the extra scroll distance that "lifts" it off the logo. */
    .footer-reveal-spacer {
      padding: var(--fr-above) 0 var(--fr-below);
      pointer-events: none;
      visibility: hidden;
    }
    .footer-reveal-spacer .footer-reveal-ghost {
      width: var(--fr-logo-w);
      aspect-ratio: 158 / 48;   /* matches the lockup SVG's viewBox */
      margin: 0 auto;
    }
