/* audit-fixes-2026-05-09.css — desktop+mobile UX audit fixes
   Loaded last so it wins specificity battles. Fixes flagged by
   /tmp/audit-desktop and /tmp/audit-mobile screenshot synthesis. */

/* ── Mobile lane hero text wrap. Was set to `overflow-wrap: anywhere`
   + `word-break: break-word` on 2026-05-09 morning to stop "Audited.
   Diffed. Fixed." from clipping the viewport edge — but combined with
   the lane-hero's flex parent (which has no width:100% on .container)
   that broke the container to a single-character column and stacked
   every letter vertically. Mobile UX walk evening 2026-05-09 caught it.
   Plain `overflow-wrap: break-word` is the standard safety net for
   unbreakable display text — it only kicks in when a word cannot fit
   on its own line, never breaks mid-word otherwise. */
@media (max-width: 768px) {
    .lane-hero h1, .lane-hero .hero-h1, .gg-section-icon,
    h1.hero-title, h1.dazzle-heading,
    .arc-hero h1, .arc-hero h2 {
        overflow-wrap: break-word;
    }
}

/* ── 3D / kinetic-bg canvas on small viewports — decorative only.
   Mobile audit (page 2 /lanes): "3D wireframe icosahedron in hero
   takes a full viewport on mobile and is decoration with no
   information — pure scroll cost." Hide under 768px so we keep the
   perf budget for content.
   2026-05-13 iPad extension: the canvas's CSS is loaded via
   media="print" onload=swap which CSP can block, falling back to
   default static positioning. On iPad the canvas renders inline at
   1620px tall, pushing the hero ~1600px below the fold. Extending
   the hide to 1100px covers iPad portrait (810) + landscape (1080)
   + iPad Pro 11" portrait (834) + landscape (1194 is over but
   acceptable). Belt-and-suspenders pending a proper deferred-CSS
   fix that doesn't depend on inline onload. */
@media (max-width: 1100px) {
    body[data-scene] #kinetic-bg { display: none; }
}

/* ── Site-wide tap target enforcement (mobile audit, multiple pages).
   WCAG 2.5.5 minimum is 44×44px. The audit flagged theme-toggle,
   "Read case study" / "View report" text-links, expand-toggles, and
   cookie buttons under-target. Apply to typical link-in-card patterns. */
@media (max-width: 768px) {
    a.tile-link, a.read-more, a.view-report,
    .case-card a, .report-card a, .card-link,
    .tier-cta, .lane-cta, .arc-btn {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }
    /* Theme toggle (light/dark) — typically a 32px sun icon */
    .theme-toggle, [data-theme-toggle] {
        min-width: 44px;
        min-height: 44px;
    }
}

/* ── Body type ≥ 16px on mobile (prevents iOS auto-zoom on input focus
   and improves readability). Mobile audit flagged ~14px body across
   lane pages and insight articles. */
@media (max-width: 768px) {
    body, p, li, .lane-bullets li, .gg-text-secondary,
    .arc-tagline, .insight-body p, .case-body p {
        font-size: max(16px, 1rem);
    }
    /* Form inputs should never be < 16px on iOS */
    input, select, textarea { font-size: max(16px, 1rem); }
}

/* ── Footer ribbon typography. Mobile UX walk evening 2026-05-09
   flagged 9.6px ribbon-meta and 11.2px legal/tagline + 12.8px
   nav-segment links across every page that loads the architect
   ribbon. Below 14px is hard-to-read and below 44px tap-target
   for nav links violates WCAG 2.5.5. Bump both. */
.architect-ribbon .ribbon-meta { font-size: 0.78rem; }
.architect-ribbon .ribbon-bottom .legal,
.architect-ribbon .ribbon-bottom .tagline { font-size: 0.85rem; }
.architect-ribbon .nav-segment a { font-size: 0.9rem; }
@media (max-width: 768px) {
    /* Ensure footer nav links hit the 44px tap-target floor on mobile.
       inline-flex + min-height keeps existing letterspacing layout. */
    .architect-ribbon .nav-segment a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        padding: 0.25rem 0;
    }
}

/* ── Mobile-nav drawer link tap targets. Mobile UX walk flagged 29px
   tall links in the slide-out menu — under WCAG 2.5.5 (44px). */
@media (max-width: 768px) {
    .mobile-nav a {
        min-height: 44px;
        display: flex;
        align-items: center;
    }
    .mobile-nav .mobile-nav-tools-label {
        /* Section labels are NOT links, so they don't need 44px,
           but bump them off the floor a little for visual rhythm. */
        padding-top: 0.4rem;
    }
}

/* ── Hide the inert "CODED BY JAKUB" footer credit only on auth-/
   transactional routes where it reads as a portfolio tell. (Kept on
   marketing pages — user explicitly retained it on 2026-05-09.) */
body[data-route="checkout"] .tagline,
body[data-route="login"] .tagline { display: none; }

/* ── Long-form articles (insights/* + case-studies/*) — improve
   readability of inline tables on mobile by stacking 4-col tables. */
@media (max-width: 768px) {
    .insight-body table, .case-body table, article table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
}

/* ── Cookie consent: stop overlapping login/checkout forms.
   Increase z-index discipline: card-style auth panels (login.html)
   should stay below the fixed banner, never side-by-side. */
@media (max-width: 768px) {
    .auth-card, .login-card, .checkout-card {
        margin-bottom: 6rem; /* leaves room for the bottom banner */
    }
}

/* ─────────────────────────────────────────────────────────────────────
   Long-form enhancer (assets/js/longform-enhancer.js):
   byline, sticky-cta, read-next, mobile-TOC. Loaded on insights/*,
   case-studies/*, reports/*, /lanes/<lane>-methodology, etc.
   ───────────────────────────────────────────────────────────────────── */

/* Byline */
.lf-byline {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    margin: 0.75rem 0 2rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid rgba(255,255,255,0.08);
    font-size: 0.95rem;
    color: var(--text-muted, #a9a9a9);
}
.lf-byline-avatar {
    display: inline-flex;
    width: 36px; height: 36px;
    align-items: center; justify-content: center;
    border-radius: 50%;
    background: linear-gradient(135deg, hsl(348,83%,47%), hsl(348,83%,30%));
    color: #fff;
    font-weight: 700;
    font-size: 0.78rem;
    letter-spacing: 0.04em;
    flex-shrink: 0;
}
.lf-byline-text strong { color: #fff; font-weight: 600; }
.lf-byline a {
    color: var(--garnet-text, hsl(348,83%,65%));
    text-decoration: none;
    border-bottom: 1px dashed rgba(170,26,51,0.5);
}

/* Sticky bottom CTA — mobile only (≤768px) so desktop readers aren't crowded */
.lf-sticky-cta {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 9000; /* below cookie banner (9999) */
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
    background: linear-gradient(180deg, rgba(12,12,12,0.96), rgba(8,8,8,0.99));
    border-top: 1px solid rgba(170,26,51,0.25);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    transform: translateY(100%);
    animation: lfStickyIn 0.6s cubic-bezier(0.16,1,0.3,1) 1.2s both;
}
@keyframes lfStickyIn { to { transform: translateY(0); } }
@media (max-width: 768px) { .lf-sticky-cta { display: flex; } body.long-form-active main, body.long-form-active article { padding-bottom: 4.5rem; } }
.lf-sticky-cta-tag {
    color: rgba(255,255,255,0.55);
    font-size: 0.78rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.lf-sticky-cta-btn {
    flex: 1;
    text-align: center;
    padding: 0.65rem 1rem;
    background: linear-gradient(135deg, #aa1a33, #cc1142);
    color: #fff;
    text-decoration: none;
    font-weight: 600;
    border-radius: 8px;
    font-size: 0.92rem;
    min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
}

/* Read-next rail */
.lf-read-next {
    margin-top: 4rem;
    padding-top: 2.5rem;
    border-top: 1px solid rgba(255,255,255,0.08);
}
.lf-read-next-h {
    font-size: 0.95rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--text-muted, #a9a9a9);
    margin: 0 0 1.5rem;
}
.lf-read-next-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1rem;
}
.lf-read-next-card {
    display: block;
    padding: 1.25rem;
    background: rgba(15,15,15,0.6);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 10px;
    text-decoration: none;
    color: inherit;
    transition: border-color 0.25s ease, transform 0.25s ease;
}
.lf-read-next-card:hover {
    border-color: rgba(170,26,51,0.5);
    transform: translateY(-2px);
}
.lf-read-next-badge {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    color: var(--garnet-text, hsl(348,83%,65%));
    margin-bottom: 0.5rem;
}
.lf-read-next-card h3 {
    margin: 0;
    font-size: 1rem;
    line-height: 1.35;
    color: #fff;
    font-weight: 600;
}

/* Mobile-collapsible TOC */
.lf-toc-mobile {
    background: rgba(15,15,15,0.6);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 8px;
    padding: 0.5rem 1rem;
    margin: 1rem 0;
}
.lf-toc-mobile summary {
    cursor: pointer;
    padding: 0.5rem 0;
    font-weight: 600;
    color: #fff;
    list-style: none;
}
.lf-toc-mobile summary::after { content: ' ↓'; color: var(--text-muted); }
.lf-toc-mobile[open] summary::after { content: ' ↑'; }

/* ── Insights filter pills — bump to 44px tap target (WCAG 2.5.5).
   Audit found pills at ~28-30px height — under-target on mobile. */
.ih-pill, .lh-pill, .filter-pill, [data-action="ihFilter"] {
    padding: 0.65rem 1.2rem !important;
    min-height: 44px !important;
    display: inline-flex !important;
    align-items: center;
    font-size: 0.88rem !important;
}
@media (max-width: 768px) {
    .ih-filters {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        flex-wrap: nowrap !important;
        /* justify-content:center clips the leading chip off the left edge
           when the row overflows horizontally — flex-start anchors chips
           on the left so the scroll behavior reads naturally. */
        justify-content: flex-start !important;
        padding: 0 1rem 0.5rem !important;
        scroll-snap-type: x mandatory;
        scroll-padding-left: 1rem;
    }
    .ih-pill { scroll-snap-align: start; flex-shrink: 0; }
}

/* ── Skip-link a11y. Pages that use bare `.skip-link` (insights.html,
   lane pages, etc.) had no rule — link rendered visible in the
   document flow at the top-left. Mobile UX walk caught it. Hide
   visually until keyboard-focused (matches .gg-skip-link pattern). */
.skip-link {
    position: absolute;
    left: -9999px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
    z-index: 9999;
}
.skip-link:focus {
    left: 0.75rem;
    top: 0.75rem;
    width: auto;
    height: auto;
    padding: 0.75rem 1rem;
    background: #aa0000;
    color: #fff;
    text-decoration: none;
    font-weight: bold;
    border-radius: 4px;
}

/* ── /pricing sticky jump-nav (#8) ──────────────────────────────────
   9 legacy SKU categories were forcing 28k mobile px; this gives users
   a one-tap jump and (on mobile) collapses each section to summary. */
.pricing-jump-nav {
    position: sticky;
    top: 60px; /* below site nav */
    z-index: 100;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding: 0.85rem 1.5rem;
    margin: 0 0 2rem;
    background: rgba(8,8,8,0.92);
    border-bottom: 1px solid rgba(170,26,51,0.2);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
}
.pricing-jump-chip {
    padding: 0.5rem 0.95rem;
    border-radius: 100px;
    background: rgba(170,26,51,0.08);
    border: 1px solid rgba(170,26,51,0.18);
    color: rgba(240,240,240,0.85);
    font-size: 0.82rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: all 0.2s ease;
    min-height: 36px;
    display: inline-flex;
    align-items: center;
}
.pricing-jump-chip:hover {
    background: rgba(170,26,51,0.18);
    color: #fff;
}
@media (max-width: 768px) {
    .pricing-jump-nav {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scroll-snap-type: x mandatory;
        padding: 0.6rem 1rem;
    }
    .pricing-jump-chip {
        scroll-snap-align: start;
        flex-shrink: 0;
        min-height: 44px;
        font-size: 0.85rem;
    }
}

.pricing-accordion-mobile {
    margin: 1rem 0 2.5rem;
    background: rgba(15,15,15,0.5);
    border: 1px solid rgba(255,255,255,0.06);
    border-radius: 10px;
    overflow: hidden;
}
.pricing-accordion-mobile summary {
    cursor: pointer;
    list-style: none;
    padding: 0.75rem 1.25rem;
    color: var(--garnet-text, hsl(348,83%,65%));
    font-weight: 600;
    font-size: 0.92rem;
}
.pricing-accordion-mobile summary::after { content: ' ↓'; color: rgba(255,255,255,0.55); }
.pricing-accordion-mobile[open] summary::after { content: ' ↑'; }
.pricing-accordion-mobile[open] { background: rgba(15,15,15,0.7); }

/* ─────────────────────────────────────────────────────────────────────
   Inline-style → class refactor (CSP style-src strict, 2026-05-09).
   65 pages have an identical "lane-crosssell" footer with 7 inline
   style attributes per instance (455 total). Hoisting to CSS classes
   so the `style-src 'unsafe-inline'` directive can be dropped from CSP.
   ───────────────────────────────────────────────────────────────────── */
.lane-crosssell {
    padding: 4rem 1.5rem 2rem;
    border-top: 1px solid rgba(255,255,255,0.06);
    margin-top: 3rem;
}
.lane-crosssell-inner {
    max-width: 1100px;
    margin: 0 auto;
    text-align: center;
}
.lane-crosssell-eyebrow {
    font-family: 'JetBrains Mono', 'SF Mono', monospace;
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: #aa1a33;
    margin-bottom: 0.75rem;
}
.lane-crosssell-h2 {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.8rem;
    font-weight: 700;
    line-height: 1.2;
    margin-bottom: 1rem;
    color: #f0f0f0;
}
.lane-crosssell-body {
    color: rgba(240,240,240,0.75);
    max-width: 620px;
    margin: 0 auto 1.5rem;
    font-size: 0.98rem;
    line-height: 1.6;
}
.lane-crosssell-cta-row { margin: 0; }
.lane-crosssell-cta {
    display: inline-block;
    padding: 0.85rem 1.75rem;
    background: #aa1a33;
    color: #fff;
    text-decoration: none;
    font-weight: 600;
    border-radius: 8px;
    font-size: 0.92rem;
    letter-spacing: 0.02em;
}
.lane-crosssell-cta:hover { background: #cc1142; color: #fff; }
.lane-crosssell-cta-row {
    display: flex;
    gap: 0.85rem;
    justify-content: center;
    flex-wrap: wrap;
}
.lane-crosssell-cta--ghost {
    background: transparent;
    color: rgba(240,240,240,0.85);
    border: 1px solid rgba(255,255,255,0.18);
}
.lane-crosssell-cta--ghost:hover {
    background: rgba(255,255,255,0.06);
    color: #fff;
    border-color: rgba(255,255,255,0.3);
}

/* ─── 2026-05-12 mobile UX audit fix ───────────────────────────────────
 * .hero-btns is `display:flex; gap:1.5rem` with no flex-wrap, so on
 * mobile widths the primary CTA + trust ribbon + two secondary CTAs
 * (4 children) get crammed into a single row, each compressed into a
 * 1-character-wide column. Real audit screenshot showed the trust-line
 * "14-day money-back · cancel any time · Secured by Stripe" rendering
 * one word per line, and the primary CTA "Start with GEO Pro — $1,999/mo"
 * compressed to a 1-char vertical strip.
 *
 * Fix: allow wrap. The .trust-line still has width:100%/flex-basis:100%
 * inline so it claims a full row; the buttons then flow naturally
 * around it on narrow screens.
 */
.hero-btns {
    flex-wrap: wrap;
}

/* On narrow viewports, stack the CTAs vertically — readability over
 * horizontal density. Each button gets its own row + full width. */
@media (max-width: 640px) {
    .hero-btns {
        flex-direction: column;
        gap: 0.75rem;
        align-items: stretch;
    }
    .hero-btns > .btn-primary,
    .hero-btns > .btn-secondary {
        width: 100%;
        text-align: center;
        margin-left: 0 !important;
    }
}

/* ─── 2026-05-13 iPad/tablet UX audit fix v2 ──────────────────────────
 *
 * Real-WebKit Playwright probe at 810×1080 (iPad portrait) + 1080×810
 * (iPad landscape) showed the existing 768px mobile breakpoint just
 * misses iPad: at 769-1024px the site renders the DESKTOP nav, but
 * cramped to the point where:
 *   - "Garnet Grid" logo wraps to 2 lines
 *   - 7 nav links + 1 CTA crush together
 *   - Last item ("CONTACT") gets clipped offscreen
 *   - Hero is pushed below the fold
 *
 * Industry standard for 769-1024px tablets is the hamburger nav.
 * Force the mobile-nav layout up to 1100px so iPad portrait (810) +
 * landscape (1080) + Pro 11" portrait (834) all get the clean
 * stacked nav. 1100 cap means small laptops at 1280+ keep desktop.
 * 1024 was too tight — iPad landscape at 1080 escaped.
 */
@media (max-width: 1100px) {
    /* hide desktop nav-links + CTA, show hamburger */
    .nav-links { display: none !important; }
    .top-nav .nav-cta { display: none; }
    .mobile-toggle { display: flex !important; }
    /* Don't let the logo wrap */
    .top-nav .logo .arch-logo-v2 { white-space: nowrap; }

    /* Tighten the hero-section vertical padding so the hero text
     * actually sits above the fold on the 1080px tall iPad portrait
     * viewport. Desktop keeps the original spacing.
     * Cover every hero class variant the site uses: .hero (landing,
     * pricing, products, audit), .contact-hero, .lane-hero,
     * .hc-hero (reports), .arc-hero (architecture-audit). */
    .hero, .contact-hero, .lane-hero, .hc-hero, .arc-hero,
    section[class*="-hero"] {
        padding-top: 4rem;
        padding-bottom: 3rem;
    }

    /* The .hero-btns column-stack we added at 640px also benefits at
     * iPad widths where the buttons + trust ribbon still feel cramped
     * side-by-side. Stack everything at <=1024 too. */
    .hero-btns {
        flex-direction: column;
        gap: 0.85rem;
        align-items: stretch;
    }
    .hero-btns > .btn-primary,
    .hero-btns > .btn-secondary,
    .hero-btns > .tier-cta {
        width: 100%;
        text-align: center;
        margin-left: 0 !important;
    }

    /* Lane card grids: at <=1024px each card gets its own row instead
     * of cramming 2-3 in a partial-width row. Cleaner reading rhythm. */
    .card-grid,
    .lane-cards,
    .lane-overview-section .card-grid {
        grid-template-columns: 1fr !important;
        gap: 1.25rem;
    }
}

/* ─── Mobile + iPad nav: opaque background regardless of scrolled state ───
 * styles.min.css gives header.main-nav `background: transparent` until JS
 * adds `.scrolled` on scroll. On mobile/iPad initial paint, content shows
 * through the fixed nav (hero text bleeds into nav, looks unfinished).
 * At ≤1100px, force a translucent dark background + blur unconditionally. */
@media (max-width: 1100px) {
    header.main-nav,
    header.main-nav:not(.scrolled) {
        background: rgba(5, 5, 5, 0.85) !important;
        -webkit-backdrop-filter: blur(12px);
        backdrop-filter: blur(12px);
        border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    }
}

/* ─── link-in-text-block: underline inline article links (iter 014) ───
 * axe rule says links in body text must be distinguishable from
 * surrounding text by something other than color alone. Underline
 * is the standard convention. Scope to article body containers so
 * we don't underline navigation/CTA buttons that are styled
 * separately. */
.gg-article-wrap p > a,
.gg-article-wrap li > a,
article.doc-body p > a,
article.doc-body li > a,
article.ar-content p > a,
article.ar-content li > a,
.cs-content p > a,
.cs-content li > a {
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* ─── Color-contrast root-cause shift (iteration 012, 2026-05-14) ───
 * Full-site axe found 455 color-contrast violation nodes — the
 * heaviest WCAG issue by 5×. Root cause: `--accent` token resolves
 * to hsl(348, 83%, 47%) = #dc143c (crimson) which is used as TEXT
 * across multiple components on dark backgrounds. At small font
 * sizes that ratio sits around 4.3:1 — below WCAG AA's 4.5:1 floor
 * for body text.
 *
 * Fix: scoped override that bumps the text-on-dark accent to
 * hsl(348, 83%, 60%) = #e64868 (clears 4.6:1 against rgba(15,15,15,
 * 0.6) and similar dark glass-bg).
 *
 * Why scoped not global: tokens.css `--accent` is also used for
 * borders + backgrounds where the original deeper red is the
 * intended visual. Changing the token globally would shift those
 * surfaces. The selectors below cover the known text-only uses;
 * iteration 013 will pull selectors from the axe JSON for the rest.
 */
.tools-tile__category,
.tools-tile__pillar,
.tools-tile__premium,
[data-render="tools"] .tools-tile [data-meta],
.lane-crosssell-eyebrow,
.report-policy__label,           /* already fixed in iter 008 — keep */
.cs-tag,
.case-tag,
.cs-eyebrow,                     /* iter 016 — case-study eyebrow */
.ar-toc__label,
.dpa-table th,
.trust-eyebrow,
.gg-insight-label .gg-insight-nav-link,
.gg-tier-eyebrow,
/* ─── iter 016 additions from full-corpus selector triage ───
 * Found via axe targets data on the iter-014 scan. Same root
 * cause: accent token resolving to #dc143c crimson used as text
 * on dark, ratio ~4.3:1 → fails AA. Bumped to #e64868 (~4.6:1).
 */
.mx-weak,                        /* comparison-table weak indicator */
.gg-minor-label-b,               /* minor labels in 3-col sections */
.arc-practice-num,               /* architect page practice numbering */
.be-card__desc,                  /* budget-estimator card desc text */
.ih-hero__badge,                 /* insights hub hero badge */
.ih-stat__num,                   /* insights hub stat numerals */
.ih-upcoming-card__cat,          /* insights upcoming-card category tag */
.ar-callout__btn,                /* article callout button text */
.audit-cat-header p,             /* architect audit-panel paragraph */
table.compare-table th,          /* vs-alternatives table header cells */
.compare-table thead th,
/* ─── iter 017 — next batch of selectors from iter-014 axe data ─── */
.walk-tag,                       /* onboarding-walkthrough card tags */
.walk-card .walk-tag,
.pbi-meta > span,                /* pbi-health-check meta spans */
.reports-eyebrow,                /* reports section eyebrow */
.lanes-eyebrow,                  /* lanes section eyebrow */
.u-eyebrow,                      /* util eyebrow class */
.report-tag,                     /* report cards tag */
.report-card .report-tag,
.tools-card__kicker,             /* render-tools card kicker */
.tools-card__pill--cat,          /* tools card category pill */
.tools-card__cta,                /* tools card CTA */
.u-card .mono,                   /* util-card mono-font accent */
.gg-link-plain[href$="ai-ml"] > .ih-upcoming-card__cat {
    color: #e64868;
}
.gg-text-garnet,
a.gg-text-garnet {
    color: #ff5577;            /* link variant — even lighter so underline + text both clear AA */
}

/* ─── CLS guards for non-article templates (iteration 011, 2026-05-14) ───
 * Full-site Lighthouse in iteration 009 surfaced 3 pages outside the
 * longform-enhancer scope (which only covers .gg-article-wrap /
 * .doc-body / .ar-content):
 *
 *   /tools — CLS 0.561 desktop / 0.444 mobile (worst measured)
 *     Cause: .tools-grid is empty in HTML; render-tools.js fills it
 *     with ~14 cards after first paint. Reserve grid height.
 *
 *   /case-studies/garnetgrid-geo-self mobile — CLS 0.216
 *     Cause: .ggself-stat / .ggself-phase-bar have desktop-sized
 *     min-heights; mobile re-stacks and the reservation under-shoots.
 *
 *   /onboarding-walkthroughs/audit-retainer mobile — CLS 0.181
 *     Cause: .day-step blocks shift as fonts load. font-display:swap
 *     is already set in fonts.css; main mitigation is `contain` on
 *     each step so a single-step shift doesn't propagate.
 */

/* /tools — reserve grid height for ~14 cards (avg ~280px each on
 * mobile single-column, ~340px desktop 3-column). Worst-case heights
 * picked so the grid doesn't expand AFTER cards land. */
.tools-grid {
    min-height: 1400px;
    content-visibility: auto;
    contain-intrinsic-size: auto 1400px;
}
@media (min-width: 768px) {
    .tools-grid {
        min-height: 1100px;
        contain-intrinsic-size: auto 1100px;
    }
}
@media (min-width: 1100px) {
    .tools-grid {
        min-height: 900px;
        contain-intrinsic-size: auto 900px;
    }
}

/* /case-studies/garnetgrid-geo-self — bump mobile reservations.
 * Phase-bar wraps to ~5 lines on mobile (currently reserves 3.5rem
 * which is wrong). Stat-bar stacks each stat vertically with extra
 * padding for the delta line. */
@media (max-width: 768px) {
    .ggself-phase-bar { min-height: 10rem !important; }
    .ggself-stat { min-height: 7.5rem !important; }
}

/* /onboarding-walkthroughs/* — contain layout on each step block so
 * font-load reflow doesn't propagate down the page. Plus a min-height
 * floor on the hero so the doc-hero text doesn't push following
 * content when fonts swap (iter 013 follow-up: 0.116 residual CLS
 * traced to the hero block reflowing as Inter loads). */
.day-step {
    contain: layout style;
}
section.doc-hero {
    min-height: 240px;
    contain: layout style;
}
@media (max-width: 768px) {
    section.doc-hero {
        min-height: 320px;
    }
}

/* ─── Reduced-motion override (a11y audit 2026-05-13) ─────────────────
 * Multiple hero animations + chatbot canvas + dazzle-heading shimmer
 * + aurora-bg keyframes ignore prefers-reduced-motion. WCAG 2.3.3 and
 * Sec. 508 §1194.22(g) require honoring the user signal. This block
 * neutralizes the noisier animations sitewide when the user opts out;
 * scroll snap + page transitions stay (they're navigational, not
 * decorative). */
@media (prefers-reduced-motion: reduce) {
    /* Cancel keyframe-driven hero/aurora animations. */
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    /* Specific override: kinetic-bg + dazzle-heading + aurora + chatbot
     * canvas are layered decorative — hide them entirely under
     * reduced-motion rather than just freezing. */
    .aurora-bg, .gridfield, .grid-shimmer, .metatron-bg-layer,
    .kinetic-bg, .dust-mote, .preloader-scanlines {
        animation: none !important;
        opacity: 0 !important;
    }
    .d-row {
        filter: none !important;
        opacity: 1 !important;
        transform: none !important;
        animation: none !important;
    }
}

/* ─── Longform article CLS guards (2026-05-13 perf audit) ───
 * /lanes/geo-methodology measured CLS = 0.242 on mobile, perf score 78.
 * Root cause: longform-enhancer.js injects a byline immediately after
 * H1 + a read-next rail at end-of-article AFTER first paint. Without
 * a reserved slot the byline shoves everything below H1 down by ~56px.
 * Two-pronged fix:
 *   1. Reserve byline space on the article element so the inject lands
 *      without shifting following content.
 *   2. `contain: layout` on article so any unavoidable shift doesn't
 *      propagate beyond the article box.
 */
article.doc-body,
article.ar-content,
.gg-article-wrap {
    contain: layout style;
}
article.doc-body > h1::after,
article.ar-content > h1::after,
.gg-article-wrap > h1::after {
    content: "";
    display: block;
    min-height: 56px; /* matches injected .lf-byline rendered height */
    margin-bottom: 0.5rem;
    /* Hidden once the byline lands and takes its place. The byline is
     * inserted via insertAdjacentElement('afterend', ...) which puts
     * it AFTER the h1 (and its ::after); the visual slot above is
     * the placeholder. When .lf-byline-injected is on body, collapse. */
}
body.long-form-active article.doc-body > h1::after,
body.long-form-active article.ar-content > h1::after,
body.long-form-active .gg-article-wrap > h1::after {
    min-height: 0;
    display: none;
}

/* ─── vs-alternatives comparison table: horizontal-scroll on mobile ───
 * Agent design-audit 2026-05-13: .compare-table is 736px wide; on a 390px
 * viewport its parent has overflow-x:visible so content clips/squashes.
 * Wrap the table in a scrollable container by giving the table itself
 * a min-width and putting the scroll on a synthetic ancestor via
 * `display: block` on <table>. (Cleanest cross-engine fix that doesn't
 * require wrapping every table in markup.) */
@media (max-width: 768px) {
    .compare-table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        max-width: 100%;
        white-space: nowrap;
    }
    .compare-table thead, .compare-table tbody, .compare-table tr {
        display: table;
        width: max-content;
        min-width: 100%;
        table-layout: fixed;
    }
    .compare-table th, .compare-table td {
        white-space: normal;
        min-width: 9rem;
    }
}

/* ─── Article code blocks: prevent mobile overflow ───
 * Agent design-audit 2026-05-13: <pre><code> in /insights/* articles has
 * no overflow rule, so long lines push the page wider than viewport.
 * Standard fix: scroll horizontally inside the <pre> element. */
.gg-article-wrap pre,
article pre,
.article-body pre {
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    word-wrap: normal;
    white-space: pre;
}
.gg-article-wrap pre code,
article pre code,
.article-body pre code {
    white-space: pre;
}

/* ─── Reports → tool feeder cross-sell ───
 * 2026-05-13: tools↔reports cross-sell loop was missing. Added a
 * "try the free quiz first" aside above the policy block on the 4
 * reports that have a free counterpart tool. */
.report-tool-feeder {
    max-width: 1100px;
    margin: 2rem auto 0;
    padding: 0.95rem 1.25rem;
    background: rgba(170, 26, 51, 0.07);
    border: 1px solid rgba(170, 26, 51, 0.22);
    border-radius: 8px;
    text-align: center;
}
.report-tool-feeder__text {
    margin: 0;
    color: rgba(240, 240, 240, 0.88);
    font-size: 0.95rem;
    line-height: 1.5;
}
.report-tool-feeder__link {
    color: #cc1142;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.report-tool-feeder__link:hover { color: #ff3050; }

/* ─── Reports policy block (delivery + scope + refund) ───
 * Agent design-audit 2026-05-13: 7 paid reports ($500-$2,500) shipped
 * with zero SLA / refund / "what's included" text. Added a shared
 * 3-card policy block above the lane-crosssell on every report. */
.report-policy {
    padding: 3rem 1.5rem 2rem;
    border-top: 1px solid rgba(255,255,255,0.06);
    margin-top: 2.5rem;
}
.report-policy__inner {
    max-width: 1100px;
    margin: 0 auto;
}
.report-policy__h {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1.5rem;
    font-weight: 700;
    text-align: center;
    color: #f0f0f0;
    margin: 0 0 1.5rem;
}
.report-policy__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1rem;
}
.report-policy__card {
    background: rgba(15,15,15,0.6);
    border: 1px solid rgba(255,255,255,0.07);
    border-radius: 8px;
    padding: 1.1rem 1.2rem;
}
.report-policy__label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    /* Was #aa1a33 = 2.65:1 vs dark card bg — failed WCAG AA (needs 4.5
     * for small text). Bumped to #e64868 = ~4.6:1, audit 2026-05-13. */
    color: #e64868;
    margin: 0 0 0.55rem;
}
.report-policy__body {
    color: rgba(240,240,240,0.78);
    font-size: 0.9rem;
    line-height: 1.55;
    margin: 0;
}
.report-policy__body a {
    color: #cc1142;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.report-policy__fineprint {
    text-align: center;
    color: rgba(240,240,240,0.55);
    font-size: 0.82rem;
    margin: 1.25rem 0 0;
    line-height: 1.5;
}

/* ─── Lane crosssell CTA: bump padding to clear 44px tap-target floor ───
 * Agent audit 2026-05-13: prior padding 0.85rem 1.75rem rendered ~42-44px
 * tall — borderline iOS HIG. Bump to clear cleanly without changing the
 * visual rhythm meaningfully. */
.lane-crosssell-cta {
    padding: 0.95rem 1.75rem !important;
    min-height: 44px;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
}

/* ─── LCP fix 2026-05-14: kill reveal animation on hero content ───
 * The site-wide `.reveal { animation: revealIn 0.8s both }` rule made
 * EVERY hero element start at opacity:0 and fade in. On heavy pages
 * (lanes, /, articles) the hero text is the LCP element — and Lighthouse
 * mobile-simulate measured 3.4s LCP largely from this 800ms delay
 * compounding on top of CSS+font load.
 *
 * Override: hero containers paint immediately. The reveal animation is
 * preserved for non-hero `.reveal` elements (capability cards, lower
 * sections) so the "fade in on scroll" feel stays on the rest of the page.
 *
 * Targets:
 *   .hero-content.reveal       — lanes, homepage
 *   .lane-hero .reveal         — lane sub-elements within hero
 *   .doc-hero .reveal          — article hero (insights/*, case-studies/*)
 *   .trust-hero .reveal        — trust page
 *   .book-hero .reveal         — booking page hero
 */
.hero-content.reveal,
.lane-hero .reveal,
.doc-hero .reveal,
.trust-hero .reveal,
.book-hero .reveal,
.dazzle-container.reveal,
.lane-hero-content.reveal,
section.lane-hero .reveal {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
}

/* ─── LCP fix 2026-05-14b: kill .d-row rowReveal animation on hero ───
 * The dazzle headline uses `animation: rowReveal 1.2s forwards` which
 * starts each .d-row at opacity:0 and fades it in over 1.2s. When the
 * .d-row is the LCP element (large hero text like "$59,988/yr." on
 * /lanes/audit-retainer-for-cfo), LCP can't fire until the animation
 * reaches paint-stable opacity. Measured: 4.4s LCP on the CFO page,
 * while sibling lane pages where .lane-sub is the LCP element are at
 * 2.1s because they don't have rowReveal blocking the LCP element.
 *
 * Override: pre-paint .d-row at final opacity + position, keep the
 * shimmerSweep + textDazzlePulse animations (visual interest stays).
 */
.lane-hero .d-row,
.lane-hero-content .d-row,
.dazzle-heading .d-row {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    /* Preserve shimmer + pulse — those are the "dazzle" effect.
       Drop rowReveal which was the blocking fade-in. */
    animation: shimmerSweep 6s linear infinite, textDazzlePulse 3s ease-in-out infinite !important;
}
