/* =========================================================================
   Farbridge Design System - Prototype 2 CSS 
========================================================================= */

@font-face {
  font-family: 'Oak Sans';
  font-weight: 300;
  font-style: normal;
  src: url('/assets/fonts/OakSans-Light.woff2') format('woff2');
  font-display: swap;
}

@font-face {
  font-family: 'Oak Sans';
  font-weight: 600;
  font-style: normal;
  src: url('/assets/fonts/OakSans-SemiBold.woff2') format('woff2');
  font-display: swap;
}

/* Inter, self-hosted. Was an @import from fonts.googleapis.com, which meant a
   third-party request on every pageview -- and a GDPR consideration for EU
   visitors. Only the latin and latin-ext subsets are shipped; the site is
   en/es/fr, so the cyrillic/greek/vietnamese subsets Google serves are dead
   weight. unicode-range is kept so the browser still only fetches what a
   given page actually needs. */

/* Inter 400 - latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/inter-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Inter 400 - latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/inter-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Inter 500 - latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/inter-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Inter 500 - latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/inter-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Inter 600 - latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/inter-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Inter 600 - latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/inter-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


:root {
  --brand-primary-blue: #1B9BFF;
  --brand-mint: #C4EDE2;
  --brand-off-white: #F5F5ED;
  --brand-gray: #B7B7C9;
  --brand-white: #FFFFFF;
  --bg-primary: var(--brand-white);
  --bg-secondary: var(--brand-off-white);
  --bg-tertiary: #EBEBE3;
  --text-primary: #111827;
  --text-secondary: #4B5563;
  /* WCAG 1.4.3: brand gray #B7B7C9 is 1.8:1 on off-white, so it stays a
     decorative colour and muted text gets its own value (5.5:1 on #F5F5ED). */
  --text-muted: #62626F;
  --text-inverse: var(--brand-white);
  /* WCAG 1.4.3: white on the brand blue #1B9BFF is 2.9:1, and so is the blue as
     text on white. Buttons, links and focus rings use this deeper action blue
     (5.8:1 against white); #1B9BFF stays for decorative accents. Dark mode
     keeps the brand blue, which already passes against the slate surfaces. */
  --action-primary: #0067B8;
  --action-hover: color-mix(in srgb, var(--action-primary) 85%, black);
  --action-secondary: var(--brand-mint);
  --border-light: #E5E7EB;
  --border-medium: var(--brand-gray);
  /* WCAG 1.4.11: a field's edge needs 3:1 against the page; --border-medium is 1.8:1. */
  --border-input: #7D7D90;
  --status-success: #9ACD32;
  --status-warning: #FCB900;
  --status-error: #EF4444;
  --font-primary: 'Oak Sans', sans-serif;
  --font-secondary: 'Inter', sans-serif;
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.5rem;
  --text-2xl: 2.25rem;
  --text-3xl: 3.5rem;
  --space-4: 0.25rem;
  --space-8: 0.5rem;
  --space-12: 0.75rem;
  --space-16: 1rem;
  --space-20: 1.25rem;
  --space-24: 1.5rem;
  --space-32: 2rem;
  --space-40: 2.5rem;
  --space-48: 3rem;
  --space-64: 4rem;
  --space-80: 5rem;
  --space-120: 7.5rem;
  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
  /* One tight contact shadow plus a wide, faint ambient one. Reads as a surface
     floating a little off the page, where --shadow-xl reads as stamped onto it. */
  --shadow-float: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.06);
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-full: 9999px;
  --transition-fast: 150ms ease-in-out;
  --transition-normal: 300ms ease-out;
  --glass-bg: rgba(255, 255, 255, 0.85);
}

[data-theme="dark"] {
  --bg-primary: #1F2937;
  --bg-secondary: #0F172A;
  --bg-tertiary: #1E293B;
  --text-primary: var(--brand-off-white);
  --text-secondary: var(--brand-gray);
  --text-muted: #9CA3AF;
  --text-inverse: #0F172A;
  --action-primary: var(--brand-primary-blue);
  --action-secondary: var(--brand-mint);
  --border-light: #334155;
  --border-medium: #475569;
  --border-input: #64748B;
  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.4);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5);
  --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.6);
  /* Same shape as the light value, deepened -- a 4% black shadow is invisible
     against a slate card. */
  --shadow-float: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.38);
  --glass-bg: rgba(15, 23, 42, 0.85);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* Page background (feedback A2). Light mode is flat white -- the client chose it
   over a blue gradient in Oct 2026 -- with no dot texture or wave (see the
   "feedback: theme" block at the end of this file). Dark mode keeps its slate
   gradient, built from these tokens. */
:root { --page-bg-end: var(--brand-white); --page-bg-stop: 100%; --page-dot: transparent; }
[data-theme="dark"] { --page-bg-end: var(--bg-secondary); --page-bg-stop: 100%; --page-dot: rgba(255, 255, 255, 0.05); }

body {
  position: relative;
  font-family: var(--font-secondary);
  background-color: var(--page-bg-end);
  background-image:
    radial-gradient(var(--page-dot) 1px, transparent 1px),
    linear-gradient(to bottom, var(--bg-primary) 0%, var(--page-bg-end) var(--page-bg-stop));
  background-size: 24px 24px, 100% 100%;
  background-attachment: scroll, fixed;
  color: var(--text-secondary);
  line-height: 1.6;
  font-size: var(--text-base);
  /* No background/colour transition: it made every theme toggle a 300ms
     full-viewport repaint of a fixed gradient (feedback A1). */
}

/* Option 9: CSS-Only Soft Organic Waves */
body::after {
  content: "";
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 380px;
  z-index: -1;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%23ffffff' fill-opacity='0.15' d='M0,192L48,181.3C96,171,192,149,288,144C384,139,480,149,576,176C672,203,768,245,864,245.3C960,245,1056,203,1152,181.3C1248,160,1344,160,1392,160L1440,160L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'/%3E%3Cpath fill='%23ffffff' fill-opacity='0.3' d='M0,224L48,208C96,192,192,160,288,165.3C384,171,480,213,576,218.7C672,224,768,192,864,181.3C960,171,1056,181,1152,192C1248,203,1344,213,1392,218.7L1440,224L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'/%3E%3C/svg%3E");
  background-size: 100% 100%;
  background-repeat: no-repeat;
  background-position: bottom;
  transform-origin: bottom;
  animation: wave-breathe 20s ease-in-out infinite alternate;
  opacity: 0.85;
  will-change: transform;
}

[data-theme="dark"] body::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%231B9BFF' fill-opacity='0.05' d='M0,192L48,181.3C96,171,192,149,288,144C384,139,480,149,576,176C672,203,768,245,864,245.3C960,245,1056,203,1152,181.3C1248,160,1344,160,1392,160L1440,160L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'/%3E%3Cpath fill='%23C4EDE2' fill-opacity='0.03' d='M0,224L48,208C96,192,192,160,288,165.3C384,171,480,213,576,218.7C672,224,768,192,864,181.3C960,171,1056,181,1152,192C1248,203,1344,213,1392,218.7L1440,224L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'/%3E%3C/svg%3E");
  /* At 3-5% opacity on slate the motion is imperceptible, so dark mode drops
     the infinite animation and its compositor layer (feedback A1). */
  animation: none;
  will-change: auto;
}

@keyframes wave-breathe {
  0% {
    transform: scaleY(0.85) translateY(15px);
  }
  100% {
    transform: scaleY(1.05) translateY(-5px);
  }
}

*:focus-visible { outline: 2px solid var(--action-primary); outline-offset: 2px; }

h1, h2, h3, h4 { font-family: var(--font-primary); color: var(--text-primary); font-weight: 600; }
h1 { font-size: var(--text-3xl); line-height: 1.1; letter-spacing: -0.02em; margin-bottom: var(--space-24); }
h2 { font-size: var(--text-2xl); line-height: 1.2; letter-spacing: -0.01em; margin-bottom: var(--space-16); }
h3 { font-size: var(--text-xl); line-height: 1.3; margin-bottom: var(--space-8); }
p { margin-bottom: var(--space-16); }
.caption { font-size: var(--text-sm); line-height: 1.4; color: var(--text-muted); }

.section { padding: var(--space-80) var(--space-32); }
.section-alt { background-color: var(--bg-secondary); border-top: 1px solid var(--border-light); border-bottom: 1px solid var(--border-light); }
.container { max-width: 1200px; margin: 0 auto; }

/* Forms & Inputs */
.mobile-menu-toggle { display: none; background: transparent; border: none; cursor: pointer; color: var(--text-primary); padding: var(--space-8); justify-content: center; align-items: center; }
.mobile-menu-toggle * { pointer-events: none; } /* iOS Safari fix */ 
.lang-toggle {
    background: transparent;
    border: none;
    font-size: var(--text-sm);
    font-family: var(--font-secondary);
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--text-primary);
    cursor: pointer;
    padding: 0;
    transition: color var(--transition-fast);
}
.lang-toggle:hover {
    color: var(--action-primary);
}

/* Header utility cluster: language, theme, then the two CTAs.
   Two dividers, not three -- the language and theme toggles are both
   utilities, so they read as one group and take no line between them. Both
   dividers are the same weight and both stretch to the cluster's full height,
   which the old inline borders did not (one was only as tall as an 18px icon). */
.nav-utils {
    display: flex;
    align-items: center;
    gap: var(--space-16);
    margin-left: var(--space-16);
    padding-left: var(--space-16);
    border-left: 1px solid var(--border-light);
}
.theme-toggle {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    transition: color var(--transition-fast);
}
.theme-toggle:hover { color: var(--text-primary); }
.nav-actions {
    display: flex;
    align-items: center;
    align-self: stretch;
    gap: var(--space-12);
    padding-left: var(--space-16);
    border-left: 1px solid var(--border-light);
}
/* .btn-secondary carries a 2px border and .btn-primary none, so the pair sits
   4px out of step. Match the box here rather than site-wide. */
.nav-actions .btn-primary { border: 2px solid transparent; }


.form-group {
  margin-bottom: var(--space-16);
  display: flex;
  flex-direction: column;
}

.form-label {
  font-weight: 500;
  margin-bottom: var(--space-8);
  color: var(--text-primary);
}

.form-input {
  background-color: var(--bg-primary);
  border: 1px solid var(--border-input);
  color: var(--text-primary);
  padding: var(--space-8) var(--space-16);
  min-height: 44px;
  border-radius: var(--radius-md);
  font-family: var(--font-secondary);
  font-size: var(--text-base);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background-color var(--transition-normal), color var(--transition-normal);
}

.form-input::placeholder {
  color: var(--text-muted);
}

textarea.form-input {
  resize: vertical;
  min-height: 120px;
}

select.form-input {
  cursor: pointer;
}

.form-input:focus {
  outline: none;
  border-color: var(--action-primary);
  box-shadow: 0 0 0 1px var(--action-primary);
}

.form-input.is-error {
  border-color: var(--status-error);
}

.form-input-sm {
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  /* The footer newsletter row wraps at narrow widths (WCAG 1.4.10); let the
     field shrink and take the row rather than holding its intrinsic size. */
  flex: 1 1 12rem;
  min-width: 0;
}

/* A visible label stacked over its control. Placeholder-only fields lose their
   name as soon as the user types (WCAG 3.3.2). */
.form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}
.form-field .form-label { margin-bottom: 0; font-size: var(--text-sm); }

/* Submission feedback injected by forms.js. Deliberately a sibling of the form,
   not a child: the footer newsletter form is a display:flex row with no wrap,
   so a status node inside it would be squeezed onto the same line as the input. */
.form-status {
  font-size: var(--text-sm);
  line-height: 1.5;
  margin-top: var(--space-8);
}
.form-status:empty { display: none; }
.form-status.is-success { color: var(--status-success); }
.form-status.is-error { color: var(--status-error); }

/* Progressive-disclosure wrapper for the gated CTAs (case studies, webinar,
   consultant network). Ships `hidden` in the markup so there is no flash of an
   open form before forms.js initialises. */
.form-gate { margin-top: var(--space-24); }

/* The UA [hidden] rule loses to any author rule that sets `display`, and several
   components here do. Making it explicit means `el.hidden = true` is reliable
   everywhere -- forms.js and the lang-toggle availability guard both depend on it. */
[hidden] { display: none !important; }

.form-error {
  color: var(--status-error);
  font-size: var(--text-sm);
  margin-bottom: var(--space-16);
}
.form-error:empty {
  display: none;
}

/* Nav Bar & Mega Menu */
.nav-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--glass-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--border-light);
  padding: 0 var(--space-32);
  min-height: 80px;
  display: flex; justify-content: space-between; align-items: center;
}
.nav-logo img { height: 40px; width: auto; }
.nav-links { display: flex; gap: var(--space-24); align-items: center; }

.nav-item {
    padding: 30px 0; /* Bridges the gap exactly to the bottom of the nav-header */
}
.nav-main-link {
    display: flex; align-items: center; gap: 4px;
    text-decoration: none; color: var(--text-primary); font-weight: 500;
    font-size: var(--text-sm); transition: color var(--transition-fast);
}
.nav-main-link:hover { color: var(--action-primary); }

.mega-menu {
    position: absolute;
    top: 100%;
    /* Pinned to both edges of the sticky .nav-header (its containing block)
       rather than width: 100vw, which counts the classic scrollbar gutter and
       pushed every panel ~15px past the viewport, adding a horizontal scrollbar. */
    left: 0;
    right: 0;
    transform: translateY(10px);
    background-color: var(--bg-primary);
    border-top: 1px solid var(--border-medium);
    border-bottom: 3px solid var(--action-primary);
    box-shadow: 0 35px 30px -15px rgba(0, 0, 0, 0.25); /* Stark drop shadow */
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 150ms ease-out 150ms, transform 150ms ease-out 150ms, visibility 0s linear 300ms;
    z-index: 1000;
}
/* Prevents flashing by adding a 150ms intentional delay on hover reveal */
/*
 * `:focus-within` deliberately removed. It was a CSS-only stand-in for the click
 * handler .accordion-toggle never had -- it made the panel reachable by keyboard,
 * but it also meant clicking the chevron to CLOSE the panel left focus on the
 * button, which immediately reopened it while aria-expanded read "false".
 * script.js now binds the chevron as a real disclosure button, so keyboard users
 * open the panel by activating it (Enter/Space) and the class is the single
 * source of truth for open state.
 */
.nav-item:hover .mega-menu,
.nav-item.menu-open .mega-menu {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateY(0);
    transition: opacity 150ms ease-out, transform 150ms ease-out, visibility 0s linear 0s;
}
/* Focus Trap Overlay */
.nav-backdrop {
    position: fixed;
    inset: 0;
    top: 80px;
    background: rgba(17, 24, 39, 0.3);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    z-index: 40;
    pointer-events: none;
    opacity: 0;
    transition: opacity 250ms ease-out;
}
/* Kept in step with the .mega-menu open selector above -- the scrim must appear
   exactly when a panel does, or it blocks clicks with nothing visible on screen. */
body:has(.nav-item:hover, .nav-item.menu-open) .nav-backdrop {
    opacity: 1;
    pointer-events: auto;
}

/* V2 CSS Grid Structural Classes */
.mega-menu-inner {
    max-width: 1280px;
    margin: 0 auto;
    padding: var(--space-32);
}
.grid-12 {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: var(--space-32);
}
.col-span-1 { grid-column: span 1; }
.col-span-2 { grid-column: span 2; }
.col-span-3 { grid-column: span 3; }
.col-span-4 { grid-column: span 4; }
.col-span-5 { grid-column: span 5; }
.col-span-6 { grid-column: span 6; display: flex; flex-direction: column; }
.col-span-7 { grid-column: span 7; }
.col-span-8 {
    grid-column: span 8;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-32);
    /* For standard node distribution (columns within the 8-col spread) */
}
.col-span-8-3col {
    grid-column: span 8;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-32);
}
.col-span-9 { grid-column: span 9; }
.col-span-10 { grid-column: span 10; }
.col-span-11 { grid-column: span 11; }
.col-span-12 { grid-column: span 12; }

.mega-menu-col { display: flex; flex-direction: column; }
.mega-menu h4 {
    font-size: var(--text-sm);
    color: var(--text-muted);
    text-transform: uppercase;
    margin-bottom: var(--space-24);
    letter-spacing: 0.05em;
}
.mega-link {
    display: none; /* Deprecated */
}
/* Interactive Funnel Zone */
.mega-menu-zone {
    display: flex;
    flex-direction: column;
    padding: var(--space-24);
    margin: calc(-1 * var(--space-24));
    border-radius: var(--radius-lg);
}

/* Redesigned Universal Mega Menu Cards */
.mega-card {
    display: flex;
    align-items: flex-start;
    gap: var(--space-16);
    padding: var(--space-24);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--text-primary);
    transition: background-color var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast);
    border: 1px solid transparent;
}
.mega-card:hover { 
    background: var(--bg-tertiary); 
    border-color: var(--border-light);
    transform: translateY(-2px);
    box-shadow: var(--shadow-sm);
}
.mega-card-icon {
    flex-shrink: 0;
    width: 32px; height: 32px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-medium);
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm); color: var(--action-primary);
}
.mega-card-content {
    display: flex; flex-direction: column; gap: var(--space-8);
}
.mega-card-content h5 {
    font-size: var(--text-base);
    font-family: var(--font-primary);
    font-weight: 600;
    margin: 0; padding: 0;
    color: var(--text-primary);
}
.mega-card-content p {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    line-height: 1.4;
    margin: 0; padding: 0;
}

/* Featured Panel -- the 4-col promo on the right of each mega menu.
   The whole panel is one link, so kicker/art/headline/CTA all share a hover. */
.mega-feature {
    display: block;
    text-decoration: none;
    color: inherit;
}
.mega-feature-kicker {
    color: var(--text-muted);
    text-transform: uppercase;
    font-family: monospace;
}
.mega-feature-media {
    background-size: cover;
    background-position: center;
    height: 120px;
    margin: var(--space-16) 0;
    transition: opacity var(--transition-fast);
}
/* Beats `.mega-menu h4`, which is styled for the small uppercase zone labels. */
.mega-menu .mega-feature-title {
    font-size: var(--text-lg);
    color: var(--text-primary);
    text-transform: none;
    letter-spacing: normal;
    line-height: 1.3;
    margin-bottom: var(--space-16);
    transition: color var(--transition-fast);
}
.mega-feature-cta {
    display: inline-flex;
    align-items: center;
    gap: var(--space-8);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--action-primary);
}
.mega-feature-cta svg { transition: transform var(--transition-fast); }
.mega-feature:hover .mega-feature-media { opacity: 0.85; }
.mega-feature:hover .mega-feature-title { color: var(--action-primary); }
.mega-feature:hover .mega-feature-cta svg { transform: translateX(4px); }
.mega-feature:focus-visible { outline: 2px solid var(--action-primary); outline-offset: 4px; }

/* Hero Section */
.hero {
    position: relative; padding: var(--space-120) var(--space-32);
    background-size: cover; background-position: center; background-attachment: fixed;
    display: flex; align-items: center; border-bottom: 1px solid var(--border-light);
}
.hero-overlay {
    position: absolute; top: 0; left: 0; right: 0; bottom: 0;
    background: linear-gradient(to right, rgba(11, 15, 25, 0.95) 0%, rgba(11, 15, 25, 0.3) 100%); z-index: 1;
}
.hero-content { position: relative; z-index: 2; max-width: 750px; color: #FFFFFF; }
.hero-content h1 { color: #FFFFFF; }
.hero-content p { color: #F3F4F6; font-size: var(--text-lg); margin-bottom: var(--space-32); }

/* Bento Hero (home page card)
   The media slot has no height of its own -- it stretches to whatever the text
   column next to it needs. So the photo's aspect ratio is set by the headline,
   and a 56px h1 wrapping to five lines in a half-width column drove the row to
   678px, squeezing the image into a 0.98:1 near-square. `cover` then discarded
   most of a 2.36:1 panorama to fill it, which is why it read as a narrow slice.
   Sizing the headline to its column keeps the slot near 4:3; replacement art
   should be authored at that ratio. */
/* Doubled up on .card deliberately: .card is defined further down the file and
   would otherwise win the box-shadow on source order alone. */
.card.bento-hero-card {
    padding: 0;
    overflow: hidden;
    box-shadow: var(--shadow-float);
}
/* .card:hover lifts the surface and recolours the border -- right for a grid of
   clickable cards, wrong for a full-width hero that isn't a link. */
.card.bento-hero-card:hover {
    transform: none;
    box-shadow: var(--shadow-float);
    border-color: var(--border-light);
}
/* --text-3xl is sized for a full-bleed headline. In a six-column card it wraps
   to five lines and shoulders the whole row taller. Scaled to the column it
   sits in, it lands at three lines and the buttons stay on one row. */
.bento-hero-title {
    font-size: clamp(2rem, 3.4vw, 2.75rem);
    line-height: 1.15;
    margin-bottom: var(--space-16);
}
.bento-hero-media {
    position: relative;
    min-height: 420px;
}
/* The photo sits inset inside the card with its own radius, so the join with
   the text column is a deliberate gutter instead of a butted edge. */
.bento-hero-plate {
    position: absolute;
    inset: var(--space-12);
    border-radius: var(--radius-md);
    overflow: hidden;
    background-color: var(--bg-secondary);
}
/* One layer per photo (patch_home_hero.py). The incoming photo is stacked on
   top of the outgoing one and is the only one that fades: fading one out while
   the other faded in would leave both half-transparent mid-way and flash the
   plate through the gap. script.js zooms whichever is showing.
   The fade's length is mirrored in initHomeHero in script.js -- keep in sync. */
.bento-hero-photo {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    opacity: 0;
    transition: opacity 1200ms ease-in-out;
}
.bento-hero-photo.is-active { opacity: 1; z-index: 1; }
.bento-hero-photo.is-entering { z-index: 2; }
.bento-hero-scrim { z-index: 3; }
/* Dissolves the photo's left edge into the text column rather than dropping a
   hard tonal cliff beside the headline. Theme-aware: fades to whatever the card
   is sitting on, white in light mode and slate in dark. */
.bento-hero-scrim {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to right,
        color-mix(in srgb, var(--bg-primary) 72%, transparent) 0%,
        color-mix(in srgb, var(--bg-primary) 24%, transparent) 15%,
        transparent 34%);
}
@media (prefers-reduced-motion: reduce) {
    .bento-hero-photo { transition: none; }
}

/* Hero entrance (initHomeHero in script.js). The head of each homepage adds
   .hero-intro to <html> before first paint, unless reduced motion is set, so the
   text starts hidden rather than showing and then jumping. script.js lifts it
   as soon as the lines are ready to slide in. Should script.js never run, the
   failsafe animation shows the text anyway after 3s. */
.hero-intro .bento-hero-title,
.hero-intro .bento-hero-sub,
.hero-intro .home-stat-figure { opacity: 0; animation: hero-failsafe 0s linear 3s forwards; }
@keyframes hero-failsafe { to { opacity: 1; } }
/* Each line slides up from behind its own mask. The padding and matching
   negative margin give accents (É) and descenders (g, p) room inside the mask. */
.hero-line { display: block; overflow: hidden; padding: 0.08em 0 0.12em; margin: -0.08em 0 -0.12em; }
.hero-line > span { display: block; animation: hero-up 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) var(--d, 0s) both; }
@keyframes hero-up { from { transform: translateY(105%); } to { transform: none; } }
/* The accent word ends in the brand blue. On arrival the blue sweeps across it
   from the left: one text fill, half blue and half the heading colour, slid
   across the word, so there's no second copy of the text to keep in step. */
.hero-accent { color: var(--action-primary); }
.hero-sweeping .hero-accent {
    background-image: linear-gradient(90deg, var(--action-primary) 50%, var(--text-primary) 50%);
    background-size: 200% 100%;
    background-position: 100% 0;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: hero-sweep 0.8s cubic-bezier(0.4, 0, 0.2, 1) 1.1s forwards;
}
@keyframes hero-sweep { to { background-position: 0 0; } }
.home-stat-suffix.is-landing { display: inline-block; animation: hero-pop 0.45s cubic-bezier(0.3, 1.8, 0.5, 1) both; }
@keyframes hero-pop { from { transform: scale(0); } to { transform: none; } }

/* Trust Marquee Bar */
.marquee-wrapper {
    background-color: var(--bg-tertiary);
    padding: var(--space-24) 0;
    overflow: hidden;
    white-space: nowrap;
    border-bottom: 1px solid var(--border-light);
}
.marquee-content {
    display: inline-block;
    animation: marquee 20s linear infinite;
    opacity: 0.6;
}
.marquee-content span {
    font-size: var(--text-2xl);
    font-family: var(--font-primary);
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 var(--space-48);
}
@keyframes marquee {
    0% { transform: translateX(0); }
    100% { transform: translateX(-50%); }
}

/* Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: var(--space-16) var(--space-32);
  font-family: var(--font-secondary); font-weight: 600; font-size: var(--text-base);
  border-radius: var(--radius-md); border: none; cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast); text-decoration: none;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: scale(0.98); }
/* .btn:hover above is unconditional, so a disabled button would still lift on
   hover and read as clickable. Both overrides are required, not just the opacity. */
.btn[disabled], .btn:disabled { opacity: 0.6; cursor: not-allowed; }
.btn[disabled]:hover, .btn:disabled:hover { transform: none; }
.btn[disabled]:active, .btn:disabled:active { transform: none; }
.btn-primary { background-color: var(--action-primary); color: var(--text-inverse); box-shadow: var(--shadow-sm); }
.btn-primary:hover { background-color: var(--action-hover); box-shadow: var(--shadow-md); color: var(--text-inverse); }
.btn-secondary { background-color: transparent; color: var(--action-primary); border: 2px solid var(--action-primary); }
.btn-secondary:hover { background-color: var(--action-primary); color: var(--text-inverse); }
.btn-ghost { background-color: transparent; color: var(--text-primary); border: 1px solid var(--border-medium); }
.btn-ghost:hover { background-color: var(--bg-tertiary); color: var(--action-primary); border-color: var(--action-primary); }
.btn-sm { padding: var(--space-8) var(--space-16); min-height: 44px; border-radius: var(--radius-sm); }

/* Grids & Cards */
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--space-32); }
.card {
  background-color: var(--bg-primary); border: 1px solid var(--border-light);
  border-radius: var(--radius-lg); padding: var(--space-32); box-shadow: var(--shadow-sm);
  transition: transform var(--transition-normal), box-shadow var(--transition-normal), border-color var(--transition-normal); display: flex; flex-direction: column;
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-xl); border-color: var(--brand-primary-blue); }
.card-icon {
    width: 48px; height: 48px; background-color: var(--bg-secondary);
    color: var(--action-primary); border-radius: var(--radius-md);
    display: flex; align-items: center; justify-content: center; margin-bottom: var(--space-24);
}

/* Ecosystem Funnel UI */
.ecosystem-flow {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-16);
    margin-top: var(--space-48);
    position: relative;
    justify-content: space-between;
}
.eco-node {
    flex: 1;
    min-width: 250px;
    background-color: var(--bg-tertiary);
    padding: var(--space-24);
    border-radius: var(--radius-md);
    position: relative;
    text-align: center;
    border: 1px solid var(--border-light);
}
.eco-node::after {
    content: "➔";
    position: absolute;
    right: -24px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 24px;
    color: var(--text-muted);
}
.eco-node:last-child::after { display: none; }
.eco-node h4 { font-family: var(--font-primary); font-size: var(--text-lg); margin-top: var(--space-16); }

/* AEO Feed */
.insight-feed { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-24); }

/* Footer (scripts/patch_nav_feedback_2026_08.py, render_footer; initSiteFooter in
   script.js). A closing headline and discovery-call button, then the brand column
   beside three balanced link columns, then the legal row with a back-to-top
   button whose ring fills as the page scrolls. */
.site-footer {
    background-color: var(--bg-secondary);
    border-top: 1px solid var(--border-medium);
    padding: var(--space-64) 0 0;
    margin-top: var(--space-64);
    text-align: left;
}
.site-footer-close {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-24);
    flex-wrap: wrap;
    padding-bottom: var(--space-48);
    border-bottom: 1px solid var(--border-light);
}
.site-footer-headline { margin: 0; font-size: var(--text-2xl); line-height: 1.15; }
/* Each line sits in its own mask; the padding and matching negative margin give
   accents and descenders room inside it. */
.site-footer-line { display: block; overflow: hidden; padding: 0.08em 0 0.12em; margin: -0.08em 0 -0.12em; }
.site-footer-line > span { display: block; }
.site-footer-accent { color: var(--action-primary); }
/* script.js arms the headline only if the footer starts off screen, then
   reveals it once, line by line, as the footer scrolls into view. */
.site-footer.is-armed .site-footer-line > span { transform: translateY(105%); }
.site-footer.is-armed.is-revealed .site-footer-line > span { transform: none; transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1); }
.site-footer.is-armed.is-revealed .site-footer-line:nth-child(2) > span { transition-delay: 0.12s; }
@media print { .site-footer.is-armed .site-footer-line > span { transform: none; } } /* printed before it was ever scrolled to */
/* The button leans toward the cursor (script.js sets its transform). */
.site-footer-cta { display: inline-flex; align-items: center; gap: var(--space-8); transition: transform 0.2s ease-out, background-color var(--transition-fast), box-shadow var(--transition-fast); }
.site-footer-cta svg { transition: transform 0.25s ease; }
.site-footer-cta:hover svg { transform: translateX(3px); }

.site-footer-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 3fr);
    gap: var(--space-48);
    padding: var(--space-48) 0;
    border-bottom: 1px solid var(--border-light);
}
.site-footer-logo { height: 40px; width: auto; margin-bottom: var(--space-16); }
.site-footer-tagline { margin: 0 0 var(--space-16); font-size: var(--text-sm); line-height: 1.6; color: var(--text-secondary); }
.site-footer-contact { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-8); margin: 0; }
.site-footer-newsletter { display: flex; flex-direction: column; gap: var(--space-8); margin-top: var(--space-24); }
.site-footer-newsletter label { font-size: var(--text-sm); font-weight: 600; color: var(--text-primary); }
.site-footer-newsletter form { display: flex; gap: var(--space-8); flex-wrap: wrap; }
.site-footer-nav { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-32); }
.site-footer-heading { margin: 0 0 var(--space-16); font-size: var(--text-sm); font-family: var(--font-primary); color: var(--text-primary); }
.site-footer-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-12); }
/* Services: eight links in two columns, filled down each column. Real columns,
   not a grid, so a label that wraps (fr/es) doesn't open a gap beside it in the
   other column. */
.site-footer-list--two { display: block; columns: 2; column-gap: var(--space-24); }
.site-footer-list--two li { break-inside: avoid; margin-bottom: var(--space-12); }

/* A hovered or focused link draws a thin underline from the left and nudges its
   icon, the same sweep as elsewhere on the site, rather than going bold (which
   shifted the text). */
.footer-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--space-8);
    color: var(--text-secondary);
    text-decoration: none;
    font-size: var(--text-sm);
    transition: color var(--transition-fast);
}
.footer-link svg { flex: none; opacity: 0.6; transition: opacity var(--transition-fast), transform 0.25s ease; }
.footer-link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -2px;
    height: 1px;
    background: var(--action-primary);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.3s ease;
}
.footer-link:hover,
.footer-link:focus-visible { color: var(--action-primary); }
.footer-link:hover::after,
.footer-link:focus-visible::after { transform: scaleX(1); }
.footer-link:hover svg,
.footer-link:focus-visible svg { opacity: 1; transform: translateX(2px); }

.site-footer-legal {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-16);
    flex-wrap: wrap;
    padding: var(--space-24) 0 var(--space-32);
}
.site-footer-legal .caption { margin: 0; color: var(--text-muted); }
.site-footer-legal-links { display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-24); }
.footer-legal-link { text-decoration: none; }
.footer-legal-link:hover,
.footer-legal-link:focus-visible { color: var(--action-primary); text-decoration: underline; }
/* Back to top: the ring fills with how far down the page you are (--scroll,
   0 to 1, set by script.js). */
.site-footer-top {
    position: relative;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--bg-primary);
    color: var(--text-primary);
    cursor: pointer;
}
.site-footer-top[hidden] { display: none; }
.site-footer-top-ring { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.site-footer-top-ring circle { fill: none; stroke: var(--border-medium); stroke-width: 2; }
.site-footer-top-ring .site-footer-top-progress {
    stroke: var(--action-primary);
    stroke-linecap: round;
    stroke-dasharray: 1;
    stroke-dashoffset: calc(1 - var(--scroll, 0));
}
.site-footer-top .feather { position: relative; transition: transform 0.25s ease; }
.site-footer-top:hover .feather,
.site-footer-top:focus-visible .feather { transform: translateY(-2px); }
[data-theme="dark"] .site-footer-top { background: var(--bg-tertiary); }

@media (max-width: 1024px) {
    .site-footer-grid { grid-template-columns: minmax(0, 1fr); gap: var(--space-32); }
}
@media (max-width: 767px) {
    .site-footer { padding-top: var(--space-48); }
    /* A full-width bar on a phone, label left and arrow right; the longest label
       ("Réserver un appel de découverte") then still fits on one line. */
    .site-footer-cta { width: 100%; justify-content: space-between; padding: var(--space-16) var(--space-24); font-size: var(--text-sm); }
    .site-footer-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .site-footer-nav .site-footer-col:first-child { grid-column: 1 / -1; }
}
@media (max-width: 480px) {
    .site-footer-list--two { columns: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .site-footer-line > span,
    .site-footer-cta,
    .site-footer-cta svg,
    .footer-link::after,
    .footer-link svg,
    .site-footer-top .feather { transition: none !important; }
}

@media (max-width: 768px) {
    body { line-height: 1.65; }
    section { margin-bottom: var(--space-48) !important; padding-top: var(--space-48) !important; }
}

/* --- Accessibility Scrims --- */
.hero-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to right, rgba(11, 15, 25, 0.95) 0%, rgba(11, 15, 25, 0.3) 100%);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: 1;
}

.card-overlay-vertical {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to top, rgba(11, 15, 25, 0.95) 0%, rgba(11, 15, 25, 0) 100%);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: 1;
}

.text-shield {
    position: relative;
    z-index: 2;
    text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.4), 0px 4px 12px rgba(0, 0, 0, 0.6);
}

@media (max-width: 1024px) {
    h1 { font-size: 2.5rem !important; }
    h2 { font-size: 2rem !important; }
    .section { padding: var(--space-48) var(--space-16); }
    .container { padding-left: var(--space-16); padding-right: var(--space-16); }
    .hero { padding: var(--space-80) var(--space-16); }
    .trust-bar { flex-wrap: wrap; gap: var(--space-16); }
    .trust-bar-logos { flex-wrap: wrap; gap: var(--space-24) !important; }
    .trust-bar-logos span { font-size: var(--text-lg) !important; }
        @keyframes slideInFromRight {
        0% { transform: translateX(100%); opacity: 0; }
        100% { transform: translateX(0); opacity: 1; }
    }
    @keyframes accordionFadeDown {
        0% { transform: translateY(-10px); opacity: 0; }
        100% { transform: translateY(0); opacity: 1; }
    }
    
    .nav-links { display: none; }
    .mobile-menu-toggle { display: flex; }
    
    /* Full Screen Premium Mobile Overlay */
    .nav-links.active {
        display: flex !important;
        flex-direction: column;
        position: fixed;
        top: 80px; left: 0; right: 0; bottom: 0;
        background: var(--bg-primary);
        padding: var(--space-16) var(--space-32);
        overflow-y: auto;
        overflow-x: hidden;
        z-index: 1000;
        gap: 0;
        align-items: flex-start;
        animation: slideInFromRight 0.35s cubic-bezier(0.25, 1, 0.5, 1) forwards;
    }

    /* Container Spacing & Dividers */
    .nav-links.active .nav-item {
        width: 100%;
        padding: var(--space-24) 0;
        border-bottom: 1px solid var(--border-medium);
        margin: 0;
    }
    
    /* Jumbo Touch-Friendly Headers */
    .nav-links.active .nav-item-heading {
        font-size: var(--text-lg);
        font-family: var(--font-primary);
        font-weight: 600;
        display: flex;
        justify-content: space-between;
        width: 100%;
        color: var(--text-primary);
    }
    .nav-links.active .nav-item-heading .nav-main-link { color: var(--text-primary); text-decoration: none; display: block; width: 100%; padding: var(--space-8) 0; }

    /* Explicit SVG Chevron Targeting for fluid rotation */
    .accordion-toggle svg {
        transition: transform 0.25s ease-out, color 0.25s ease;
        align-self: center; /* keep chevron centered relative to big text */
        width: 24px; height: 24px;
    }

    .nav-links.active .mega-menu {
        position: static;
        width: 100%;
        transform: none !important;
        box-shadow: none;
        border: none;
        opacity: 1; visibility: visible; pointer-events: auto;
        display: none;
        padding: var(--space-16) 0 0 0;
        background: transparent;
    }
    
    /* Accordion Reveal Engine */
    .nav-item.mobile-expanded .mega-menu { 
        display: block; 
        animation: accordionFadeDown 0.3s ease-out forwards;
    }
    .nav-item.mobile-expanded .accordion-toggle svg {
        transform: rotate(180deg);
        color: var(--action-primary);
    }

    /* Premium Nested Card Mobile Re-Scaling */
    .nav-links.active .mega-card {
        padding: var(--space-16) var(--space-24);
        border: none;
        border-radius: var(--radius-sm);
        border-left: 3px solid transparent;
        margin-bottom: var(--space-8);
        background: var(--bg-secondary);
        display: flex;
        gap: var(--space-16);
    }
    .nav-links.active .mega-card:hover {
        border-left: 3px solid var(--action-primary);
        transform: translateX(4px);
        background: var(--bg-tertiary);
    }
    /* Scale the micro-typography larger for mobile readability */
    .nav-links.active .mega-menu-zone h4 { 
        font-size: var(--text-base) !important; 
        font-weight: 600;
        margin-top: var(--space-16); 
        margin-bottom: var(--space-24); 
        color: var(--text-primary) !important;
    }
    .nav-links.active .mega-card h5 { 
        font-size: var(--text-lg) !important; 
    }
    .nav-links.active .mega-card .caption { 
        font-size: var(--text-base) !important; 
    }
    .nav-links.active .mega-card-icon svg {
        width: 20px !important;
        height: 20px !important;
    }

    /* Noise Reduction: Hide desktop feature boxes and deep grids on mobile accordions */
    .nav-links.active .col-span-4 { display: none !important; }
    .nav-links.active .grid-12 { display: flex; flex-direction: column; gap: 0; }

    body:has(.nav-links.active) { overflow: hidden; }
    .eco-node::after { display: none; }
    .insight-feed { grid-template-columns: 1fr; }

    /* Responsive Grid Reversals */
    .grid-12 { grid-template-columns: minmax(0, 1fr) !important; }
    [class^="col-span-"] { grid-column: span 1 !important; width: 100% !important; }
    
    /* V2 Bento Box Fallbacks */
    /* minmax(0, 1fr), not 1fr: a bare 1fr track grows to its widest card's
       min-content, which ran these grids past a 320px viewport (WCAG 1.4.10). */
    div[style*="grid-template-columns: repeat(4, 1fr)"] { grid-template-columns: minmax(0, 1fr) !important; }
    div[style*="grid-template-columns: repeat(2, 1fr)"] { grid-template-columns: minmax(0, 1fr) !important; }
    div[style*="grid-column: span 2"], div[style*="grid-column: span 3"] { grid-column: span 1 !important; }
    div[style*="grid-row: span 2"] { grid-row: auto !important; }
    
    /* Responsive Containers */
    .card[style*="flex-direction: row"] { flex-direction: column !important; }
    .card > div[style*="width: 35%"], .card > div[style*="width: 40%"] { width: 100% !important; min-height: 200px !important; }
    .card > div[style*="width: 65%"] { width: 100% !important; }
    /* Was .hero-gallery-wrap, a class no page has ever carried -- so the rule
       matched nothing and the hero media kept its full desktop height on
       phones. .bento-hero-media is the element it was always meant to target. */
    .bento-hero-media { position: relative !important; min-height: 260px !important; }
    /* Full-bleed inside the card on mobile: a 12px gutter around a 260px plate
       just reads as a misprint at that size. */
    .bento-hero-plate { inset: 0 !important; border-radius: 0 !important; }
    /* The columns stack, so the scrim would fade the photo's left edge against
       nothing. Fade the top edge into the copy above it instead. */
    .bento-hero-scrim {
        background: linear-gradient(to bottom,
            color-mix(in srgb, var(--bg-primary) 60%, transparent) 0%,
            transparent 28%) !important;
    }

    /* --- Primary CTAs & Utilities Mobile Enhancement --- */
    /* One flex row in the same reading order as the desktop header: the utility
       toggles come before the CTAs. This used to be a 2-column grid, which put
       the toggles above the buttons -- a layout nobody saw until the cluster
       gained its .nav-utils class and these rules started matching again.
       It wraps rather than shrinking, for a reason measured on a 375px screen:
       three 44px toggles plus the gaps leave 143px for the CTA column, and
       "Connexion/Inscription" -- the longest of the six labels across en/es/fr --
       needs 139px of content box and spilled 16px out of its button. Wrapping
       gives the buttons the full width and costs a row the menu can scroll to;
       shrinking the tap targets to buy those pixels would not. */
    .nav-links.active .nav-utils {
        display: flex !important;
        flex-direction: row !important;
        flex-wrap: wrap !important;
        align-items: center !important;
        margin-left: 0 !important;
        padding-left: 0 !important;
        padding-top: var(--space-32) !important;
        padding-bottom: var(--space-32) !important;
        border-left: none !important;
        border-top: 1px solid var(--border-medium) !important;
        width: 100% !important;
        gap: var(--space-12) !important;
        margin-top: auto !important; /* Push firmly to bottom of the viewport if space permits */
    }

    /* Square 44px tap targets: big enough for a thumb, and held at 44 rather
       than trimmed to fit the CTAs onto the same row -- see above. */
    .nav-links.active .nav-search-toggle,
    .nav-links.active .nav-utils .lang-toggle,
    .nav-links.active .theme-toggle {
        flex: 0 0 44px !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
        width: 44px !important;
        height: 44px !important;
        padding: 0 !important;
        background: var(--bg-secondary) !important;
        border-radius: var(--radius-md) !important;
        border: 1px solid var(--border-light) !important;
        margin-bottom: 0 !important;
    }

    /* The CTAs claim a row of their own below the toggles, stacked so both stay
       full-width. The 100% basis is what forces the wrap. */
    .nav-links.active .nav-actions {
        flex: 1 1 100% !important;
        min-width: 0 !important;
        display: flex !important;
        flex-direction: column !important;
        border-left: none !important;
        padding-left: 0 !important;
        gap: var(--space-12) !important;
    }

    /* Thumb-sized, but scaled to the narrower column the toggles leave beside
       them: at text-lg with 16px side padding, "Discovery Call" wrapped onto two
       lines on a 320px screen. min-height keeps the tap target honest for the
       longer French labels, which still wrap. */
    .nav-links.active .btn-primary,
    .nav-links.active .btn-secondary {
        width: 100% !important;
        text-align: center !important;
        justify-content: center !important;
        padding: var(--space-12) var(--space-8) !important;
        font-size: var(--text-base) !important;
        min-height: 48px !important;
        border-radius: var(--radius-md) !important;
    }
}


/* Mobile Stacking Context Breaks */
.nav-header.menu-open { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; transform: none !important; z-index: 99999 !important; }
.nav-links.active { z-index: 99999 !important; }


/* ==========================================================================
   BLOG / INSIGHTS
   Index listing + long-form article layout.
   Article structure follows the optimization standard in
   Knowledge_Core/Blog_Topics_Catalog.md: H1 as question, direct answer block
   immediately below, sub-question H2s, closing FAQ.
   ========================================================================== */

/* --- Index: filters ------------------------------------------------------ */
.blog-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8);
  margin-bottom: var(--space-40);
}

.pillar-chip {
  font-family: var(--font-secondary);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text-secondary);
  background-color: transparent;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-full);
  padding: var(--space-8) var(--space-16);
  min-height: 44px;
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast), background-color var(--transition-fast);
}

.pillar-chip:hover { color: var(--action-primary); border-color: var(--action-primary); }

.pillar-chip[aria-pressed="true"] {
  color: var(--text-inverse);
  background-color: var(--action-primary);
  border-color: var(--action-primary);
}

/* --- Index: post grid ---------------------------------------------------- */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--space-24);
}

.blog-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
  color: inherit;
  border-top: 4px solid var(--brand-primary-blue);
}

.blog-card h3 {
  margin-top: var(--space-16);
  margin-bottom: var(--space-16);
  font-size: var(--text-xl);
  line-height: 1.25;
}

.blog-card p {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: 1.6;
  margin-bottom: var(--space-24);
}

.blog-card-pillar {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--action-primary);
}

.blog-card-meta {
  margin-top: auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8);
  align-items: center;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.blog-card-meta span + span::before { content: "\00b7"; margin-right: var(--space-8); }

.blog-card[hidden] { display: none; }

/* --- Index: empty state -------------------------------------------------- */
.blog-empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: var(--space-64) var(--space-24);
  border: 1px dashed var(--border-medium);
  border-radius: var(--radius-lg);
  color: var(--text-secondary);
}

/* --- Article: shell ------------------------------------------------------ */
.article {
  max-width: 72ch;
  margin: 0 auto;
  font-size: var(--text-lg);
  line-height: 1.75;
  color: var(--text-primary);
}

.article-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8);
  align-items: center;
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin-bottom: var(--space-24);
}

.article-meta a { color: var(--text-secondary); }
.article-meta span + span::before { content: "\00b7"; margin-right: var(--space-8); }

/* --- Article: the direct-answer block ------------------------------------
   40-60 words, self-contained, sits immediately under the H1. This is the
   passage most likely to be quoted, so it must stand alone without context. */
.article-answer {
  background-color: var(--bg-tertiary);
  border-left: 4px solid var(--brand-primary-blue);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  padding: var(--space-24) var(--space-32);
  margin-bottom: var(--space-48);
  font-size: var(--text-lg);
  line-height: 1.6;
  color: var(--text-primary);
}

.article-answer p { margin: 0; }
.article-answer p + p { margin-top: var(--space-16); }

/* --- Article: prose ------------------------------------------------------ */
.article h2 {
  font-size: var(--text-2xl);
  line-height: 1.2;
  margin-top: var(--space-64);
  margin-bottom: var(--space-24);
  scroll-margin-top: var(--space-80);
}

.article h3 {
  font-size: var(--text-xl);
  line-height: 1.3;
  margin-top: var(--space-40);
  margin-bottom: var(--space-16);
  scroll-margin-top: var(--space-80);
}

.article p { margin-bottom: var(--space-24); }

/* :not(.btn) so buttons in the article body keep their own fill and label
   colour instead of inheriting prose-link blue. */
.article a:not(.btn) { color: var(--action-primary); text-decoration: underline; text-underline-offset: 2px; overflow-wrap: anywhere; }
.article a:not(.btn):hover { color: var(--action-hover); }

.article ul, .article ol { margin: 0 0 var(--space-24) var(--space-32); }
.article li { margin-bottom: var(--space-8); }

.article blockquote {
  margin: var(--space-32) 0;
  padding-left: var(--space-24);
  border-left: 3px solid var(--border-medium);
  color: var(--text-secondary);
  font-style: italic;
}

.article figure { margin: var(--space-40) 0; }
.article img { max-width: 100%; height: auto; border-radius: var(--radius-md); }
.article figcaption {
  margin-top: var(--space-8);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Tables carry the quotable facts - keep them readable and scrollable. */
.article-table-wrap { overflow-x: auto; margin-bottom: var(--space-32); }

/* When an .article sits directly in the 12-col grid (the legal pages do this),
   the grid item's default min-width:auto lets a wide table blow the whole track
   out to its max-content width - on mobile that scrolled the page sideways
   instead of scrolling the table. Cap the track so .article-table-wrap does the
   scrolling, which is what it is there for. */
.grid-12 > .article { min-width: 0; }

.article table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  line-height: 1.5;
}

.article th, .article td {
  text-align: left;
  padding: var(--space-8) var(--space-16);
  border-bottom: 1px solid var(--border-light);
  vertical-align: top;
}

.article th {
  font-weight: 700;
  color: var(--text-primary);
  border-bottom: 2px solid var(--border-medium);
  white-space: nowrap;
}

/* --- Article: key-takeaway callout --------------------------------------- */
.article-callout {
  background-color: var(--bg-secondary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  padding: var(--space-24) var(--space-32);
  margin: var(--space-40) 0;
  font-size: var(--text-base);
}

.article-callout h4 {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--action-primary);
  margin-bottom: var(--space-8);
}

/* --- Article: FAQ -------------------------------------------------------- */
.article-faq { margin-top: var(--space-64); }

.article-faq details {
  border-bottom: 1px solid var(--border-light);
  padding: var(--space-16) 0;
}

.article-faq summary {
  cursor: pointer;
  font-weight: 700;
  font-size: var(--text-base);
  color: var(--text-primary);
  min-height: 44px;
  display: flex;
  align-items: center;
}

.article-faq summary:hover { color: var(--action-primary); }

.article-faq details p {
  margin-top: var(--space-16);
  margin-bottom: 0;
  font-size: var(--text-base);
  color: var(--text-secondary);
}

/* --- Article: sources ---------------------------------------------------- */
.article-sources {
  margin-top: var(--space-64);
  padding-top: var(--space-24);
  border-top: 1px solid var(--border-light);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.article-sources h2 { font-size: var(--text-lg); margin-top: 0; margin-bottom: var(--space-16); }
.article-sources ol { margin-left: var(--space-24); }

/* --- Article: review notice ---------------------------------------------- */
.article-review-notice {
  margin-top: var(--space-40);
  padding: var(--space-16) var(--space-24);
  border-radius: var(--radius-md);
  background-color: var(--bg-tertiary);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

/* --- Article: closing CTA ------------------------------------------------ */
.article-cta {
  margin-top: var(--space-64);
  padding: var(--space-40);
  border-radius: var(--radius-lg);
  background-color: var(--bg-secondary);
  border: 1px solid var(--border-light);
  text-align: center;
}

.article-cta h2 { margin-top: 0; margin-bottom: var(--space-16); font-size: var(--text-xl); }
.article-cta p { color: var(--text-secondary); font-size: var(--text-base); }

/* --- Responsive ---------------------------------------------------------- */
@media (max-width: 768px) {
  .article { font-size: var(--text-base); }
  .article h2 { font-size: var(--text-xl); margin-top: var(--space-48); }
  .article h3 { font-size: var(--text-lg); }
  .article-answer { padding: var(--space-16) var(--space-24); }
  .article-cta { padding: var(--space-24); }
  .blog-grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   Site search
   ==========================================================================
   The header magnifier and the lightbox it opens. Only .nav-search-toggle
   exists in the markup -- everything from .site-search down is built by
   initSiteSearch() in script.js the first time the dialog is opened, so these
   selectors match nothing until then.
   ========================================================================== */

/* Sits in .nav-utils immediately right of the Contact us node, so it reads as
   the first of the utilities rather than an extra nav destination. Deliberately
   the same silhouette as .theme-toggle -- they are peers. */
.nav-search-toggle {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  transition: color var(--transition-fast);
}
.nav-search-toggle:hover { color: var(--text-primary); }
.nav-search-toggle[aria-expanded="true"] { color: var(--action-primary); }

/* The dialog is fixed and full-viewport, so the page behind it must not also
   scroll -- two scrollable surfaces under one wheel is the classic modal bug. */
body.search-open { overflow: hidden; }

.site-search {
  position: fixed;
  inset: 0;
  /* Above .nav-links.active (99999), which the mobile menu raises so it can
     escape the header's stacking context. */
  z-index: 100000;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 12vh var(--space-24) var(--space-24);
}
.site-search[hidden] { display: none; }

.site-search-scrim {
  position: absolute;
  inset: 0;
  background: rgba(17, 24, 39, 0.45);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  animation: site-search-fade 150ms ease-out;
}
[data-theme="dark"] .site-search-scrim { background: rgba(2, 6, 23, 0.6); }

.site-search-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 640px;
  max-height: 76vh;
  overflow: hidden;
  background: var(--bg-primary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  animation: site-search-rise 180ms ease-out;
}

/* --- Field --------------------------------------------------------------- */
.site-search-field {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  padding: var(--space-16) var(--space-20);
  border-bottom: 1px solid var(--border-light);
}
.site-search-field > svg {
  flex: 0 0 20px;
  width: 20px;
  height: 20px;
  color: var(--text-muted);
}
.site-search-input {
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  font-family: var(--font-secondary);
  font-size: var(--text-lg);
  color: var(--text-primary);
}
.site-search-input::placeholder { color: var(--text-muted); }

.site-search-clear {
  display: none;
  flex: 0 0 auto;
  padding: var(--space-4);
  background: none;
  border: none;
  border-radius: var(--radius-full);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--transition-fast);
}
/* Only offer to clear when there is something to clear. :placeholder-shown is
   that state itself, so this needs no JS to stay in step with the field. */
.site-search-input:not(:placeholder-shown) ~ .site-search-clear { display: flex; }
.site-search-clear:hover { color: var(--text-primary); }
.site-search-clear svg { width: 16px; height: 16px; }

.site-search-close {
  flex: 0 0 auto;
  padding: var(--space-4) var(--space-8);
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm);
  font-family: var(--font-secondary);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.site-search-close:hover { color: var(--text-primary); border-color: var(--border-medium); }

/* Screen-reader-only result count. A visible count adds chrome to a list whose
   length is already on screen, but a non-sighted user needs it announced. */
.site-search-status {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Results ------------------------------------------------------------- */
.site-search-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.site-search-results { list-style: none; margin: 0; padding: var(--space-8); }
.site-search-results[hidden] { display: none; }

.site-search-result-link {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-12) var(--space-16);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: inherit;
  /* The accent bar is a transparent border rather than a pseudo-element so the
     row does not shift by 3px when it becomes active. */
  border-left: 3px solid transparent;
}
.site-search-result-link.is-active {
  background: var(--bg-secondary);
  border-left-color: var(--action-primary);
}
.site-search-result-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-8);
  min-width: 0;
}
.site-search-result-badge {
  flex: 0 0 auto;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.site-search-result-title {
  font-family: var(--font-primary);
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--text-primary);
  /* Titles and snippets wrap in full rather than truncating: an ellipsis or a
     line clamp cuts text off once a user widens letter/word spacing
     (WCAG 1.4.12). The snippets are already trimmed to length in script.js. */
  min-width: 0;
  overflow-wrap: anywhere;
}
.site-search-result-snippet {
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--text-secondary);
}
/* <mark>'s UA default is a hard yellow that belongs to no palette here. */
.site-search-panel mark {
  background: color-mix(in srgb, var(--action-primary) 22%, transparent);
  color: inherit;
  border-radius: 2px;
  padding: 0 1px;
}

/* --- Empty, error and loading -------------------------------------------- */
.site-search-message {
  padding: var(--space-32) var(--space-24);
  text-align: center;
}
.site-search-message-title {
  margin-bottom: var(--space-4);
  font-family: var(--font-primary);
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--text-primary);
  /* A pasted paragraph in the field must not stretch the dialog. */
  overflow-wrap: anywhere;
}
.site-search-message-hint {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
}
.site-search-retry {
  margin-top: var(--space-16);
  padding: var(--space-8) var(--space-16);
  background: var(--action-primary);
  border: none;
  border-radius: var(--radius-md);
  font-family: var(--font-secondary);
  font-size: var(--text-sm);
  color: var(--text-inverse);
  cursor: pointer;
}
.site-search-retry:hover { background: var(--action-hover); }

/* The corpus is one fetch away on first open. A bar beats a spinner: it says
   "arriving" without implying the search itself is slow. */
.site-search-body[data-state="loading"]::after {
  content: "";
  display: block;
  height: 2px;
  margin: var(--space-32) auto;
  width: 30%;
  border-radius: var(--radius-full);
  background: var(--action-primary);
  animation: site-search-pulse 1s ease-in-out infinite;
}

/* --- Footer hints -------------------------------------------------------- */
.site-search-foot {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-8) var(--space-20);
  border-top: 1px solid var(--border-light);
  background: var(--bg-secondary);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.site-search-foot kbd {
  padding: 1px var(--space-4);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  font-family: var(--font-secondary);
  font-size: var(--text-xs);
  color: var(--text-secondary);
}
.site-search-foot-sep { margin: 0 var(--space-8); }

@keyframes site-search-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes site-search-rise {
  from { opacity: 0; transform: translateY(-8px) scale(0.99); }
  to { opacity: 1; transform: none; }
}
@keyframes site-search-pulse { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .site-search-scrim,
  .site-search-panel { animation: none; }
  .site-search-body[data-state="loading"]::after { animation: none; opacity: 0.5; }
}

/* --- Responsive ----------------------------------------------------------- */
@media (max-width: 1024px) {
  /* Full-bleed sheet. At this width a centred 640px card with a scrim around it
     wastes the only screen space the results have. */
  .site-search { padding: 0; }
  .site-search-panel {
    max-width: none;
    max-height: 100%;
    height: 100%;
    border: none;
    border-radius: 0;
  }
  .site-search-foot { display: none; }
}

/* === feedback: nav === */
/* Services mega-menu carries eight cards (feedback B1). Tighten the card padding
   on desktop so the 2x4 grid stays about as tall as the other panels. Mobile
   accordions keep their own sizing from the max-width: 1024px block. */
@media (min-width: 1025px) {
    .mega-card-grid--dense { row-gap: var(--space-4) !important; }
    .mega-card-grid--dense .mega-card { padding: var(--space-12) var(--space-16); }
    .mega-card-grid--dense .mega-card-content { gap: var(--space-4); }
}

/* === feedback: theme === */
/* Flat white page in light mode (feedback A2): no gradient, dot texture or wave. */
:root:not([data-theme="dark"]) body {
  background-color: var(--brand-white);
  background-image: none;
}
/* The white waves are invisible on a flat white page; skip the layer entirely. */
:root:not([data-theme="dark"]) body::after { display: none; }

@media (prefers-reduced-motion: reduce) {
  body::after { animation: none; will-change: auto; }
}

/* Theme toggle (feedback A1). script.js adds this class for one frame around
   the data-theme swap so nothing animates from the old palette to the new one:
   the swap becomes a single style recalc and paint instead of 150-300ms of
   per-element colour/border/shadow tweens. */
.theme-switching *,
.theme-switching *::before,
.theme-switching *::after {
  transition: none !important;
  animation-play-state: paused !important;
}

/* === feedback: learn === */
/* F1: GxP Academy hero. gxp-academy.jpg has captions baked into the top of
   each panel that were being cropped mid-word. The layer is 125% of the box
   height and anchored to the bottom, so the caption band (top ~16% of the
   image) always sits outside the visible area, at any box aspect ratio. */
.academy-hero-media {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 125%;
    background: url(/assets/images/gxp-academy.jpg) center bottom / cover no-repeat;
    border-left: 1px solid var(--border-light);
}
/* F3: auditor-training bundle and coaching sections */
.learn-section { margin-bottom: var(--space-64); }
.learn-section-head { max-width: 760px; margin-bottom: var(--space-32); }
.learn-section-head h2 { font-size: var(--text-2xl); margin-bottom: var(--space-16); color: var(--text-primary); }
.learn-section-head p { color: var(--text-secondary); font-size: var(--text-lg); line-height: 1.7; margin: 0; }
.learn-section-head .learn-eyebrow {
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--action-primary);
    margin-bottom: var(--space-8);
}
.learn-split {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
    gap: var(--space-24);
}
.learn-card, .learn-coaching { border-top: 4px solid var(--action-primary); }
.learn-card h3, .learn-coaching h3 { font-size: var(--text-lg); margin-bottom: var(--space-8); color: var(--text-primary); }
.learn-card p, .learn-coaching p { color: var(--text-secondary); line-height: 1.8; margin: 0; }
.learn-coaching p { margin-bottom: var(--space-24); max-width: 72ch; }
.learn-card-icon { display: block; color: var(--action-primary); margin-bottom: var(--space-16); }
[data-theme="dark"] .learn-card,
[data-theme="dark"] .learn-coaching { border-top-color: var(--action-primary); }
@media (max-width: 1024px) {
    .academy-hero-media { border-left: 0; border-top: 1px solid var(--border-light); }
}
@media (max-width: 768px) {
    .learn-section { margin-bottom: var(--space-48); }
    .learn-section-head p { font-size: var(--text-base); }
    .learn-coaching .btn { width: 100%; justify-content: center; text-align: center; }
}

/* === feedback: svc-a === */
/* Services pages (feedback E1-E3, E7): in-page CTA anchors, the audit-type list
   on Audits & Mock Inspections, and the Quality Assurance hub's service grid and
   GxP-array list. Colours come from the theme tokens, so dark mode follows. */
.svc-anchor { scroll-margin-top: 96px; }

.svc-checklist {
    list-style: none; padding: 0; margin: var(--space-8) 0 0;
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-16) var(--space-32);
}
.svc-checklist li {
    position: relative; padding-left: var(--space-32);
    color: var(--text-secondary); line-height: 1.7;
}
.svc-checklist li::before {
    content: "\2713"; position: absolute; left: 0; top: 0;
    color: var(--action-primary); font-weight: 700;
}
.svc-checklist li strong { color: var(--text-primary); }
.svc-checklist li:last-child { grid-column: 1 / -1; }

.qa-service-grid {
    list-style: none; padding: 0; margin: 0;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); gap: var(--space-24);
}
.qa-service-grid > li { display: flex; }
.qa-service-card {
    flex: 1; gap: var(--space-12);
    color: var(--text-primary); text-decoration: none;
    border-top: 4px solid var(--action-primary);
}
.qa-service-card--static { border-top-color: var(--border-medium); }
.qa-service-card--static:hover { transform: none; box-shadow: var(--shadow-sm); border-color: var(--border-light); border-top-color: var(--border-medium); }
.qa-service-icon {
    width: 40px; height: 40px; border-radius: var(--radius-md);
    display: inline-flex; align-items: center; justify-content: center;
    background-color: var(--bg-secondary); color: var(--action-primary);
}
.qa-service-title { font-size: var(--text-lg); margin: 0; color: var(--text-primary); }
.qa-service-text { margin: 0; color: var(--text-secondary); line-height: 1.6; }
.qa-service-more { margin-top: auto; padding-top: var(--space-8); font-weight: 600; color: var(--action-primary); }
a.qa-service-card:hover .qa-service-more { text-decoration: underline; }

.gxp-array {
    list-style: none; padding: 0; margin: 0;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); gap: var(--space-12);
}
.gxp-array-item {
    display: flex; align-items: center; gap: var(--space-12);
    padding: var(--space-12) var(--space-16);
    border: 1px solid var(--border-light); border-radius: var(--radius-md);
    background-color: var(--bg-secondary);
}
.gxp-array-code {
    flex: 0 0 auto; min-width: 3.5rem; text-align: center;
    padding: var(--space-4) var(--space-8); border-radius: var(--radius-full);
    background-color: var(--action-primary); color: var(--text-inverse);
    font-family: var(--font-primary); font-weight: 700; font-size: var(--text-sm);
    text-decoration: none; cursor: default;
}
.gxp-array-name { color: var(--text-primary); font-size: var(--text-sm); line-height: 1.4; }

[data-theme="dark"] .gxp-array-item { border-color: var(--border-medium); }

@media (max-width: 768px) {
    .svc-checklist { grid-template-columns: minmax(0, 1fr); }
    .svc-checklist li:last-child { grid-column: auto; }
}

/* === feedback: about === */
/* D2: round leader portraits. Faces sit high in both source photos, so a plain
   "cover + center" crop cut off foreheads; zoom slightly and anchor on the face.
   Stephanie: 1166x1166, face centre ~(590,300). Steven: 1284x1594, face ~(650,560). */
.leader-photo {
    flex-shrink: 0;
    border-radius: var(--radius-full);
    background-color: var(--bg-tertiary);
    background-repeat: no-repeat;
}
.leader-photo--stephanie {
    background-image: url(/assets/images/stephanie-verbrugghe-round.jpg);
    background-size: 180% auto;
    background-position: 51% 0%;
}
.leader-photo--steven {
    background-image: url(/assets/images/steven-kennedy-round.jpg);
    background-size: 130% auto;
    background-position: 53% 11%;
}
/* Inline text link inside body copy (WCAG 1.4.1: not colour alone). */
.text-link { color: var(--action-primary); text-decoration: underline; text-underline-offset: 2px; }
.text-link:hover { color: var(--action-hover); }
[data-theme="dark"] .text-link:hover { color: var(--brand-mint); }

/* D1: "Our strengths" -- Good Practices list + worldwide auditor network. */
.about-strengths { padding: var(--space-48); border-top: 4px solid var(--action-primary); }
.about-strengths:hover { transform: none; }
.about-strengths-intro { font-size: var(--text-lg); color: var(--text-secondary); line-height: 1.7; margin-bottom: var(--space-24); }
.gxp-practice-list {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-12) var(--space-24);
    margin-bottom: var(--space-32);
}
.gxp-practice-list li {
    display: flex;
    align-items: baseline;
    gap: var(--space-12);
    padding: var(--space-12) var(--space-16);
    background-color: var(--bg-secondary);
    border-left: 3px solid var(--action-primary);
    border-radius: var(--radius-sm);
    line-height: 1.5;
}
.gxp-practice-code {
    flex: 0 0 auto;
    min-width: 6.5rem;
    font-family: var(--font-primary);
    font-weight: 700;
    color: var(--text-primary);
}
.gxp-practice-name { color: var(--text-secondary); }
.about-network-regions {
    font-size: var(--text-base);
    color: var(--text-secondary);
    line-height: 1.8;
    padding-top: var(--space-24);
    border-top: 1px solid var(--border-light);
}
[data-theme="dark"] .gxp-practice-list li { background-color: var(--bg-tertiary); border-left-color: var(--brand-primary-blue); }
@media (max-width: 768px) {
    .about-strengths { padding: var(--space-24); }
    .gxp-practice-list { grid-template-columns: minmax(0, 1fr); }
    .gxp-practice-list li { flex-direction: column; gap: var(--space-4); }
}


/* === feedback: home === */
/* Homepage, client feedback C1-C9 (Aug 2026). */

/* C4: four headline figures; the rest sit in the track record band below the
   Ecosystem. Lists, so a screen reader announces the count and each figure
   reads with its label. */
.home-stats {
    list-style: none;
    margin: 0;
    background: var(--bg-primary);
    border-top: 1px solid var(--border-light);
    padding: var(--space-32) var(--space-48);
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-24);
    text-align: center;
}
.home-stats li { display: flex; flex-direction: column; align-items: center; gap: var(--space-4); }
/* Each figure keeps time with the hero photo that illustrates it (initHomeHero):
   while its photo shows, it takes a soft tint and a slight lift, and the track
   under it fills until the next photo. Paused, the fill stops where it is. */
.home-stats li {
    position: relative;
    padding: var(--space-8) var(--space-8) var(--space-16);
    border-radius: var(--radius-md);
    transition: background-color 0.4s ease;
}
.home-stats li .home-stat-figure { transition: transform 0.4s ease; }
.home-stats li.is-active { background-color: color-mix(in srgb, var(--action-primary) 7%, transparent); }
.home-stats li.is-active .home-stat-figure { transform: translateY(-2px); }
.home-stat-progress {
    position: absolute;
    left: 30%;
    right: 30%;
    bottom: var(--space-4);
    height: 3px;
    border-radius: var(--radius-full);
    overflow: hidden;
    background: transparent;
    transition: background-color 0.4s ease;
}
.home-stats li.is-active .home-stat-progress { background: var(--border-light); }
.home-stat-progress > span {
    display: block;
    height: 100%;
    background: var(--action-primary);
    transform: scaleX(0);
    transform-origin: left;
}
.home-stat-figure { font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) {
    .home-stats li,
    .home-stats li .home-stat-figure,
    .home-stat-progress { transition: none; }
}
.home-stat-figure {
    font-family: var(--font-primary);
    font-size: var(--text-2xl);
    font-weight: 700;
    line-height: 1.1;
    color: var(--action-primary);
}
.home-stat-label { color: var(--text-muted); }
/* Track record band (patch_home_track_record_band.py; initTrackRecordBand in
   script.js). It replaced a looping ticker that needed a pause button. The band
   runs edge to edge to break up the run of card sections. The map is decorative
   (aria-hidden): the figures carry the meaning. */
.home-record {
    background: var(--bg-secondary);
    padding: var(--space-64) 0;
    margin-bottom: var(--space-80);
}
[data-theme="dark"] .home-record { background: var(--bg-tertiary); }
.home-record-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    gap: var(--space-48);
    align-items: center;
}
.home-record-title { font-size: var(--text-2xl); margin: 0 0 var(--space-4); }
.home-record-sub { font-size: var(--text-lg); color: var(--text-secondary); margin: 0 0 var(--space-24); }
.home-record-figs {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-24) var(--space-32);
}
.home-record-fig { display: flex; flex-direction: column; gap: var(--space-4); }
.home-record-fig--lead {
    grid-column: 1 / -1;
    flex-direction: row;
    align-items: baseline;
    gap: var(--space-12);
    padding-bottom: var(--space-24);
    border-bottom: 1px solid var(--border-medium);
}
/* tabular-nums keeps each figure the same width while it counts up. */
.home-record-num {
    font-family: var(--font-primary);
    font-size: var(--text-xl);
    font-weight: 700;
    line-height: 1.1;
    color: var(--action-primary);
    font-variant-numeric: tabular-nums;
}
.home-record-fig--lead .home-record-num { font-size: var(--text-2xl); }
.home-record-label { color: var(--text-secondary); line-height: 1.4; }

.rec-map { display: block; width: 100%; height: auto; overflow: visible; }
.rec-map .rec-dots { fill: var(--brand-gray); }
.rec-map .rec-spoke { fill: none; stroke: var(--brand-primary-blue); stroke-opacity: 0.5; stroke-width: 1.2; }
.rec-map .rec-arc { fill: none; stroke: var(--brand-primary-blue); stroke-width: 1.5; stroke-linecap: round; }
.rec-map .rec-na { fill: var(--brand-primary-blue); }
.rec-map .rec-lit, .rec-map .rec-hub { fill: var(--action-primary); }
.rec-map .rec-hub { stroke: var(--bg-secondary); stroke-width: 1.5; }
.rec-map .rec-label { font-family: var(--font-secondary); font-size: 7.5px; fill: var(--text-muted); }
[data-theme="dark"] .rec-map .rec-dots { fill: var(--border-medium); }
[data-theme="dark"] .rec-map .rec-hub { stroke: var(--bg-tertiary); }

/* The network draws itself once (about 3.1s in all), then holds. Each element
   carries its own start time as --d. .is-armed applies the animations paused, which
   holds every element on its first frame (lines undrawn, dots at scale 0) until
   .is-playing lets them run. With neither class, as without script.js or under
   reduced motion, the finished map shows. Nothing moves for longer than five
   seconds, which is why there is no pause control (WCAG 2.2.2). */
.rec-map .rec-lit, .rec-map .rec-na, .rec-map .rec-hub { transform-box: fill-box; transform-origin: center; }
.rec-map .rec-spoke, .rec-map .rec-arc { stroke-dasharray: 1; }
.home-record.is-armed .rec-spoke { animation: rec-draw 0.35s ease-in-out var(--d) both paused; }
.home-record.is-armed .rec-arc { animation: rec-draw 0.9s ease-in-out var(--d) both paused; }
.home-record.is-armed .rec-lit,
.home-record.is-armed .rec-na,
.home-record.is-armed .rec-hub { animation: rec-pop 0.42s ease-out var(--d) both paused; }
.home-record.is-playing .rec-map * { animation-play-state: running; }
@keyframes rec-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes rec-pop { 0% { transform: scale(0); } 60% { transform: scale(1.5); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) {
    .home-record .rec-map * { animation: none !important; }
}
@media (max-width: 1024px) {
    .home-record { padding: var(--space-48) 0; }
    .home-record-inner { grid-template-columns: minmax(0, 1fr); gap: var(--space-32); }
    .home-record-map { width: 100%; max-width: 26rem; margin: 0 auto; }
}
@media (max-width: 480px) {
    .home-record-fig--lead { flex-direction: column; gap: var(--space-4); }
}

/* How You Engage Us: editorial rows (patch_home_engage_rows.py). They replaced
   four cards that were links without looking like it. On hover or keyboard
   focus an accent tint sweeps across the row, the number rolls up and the
   service's icon rolls into its place, and the arrow turns to point right. The
   visitor starts every one of these, so WCAG 2.2.2 doesn't come into it. */
.home-engage-list { list-style: none; margin: 0; padding: 0; }
.home-engage-list li { border-top: 1px solid var(--border-light); }
.home-engage-list li:last-child { border-bottom: 1px solid var(--border-light); }
/* --ac is each row's accent. The brand mint and the warning yellow are too pale
   on white for an icon (the old Staffing card's was about 1.3:1), so those rows
   use a darker ink in light mode and the brand colour itself in dark. */
.home-engage-row--project { --ac: var(--status-error); }
.home-engage-row--staffing { --ac: color-mix(in srgb, var(--brand-mint) 20%, #0F6E56); }
.home-engage-row--fte { --ac: color-mix(in srgb, var(--status-warning) 68%, black); }
.home-engage-row--clinic { --ac: var(--action-primary); }
[data-theme="dark"] .home-engage-row--staffing { --ac: var(--brand-mint); }
[data-theme="dark"] .home-engage-row--fte { --ac: var(--status-warning); }
.home-engage-row {
    position: relative;
    overflow: hidden;
    display: grid;
    grid-template-columns: 3rem minmax(0, 1fr) 2rem;
    align-items: center;
    gap: var(--space-24);
    padding: var(--space-24) var(--space-16);
    color: inherit;
    text-decoration: none;
}
.home-engage-row:focus-visible { outline-offset: -2px; }
.home-engage-row::before {
    content: "";
    position: absolute;
    inset: 0;
    background: color-mix(in srgb, var(--ac) 10%, transparent);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}
.home-engage-row > * { position: relative; } /* above the sweep */
/* The number and the icon are stacked in a one-item-tall window; the hover
   state slides the stack up by exactly one item. */
.home-engage-slot { height: 2.5rem; overflow: hidden; }
.home-engage-slot-track { display: flex; flex-direction: column; transition: transform 0.4s cubic-bezier(0.5, 0, 0.2, 1.3); }
.home-engage-num,
.home-engage-icon { height: 2.5rem; display: flex; align-items: center; }
.home-engage-num {
    font-family: var(--font-primary);
    font-size: var(--text-xl);
    font-weight: 600;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.home-engage-num::before { content: attr(data-num); } /* kept out of the page text */
.home-engage-icon {
    width: 2.5rem;
    justify-content: center;
    border-radius: var(--radius-md);
    color: var(--ac);
    background: color-mix(in srgb, var(--ac) 14%, transparent);
}
.home-engage-text { display: grid; gap: var(--space-4); }
.home-engage-title { margin: 0; font-size: var(--text-lg); color: var(--text-primary); }
.home-engage-desc { margin: 0; font-size: var(--text-base); line-height: 1.5; color: var(--text-secondary); }
.home-engage-arrow { display: flex; justify-content: flex-end; color: var(--text-muted); }
.home-engage-arrow svg { transition: transform 0.3s ease, color 0.3s ease; }
.home-engage-row:hover::before,
.home-engage-row:focus-visible::before,
.home-engage-row:active::before { transform: scaleX(1); }
.home-engage-row:hover .home-engage-slot-track,
.home-engage-row:focus-visible .home-engage-slot-track { transform: translateY(-2.5rem); }
.home-engage-row:hover .home-engage-arrow,
.home-engage-row:focus-visible .home-engage-arrow { color: var(--ac); }
.home-engage-row:hover .home-engage-arrow svg,
.home-engage-row:focus-visible .home-engage-arrow svg { transform: rotate(45deg); }
/* Nothing hovers on a touchscreen, so the arrow carries the row's colour at rest
   to say "this is a link"; a tap still shows the sweep (:active, above). */
@media (hover: none) {
    .home-engage-arrow { color: var(--ac); }
}
/* Title beside description only once there's room for both: on a tablet the
   description column came out too narrow and the rows ran tall. */
@media (min-width: 1025px) {
    .home-engage-text { grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr); align-items: baseline; gap: var(--space-24); }
}
@media (max-width: 767px) {
    .home-engage-row { grid-template-columns: 2.5rem minmax(0, 1fr) 1.5rem; gap: var(--space-16); padding: var(--space-16) var(--space-8); }
}
@media (prefers-reduced-motion: reduce) {
    .home-engage-row::before,
    .home-engage-slot-track,
    .home-engage-arrow svg { transition: none; }
}

/* Expert Spotlight: an "Ask Stéphanie" thread (patch_home_spotlight.py;
   initSpotlightThread in script.js). Each list item is one exchange, a visitor's
   question bubble and her answer bubble. Without script.js, or under reduced
   motion, the whole conversation shows as a plain list. With it (.is-live), it
   plays out in a fixed window: new exchanges arrive at the bottom and older ones
   scroll off the top under a fade. */
.home-spotlight-card {
    padding: 0;
    overflow: hidden;
    display: grid;
    grid-template-columns: 35% minmax(0, 1fr);
    border-radius: var(--radius-lg);
}
.card.home-spotlight-card:hover { transform: none; box-shadow: var(--shadow-sm); border-color: var(--border-light); }
.home-spotlight-photo { min-height: 350px; background-size: cover; background-position: top center; }
.home-spotlight-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
    min-width: 0;
    padding: var(--space-40) var(--space-48) var(--space-32);
    background: var(--bg-primary);
}
.home-spotlight-label {
    margin: 0;
    font-size: var(--text-sm);
    font-family: var(--font-secondary);
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--action-primary);
}
.home-spotlight-thread { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-16); }
.home-spotlight-turn { display: flex; flex-direction: column; gap: var(--space-8); }
.home-spotlight-q,
.home-spotlight-a {
    max-width: 88%;
    margin: 0;
    padding: var(--space-12) var(--space-16);
    border-radius: var(--radius-lg);
    line-height: 1.55;
}
.home-spotlight-q {
    align-self: flex-end;
    background: var(--bg-secondary);
    border-bottom-right-radius: var(--radius-sm);
    color: var(--text-primary);
    font-weight: 600;
}
.home-spotlight-a {
    align-self: flex-start;
    background: color-mix(in srgb, var(--action-primary) 9%, var(--bg-primary));
    border-bottom-left-radius: var(--radius-sm);
    color: var(--text-primary);
}
.home-spotlight-a p { margin: 0; }
.home-spotlight-more { display: inline-block; margin-top: var(--space-8); font-weight: 600; color: var(--action-primary); text-decoration: none; }
.home-spotlight-more:hover { text-decoration: underline; }
.home-spotlight-turn--cta .home-spotlight-a { background: none; padding: 0; }
[data-theme="dark"] .home-spotlight-body { background: var(--bg-tertiary); }
[data-theme="dark"] .home-spotlight-q { background: var(--bg-primary); }
[data-theme="dark"] .home-spotlight-a { background: color-mix(in srgb, var(--action-primary) 16%, var(--bg-tertiary)); }
.home-spotlight-who { display: flex; align-items: center; justify-content: space-between; gap: var(--space-16); flex-wrap: wrap; margin-top: auto; }
.home-spotlight-name { margin: 0; font-size: var(--text-base); }
.home-spotlight-role { margin: 0; color: var(--text-muted); }
.home-spotlight-links { display: flex; gap: var(--space-8); flex-wrap: wrap; }
.home-spotlight-links .btn { gap: var(--space-8); }
.home-spotlight-links svg { width: 16px; height: 16px; }

/* Playing. The window is a fixed height with the conversation pinned to its
   bottom; turns not reached yet are clipped out of sight but stay in the page,
   so a screen reader can still read the whole list. Each part of a turn rises
   in as it arrives: the question, then her typing dots, then the answer. */
/* --spotlight-h is set by script.js to fit the tallest exchange below the fade
   (the QP-declaration answer runs long, longer still in fr/es), and re-measured
   when the width changes. */
.home-spotlight.is-live .home-spotlight-window {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    height: max(26rem, var(--spotlight-h, 0px));
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 18%);
    mask-image: linear-gradient(to bottom, transparent 0, #000 18%);
}
.home-spotlight.is-live .home-spotlight-thread { transition: opacity 0.5s ease; }
.home-spotlight.is-live .home-spotlight-thread.is-clearing { opacity: 0; }
.home-spotlight.is-live .home-spotlight-turn:not(.is-shown) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}
.home-spotlight.is-live .home-spotlight-q,
.home-spotlight.is-live .home-spotlight-a { opacity: 0; transform: translateY(10px); transition: opacity 0.4s ease, transform 0.4s ease; }
.home-spotlight.is-live .is-asked .home-spotlight-q,
.home-spotlight.is-live .is-answered .home-spotlight-a { opacity: 1; transform: none; }
/* Only an exchange on screen waits for its answer; ones still to come keep theirs
   (clipped, above) so a screen reader can read ahead. */
.home-spotlight.is-live .home-spotlight-turn.is-shown:not(.is-answered) .home-spotlight-a { display: none; }
.home-spotlight-typing {
    align-self: flex-start;
    display: flex;
    gap: 5px;
    padding: var(--space-12) var(--space-16);
    border-radius: var(--radius-lg);
    border-bottom-left-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--action-primary) 9%, var(--bg-primary));
}
[data-theme="dark"] .home-spotlight-typing { background: color-mix(in srgb, var(--action-primary) 16%, var(--bg-tertiary)); }
.home-spotlight-typing span { width: 7px; height: 7px; border-radius: var(--radius-full); background: var(--action-primary); animation: spotlight-typing 1s ease-in-out infinite; }
.home-spotlight-typing span:nth-child(2) { animation-delay: 0.15s; }
.home-spotlight-typing span:nth-child(3) { animation-delay: 0.3s; }
.home-spotlight.is-paused .home-spotlight-typing span { animation-play-state: paused; }
@keyframes spotlight-typing { 0%, 60%, 100% { transform: none; opacity: 0.4; } 30% { transform: translateY(-3px); opacity: 1; } }

@media (max-width: 767px) {
    .home-spotlight-card { grid-template-columns: minmax(0, 1fr); }
    .home-spotlight-photo { min-height: 260px; }
    .home-spotlight-body { padding: var(--space-24) var(--space-16); }
    .home-spotlight.is-live .home-spotlight-window { height: max(30rem, var(--spotlight-h, 0px)); }
    .home-spotlight-q, .home-spotlight-a { max-width: 94%; font-size: var(--text-sm); }
}
@media (prefers-reduced-motion: reduce) {
    .home-spotlight-q, .home-spotlight-a, .home-spotlight-thread { transition: none !important; }
    .home-spotlight-typing span { animation: none; }
}
}

/* Ecosystem: four expanding panels (markup from patch_home_ecosystem_panels.py,
   behaviour from initEcosystemPanels in script.js). The C5 lead box spanned
   three rows and stretched past the fold; now one panel is open at a time and
   Staffing, Recruitment and Training is the one open at load.
   Until script.js adds .is-ready the panels are a plain grid with every body
   showing, so the copy never depends on the script. */
.home-section-sub {
    text-align: center;
    color: var(--text-secondary);
    font-size: var(--text-lg);
    max-width: 46rem;
    margin: 0 auto var(--space-32);
}
.home-eco-panels {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
    gap: var(--space-16);
}
.home-eco-panel {
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
    min-width: 0;
    background: var(--bg-primary);
    border: 1px solid var(--border-light);
    border-top: 4px solid var(--eco-accent);
    border-radius: var(--radius-lg);
    padding: var(--space-24);
    box-shadow: var(--shadow-sm);
}
/* --eco-accent is the border and art tint; --eco-ink draws the illustration.
   Yellow and red need a darker ink than the border to read on a light tint. */
.home-eco-panel--staff,
.home-eco-panel--quality { --eco-accent: var(--action-primary); --eco-ink: var(--action-primary); --eco-glow: var(--brand-primary-blue); }
.home-eco-panel--pv { --eco-accent: var(--status-warning); --eco-ink: color-mix(in srgb, var(--status-warning) 68%, black); --eco-glow: var(--status-warning); }
.home-eco-panel--ra { --eco-accent: var(--status-error); --eco-ink: color-mix(in srgb, var(--status-error) 88%, black); --eco-glow: var(--status-error); }
[data-theme="dark"] .home-eco-panel { background: var(--bg-tertiary); }
[data-theme="dark"] .home-eco-panel--pv,
[data-theme="dark"] .home-eco-panel--ra { --eco-ink: var(--eco-accent); }
.home-eco-art {
    flex-shrink: 0;
    height: 9rem;
    padding: var(--space-12);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--eco-accent) 10%, transparent);
}
.home-eco-title { margin: 0; font-size: var(--text-lg); }
.home-eco-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-8);
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: var(--text-primary);
    text-align: left;
    cursor: pointer;
    hyphens: auto;
    overflow-wrap: anywhere;
}
.home-eco-toggle:focus-visible { outline-offset: 4px; border-radius: var(--radius-sm); }
.home-eco-chevron { display: none; flex-shrink: 0; color: var(--text-secondary); }
.home-eco-body { display: flex; flex-direction: column; gap: var(--space-12); flex: 1 1 auto; }
.home-eco-text { margin: 0; font-size: var(--text-base); line-height: 1.6; color: var(--text-secondary); }
.home-eco-chips { display: flex; flex-wrap: wrap; gap: var(--space-8); margin: 0; padding: 0; list-style: none; }
.home-eco-chips li {
    font-size: var(--text-sm);
    color: var(--text-secondary);
    border: 1px solid var(--border-medium);
    border-radius: var(--radius-md); /* not a pill: a long chip wraps in a closed panel */
    padding: 2px var(--space-12);
}
.home-eco-link { align-self: flex-start; margin-top: auto; }

/* Desktop: one row. The open panel takes 2.4 shares of the width; the body is
   pinned to that open width (100cqw is the row), so its text never reflows
   while the panel grows -- it is clipped, then revealed.
   Transitions wait for .is-live, which script.js adds a frame after .is-ready:
   otherwise the switch from grid to row would itself animate on page load.
   The flex values are set at every width, not just in the row: the accordion's
   grid ignores them, and if they only appeared at 1025px, crossing that width
   (a resized window, a rotated tablet) would grow the panels in from zero. */
.is-ready .home-eco-panel { flex: 1 1 0; }
.is-ready .home-eco-panel.is-open { flex-grow: 2.4; }
@media (min-width: 1025px) {
    .home-eco-panels.is-ready { display: flex; height: 30rem; container-type: inline-size; }
    .is-ready .home-eco-panel { overflow: hidden; cursor: pointer; }
    .is-live .home-eco-panel { transition: flex-grow 0.5s ease, box-shadow 0.3s ease, border-color 0.3s ease; }
    .is-ready .home-eco-panel:not(.is-open):hover { border-color: var(--eco-accent); }
    .is-ready .home-eco-panel.is-open { cursor: auto; box-shadow: var(--shadow-float); }
    .is-ready .home-eco-body {
        flex: none;
        width: calc((100cqw - 3 * var(--space-16)) * 2.4 / 5.4 - 2 * var(--space-24) - 2px);
        min-height: 0;
    }
    .is-live .home-eco-body { transition: opacity 0.3s ease 0.2s; }
    .is-ready .home-eco-panel:not(.is-open) .home-eco-body { visibility: hidden; opacity: 0; }
    .is-live .home-eco-panel:not(.is-open) .home-eco-body { transition: opacity 0.15s ease, visibility 0s linear 0.15s; }
    .is-ready .home-eco-link { margin-top: 0; }
}
/* Below the 1200px container the open panel narrows and the fr/es copy wraps
   an extra line or two; a shorter illustration and a taller row keep it inside. */
@media (min-width: 1025px) and (max-width: 1279px) {
    .home-eco-panels.is-ready { height: 32rem; }
    .is-ready .home-eco-art { height: 7.5rem; }
}

/* Tablet and phone: a stacked accordion. A closed panel is one row (art
   thumbnail, title, chevron); the open one shows the art as a banner. */
@media (max-width: 1024px) {
    .home-eco-panels.is-ready { grid-template-columns: minmax(0, 1fr); gap: var(--space-12); }
    .is-ready .home-eco-panel {
        display: grid;
        grid-template-columns: 4rem minmax(0, 1fr);
        align-items: center;
        gap: var(--space-16);
        padding: var(--space-16);
        cursor: pointer;
    }
    .is-ready .home-eco-panel.is-open { cursor: auto; }
    .is-ready .home-eco-art { height: 4rem; padding: var(--space-4); }
    .is-ready .home-eco-panel.is-open .home-eco-art { grid-column: 1 / -1; height: 9rem; padding: var(--space-12); }
    .is-ready .home-eco-panel.is-open .home-eco-title,
    .is-ready .home-eco-chips,
    .is-ready .home-eco-body { grid-column: 1 / -1; }
    .is-ready .home-eco-panel:not(.is-open) .home-eco-chips,
    .is-ready .home-eco-panel:not(.is-open) .home-eco-body { display: none; }
    .is-ready .home-eco-chevron { display: block; }
    .is-live .home-eco-chevron { transition: transform 0.3s ease; }
    .is-ready .is-open .home-eco-chevron { transform: rotate(180deg); }
}

/* Illustrations. Presentation attributes can't take var(), so the drawing is
   coloured from here. Each animation runs at most five seconds and ends on the
   frame it started from, so a panel at rest looks the same whether or not it
   has played. That cap is also why there is no pause control: WCAG 2.2.2 only
   asks for one on motion that lasts longer than five seconds. */
.eco-ill { display: block; width: 100%; height: 100%; overflow: visible; }
.eco-ill .eco-ink { fill: var(--eco-ink); }
.eco-ill .eco-glow { fill: var(--eco-glow); }
.eco-ill .eco-faint { opacity: 0.6; }
.eco-ill .eco-dots { fill: var(--brand-gray); }
.eco-ill .eco-line { fill: none; stroke: var(--brand-gray); stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }
.eco-ill .eco-bars { stroke-width: 2.5; }
.eco-ill .eco-ink-s { fill: none; stroke: var(--eco-ink); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.eco-ill .eco-check { stroke-width: 3; }
.eco-ill .eco-paper { fill: var(--bg-primary); }
.eco-ill .eco-mint { fill: none; stroke: var(--brand-mint); stroke-width: 3; }
.eco-ill .eco-dash { fill: none; stroke: var(--eco-glow); stroke-width: 1.5; stroke-dasharray: 4 4; }
.eco-ill .eco-route { stroke: var(--brand-gray); }
.eco-ill .eco-ring { fill: none; stroke: var(--eco-ink); stroke-opacity: 0.3; stroke-width: 2; }
.eco-ill .eco-ring-in { fill: none; stroke: var(--brand-gray); stroke-dasharray: 2 4; }
.eco-ill .eco-ripple { fill: none; stroke: var(--eco-glow); stroke-width: 2; opacity: 0; }
.eco-ill .eco-text-lines { fill: none; stroke: var(--eco-ink); stroke-opacity: 0.55; stroke-width: 2.5; stroke-linecap: round; }
.eco-ill .eco-draw { stroke-dasharray: 40; }
.eco-ill .eco-pulse,
.eco-ill .eco-ripple { transform-box: fill-box; transform-origin: center; }
.eco-ill .eco-orbit { transform-box: view-box; transform-origin: 100px 60px; }
[data-theme="dark"] .eco-ill .eco-paper { fill: var(--bg-tertiary); }

.is-playing .eco-ill .eco-pulse { animation: eco-pulse 1.4s ease-in-out 3 both; }
.is-playing .eco-ill .eco-d1 { animation-delay: 0.2s; }
.is-playing .eco-ill .eco-d2 { animation-delay: 0.4s; }
.is-playing .eco-ill .eco-d3 { animation-delay: 0.6s; }
.is-playing .eco-ill .eco-dash { animation: eco-dash 1.2s linear 4; }
.is-playing .eco-ill .eco-draw { animation: eco-draw 1.2s ease-out 0.4s both; }
.is-playing .eco-ill .eco-ripple { animation: eco-ripple 1.5s ease-out 3; }
.is-playing .eco-ill .eco-orbit { animation: eco-orbit 4.4s ease-in-out; }
.is-playing .eco-ill .eco-bob { animation: eco-bob 2.2s ease-in-out 2; }
@keyframes eco-pulse { 50% { transform: scale(1.35); } }
@keyframes eco-dash { to { stroke-dashoffset: -16; } }
@keyframes eco-draw { from { stroke-dashoffset: 40; } to { stroke-dashoffset: 0; } }
@keyframes eco-ripple { from { transform: scale(0.5); opacity: 0.9; } to { transform: scale(2.6); opacity: 0; } }
@keyframes eco-orbit { to { transform: rotate(360deg); } }
@keyframes eco-bob { 50% { transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) {
    .eco-ill * { animation: none !important; }
    .home-eco-panel, .home-eco-body, .home-eco-chevron { transition: none !important; }
}

/* C9: testimonials. Each quote is a <figure>; the grid takes more of them as
   they arrive. A lone quote is held to a readable measure and centred. */
.home-testimonial-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
    gap: var(--space-24);
}
.home-testimonial {
    margin: 0;
    background: var(--bg-primary);
    border: 1px solid var(--border-light);
    border-left: 4px solid var(--action-primary);
    border-radius: var(--radius-lg);
    padding: var(--space-32);
    box-shadow: var(--shadow-sm);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: var(--space-24);
}
.home-testimonial:only-child { max-width: 52rem; width: 100%; justify-self: center; }
.home-testimonial blockquote {
    margin: 0;
    font-size: var(--text-lg);
    line-height: 1.6;
    font-style: italic;
    color: var(--text-primary);
}
.home-testimonial figcaption { display: flex; align-items: center; gap: var(--space-12); }
.home-testimonial-who { display: flex; flex-direction: column; gap: var(--space-4); }
.home-testimonial-name { font-weight: 600; color: var(--text-primary); }
.home-testimonial-role { font-size: var(--text-sm); color: var(--text-muted); }
[data-theme="dark"] .home-testimonial { background: var(--bg-tertiary); }

/* Each quote takes one of four accents in turn (patch_home_testimonials.py),
   the engage rows' set: its card edge, its initials and its dot. */
.home-ac-1 { --ac: var(--action-primary); }
.home-ac-2 { --ac: var(--status-error); }
.home-ac-3 { --ac: color-mix(in srgb, var(--brand-mint) 20%, #0F6E56); }
.home-ac-4 { --ac: color-mix(in srgb, var(--status-warning) 68%, black); }
[data-theme="dark"] .home-ac-3 { --ac: var(--brand-mint); }
[data-theme="dark"] .home-ac-4 { --ac: var(--status-warning); }
.home-testimonial { position: relative; border-left-color: var(--ac, var(--action-primary)); }
.home-testimonial-avatar {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: var(--radius-full);
    background: var(--ac);
    color: #fff;
    font-size: var(--text-sm);
    font-weight: 600;
}
/* The dark-theme accents are light, so their initials go dark. */
[data-theme="dark"] .home-testimonial-avatar { color: var(--bg-secondary); }

/* Deck: script.js adds .is-deck (initTestimonialDeck). Every card sits in the
   same grid cell, so the stack is as tall as the longest quote without anyone
   measuring it; the padding leaves room for the cards fanned out behind. The
   current card is flat at the front, the next two fan out at an angle, the rest
   wait behind them unseen, and the one that just left spins away to the left. */
.home-testimonials.is-deck { overflow-x: clip; }
.is-deck .home-testimonial-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    max-width: 56rem;
    margin: 0 auto;
    padding: 0 var(--space-32) var(--space-24) 0;
}
/* Small angles, larger offsets: a wide card turned about its centre lifts its
   far corner, so the angle stays low and the offset does the fanning, out to
   the right and below. The cards behind take a hint of their accent and a firmer
   edge, or white-on-white they'd barely read as a deck. */
.is-deck .home-testimonial {
    grid-area: 1 / 1;
    max-width: none;
    opacity: 0;
    transform: translate(22px, 18px) rotate(3deg);
    transition: transform 0.65s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.65s ease;
}
.is-deck .home-testimonial.is-next,
.is-deck .home-testimonial.is-after {
    background: color-mix(in srgb, var(--ac) 6%, var(--bg-primary));
    border-color: var(--border-medium);
    border-left-color: var(--ac);
}
[data-theme="dark"] .is-deck .home-testimonial.is-next,
[data-theme="dark"] .is-deck .home-testimonial.is-after { background: color-mix(in srgb, var(--ac) 8%, var(--bg-tertiary)); }
.is-deck .home-testimonial.is-current { opacity: 1; transform: none; z-index: 3; }
.is-deck .home-testimonial.is-next { opacity: 0.9; transform: translate(11px, 9px) rotate(1.5deg); z-index: 2; }
.is-deck .home-testimonial.is-after { opacity: 0.6; transform: translate(22px, 18px) rotate(3deg); z-index: 1; }
.is-deck .home-testimonial.is-leaving { opacity: 0; transform: translate(-120%, -10px) rotate(-12deg); z-index: 4; }
/* The front card's accent tint sweeps in from the left, as on the engage rows. */
.is-deck .home-testimonial::before {
    content: "";
    position: absolute;
    inset: 0;
    background: color-mix(in srgb, var(--ac) 7%, transparent);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.55s cubic-bezier(0.4, 0, 0.2, 1) 0.15s;
    pointer-events: none;
}
.is-deck .home-testimonial.is-current::before { transform: scaleX(1); }
.is-deck .home-testimonial > * { position: relative; }

/* Controls: an arrow at each end, a dot per quote between. The current dot is a
   short pill that fills as its quote's time runs (and freezes while the deck is
   paused); a hovered or focused dot opens into a pill with the client's name. */
.home-deck-controls { display: flex; align-items: center; justify-content: center; gap: var(--space-12); margin-top: var(--space-24); }
.home-deck-controls[hidden] { display: none; }
.home-deck-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex: none;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-medium);
    background: var(--bg-primary);
    color: var(--text-primary);
    cursor: pointer;
    transition: border-color 0.2s ease, color 0.2s ease;
}
.home-deck-step:hover { border-color: var(--action-primary); color: var(--action-primary); }
.home-deck-dots { display: flex; align-items: center; gap: var(--space-4); }
.home-deck-dot {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    height: 32px;
    padding: 0 2px;
    border: 0;
    background: none;
    cursor: pointer;
}
.home-deck-pill {
    position: relative;
    display: flex;
    align-items: center;
    min-width: 10px;
    max-width: 10px;
    height: 10px;
    border-radius: var(--radius-full);
    overflow: hidden;
    background: var(--border-medium);
    transition: max-width 0.4s cubic-bezier(0.4, 0, 0.2, 1), height 0.3s ease, background-color 0.25s ease;
}
.home-deck-fill {
    position: absolute;
    inset: 0;
    background: var(--ac);
    opacity: 0.45;
    transform: scaleX(0);
    transform-origin: left;
}
.home-deck-name {
    position: relative;
    padding: 0 var(--space-12);
    font-size: var(--text-sm);
    font-weight: 600;
    white-space: nowrap;
    color: #fff;
    opacity: 0;
    transition: opacity 0.2s ease;
}
[data-theme="dark"] .home-deck-name { color: var(--bg-secondary); }
.home-deck-dot[aria-current="true"] .home-deck-pill { max-width: 2.25rem; background: color-mix(in srgb, var(--ac) 25%, transparent); }
.home-deck-dot:focus-visible .home-deck-pill { max-width: 12rem; height: 1.5rem; background: var(--ac); }
.home-deck-dot:focus-visible .home-deck-name { opacity: 1; transition-delay: 0.12s; }
/* Hover only where there is a pointer that hovers: a tap on a phone would leave
   the pill stuck open and push the row wider than the screen. */
@media (hover: hover) {
    .home-deck-dot:hover .home-deck-pill { max-width: 12rem; height: 1.5rem; background: var(--ac); }
    .home-deck-dot:hover .home-deck-name { opacity: 1; transition-delay: 0.12s; }
}
/* The longest quotes run to about 80 words; on a narrower screen the deck,
   which is as tall as the longest of them, would otherwise run very tall. */
@media (max-width: 1024px) {
    .home-testimonial blockquote { font-size: var(--text-base); }
}
@media (max-width: 767px) {
    .is-deck .home-testimonial-grid { padding: 0 var(--space-24) var(--space-20) 0; }
    .home-deck-controls { gap: var(--space-8); }
    .home-deck-dots { gap: 0; }
    .home-deck-dot { min-width: 20px; }
}
@media (prefers-reduced-motion: reduce) {
    .is-deck .home-testimonial,
    .is-deck .home-testimonial::before,
    .home-deck-pill,
    .home-deck-name { transition: none; }
}

@media (max-width: 1024px) {
    .home-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: var(--space-24) var(--space-16); }
    .home-testimonial { padding: var(--space-24); }
    .guarantee-bar { padding: var(--space-16) !important; }
}
@media (max-width: 480px) {
    .home-stat-figure { font-size: var(--text-xl); }
}
