/* TH Component Library -- global shared components for THUSA MSP Portal */
/* Reference page: app/static/designs/th-component-library.html */
/* Brand Bible: BRAND_BIBLE.md */

/* ================================================================
   DESIGN TOKENS -- component-scoped only
   WHY: Radii, shadows, motion and the extended semantic ramp that the
        sitewide token layer does not define.
   CONTEXT: All .th-* components use these; dark mode is primary.
   SOURCE: templates/theme/_design_tokens.html, fed from theme.json, which
        is fed from .thusa_brand-id/. This file used to re-declare the brand
        accent, the greys and the text colours as its own :root -- values
        extracted from thusamsp.com via Playwright in April 2026, which had
        since diverged from theme.json (#0B0C0F vs #0A0A0C, #151618 vs
        #15171B, #B5B5B5 vs #9CA0A8). Two homes for one fact; the inline
        token block already won on document order, so those declarations
        were dead weight that only served to mislead. Removed.
   ================================================================ */
:root {
    /* Semantic colors */
    --th-green: #10B981;
    --th-green-dark: #059669;
    --th-green-light: rgba(16,185,129,0.15);
    --th-red: #EF4444;
    --th-red-light: rgba(239,68,68,0.15);
    --th-orange: #F97316;
    --th-orange-light: rgba(249,115,22,0.15);
    --th-yellow: #EAB308;
    --th-yellow-light: rgba(234,179,8,0.15);
    --th-indigo: #6366F1;
    --th-indigo-light: rgba(99,102,241,0.15);

    /* Dark theme (primary). --th-text/-secondary/-muted, --th-bg, --th-surface,
       --th-surface-mid, --th-border and the pink trio all come from the sitewide
       token block -- do not re-declare them here. */
    --th-surface-elevated: var(--card-2, #1B1E23);
    --th-card: var(--card, #15171B);
    --th-border-hover: rgba(255,255,255,0.2);
    --th-divider: rgba(255,255,255,0.05);
    --th-glass: rgba(255,255,255,0.05);

    /* Shadows */
    --th-shadow: 0 2px 8px rgba(0,0,0,0.3);
    --th-shadow-hover: 0 8px 24px rgba(0,0,0,0.4);
    --th-shadow-glow: 0 0 20px color-mix(in srgb, var(--mag, #D41367) 30%, transparent);

    /* Radii -- pill-first design */
    --th-radius: 12px;
    --th-radius-sm: 8px;
    --th-radius-lg: 16px;
    --th-radius-xl: 24px;
    --th-radius-pill: 320px;

    /* Motion */
    --th-transition: all 0.2s ease;
    --th-transition-slow: all 0.3s ease;
}

/* Light mode overrides */
[data-bs-theme="light"], [data-theme="light"] {
    --th-text: #151618;
    --th-text-secondary: #52525B;
    --th-text-muted: #9CA3AF;
    --th-bg: #FBFBFB;
    --th-surface: #FFFFFF;
    --th-surface-elevated: #FFFFFF;
    --th-surface-mid: #EBEBEB;
    --th-card: #FFFFFF;
    --th-border: #E2E5EC;
    --th-border-hover: var(--mag, #D41367);
    --th-divider: #F0F2F5;
    --th-glass: rgba(0,0,0,0.03);
    --th-shadow: 0 2px 8px rgba(0,0,0,0.06);
    --th-shadow-hover: 0 8px 24px rgba(0,0,0,0.1);
    /* Derived from the accent, not a declared fourth pink. The old #FDE8F0 was an
       off-spec hue: brandbook p6 pairs 214C exclusively with black. */
    --th-pink-light: color-mix(in srgb, var(--mag, #D41367) 12%, #FFFFFF);
    --th-green-light: #D1FAE5;
    --th-red-light: #FEE2E2;
    --th-orange-light: #FFEDD5;
    --th-yellow-light: #FEF3C7;
    --th-indigo-light: #EEF2FF;
}


/* ================================================================
   1. PILL NAVIGATION
   WHY: Cross-page navigation for service sections
   CONTEXT: Dashboard / Services / Monitoring / Reports
   ================================================================ */
.th-pill-nav {
    display: flex;
    gap: 2px;
    background: var(--th-surface-mid);
    padding: 3px;
    border-radius: var(--th-radius);
}
.th-pill {
    padding: 0.4rem 0.9rem;
    background: transparent;
    border: none;
    color: var(--th-text-secondary);
    font-size: 13px;
    font-weight: 500;
    border-radius: var(--th-radius-sm);
    cursor: pointer;
    transition: var(--th-transition);
    text-decoration: none;
    white-space: nowrap;
}
.th-pill:hover { color: var(--th-text); }
.th-pill.active {
    background: var(--th-surface-elevated);
    color: var(--th-text);
    box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
.th-pill i { margin-right: 0.3rem; font-size: 11px; }


/* ================================================================
   2. TAB BAR
   WHY: ALL tab/filter bars across portal MUST use .th-tabs
   CONTEXT: Never write inline pill-tab CSS -- this handles dark/light
   ================================================================ */
.th-tabs {
    display: flex;
    gap: 2px;
    background: var(--th-surface-mid);
    padding: 3px;
    border-radius: var(--th-radius);
    flex-wrap: wrap;
}
.th-tab {
    padding: 0.4rem 0.9rem;
    background: transparent;
    border: none;
    color: var(--th-text-secondary);
    font-size: 13px;
    font-weight: 500;
    border-radius: var(--th-radius-sm);
    cursor: pointer;
    transition: var(--th-transition);
    text-decoration: none;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.th-tab:hover { color: var(--th-text); }
.th-tab.active {
    background: var(--th-surface-elevated);
    color: var(--th-text);
    box-shadow: 0 1px 2px rgba(0,0,0,0.15);
    font-weight: 600;
}
.th-tab i { font-size: 12px; }
.th-tab-count {
    font-size: 11px;
    font-weight: 700;
    background: var(--th-pink-light);
    color: var(--th-pink);
    padding: 1px 7px;
    border-radius: var(--th-radius-pill);
    min-width: 20px;
    text-align: center;
}
.th-tab.active .th-tab-count {
    background: var(--th-pink);
    color: #fff;
}


/* ================================================================
   3. BUTTONS
   WHY: Unified button system -- pill-first to match Thusa brand
   CONTEXT: ALL buttons default to pill shape (border-radius: 320px)
   RULE: White text on ALL colored buttons, always
   ================================================================ */

/* Base button -- pill by default */
.th-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.5rem 1.2rem;
    font-size: 13px;
    font-weight: 600;
    border-radius: var(--th-radius-pill);
    border: 1px solid transparent;
    cursor: pointer;
    transition: var(--th-transition);
    text-decoration: none;
    white-space: nowrap;
    line-height: 1.4;
    font-family: inherit;
}
.th-btn:disabled, .th-btn.disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}
.th-btn i, .th-btn .ph { font-size: 14px; }

/* Primary -- Thusa Pink (main CTA) */
.th-btn-primary {
    background: var(--th-pink);
    color: #fff;
    border-color: var(--th-pink);
}
.th-btn-primary:hover {
    background: var(--th-pink-dark);
    border-color: var(--th-pink-dark);
    color: #fff;
    box-shadow: var(--th-shadow-glow);
}

/* Dark -- near-black background */
.th-btn-dark {
    background: var(--th-bg);
    color: #fff;
    border-color: var(--th-border-hover);
}
.th-btn-dark:hover {
    background: var(--th-surface-elevated);
    border-color: var(--th-border-hover);
    color: #fff;
}

/* Success -- green for confirmations */
.th-btn-success {
    background: var(--th-green);
    color: #fff;
    border-color: var(--th-green);
}
.th-btn-success:hover {
    background: var(--th-green-dark);
    border-color: var(--th-green-dark);
    color: #fff;
}

/* Danger -- red for destructive actions */
.th-btn-danger {
    background: var(--th-red);
    color: #fff;
    border-color: var(--th-red);
}
.th-btn-danger:hover { background: #DC2626; border-color: #DC2626; color: #fff; }

/* Warning -- orange for caution */
.th-btn-warning {
    background: var(--th-orange);
    color: #fff;
    border-color: var(--th-orange);
}
.th-btn-warning:hover { background: #EA580C; border-color: #EA580C; color: #fff; }

/* Outline -- border only, pink accent */
.th-btn-outline {
    background: transparent;
    color: var(--th-text);
    border-color: var(--th-border-hover);
}
.th-btn-outline:hover {
    border-color: var(--th-pink);
    color: var(--th-pink);
    background: var(--th-pink-light);
}

/* Ghost -- no border, subtle hover */
.th-btn-ghost {
    background: transparent;
    color: var(--th-text-secondary);
    border-color: transparent;
}
.th-btn-ghost:hover { background: var(--th-glass); color: var(--th-text); }

/* Sizes */
.th-btn-sm { padding: 0.3rem 0.8rem; font-size: 12px; }
.th-btn-sm i { font-size: 12px; }
.th-btn-lg { padding: 0.7rem 1.6rem; font-size: 15px; }
.th-btn-lg i { font-size: 16px; }

/* Square variant (overrides pill default) */
.th-btn-square { border-radius: var(--th-radius-sm); }

/* Full width */
.th-btn-block { width: 100%; }

/* Icon-only circle button */
.th-btn-icon {
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: 50%;
}
.th-btn-icon.th-btn-sm { width: 32px; height: 32px; }
.th-btn-icon.th-btn-lg { width: 48px; height: 48px; }

/* Arrow CTA (Thusa signature style -- pink circle with arrow) */
.th-btn-arrow {
    width: 48px;
    height: 48px;
    padding: 0;
    border-radius: 50%;
    background: var(--th-pink);
    color: #fff;
    border: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.th-btn-arrow:hover {
    background: var(--th-pink-dark);
    box-shadow: var(--th-shadow-glow);
    color: #fff;
}
.th-btn-arrow i, .th-btn-arrow .ph { font-size: 18px; }

/* Button group */
.th-btn-group {
    display: inline-flex;
    border-radius: var(--th-radius-sm);
    overflow: hidden;
}
.th-btn-group .th-btn {
    border-radius: 0;
    border-right-width: 0;
}
.th-btn-group .th-btn:first-child { border-radius: var(--th-radius-sm) 0 0 var(--th-radius-sm); }
.th-btn-group .th-btn:last-child { border-radius: 0 var(--th-radius-sm) var(--th-radius-sm) 0; border-right-width: 1px; }


/* ================================================================
   4. BADGES & STATUS INDICATORS
   WHY: Consistent status communication (service health, tickets, etc.)
   CONTEXT: Service status, client status, ticket counts
   ================================================================ */

/* Inline badge */
.th-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px;
    font-size: 11px;
    font-weight: 600;
    border-radius: var(--th-radius-sm);
    white-space: nowrap;
    line-height: 1.5;
}
.th-badge-pink { background: var(--th-pink-light); color: var(--th-pink); }
.th-badge-green { background: var(--th-green-light); color: var(--th-green); }
.th-badge-red { background: var(--th-red-light); color: var(--th-red); }
.th-badge-orange { background: var(--th-orange-light); color: var(--th-orange); }
.th-badge-yellow { background: var(--th-yellow-light); color: var(--th-yellow); }
.th-badge-indigo { background: var(--th-indigo-light); color: var(--th-indigo); }
.th-badge-muted { background: var(--th-glass); color: var(--th-text-secondary); }

/* Pill badge (count) */
.th-badge-pill {
    border-radius: var(--th-radius-pill);
    min-width: 22px;
    text-align: center;
    padding: 2px 8px;
}

/* Status dot indicator */
.th-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    display: inline-block;
    flex-shrink: 0;
}
.th-dot-green { background: var(--th-green); }
.th-dot-orange { background: var(--th-orange); }
.th-dot-red { background: var(--th-red); }
.th-dot-gray { background: var(--th-text-muted); }
.th-dot-pink { background: var(--th-pink); }

/* Pulsing dot (live/active indicator) */
.th-dot-pulse {
    position: relative;
}
.th-dot-pulse::after {
    content: '';
    position: absolute;
    top: -2px;
    left: -2px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: inherit;
    opacity: 0.4;
    animation: th-pulse 1.5s ease-in-out infinite;
}
@keyframes th-pulse {
    0%, 100% { transform: scale(1); opacity: 0.4; }
    50% { transform: scale(1.5); opacity: 0; }
}

/* Service status inline (dot + label) */
.th-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--th-text-secondary);
}

/* Category / Service pill */
.th-category-pill {
    font-size: 10px;
    font-weight: 600;
    padding: 3px 10px;
    border-radius: var(--th-radius-pill);
    background: var(--th-pink-light);
    color: var(--th-pink);
    text-decoration: none;
}
.th-category-pill:hover { opacity: 0.85; color: var(--th-pink); }


/* ================================================================
   5. SERVICE CARD
   WHY: Standardized service/offering tile for portal and marketing
   CONTEXT: Replaces "product card" from TT -- used for MSP services
   ================================================================ */
/* CARD SURFACE CONTRACT (Pulse f50120c0)
   The card layer had drifted into two token generations. Home -- which is the
   design system of record for this pass -- draws on the Direction 1b
   vocabulary: var(--canvas) ground, a 1px var(--line) edge, SQUARE corners
   (--r-0), --sp-* padding, and a border-colour-only transition to var(--mag).
   .th-tile, .th-outcome-card, .th-result-card and .th-split-card all speak it.

   These five did not. They carried the older --th-* set: --th-radius 12px or
   --th-radius-lg 16px rounded corners, --th-card / --th-border, and
   `transition: all`. Rounded-against-square is the inconsistency the bug is
   pointing at -- the same component reads as two different components
   depending on which page you land on.

   Each of the five keeps its own LAYOUT (flex direction, gap, icon sizes,
   whatever it needs to do its job) and adopts the shared SURFACE. Layout is
   per-component; surface is not. */
.th-service-card {
    background: var(--canvas);
    border-radius: var(--r-0);
    border: 1px solid var(--line);
    overflow: visible;
    display: flex;
    flex-direction: column;
    transition: border-color var(--dur-base) var(--ease);
    position: relative;
    padding: var(--sp-9);
}
.th-service-card:hover {
    border-color: var(--mag);
}

/* Icon container at top of card */
.th-service-icon {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    margin-bottom: 16px;
    font-size: 20px;
}
.th-service-icon-pink {
    background: var(--th-pink);
    color: #fff;
}
.th-service-icon-outline {
    background: transparent;
    border: 1px solid var(--th-border-hover);
    color: var(--th-pink);
}
.th-service-icon-ghost {
    background: var(--th-glass);
    color: var(--th-text);
}

/* Service card content */
.th-service-title {
    font-size: 18px;
    font-weight: 600;
    font-family: var(--font-heading);
    color: var(--th-text);
    margin-bottom: 8px;
    line-height: 1.3;
}
.th-service-desc {
    font-size: 14px;
    line-height: 1.6;
    color: var(--th-text-secondary);
    margin-bottom: 16px;
    flex: 1;
}
.th-service-link {
    font-size: 13px;
    font-weight: 600;
    color: var(--th-pink);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: var(--th-transition);
}
.th-service-link:hover { gap: 10px; }
.th-service-link i, .th-service-link .ph { font-size: 12px; }

/* Service grid */
.th-service-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
}
@media (max-width: 1024px) { .th-service-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .th-service-grid { grid-template-columns: 1fr; } }


/* ================================================================
   6. HERO SECTION
   WHY: Dark hero banner with photo overlay + accent word highlighting
   CONTEXT: Based on thusamsp.com hero -- large text, dark overlay, pink accents
   ================================================================ */
.th-hero {
    background: var(--th-bg);
    border-radius: var(--th-radius-lg);
    overflow: hidden;
    position: relative;
    min-height: 480px;
    display: flex;
    align-items: flex-end;
    padding: 48px;
}
.th-hero-bg {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    z-index: 0;
}
.th-hero-bg::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(11,12,15,0.3) 0%, rgba(11,12,15,0.85) 100%);
}
.th-hero-content {
    position: relative;
    z-index: 1;
    max-width: 700px;
}
.th-hero h1 {
    font-family: var(--font-heading);
    font-size: clamp(32px, 5vw, 64px);
    font-weight: 400;
    line-height: 1.0;
    color: #FFFFFF;
    margin-bottom: 16px;
}
.th-hero h1 .accent {
    color: var(--th-pink);
}
.th-hero-sub {
    font-size: 16px;
    line-height: 1.6;
    color: rgba(255,255,255,0.8);
    margin-bottom: 28px;
    max-width: 520px;
}
.th-hero-ctas {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}
@media (max-width: 768px) {
    .th-hero { padding: 32px 24px; min-height: 360px; }
}

/* Eyebrow tag */
.th-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--th-pink);
    margin-bottom: 14px;
}
.th-eyebrow-dot {
    width: 6px;
    height: 6px;
    background: var(--th-pink);
    border-radius: 50%;
}


/* ================================================================
   7. VALUE PROPOSITION STRIP
   WHY: Three-column feature highlights below hero
   CONTEXT: Tailored Solutions / Strategic Partner / Committed to Success
   ================================================================ */
.th-vp-strip {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    border: 1px solid var(--th-border);
    border-radius: var(--th-radius);
    overflow: hidden;
    background: var(--th-card);
    margin-top: 16px;
}
.th-vp {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 20px 24px;
    border-right: 1px solid var(--th-border);
    transition: background 0.15s;
}
.th-vp:last-child { border-right: none; }
.th-vp:hover { background: var(--th-pink-light); }
.th-vp-icon {
    width: 40px;
    height: 40px;
    background: var(--th-pink-light);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--th-pink);
    font-size: 16px;
}
.th-vp-title {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--th-text);
    margin-bottom: 4px;
}
.th-vp-desc { font-size: 12px; color: var(--th-text-secondary); line-height: 1.5; }
@media (max-width: 768px) {
    .th-vp-strip { grid-template-columns: 1fr; }
    .th-vp { border-right: none; border-bottom: 1px solid var(--th-border); }
    .th-vp:last-child { border-bottom: none; }
}


/* ================================================================
   8. STAT CARD
   WHY: Dashboard KPI tiles (uptime, tickets, clients, SLA)
   CONTEXT: Admin portal, service dashboard
   ================================================================ */
.th-stat-card {
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    padding: var(--sp-6);
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.th-stat-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--th-text-muted);
}
.th-stat-value {
    font-size: 24px;
    font-weight: 800;
    font-family: var(--font-heading);
    color: var(--th-text);
    line-height: 1.2;
}
.th-stat-change {
    font-size: 12px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.th-stat-change.up { color: var(--th-green); }
.th-stat-change.down { color: var(--th-red); }
.th-stat-change.flat { color: var(--th-text-muted); }

/* Stat grid */
.th-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px;
}


/* ================================================================
   9. SECTION HEADER
   WHY: Consistent section dividers with title + optional action
   ================================================================ */
.th-section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--th-border);
}
.th-section-title {
    font-size: 16px;
    font-weight: 700;
    font-family: var(--font-heading);
    color: var(--th-text);
    display: flex;
    align-items: center;
    gap: 8px;
}
.th-section-title i, .th-section-title .ph { color: var(--th-pink); font-size: 16px; }
.th-section-action {
    font-size: 13px;
    color: var(--th-pink);
    font-weight: 600;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.th-section-action:hover { gap: 10px; }


/* ================================================================
   10. PARTNER LOGO STRIP
   WHY: Display technology partner logos (grayscale on dark bg)
   CONTEXT: Powered By section -- Mimecast, Veeam, Microsoft, etc.
   ================================================================ */
.th-partner-strip {
    display: flex;
    align-items: center;
    gap: 32px;
    padding: 24px 0;
    flex-wrap: wrap;
    justify-content: center;
}
.th-partner-strip img {
    height: 28px;
    opacity: 0.5;
    filter: grayscale(1) brightness(2);
    transition: var(--th-transition);
}
.th-partner-strip img:hover {
    opacity: 1;
    filter: grayscale(0);
}
.th-partner-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--th-text-muted);
    width: 100%;
    text-align: center;
    margin-bottom: 8px;
}


/* ================================================================
   11. TESTIMONIAL CARD
   WHY: Client testimonial display with star rating
   CONTEXT: Social proof section -- case studies, reviews
   ================================================================ */
.th-testimonial-card {
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    padding: var(--sp-9);
    display: flex;
    flex-direction: column;
    gap: 16px;
}
.th-testimonial-stars {
    display: flex;
    gap: 2px;
    color: var(--th-yellow);
    font-size: 14px;
}
.th-testimonial-quote {
    font-size: 14px;
    line-height: 1.7;
    color: var(--th-text-secondary);
    font-style: italic;
}
.th-testimonial-author {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: auto;
}
.th-testimonial-avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--th-pink-light);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 14px;
    color: var(--th-pink);
}
.th-testimonial-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--th-text);
}
.th-testimonial-role {
    font-size: 12px;
    color: var(--th-text-muted);
}

/* Testimonial grid */
.th-testimonial-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
}
@media (max-width: 1024px) { .th-testimonial-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .th-testimonial-grid { grid-template-columns: 1fr; } }


/* ================================================================
   12. INDUSTRY CARD
   WHY: Display industry verticals served (dark card grid)
   CONTEXT: Professional Services, Manufacturing, Medical, etc.
   ================================================================ */
.th-industry-card {
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    padding: var(--sp-7);
    transition: border-color var(--dur-base) var(--ease);
    display: flex;
    align-items: center;
    gap: 14px;
}
/* No background swap on hover. The 1b cards move their border and nothing
   else, and a ground that changes under the cursor was the loudest of the
   divergences on a grid of eight. */
.th-industry-card:hover {
    border-color: var(--mag);
}
.th-industry-icon {
    width: 40px;
    height: 40px;
    border-radius: var(--th-radius-sm);
    background: var(--th-glass);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    color: var(--th-pink);
    flex-shrink: 0;
}
.th-industry-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--th-text);
}
.th-industry-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}
@media (max-width: 768px) { .th-industry-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .th-industry-grid { grid-template-columns: 1fr; } }


/* ================================================================
   13. FORM ELEMENTS
   WHY: Branded inputs consistent with Thusa dark-first tokens
   CONTEXT: Search, filters, contact forms, portal inputs
   ================================================================ */
.th-input {
    width: 100%;
    padding: 0.55rem 0.85rem;
    font-size: 14px;
    border: 1px solid var(--th-border);
    border-radius: var(--th-radius-sm);
    background: var(--th-surface);
    color: var(--th-text);
    transition: var(--th-transition);
    line-height: 1.5;
    font-family: inherit;
}
.th-input:focus {
    outline: none;
    border-color: var(--th-pink);
    box-shadow: 0 0 0 3px var(--mag-soft);
}
.th-input::placeholder { color: var(--th-text-muted); }

.th-select {
    width: 100%;
    padding: 0.55rem 0.85rem;
    font-size: 14px;
    border: 1px solid var(--th-border);
    border-radius: var(--th-radius-sm);
    background: var(--th-surface);
    color: var(--th-text);
    transition: var(--th-transition);
    cursor: pointer;
    appearance: none;
    font-family: inherit;
    background-image: url("data:image/svg+xml,%3Csvg width='10' height='6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23B5B5B5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    padding-right: 30px;
}
.th-select:focus {
    outline: none;
    border-color: var(--th-pink);
    box-shadow: 0 0 0 3px var(--mag-soft);
}

/* Input with icon */
.th-input-group {
    position: relative;
    display: flex;
    align-items: center;
}
.th-input-group .th-input { padding-left: 2.4rem; }
.th-input-group i, .th-input-group .ph {
    position: absolute;
    left: 0.85rem;
    color: var(--th-text-muted);
    font-size: 14px;
    pointer-events: none;
}

/* Checkbox / Radio */
.th-check {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--th-text-secondary);
    cursor: pointer;
    padding: 4px 0;
}
.th-check input[type="checkbox"],
.th-check input[type="radio"] {
    accent-color: var(--th-pink);
    width: 16px;
    height: 16px;
    cursor: pointer;
}
.th-check:hover { color: var(--th-text); }


/* ================================================================
   14. PAGINATION
   WHY: Consistent page navigation across paginated views
   ================================================================ */
.th-pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 4px;
    margin-top: 24px;
}
.th-page-link {
    padding: 8px 14px;
    border: 1px solid var(--th-border);
    background: var(--th-card);
    border-radius: var(--th-radius-sm);
    font-size: 13px;
    cursor: pointer;
    color: var(--th-text-secondary);
    text-decoration: none;
    transition: var(--th-transition);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
}
.th-page-link:hover { border-color: var(--th-pink); color: var(--th-pink); }
.th-page-link.active {
    background: var(--th-pink);
    color: #fff;
    border-color: var(--th-pink);
}
.th-page-link.disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }


/* ================================================================
   15. SIDEBAR FILTER
   WHY: Reusable sidebar filter panel
   CONTEXT: Service type, status, client filters
   ================================================================ */
.th-sidebar { height: fit-content; position: sticky; top: 80px; }
/* Shadow dropped along with the radius. Nothing on the home page lifts off the
   canvas -- depth there is carried by the border, not by a drop shadow -- and
   a shadow under a square edge reads as a mistake rather than as elevation. */
.th-sidebar-card {
    background: var(--canvas);
    border-radius: var(--r-0);
    border: 1px solid var(--line);
    overflow: hidden;
}
.th-sidebar-header {
    padding: 14px 16px;
    font-size: 14px;
    font-weight: 600;
    border-bottom: 1px solid var(--th-border);
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--th-text);
}
.th-filter-group {
    padding: 14px 16px;
    border-bottom: 1px solid var(--th-border);
}
.th-filter-group:last-child { border-bottom: none; }
.th-filter-group h4 {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--th-text-secondary);
    margin-bottom: 10px;
}
.th-filter-option {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--th-text-secondary);
    padding: 4px 0;
    cursor: pointer;
}
.th-filter-option:hover { color: var(--th-text); }
.th-filter-count { margin-left: auto; font-size: 11px; color: var(--th-text-muted); }


/* ================================================================
   16. EMPTY STATE
   WHY: Consistent "no results" messaging
   ================================================================ */
.th-empty-state {
    text-align: center;
    padding: 48px 20px;
    color: var(--th-text-secondary);
}
.th-empty-state i, .th-empty-state .ph {
    font-size: 48px;
    color: var(--th-text-muted);
    margin-bottom: 16px;
    display: block;
}
.th-empty-state h4 {
    font-size: 16px;
    font-weight: 600;
    font-family: var(--font-heading);
    color: var(--th-text);
    margin-bottom: 8px;
}
.th-empty-state p {
    font-size: 13px;
    color: var(--th-text-secondary);
    margin-bottom: 16px;
}


/* ================================================================
   17. CTA BANNER
   WHY: Call-to-action section with photo background (Thusa signature)
   CONTEXT: "Ready to..." section seen on thusamsp.com
   ================================================================ */
.th-cta-banner {
    background: var(--th-surface);
    border-radius: var(--th-radius-lg);
    overflow: hidden;
    position: relative;
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 300px;
}
.th-cta-banner-content {
    padding: 40px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}
.th-cta-banner-img {
    position: relative;
    overflow: hidden;
}
.th-cta-banner-img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.th-cta-banner h2 {
    font-family: var(--font-heading);
    font-size: clamp(24px, 3vw, 40px);
    font-weight: 400;
    line-height: 1.1;
    color: var(--th-text);
    margin-bottom: 16px;
}
.th-cta-banner h2 .accent { color: var(--th-pink); }
.th-cta-banner p {
    font-size: 14px;
    color: var(--th-text-secondary);
    margin-bottom: 24px;
    line-height: 1.6;
}
@media (max-width: 768px) {
    .th-cta-banner { grid-template-columns: 1fr; }
    .th-cta-banner-img { display: none; }
    .th-cta-banner-content { padding: 32px 24px; }
}


/* ================================================================
   WCAG TOUCH TARGETS
   ================================================================ */
@media (max-width: 768px) {
    .th-btn { min-height: 44px; min-width: 44px; }
    .th-page-link { min-height: 44px; min-width: 44px; }
    .th-tab { min-height: 44px; }
}


/* ================================================================
   DIRECTION 1b -- "Cinematic"
   WHY: The approved homepage direction (2026-08). Full-bleed dark
        imagery, a magenta signal rail, square editorial cards and a
        dark four-column mega menu.
   CONTEXT: Every value here reads a token from templates/theme/
        _design_tokens.html, which is fed from theme.json. Nothing in
        this block may carry a literal colour or font-family -- the
        design-token gate treats those as brand claims.
   SCOPE: Shared chrome + homepage + public Zone 1/3 templates. The
        cart, accounts and auth surfaces deliberately keep the older
        pill-radius system, so a corner mismatch across that boundary
        is expected until they are brought across in a later pass.

   BREAKPOINT LADDER -- custom properties cannot be read inside a
   @media query, so these are a fixed constant set. Use only these:
     1100px  nav collapses to the mobile panel; mega menu disabled
      980px  3-col -> 1-col; why-grid stacks; results stack
      900px  offering rows reflow; vendor grid 6 -> 3
      768px  decision cards stack; stat band 4 -> 2x2
      640px  footer 2 -> 1 col
      480px  card padding tightens
   The page gutter is NOT in this ladder -- it is clamp()ed at its source in
   theme/_design_tokens.html, because a :root override here cannot win against
   that block's document order.
   1100/1101 is load-bearing: base.html's matchMedia auto-closes the
   mobile panel at the same value. Change one and you must change both,
   or the panel is stranded open on resize.
   ================================================================ */

/* ---- Motion ---------------------------------------------------
   One-shot, hero only, with `both` fill so the end state persists.
   The global prefers-reduced-motion block zeroes animation for `*`,
   which leaves the end state -- legible without ever having moved. */
@keyframes th-rise {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
}
@keyframes th-rail {
    from { transform: scaleY(0); }
    to   { transform: scaleY(1); }
}

/* ---- Repeating devices ----------------------------------------
   The 1b grammar is four devices reused across eleven sections, so they
   are named for the device rather than the section that hosts them. */

/* The signal rail. A flex sibling, NOT a ::before -- it has to stretch
   to the height of the copy block it sits beside. */
.th-rail {
    flex: none;
    width: 2px;
    align-self: stretch;
    background: var(--mag);
    transform-origin: top;
}
.th-hero-body .th-rail { animation: th-rail var(--dur-rail) var(--ease) both; }

/* The 1b eyebrow metrics differ from the original .th-eyebrow, which
   other templates still use -- so it is extended here, not redefined. */
.th-eyebrow.th-eyebrow--mono {
    /* Two classes deliberately. The base .th-eyebrow is a bordered pill declared
       in base.html's inline <style>, which the browser applies AFTER this linked
       stylesheet -- so a single-class modifier here loses on document order no
       matter what it says. Raising specificity wins regardless of order, and
       leaves the base rule intact for the templates still using the pill. */
    border: 0;
    border-radius: var(--r-0);
    padding: 0;
    margin-bottom: var(--sp-4);
    font-family: var(--font-mono);
    font-size: var(--fs-2);
    font-weight: 600;
    letter-spacing: var(--ls-eyebrow);
    color: var(--mag);
    gap: 0;
}
.th-eyebrow.th-eyebrow--muted { color: var(--fg-3); }

/* Two-line display heading: line one in --fg, line two in the accent. */
.th-split-h {
    margin: 0;
    font-family: var(--font-heading);
    font-weight: 700;
    line-height: var(--lh-head);
    letter-spacing: var(--ls-head);
    color: var(--fg);
}
.th-split-h .th-accent { color: var(--mag); }

/* Magenta bar that wipes in from the left on parent hover. */
.th-swipe {
    display: block;
    height: 3px;
    width: 100%;
    background: var(--mag);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--dur-slow) var(--ease);
}
.th-split-card:hover .th-swipe,
.th-split-card:focus-visible .th-swipe { transform: scaleX(1); }

/* Inline "Read the outcome ->" affordance. */
.th-arrow-link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--fs-5);
    font-weight: 600;
    color: var(--mag);
    text-decoration: none;
}
.th-arrow-link:hover { color: var(--mag-press); }

/* The 1b CTAs are larger than the 13px .th-btn default. Pair with the
   existing .th-btn-outline / .th-btn-ghost rather than new colours. */
.th-btn-cine {
    padding: var(--sp-4) var(--sp-8);
    font-size: var(--fs-5);
}
.th-btn-outline.th-btn-cine {
    border-color: var(--mag);
    color: var(--fg);
}
.th-btn-outline.th-btn-cine:hover {
    background: var(--mag);
    color: var(--fg-hi);
}
.th-btn-ghost.th-btn-cine {
    border-color: var(--line-invert);
    color: var(--fg-1);
}
.th-btn-ghost.th-btn-cine:hover { color: var(--fg); border-color: var(--fg-2); }

/* Shared section shell. --gutter is the single responsive lever. */
.th-sec {
    padding: var(--sec-y) var(--pad-x);
}
.th-sec--deep { background: var(--canvas-deep); }
.th-sec--ruled { border-block: 1px solid var(--line-soft); }

/* Section header: rail + eyebrow + display heading. */
.th-sec-head {
    display: flex;
    gap: var(--sp-9);
    margin-bottom: var(--sp-10);
}
.th-sec-head .th-split-h { font-size: var(--fs-13); }
.th-sec-head--split {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-8);
    flex-wrap: wrap;
    margin-bottom: var(--sp-10);
}
.th-sec-head--split .th-split-h { font-size: var(--fs-13); }

/* ---- A2 Hero --------------------------------------------------
   Three absolutely-positioned layers under one relative parent:
   wash (magenta bloom), media (the photograph), scrim (legibility).
   The nav renders inside this stacking context, transparent. */
.th-hero-cine {
    position: relative;
    min-height: 720px;
    overflow: hidden;
    padding-bottom: var(--sp-11);
    background: var(--black);
    display: flex;
    flex-direction: column;
}
.th-hero-wash,
.th-hero-media,
.th-hero-scrim {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
.th-hero-wash {
    background:
        radial-gradient(70% 90% at 78% 18%,
            color-mix(in srgb, var(--mag) 28%, transparent), transparent 62%),
        linear-gradient(180deg, transparent, var(--canvas));
    z-index: 2;
}
.th-hero-media { z-index: 0; }
.th-hero-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.th-hero-scrim {
    z-index: 1;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--black) 92%, transparent) 0%,
        color-mix(in srgb, var(--black) 35%, transparent) 58%,
        color-mix(in srgb, var(--black) 70%, transparent) 100%);
}
.th-hero-body {
    position: relative;
    z-index: 3;
    display: flex;
    gap: var(--sp-8);
    padding: var(--sp-12) var(--pad-x) 0;
    margin-top: auto;
}
/* The cap lives here, not on .th-hero-body: --pad-x is the centred column, and
   box-sizing is border-box, so a max-width up there is measured across the two
   gutters instead of beside them. Same rule as every other --pad-x section. */
.th-hero-copy {
    max-width: 1000px;
    animation: th-rise var(--dur-rise) var(--ease) var(--delay-rise) both;
}
.th-hero-h {
    font-size: var(--fs-15);
    line-height: 0.98;
    letter-spacing: var(--ls-hero);
    max-width: 900px;
    margin: var(--sp-5) 0 var(--sp-6);
}
.th-hero-lede {
    font-size: var(--fs-8);
    line-height: var(--lh-body);
    font-weight: 300;
    color: var(--fg-1);
    max-width: 620px;
    margin: 0 0 var(--sp-9);
}
.th-hero-ctas { display: flex; flex-wrap: wrap; gap: var(--sp-4); }

/* ---- A3 Stat band --------------------------------------------- */
.th-statband {
    display: flex;
    flex-wrap: wrap;
    background: var(--canvas);
    border-bottom: 1px solid var(--line-soft);
    /* Padding here, not on .th-stat: the band's bottom rule should still run the
       full width while the figures line up with the rest of the page. */
    padding-inline: var(--pad-x);
}
.th-stat {
    flex: 1 1 220px;
    display: flex;
    align-items: baseline;
    gap: var(--sp-4);
    padding: var(--sp-9) var(--sp-8);
    border-right: 1px solid var(--line-soft);
}
.th-stat:last-child { border-right: 0; }
.th-stat-num {
    font-family: var(--font-heading);
    font-size: var(--fs-11);
    font-weight: 700;
    letter-spacing: var(--ls-head);
    color: var(--fg);
    white-space: nowrap;
}
/* A single accent on the first figure is deliberate -- four magenta
   numbers reads as decoration, one reads as emphasis. */
.th-stat:first-child .th-stat-num { color: var(--mag); }
.th-stat-lbl { font-size: var(--fs-4); color: var(--fg-2); }

/* ---- A4 Decision split --------------------------------------- */
.th-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    padding-inline: var(--pad-x);
}
.th-split-card {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: var(--sp-4);
    min-height: 420px;
    padding: var(--sp-11);
    text-decoration: none;
    border-right: 1px solid var(--line-soft);
    background: linear-gradient(180deg, var(--canvas), var(--black));
    transition: background var(--dur-mid) var(--ease);
}
.th-split-card:last-child { border-right: 0; }
.th-split-card:hover { background: linear-gradient(180deg, var(--card), var(--black)); }
.th-split-card h2 {
    margin: var(--sp-3) 0 var(--sp-4);
    font-size: var(--fs-12);
    font-weight: 700;
    letter-spacing: var(--ls-head);
    color: var(--fg);
}
.th-split-card p {
    margin: 0 0 var(--sp-5);
    font-size: var(--fs-6);
    line-height: var(--lh-body);
    color: var(--fg-1);
    max-width: 46ch;
}

/* ---- A5 Featured outcomes ------------------------------------ */
.th-outcome-grid { display: grid; --grid-gap: var(--sp-8); gap: var(--grid-gap); }
.th-outcome-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    overflow: hidden;
    background: var(--canvas);
    transition: border-color var(--dur-base) var(--ease);
}
.th-outcome-card:hover { border-color: var(--mag); }
/* aspect-ratio, not a fixed height. The track widens with the content column
   while a locked 200px did not, so the crop drifted continuously with viewport
   width: 426x200 (2.13:1) at 1440 and 565x200 (2.82:1) at 2560, against a
   720x400 source that is 1.80:1. Cards on the same page got visibly different
   framing depending on the display they were opened on.

   9/5 is the source ratio exactly (720/400). .th-result-media was already
   correct at 1.78:1 and is the pattern this now follows. min-height keeps the
   band from collapsing in the single-column layout. */
.th-outcome-media {
    position: relative;
    aspect-ratio: 9 / 5;
    min-height: 190px;
    background: var(--card);
}
.th-outcome-media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.th-outcome-body { padding: var(--sp-9); }
.th-outcome-body h3 {
    margin: 0 0 var(--sp-3);
    font-size: var(--fs-10);
    font-weight: 600;
    letter-spacing: var(--ls-sub);
    color: var(--fg);
}
.th-outcome-body p {
    margin: 0 0 var(--sp-5);
    font-size: var(--fs-5);
    line-height: var(--lh-loose);
    color: var(--fg-2);
}

/* ---- A6 Offerings list ---------------------------------------
   A real <ul>: a list of three or more inside <main> is a scored
   AI-readiness signal, and bare <a> siblings are not one. */
.th-offering-rows {
    list-style: none;
    margin: 0;
    padding: 0;
    border: 1px solid var(--line);
}
.th-offering-rows > li { border-bottom: 1px solid var(--line); }
.th-offering-rows > li:last-child { border-bottom: 0; }
.th-offering-row {
    display: grid;
    grid-template-columns: 56px minmax(0, 320px) 1fr 40px;
    gap: var(--sp-9);
    align-items: center;
    padding: var(--sp-8) var(--sp-9);
    text-decoration: none;
    transition: background var(--dur-fast) var(--ease);
}
.th-offering-row:hover { background: var(--card); }
.th-offering-glyph {
    width: 40px;
    height: 40px;
    border: 1px solid var(--mag);
    border-radius: var(--r-pill);
    display: grid;
    place-items: center;
    color: var(--mag);
}
.th-offering-row h3 {
    margin: 0;
    font-size: var(--fs-9);
    font-weight: 600;
    letter-spacing: var(--ls-sub);
    color: var(--fg);
}
.th-offering-row p {
    margin: 0;
    font-size: var(--fs-5);
    line-height: var(--lh-body);
    color: var(--fg-2);
}
.th-offering-arrow { text-align: right; color: var(--mag); }

/* ---- A7 Why THUSA -------------------------------------------- */
.th-why {
    padding: var(--sec-y-lg) var(--pad-x);
    background: linear-gradient(120deg, var(--canvas), var(--black));
    border-block: 1px solid var(--line-soft);
}
 /* The copy track is sized to the measure its content actually occupies, and
   the plates take the remainder -- not the other way round.

   It was `1fr 520px`, which failed twice over. The 520px plate track was fixed,
   so both plates rendered 251x228 at a 1440 viewport and 251x228 at 2560:
   0.45x of their own 560x460 source, unable to grow at any width. And because
   the copy track was `1fr` while the copy inside it is capped much narrower
   (--th-why-lede 560px, .th-pillar 230px), the left track claimed 761px at 1440
   for ~600px of text -- leaving a ~265px empty gap between the copy and the
   plates. The section read as two small pictures marooned in a black field.

   620px is the copy's real measure: the 560px lede plus gutter, and wide enough
   for the two 230px pillars side by side. Everything left over goes to the
   plates, so they reach ~530px each at 2560 -- just under their 560px native
   width, which is the upscale ceiling. */
.th-why-grid {
    display: grid;
    grid-template-columns: minmax(0, 620px) minmax(0, 1fr);
    gap: var(--sp-11);
    align-items: center;
}
.th-why .th-split-h { font-size: var(--fs-13); }
.th-why-lede {
    font-size: var(--fs-7);
    line-height: var(--lh-loose);
    font-weight: 300;
    color: var(--fg-1);
    max-width: 560px;
    margin: var(--sp-5) 0 var(--sp-10);
}
.th-why-pillars { display: flex; flex-wrap: wrap; gap: var(--sp-10); }
.th-pillar { max-width: 230px; }
.th-pillar h3 {
    margin: 0 0 var(--sp-2);
    font-size: var(--fs-6);
    font-weight: 600;
    color: var(--fg);
}
.th-pillar p {
    margin: 0;
    font-size: var(--fs-4);
    line-height: var(--lh-body);
    color: var(--fg-2);
}
.th-why-plates {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-4);
}
/* aspect-ratio, not a fixed height: the plates now widen with their track, and
   a locked 230px would flatten the crop as they grew -- 6/5 tracks the 560x460
   source (1.22) so the framing holds at every width. The 980px breakpoint below
   still pins an explicit height, which deliberately wins there. */
.th-plate {
    position: relative;
    aspect-ratio: 6 / 5;
    margin: 0;
    border: 1px solid var(--line);
    background: var(--card);
    overflow: hidden;
}
.th-plate img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* The stagger IS the composition -- without the offset this reads as
   two boxes rather than an asymmetric plate pair. */
.th-plate--offset { margin-top: var(--sp-9); }

/* ---- A8 Sectors ---------------------------------------------- */
.th-sectors {
    padding: 70px var(--pad-x);
    border-bottom: 1px solid var(--line-soft);
}
.th-sector-pills {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
    margin: var(--sp-6) 0 0;
    padding: 0;
}
.th-sector-pill {
    display: inline-block;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: var(--sp-3) var(--sp-7);
    font-size: var(--fs-5);
    color: var(--fg-1);
}

/* ---- A9 Case results ---------------------------------------- */
/* Three equal tracks, not 1.3fr + 1fr + 1fr. The lead card's extra width was
   deliberate emphasis on the first case, and it read as a broken grid rather
   than as a hierarchy -- reported against the live site. The floor moved off
   the lead card onto every card so all three keep a height when the ledes are
   short, which is what grid stretch alone does not give. */
.th-result-grid { display: grid; --grid-gap: var(--sp-6); gap: var(--grid-gap); }
.th-result-card {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: var(--sp-3);
    min-height: 400px;
    padding: var(--sp-9);
    text-decoration: none;
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    background: var(--black);
    transition: border-color var(--dur-base) var(--ease);
}
.th-result-card:hover { border-color: var(--mag); }
.th-result-metric {
    font-family: var(--font-heading);
    font-size: var(--fs-12);
    font-weight: 700;
    letter-spacing: var(--ls-head);
    line-height: var(--lh-tight);
    color: var(--fg);
}
.th-result-card p {
    margin: 0 0 var(--sp-4);
    font-size: var(--fs-5);
    line-height: var(--lh-loose);
    color: var(--fg-2);
}

/* ---- A10 Vendor grid (static variant) -----------------------
   The comps default to this. A static grid rather than a marquee, which
   is why this direction needs no drift keyframe and carries no
   reduced-motion liability. Collapsed hairlines via top/left on the
   container and right/bottom on each cell. */
.th-vendors {
    padding: 52px var(--pad-x);
    border-bottom: 1px solid var(--line-soft);
}
.th-vendors-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-8);
    flex-wrap: wrap;
    margin-bottom: var(--sp-7);
}
.th-vendors-note { font-size: var(--fs-3); color: var(--fg-3); }
.th-vendor-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    border-top: 1px solid var(--line-soft);
    border-left: 1px solid var(--line-soft);
}
.th-vendor-cell {
    display: grid;
    place-items: center;
    height: 82px;
    padding: var(--sp-3);
    text-align: center;
    font-size: var(--fs-5);
    font-weight: 600;
    color: var(--fg-1);
    border-right: 1px solid var(--line-soft);
    border-bottom: 1px solid var(--line-soft);
}
.th-vendor-cell img {
    max-width: 100%;
    max-height: 40px;
    object-fit: contain;
}

/* ---- A11 Closing CTA ---------------------------------------- */
.th-close {
    padding: var(--sp-13) var(--pad-x);
    text-align: center;
    background: radial-gradient(80% 120% at 50% 100%,
        color-mix(in srgb, var(--mag) 22%, transparent), transparent 60%);
}
.th-close .th-split-h {
    font-size: var(--fs-14);
    line-height: var(--lh-tight);
    letter-spacing: var(--ls-hero);
    max-width: 900px;
    margin-inline: auto;
}
.th-close p {
    margin: var(--sp-6) auto var(--sp-10);
    max-width: 600px;
    font-size: var(--fs-7);
    font-weight: 300;
    line-height: var(--lh-body);
    color: var(--fg-1);
}
.th-close-ctas {
    display: flex;
    gap: var(--sp-4);
    justify-content: center;
    flex-wrap: wrap;
}

/* ================================================================
   RESPONSIVE -- only the six breakpoints documented at the top.
   ================================================================ */
@media (max-width: 1100px) {
    .th-hero-cine { min-height: 620px; }
}
@media (max-width: 980px) {
    /* .th-outcome-grid / .th-result-grid deliberately have no override here.
       They used to be set to `1fr` at this breakpoint, and it never applied: the
       shared auto-fit rule further down this file has equal specificity and comes
       later in document order, and a media query does not raise specificity. So
       the file stated a single-column collapse that never rendered -- measured
       two columns at 900px. Removed rather than given an !important, because the
       shared rule already degrades correctly on its own 280px track floor:
       two-up at 900px and at 640px, one-up by 480px. */
    /* A 400px floor on a single column is three near-empty tiles in a row. */
    .th-result-card { min-height: 320px; }
    .th-why-grid { grid-template-columns: 1fr; gap: var(--sp-10); }
    .th-why-plates { grid-template-columns: 1fr 1fr; }
    /* No height override here: the base aspect-ratio governs at tablet too.
       The old fixed 190px was tuned when the plates were ~250px wide inside the
       520px track. Once the grid collapses to one column they go two-up at
       ~407px wide, and 190px tall against that width is a 2.14:1 letterbox from
       a 1.22:1 source -- flatter and squatter than the desktop framing it is
       supposed to echo. */
    /* The stagger only reads at two columns beside a copy block. */
    .th-plate--offset { margin-top: 0; }
}
@media (max-width: 900px) {
    .th-offering-row {
        grid-template-columns: 40px 1fr;
        gap: var(--sp-4) var(--sp-6);
    }
    .th-offering-row p { grid-column: 2; }
    .th-offering-arrow { display: none; }
    .th-vendor-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 768px) {
    .th-split { grid-template-columns: 1fr; }
    .th-split-card {
        min-height: 0;
        padding: var(--sp-10) var(--pad-x);
        border-right: 0;
        border-bottom: 1px solid var(--line-soft);
    }
    .th-split-card:last-child { border-bottom: 0; }
    .th-stat { flex: 1 1 45%; padding: var(--sp-7) var(--pad-x); }
    /* Flex borders cannot express a 2x2 hairline; switch to the grid. */
    .th-stat:nth-child(2n) { border-right: 0; }
    .th-stat:nth-child(-n+2) { border-bottom: 1px solid var(--line-soft); }
    .th-hero-body { padding-top: var(--sp-11); }
}
@media (max-width: 640px) {
    .th-vendor-grid { grid-template-columns: repeat(2, 1fr); }
    .th-why-plates { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
    .th-outcome-body { padding: var(--sp-7); }
    .th-result-card { padding: var(--sp-7); }
}


/* ================================================================
   DIRECTION 1b -- MEGA MENU (paper columnar variant)
   WHY paper: the client signed off the "Editorial" comp, which inverts
        the panel to paper against the black bar. This previously read
        "WHY dark", on the grounds that inverting would need a whole
        inverted token ramp on a dark-only site. That ramp now exists --
        --paper-* in theme.json, emitted by theme/_design_tokens.html --
        so the objection is spent. The site itself is still dark-only;
        this is one component, not a light theme.
   CONTEXT: markup in templates/nav/_mega_offerings.html and
        _mega_outcomes.html, data from cms/templatetags/nav_tags.py.

   NO-JS CONTRACT -- this is the reason the menu is CSS-driven:
     mouse    -> :hover opens it
     keyboard -> :focus-within opens it, Tab walks it in DOM order
     touch    -> neither selector matches (hover:hover / pointer:fine),
                 so tapping the trigger just follows its href to the
                 index page, which lists the same links
   Nothing is reachable ONLY through the panel. That is what keeps it
   navigation sugar rather than JS-rendered primary content. JS adds
   aria-expanded syncing and Escape-to-close; it never controls display.
   ================================================================ */
.th-mega {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    /* Clears the bar's magenta base rule -- see --nav-rule in base.html.
       That rule is now the divider between bar and panel, so the panel does
       not draw a second border-top of its own. */
    top: calc(100% + var(--nav-rule, 0px));
    z-index: var(--z-mega);
    /* Rebind the ramp for the subtree rather than restating every rule below in
       a paper variant. Each descendant already reads --fg / --card / --line, so
       one binding here inverts the whole panel and keeps a single source for
       each of those roles. Anything that must stay dark -- the promo card --
       binds itself back explicitly. */
    --canvas: var(--paper);
    --card: var(--paper-surface);
    --line: var(--paper-line);
    --line-soft: var(--paper-line);
    --fg: var(--paper-fg);
    --fg-2: var(--paper-fg-2);
    --fg-3: var(--paper-fg-3);
    background: var(--paper);
    color: var(--paper-fg);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-overlay);
    padding: 0 var(--pad-x) 30px;
    /* Uncapping the outcome rows made the tallest panel ~740px, which clears a
       900px viewport but not a 768px laptop. Cap it to what is actually left
       below the bar and let the overflow scroll, rather than letting rows fall
       off the bottom of the screen with no way to reach them. */
    max-height: calc(100vh - var(--nav-h) - var(--nav-rule, 0px));
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* Pointer-capable devices only. A touch tap must fall through to the
   href instead of opening a panel it cannot dismiss. */
@media (min-width: 1101px) and (hover: hover) and (pointer: fine) {
    .th-has-mega:hover > .th-mega { display: block; }
}
/* Keyboard route, deliberately not gated on hover capability. */
@media (min-width: 1101px) {
    .th-has-mega:focus-within > .th-mega { display: block; }
}

/* Scrolled state deepens the tint only. The blur now lives on .nav--flush
   itself so the bar is frosted at the top of the page too, and the 2px
   magenta base rule is inherited from .nav on every state -- neither is
   re-declared here, or this rule would silently undo both. */
.nav--flush.is-scrolled {
    background: color-mix(in srgb, var(--canvas) 88%, transparent);
}

/* Orienting rail, then the columns, then the promo card. The rail is a real
   grid track rather than a header strip above the columns: it is what gives
   the panel a reading order (why you are here -> what there is -> where it
   all lives) instead of a wall of equal-weight links. */
.th-mega-cols {
    display: grid;
    grid-template-columns: minmax(240px, 300px) repeat(var(--mega-cols, 4), minmax(0, 1fr)) minmax(240px, 300px);
    align-items: start;
    padding-top: var(--sp-9);
}
.th-mega-cols[data-cols="3"] { --mega-cols: 3; }
.th-mega-cols[data-cols="2"] { --mega-cols: 2; }
.th-mega-cols[data-cols="1"] { --mega-cols: 1; }

.th-mega-rail {
    padding-right: var(--sp-10);
    min-width: 0;
}
.th-mega-rail > p { margin: 0; }
/* Scoped to .th-mega throughout this block. As bare classes these lost the
   cascade to .th-eyebrow--mono and to the sitewide `a` colour: the kicker's
   gap computed to 0, so the 26px tick ran straight into the label, and the
   rail CTA rendered in the paper secondary grey instead of magenta. Both were
   visible in the comp comparison and neither was visible in the CSS. */
.th-mega .th-mega-rail-kicker {
    display: flex;
    align-items: center;
    gap: var(--sp-5);
    padding: 0;
    border: 0;
    color: var(--mag);
}
/* The -4px lift is for baseline alignment beside .th-mega-group's label. Here
   the row is centre-aligned, so the lift only pushes the rule off centre. */
.th-mega .th-mega-rail-kicker .th-mega-tick { transform: none; }
.th-mega .th-mega-rail-h {
    margin: var(--sp-5) 0 var(--sp-5) !important;
    font-family: var(--font-heading);
    font-size: var(--fs-12);
    font-weight: 700;
    line-height: 1.08;
    letter-spacing: var(--ls-head);
    color: var(--fg);
}
.th-mega .th-mega-rail-copy {
    font-size: var(--fs-3);
    line-height: var(--lh-body);
    color: var(--fg-2);
    max-width: 34ch;
}
/* No rule under this. The comp sets the label as two wrapped lines of magenta
   mono with the arrow right-aligned against the block and nothing else -- an
   underline was in the first pass and is not in the reference. The label is
   allowed to wrap; that is what puts the arrow beside a two-line block rather
   than beside a single long line. */
.th-mega .th-mega-rail-cta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-6);
    width: 100%;
    max-width: 32ch;
    margin-top: var(--sp-7);
    font-family: var(--font-mono);
    font-size: var(--fs-3);
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    text-decoration: none;
    color: var(--mag);
}
.th-mega-rail-arrow {
    flex: none;
    font-size: var(--fs-4);
    transition: transform var(--dur-fast) var(--ease);
}
.th-mega .th-mega-rail-cta:hover .th-mega-rail-arrow,
.th-mega .th-mega-rail-cta:focus-visible .th-mega-rail-arrow { transform: translateX(4px); }

.th-mega .th-mega-aside {
    margin-top: var(--sp-5) !important;
    font-size: var(--fs-2);
    color: var(--fg-3);
}
.th-mega .th-mega-aside a { color: var(--fg-2); font-weight: 600; }
.th-mega .th-mega-aside a:hover { color: var(--mag); }

.th-mega-col {
    padding: 0 var(--sp-8) 0 0;
    min-width: 0;
}
.th-mega-col + .th-mega-col { padding-left: var(--sp-8); }

/* Label and its count sit on one rule, per the reference: the count is the
   column's own page total, so the rule reads as a measured set rather than
   an arbitrary list. */
.th-mega .th-mega-group {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-4);
    margin: 0 0 var(--sp-5);
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--line);
    font-family: var(--font-mono);
    font-size: var(--fs-1);
    font-weight: 700;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--mag);
}
.th-mega .th-mega-count { flex: none; color: var(--mag); opacity: 0.75; }
.th-mega-group-link {
    color: inherit;
    text-decoration: none;
}
.th-mega-group-link:hover,
.th-mega-group-link:focus-visible { text-decoration: underline; }
.th-mega-tick {
    flex: none;
    width: 26px;
    height: 2px;
    background: var(--mag);
    transform: translateY(-4px);
}

/* Rows carry no rule of their own -- the group rule above is the only line in
   the column, which is what stops the panel reading as a table. */
.th-mega-item {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
    text-decoration: none;
    color: inherit;
    transition: color var(--dur-fast) var(--ease),
                transform var(--dur-fast) var(--ease);
}
.th-mega-item:hover .th-mega-item-t,
.th-mega-item:focus-visible .th-mega-item-t { color: var(--mag); }
.th-mega-item:hover,
.th-mega-item:focus-visible { transform: translateX(3px); }
.th-mega-item-body { display: block; min-width: 0; }
.th-mega-item-t {
    display: block;
    font-size: var(--fs-4);
    font-weight: 600;
    letter-spacing: var(--ls-sub);
    margin-bottom: 3px;
    color: var(--fg);
}
.th-mega-item-d {
    display: block;
    font-size: var(--fs-3);
    line-height: 1.5;
    color: var(--fg-2);
}
.th-mega-item-arrow { flex: none; font-size: var(--fs-3); color: var(--mag); }


/* The promo is a filled card, not a rail, so the panel closes on a block of
   colour the way the reference does. The numeral is the live index total --
   it is decorative in weight but not in truth, so it must stay bound to the
   same count the CTA announces, and it is aria-hidden because the CTA below
   already says the number in words. */
/* Scoped to .th-mega so it outranks the sitewide `a` colour -- as a bare
   class this lost the cascade and the card's own text colour fell back to
   the muted link grey. Every visible child sets its own colour, so nothing
   looked wrong; the next child added would have inherited the wrong one. */
.th-mega .th-mega-promo {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    align-self: stretch;
    padding: var(--sp-7);
    /* Binds back to the dark ramp, against the panel's paper. The comp closes
       the panel on a block of colour, and it is the only element in here that
       does -- so it restates the roles the parent inverted instead of
       inheriting them. */
    --fg: var(--ink-fg);
    --fg-2: var(--ink-fg-2);
    color: var(--ink-fg);
    background: linear-gradient(
        160deg,
        color-mix(in srgb, var(--mag) 30%, var(--ink)) 0%,
        var(--ink) 70%
    );
    text-decoration: none;
    transition: transform var(--dur-fast) var(--ease);
}
.th-mega-promo:hover,
.th-mega-promo:focus-visible { transform: translateY(-2px); }
.th-mega-promo-num {
    font-family: var(--font-heading);
    font-size: var(--fs-14);
    font-weight: 700;
    line-height: 1;
    letter-spacing: var(--ls-head);
    color: var(--mag);
}
.th-mega-promo-h {
    margin-top: var(--sp-6);
    font-family: var(--font-heading);
    font-size: var(--fs-8);
    font-weight: 700;
    line-height: 1.15;
    color: var(--fg);
}
.th-mega-promo-copy {
    margin-top: var(--sp-3);
    font-size: var(--fs-3);
    line-height: var(--lh-body);
    color: var(--fg-2);
}
.th-mega-promo-cta {
    margin-top: auto;
    padding-top: var(--sp-6);
    font-family: var(--font-mono);
    font-size: var(--fs-1);
    font-weight: 700;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--mag);
}

/* The caret is decorative; the label carries the meaning. */
.th-caret {
    display: inline-block;
    margin-left: 5px;
    font-size: 9px;
    color: var(--fg-3);
    transition: color var(--dur-fast) var(--ease);
}
.th-has-mega:hover .th-caret,
.th-has-mega:focus-within .th-caret { color: var(--mag); }

/* ---- Mobile disclosures --------------------------------------
   Native <details> inside the existing mobile panel: no JS, and the
   accessible pattern for this already exists in the platform. The paper
   inversion is dropped here -- a white sheet inside a dark full-screen
   panel reads as a rendering bug, not a design.
   ------------------------------------------------------------- */
.th-nav-m-group { border-bottom: 1px solid var(--line-soft); }
.th-nav-m-group > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--sp-4) 0;
    font-size: var(--fs-6);
    font-weight: 600;
    color: var(--fg);
    cursor: pointer;
    list-style: none;
}
.th-nav-m-group > summary::-webkit-details-marker { display: none; }
.th-nav-m-group > summary::after {
    content: "+";
    font-family: var(--font-mono);
    color: var(--mag);
}
.th-nav-m-group[open] > summary::after { content: "\2013"; }
.th-nav-m-group-label {
    margin: var(--sp-4) 0 var(--sp-1);
    font-family: var(--font-mono);
    font-size: var(--fs-1);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--fg-3);
}
.th-nav-m-all { color: var(--mag) !important; font-weight: 600; }

/* ================================================================
   DIRECTION 1b -- FOOTER
   The link inventory is unchanged from the pre-1b footer and must stay
   that way: it carries the CR-008 request-support rule, the only crawl
   path to /become-a-client/, all five Zone 0 compliance pages, the
   cookie-settings reopen hook, and the theme.json legal name / reg /
   VAT. Only the typography moves.
   ================================================================ */
.th-foot-h {
    margin: 0 0 var(--sp-4);
    font-family: var(--font-mono);
    font-size: var(--fs-3);
    font-weight: 600;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--fg-3);
}

@media (max-width: 1100px) {
    /* Below the nav breakpoint the panel never opens, so it costs nothing
       to render -- but it must not be reachable by Tab while hidden. */
    .th-mega { display: none !important; }
}


/* ================================================================
   DIRECTION 1b -- INTERIOR PAGES (Zone 1 + Zone 3)
   WHY: The thirteen public page templates all drew from one
        vocabulary already (.page-hero / .page-h1 / .page-lede /
        .section-label), but the card grids carried their layout in
        inline style attributes and their hover state in inline
        onmouseover/onmouseout handlers. Inline styles cannot be
        restyled from here, and a JS hover breaks the no-JS rule for
        no reason -- :hover has been in CSS since 1996.
   CONTEXT: markup in templates/cms/_page_hero.html and
        _index_card.html, which every one of the thirteen includes.
   ================================================================ */

/* ---- Page hero ------------------------------------------------
   The interior counterpart to the homepage hero: same rail-and-eyebrow
   grammar, no photograph, and a rule under the heading. */
.th-page-hero {
    position: relative;
    padding: var(--sec-y) var(--pad-x) var(--sp-11);
    border-bottom: 1px solid var(--line-soft);
    background: linear-gradient(160deg, var(--canvas), var(--black));
    overflow: hidden;
}
.th-page-hero-body {
    position: relative;
    display: flex;
    gap: var(--sp-8);
    max-width: 900px;
}
@media (min-width: 1024px) {
    .th-page-hero-body { max-width: 1200px; }
}
.th-page-h1 {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--fs-13);
    font-weight: 700;
    line-height: var(--lh-head);
    letter-spacing: var(--ls-head);
    color: var(--fg);
    text-wrap: balance;
}
.th-page-h1 .th-accent { color: var(--mag); }
.th-page-rule {
    display: block;
    width: 48px;
    height: 2px;
    background: var(--mag);
    margin: var(--sp-6) 0 0;
}
.th-page-lede {
    font-size: var(--fs-7);
    line-height: var(--lh-loose);
    font-weight: 300;
    color: var(--fg-1);
    max-width: 640px;
    margin: var(--sp-6) 0 0;
    text-wrap: pretty;
}
.th-page-lede p:first-child { margin-top: 0; }
.th-page-lede p:last-child { margin-bottom: 0; }

/* ---- Index card grid ------------------------------------------
   Square, hairlined, magenta border on hover. Replaces four inline
   style attributes and a pair of inline event handlers per card. */
/* ================================================================
   DYNAMIC CARD GRIDS

   auto-FIT, not auto-FILL. That one word is the whole reported defect:
   auto-fill keeps the empty tracks it created, so three outcome tiles in a
   1939px row sat in the first three of six slots and left half the page
   blank. auto-fit collapses the empty tracks and the real items stretch to
   fill the row.

   --grid-max-cols caps how many columns can ever form, by forcing the minimum
   track to at least one Nth of the row (minus its gaps). Without it a wide
   display on a long list produces seven or eight thin columns.

   There is deliberately no matching minimum column count. "At least three
   across" is right on a desktop and wrong on a 390px phone, and the 260-280px
   track floor already puts three across at every width where three fit.
   ================================================================ */
.th-grid-dynamic,
.th-tile-grid,
.th-mini-grid,
.th-outcome-grid,
.th-result-grid {
    --grid-max-cols: 5;
    --grid-min-track: 280px;
    grid-template-columns: repeat(
        auto-fit,
        minmax(
            max(
                var(--grid-min-track),
                calc(
                    (100% - (var(--grid-max-cols) - 1) * var(--grid-gap, 0px))
                    / var(--grid-max-cols)
                )
            ),
            1fr
        )
    );
}
.th-tile-grid {
    display: grid;
    --grid-gap: var(--sp-7);
    gap: var(--grid-gap);
    list-style: none;
    margin: 0;
    padding: 0;
}
.th-tile {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: var(--sp-9);
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    text-decoration: none;
    color: inherit;
    transition: border-color var(--dur-base) var(--ease);
}
.th-tile:hover,
.th-tile:focus-visible { border-color: var(--mag); }
/* A media card moves its padding to the inner wrapper so the image can run
   to the card edge. */
/* Case-result cards on the home page take the same media band as the index
   tiles (Pulse 8a546dd0). Only a card that HAS an image gets the modifier, so
   a mixed row -- one case study with photography, two without -- still lines
   up: the grid stretches every card to the tallest, and the min-height floor
   that T-3 put on .th-result-card holds the ones without. */
.th-result-card--media { padding: 0; }
.th-result-media,
.th-tile-media {
    display: block;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-bottom: 1px solid var(--line);
    background: var(--canvas);
}
.th-result-media img,
.th-tile-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The band is edge to edge, so the text below it needs the padding the card
   itself gave up. */
.th-result-card--media > :not(.th-result-media) { margin-inline: var(--sp-9); }
.th-result-card--media > :not(.th-result-media):first-of-type { margin-top: var(--sp-7); }
.th-result-card--media > :last-child { margin-bottom: var(--sp-9); }

.th-tile--media { padding: 0; }
.th-tile-media {
    display: block;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-bottom: 1px solid var(--line);
    background: var(--canvas);
}
.th-tile-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.th-tile-inner {
    display: flex;
    flex-direction: column;
    flex: 1;
}
.th-tile--media .th-tile-inner { padding: var(--sp-7) var(--sp-7) var(--sp-8); }
.th-tile-icon { margin-bottom: var(--sp-7); color: var(--mag); }

/* Case-study card: leads with the client's own words rather than a title,
   which is why the quote is styled at heading weight and the <h3> is not. */
.th-tile-quote {
    margin: 0 0 var(--sp-6);
    font-size: var(--fs-8);
    font-weight: 500;
    line-height: 1.4;
    letter-spacing: var(--ls-sub);
    color: var(--fg);
    text-wrap: balance;
}
.th-tile-client {
    margin: 0 0 var(--sp-5);
    font-family: var(--font-mono);
    font-size: var(--fs-3);
    line-height: 1.5;
    color: var(--fg-2);
}
.th-tile-client strong {
    display: block;
    margin-bottom: 4px;
    font-weight: 500;
    color: var(--fg);
}
.th-tile-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin-bottom: var(--sp-5);
}
.th-tag {
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: 4px 10px;
    font-size: var(--fs-3);
    color: var(--fg-2);
}
/* The outcome tag is accented so the offering/outcome pair reads as two
   different kinds of link, which is the PRD 6.4 binding made visible. */
.th-tag--outcome {
    border-color: color-mix(in srgb, var(--mag) 40%, transparent);
    color: var(--mag);
}

/* Empty state for an index with nothing published yet. */
.th-empty {
    grid-column: 1 / -1;
    padding: var(--sp-12) var(--sp-9);
    text-align: center;
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
}
.th-empty h2 {
    margin: var(--sp-3) 0 var(--sp-2);
    font-size: var(--fs-9);
    font-weight: 600;
    color: var(--fg);
}
.th-empty p { margin: 0; font-size: var(--fs-5); color: var(--fg-2); }
.th-tile-title {
    margin: 0 0 var(--sp-3);
    font-size: var(--fs-10);
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: var(--ls-sub);
    color: var(--fg);
}
.th-tile-body {
    margin: 0 0 var(--sp-5);
    font-size: var(--fs-5);
    line-height: var(--lh-loose);
    color: var(--fg-2);
}
/* Pushes the affordance to the card floor so a grid of uneven copy
   still lines its calls-to-action up. */
.th-tile-more {
    margin-top: auto;
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--fs-5);
    font-weight: 600;
    color: var(--mag);
}
.th-tile-meta {
    margin: 0 0 var(--sp-3);
    font-family: var(--font-mono);
    font-size: var(--fs-1);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--fg-3);
}

/* ---- Body / prose -------------------------------------------- */
.th-page-section { padding: var(--sec-y) var(--pad-x); }
.th-page-section--tight { padding: var(--sp-11) var(--pad-x); }
.th-prose {
    font-size: var(--fs-6);
    line-height: var(--lh-loose);
    color: var(--fg-1);
}
.th-prose h2 {
    margin: var(--sp-11) 0 var(--sp-5);
    font-family: var(--font-heading);
    font-size: var(--fs-11);
    font-weight: 700;
    letter-spacing: var(--ls-head);
    color: var(--fg);
}
.th-prose h3 {
    margin: var(--sp-9) 0 var(--sp-4);
    font-size: var(--fs-9);
    font-weight: 600;
    letter-spacing: var(--ls-sub);
    color: var(--fg);
}
.th-prose > *:first-child { margin-top: 0; }
.th-prose a { color: var(--mag); text-decoration: underline; }
.th-prose ul, .th-prose ol { padding-left: 1.2em; }
.th-prose li { margin-bottom: var(--sp-2); }
/* The 2026-11-06 legal documents (cms/legal_text.py wraps each in .legal-doc).
   th-prose has no paragraph spacing, which ran numbered clauses together; scoped to
   the wrapper so other th-prose pages (careers, standard terms) are unchanged. */
.legal-doc p + p,
.legal-doc p + ul, .legal-doc p + ol,
.legal-doc ul + p, .legal-doc ol + p { margin-top: 0.85em; }
.legal-doc h3 + p { margin-top: 0; }
/* Visible <details> FAQ markup on outcome pages is mandated (PRD 6.2) and
   is a scored readiness signal, so it is styled to be used, not hidden.

   Matched to .th-faq-item (Pulse f50120c0). A <details> written into body copy
   used to render as a bare top-hairline row while the same content routed
   through the `faq` StreamField block came out as a bordered card -- two
   accordions on the same page, differing only by which authoring path produced
   them. The card is the home-page vocabulary, so the card wins, and the
   +/- affordance is picked up here too rather than left implicit. */
.th-prose details {
    margin-bottom: var(--sp-3);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    background: var(--canvas);
    overflow: hidden;
}
.th-prose details summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-6);
    padding: var(--sp-5) var(--sp-7);
    cursor: pointer;
    font-size: var(--fs-5);
    font-weight: 600;
    color: var(--fg);
    list-style: none;
}
.th-prose details summary::-webkit-details-marker { display: none; }
.th-prose details summary::after {
    content: "+";
    flex: none;
    font-family: var(--font-mono);
    color: var(--mag);
}
.th-prose details[open] summary::after { content: "\2013"; }
/* The answer sits on the summary's horizontal padding, not the card's edge. */
.th-prose details > *:not(summary) {
    margin: 0;
    padding: 0 var(--sp-7) var(--sp-6);
}

/* ---- Breadcrumbs --------------------------------------------
   Sits above the page hero on every interior page. */
.th-breadcrumbs { padding: var(--sp-7) var(--pad-x) 0; }
.th-breadcrumbs ol {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-3);
    margin: 0;
    padding: 0;
    font-family: var(--font-mono);
    font-size: var(--fs-1);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
}
.th-breadcrumbs li { display: flex; align-items: center; gap: var(--sp-3); }
.th-breadcrumbs a {
    color: var(--fg-3);
    text-decoration: none;
    transition: color var(--dur-fast) var(--ease);
}
.th-breadcrumbs a:hover,
.th-breadcrumbs a:focus-visible { color: var(--mag); }
.th-breadcrumbs [aria-current="page"] { color: var(--fg); }
.th-breadcrumbs-sep { color: var(--fg-3); opacity: 0.6; }

/* Pull quote. The magenta left edge is the only place a 3px accent rule
   appears at this scale -- it marks the client's own words. */
/* Canvas ground, not var(--card) (Pulse f50120c0). It was the last surface on
   the raised grey, so on a case study it read as a slab dropped between cards
   that all sit on the canvas. The magenta left bar stays -- that is the quote's
   signature and .th-card-outcome uses the same device for the same reason. */
.th-pullquote {
    margin: 0 0 var(--sp-11);
    padding: var(--sp-9) var(--sp-9) var(--sp-9) var(--sp-8);
    background: var(--canvas);
    border: 1px solid var(--line);
    border-left: 3px solid var(--mag);
    border-radius: var(--r-0);
}
.th-pullquote blockquote {
    margin: 0;
    font-size: var(--fs-10);
    font-weight: 500;
    line-height: 1.45;
    letter-spacing: var(--ls-sub);
    color: var(--fg);
    text-wrap: balance;
}
.th-pullquote figcaption {
    margin-top: var(--sp-6);
    font-family: var(--font-mono);
    font-size: var(--fs-3);
    line-height: 1.6;
    color: var(--fg-2);
}
.th-pullquote figcaption strong { color: var(--fg); font-weight: 500; }

/* Article lead image. Sized by the asset, not by the column.
   Every case-study featured image is 705x260, and `width: 100%` scaled that
   raster up past its own resolution. It was worst on precisely the pages that
   have a lead image: base.html sets `.site-main--article .prose-shell > * {
   max-width: none }`, so the figure is not held to --prose-measure and stretched
   to the full shell -- 1760px at a 2560 viewport, a 2.49x upscale.
   `width: fit-content` lets the figure shrink to the image and `margin: auto`
   centres it; an asset larger than the shell is still capped by the max-width.
   No frame: the hairline read as a border around the artwork rather than an
   edge of the page. */
.th-article-figure {
    margin: var(--sp-8) auto var(--sp-11);
    width: fit-content;
    max-width: 100%;
}
.th-article-figure img { max-width: 100%; height: auto; display: block; }

/* ---- Compact link cards -------------------------------------
   Used for capability domains and offering cross-links: an icon, a title and
   one line. Same square-and-hairline treatment as .th-tile, at a smaller
   scale, and hovering is CSS rather than the inline handlers this replaced. */
.th-mini-grid { display: grid; --grid-gap: var(--sp-3); --grid-min-track: 260px; gap: var(--grid-gap); list-style: none; margin: 0; padding: 0; }
.th-mini {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-4);
    padding: var(--sp-6);
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    text-decoration: none;
    color: var(--fg);
    height: 100%;
    transition: border-color var(--dur-base) var(--ease);
}
.th-mini:hover,
.th-mini:focus-visible { border-color: var(--mag); }
.th-mini-icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    color: var(--mag);
    font-size: 22px;
}
.th-mini-text { min-width: 0; }
.th-mini-title {
    display: block;
    font-size: var(--fs-4);
    font-weight: 600;
    line-height: 1.3;
    margin-bottom: 4px;
}
.th-mini-desc {
    display: block;
    font-size: var(--fs-3);
    line-height: 1.5;
    color: var(--fg-2);
}
.th-mini-kicker {
    display: block;
    margin-top: 2px;
    font-family: var(--font-mono);
    font-size: var(--fs-2);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--fg-3);
}

/* ---- FAQ disclosures ----------------------------------------
   Visible <details> markup, not a JS accordion. On /outcomes/ pages 4-6 of
   these are mandated (PRD 6.2) and the element is a counted readiness signal,
   so it has to be real markup that works with scripting off.
   Note faq_schema_from_body is a deliberate no-op -- Google retired the FAQ
   rich result. These are for readers, not for a rich snippet. */
.th-faq { margin-top: var(--sp-11); }
.th-faq-item {
    margin-bottom: var(--sp-3);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
    background: var(--canvas);
    overflow: hidden;
}
.th-faq-item > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-6);
    padding: var(--sp-5) var(--sp-7);
    cursor: pointer;
    font-size: var(--fs-5);
    font-weight: 600;
    color: var(--fg);
    list-style: none;
}
.th-faq-item > summary::-webkit-details-marker { display: none; }
.th-faq-item > summary::after {
    content: "+";
    flex: none;
    font-family: var(--font-mono);
    color: var(--mag);
}
.th-faq-item[open] > summary::after { content: "3"; }
.th-faq-answer {
    padding: 0 var(--sp-7) var(--sp-6);
    border-top: 1px solid var(--line-soft);
    font-size: var(--fs-4);
    line-height: var(--lh-loose);
    color: var(--fg-2);
}
.th-faq-answer > *:first-child { margin-top: var(--sp-5); }

/* Section heading inside an article body. */
.th-sub-h {
    margin: 0 0 var(--sp-2);
    font-family: var(--font-heading);
    font-size: var(--fs-11);
    font-weight: 700;
    letter-spacing: var(--ls-head);
    color: var(--fg);
}

/* ---- Closing CTA strip on interior pages --------------------- */
.th-page-cta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-7);
    flex-wrap: wrap;
    margin-top: var(--sp-11);
    padding: var(--sp-9);
    background: var(--canvas);
    border: 1px solid var(--line);
    border-radius: var(--r-0);
}
.th-page-cta h2 {
    margin: 0;
    font-size: var(--fs-10);
    font-weight: 600;
    letter-spacing: var(--ls-sub);
    color: var(--fg);
}

/* ---- Related / cross-link strip ------------------------------ */
.th-related {
    margin-top: var(--sp-11);
    padding-top: var(--sp-10);
    border-top: 1px solid var(--line);
}
.th-related-label {
    margin: 0 0 var(--sp-5);
    font-family: var(--font-mono);
    font-size: var(--fs-1);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--fg-3);
}
.th-pill-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
    list-style: none;
    margin: 0;
    padding: 0;
}
.th-pill-link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: var(--sp-3) var(--sp-7);
    font-size: var(--fs-5);
    color: var(--fg-1);
    text-decoration: none;
    transition: border-color var(--dur-fast) var(--ease),
                color var(--dur-fast) var(--ease);
}
.th-pill-link:hover,
.th-pill-link:focus-visible { border-color: var(--mag); color: var(--fg); }

@media (max-width: 768px) {
    .th-page-cta { flex-direction: column; align-items: flex-start; }
}
