/* ==========================================================================
   NetrAI — Mobile layer
   --------------------------------------------------------------------------
   This file is loaded LAST on every page. It never touches the desktop
   design: everything below either applies at every width as a hardening
   measure (overflow guards, tap-target minimums, safe-area insets) or is
   scoped inside a max-width / coarse-pointer query.

   The three things that made the old build feel broken on a phone, and what
   is done about each:

   1. RHYTHM. `section { padding: clamp(96px, 12vw, 172px) 0 }` resolves to
      96px top AND bottom on a 390px screen — nearly 200px of empty page
      between every block. On desktop that reads as confidence; on a phone it
      reads as "the content fell off". The scale is retuned below so the page
      moves at a phone's pace.

   2. DENSITY. Desktop type sizes, 32px gutters and 40px card padding leave a
      ~260px measure on a small phone. Gutters, padding and the type ramp all
      step down together so the measure stays readable.

   3. WEIGHT. Six simultaneous `backdrop-filter: blur(26px) saturate(180%)`
      surfaces plus three rAF canvases is a slideshow on a mid-range Android.
      Blur is cut, canvases are skipped (see js/layout/mobile.js), and every
      hover-only flourish is disabled on touch so nothing sticks in its
      hover state after a tap.

   Breakpoints used here, matching the ones already in the codebase:
      <= 900px   large tablet / small laptop folding point
      <= 860px   the site's existing "mobile nav" line
      <= 640px   phones
      <= 375px   small phones (iPhone SE / mini, older Androids)
   ========================================================================== */


/* ==========================================================================
   0. Foundations — applied at all widths
   ========================================================================== */

:root {
  /* Notch / home-indicator insets, resolved to 0 on hardware without them. */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);

  /* Real viewport height. iOS Safari's 100vh includes the URL bar, so a
     100vh panel is always taller than the screen and its bottom edge hides
     under the chrome. js/layout/mobile.js keeps --app-vh in sync with the visual
     viewport; the fallback here is used before the script runs. */
  --app-vh: 1vh;
}

html {
  /* Stops iOS/Android inflating type in landscape, which is what makes a
     rotated phone suddenly look like a different site. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* `overflow-x: hidden` on <body> alone does not stop the page scrolling
   sideways — the overflow escapes to the viewport. Clipping both, and
   `clip` rather than `hidden` where supported, keeps position:sticky
   working (an overflow:hidden ancestor silently kills sticky). */
html, body { overflow-x: hidden; max-width: 100%; }
@supports (overflow: clip) {
  html, body { overflow-x: clip; }
}

/* Grey flash on every tap is a dead giveaway of an unadapted desktop site. */
* { -webkit-tap-highlight-color: transparent; }

/* Long unbroken strings — emails, URLs, ₹ figures — are the usual cause of a
   single element widening the whole document. */
body { overflow-wrap: break-word; }
h1, h2, h3, h4, p, li, a, blockquote, td, th { overflow-wrap: break-word; }

/* Media never exceeds its column. */
img, svg, video, canvas, iframe { max-width: 100%; }

/* The drawer footer is injected into .nav-links by js/layout/mobile.js. On desktop
   .nav-links IS the horizontal glass capsule, so the block must be absent
   there or it would break the pill apart. It is only ever shown inside the
   <= 860px drawer. */
.nav-drawer-foot,
.nav-drawer-search,
.nav-drawer-contact { display: none; }

/* Anchor landings clear the real header rather than a hard-coded 104px.
   --hdr-h is measured and kept current by js/layout/mobile.js. */
section[id],
.price-item[id],
.faq-item[id],
h3[id] { scroll-margin-top: calc(var(--hdr-h, 104px) + 16px); }

/* Horizontal rails get an edge fade on whichever side has more to show, so a
   cut-off table reads as "scrollable" rather than "broken". The attribute is
   written by js/layout/mobile.js. */
[data-scrollable="start"] {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 40px), transparent 100%);
  mask-image: linear-gradient(90deg, #000 calc(100% - 40px), transparent 100%);
}
[data-scrollable="end"] {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 40px);
  mask-image: linear-gradient(90deg, transparent 0, #000 40px);
}
[data-scrollable="both"] {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 40px, #000 calc(100% - 40px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 40px, #000 calc(100% - 40px), transparent 100%);
}
.compare-scroll-hint { transition: opacity 0.3s ease; }


/* ==========================================================================
   1. Touch devices — any size
   Hover styling on a touchscreen is not "unused", it is actively wrong: the
   :hover state latches after a tap and stays until you touch something else,
   so cards sit lifted and buttons stay bright. All of it is unwound here.
   ========================================================================== */

@media (hover: none), (pointer: coarse) {

  .card:hover,
  .work-card:hover,
  .price-item:hover,
  .service-card:hover,
  .mvv-card:hover,
  .combo-card:hover,
  .cart-dock:hover,
  .nav-cta-btn:hover,
  .btn-primary:hover,
  .review-card:hover {
    transform: none;
  }

  .btn:hover::before { transform: translateX(-130%); }
  .btn-primary:hover::after { transform: none; }
  .footer-grid ul li a:hover { transform: none; }
  .footer-grid ul li a:hover::before { width: 0; opacity: 0; margin-right: 0; }
  .work-card:hover .work-mock { opacity: 0; }
  .work-card:hover .work-thumb > span { opacity: 1; transform: none; }
  .video-frame:hover .video-play-btn { transform: none; }
  .client-marquee:hover .client-marquee-track { animation-play-state: running; }

  /* Every interactive control clears the 44px minimum target. Applied as a
     min-height rather than padding so nothing reflows. */
  .btn,
  .nav-cta-btn,
  .nav-toggle,
  .nav-search-btn,
  .tier-btn,
  .filter-chip,
  .cat-chip,
  .faq-question,
  .advisor-option,
  .service-toggle,
  .copy-btn,
  .cart-dock-cta { min-height: 44px; }

  /* Small icon-only controls get their target grown with an invisible
     pseudo-element rather than by resizing them, so the layout is untouched.

     CAREFUL: only elements whose position is *static* may be listed here.
     `position: relative` is what makes the pseudo-element anchor to the
     button, but applying it to something already positioned re-anchors the
     element itself. `.cart-close` is `position: absolute; top: 18px; right:
     20px` — putting it in this list dropped it back into normal flow and
     parked the panel's close button in the top-left corner, overlapping the
     drag handle. Already-positioned controls are handled below instead. */
  .cat-nav,
  .aitg-cc { position: relative; }
  .cat-nav::after,
  .aitg-cc::after {
    content: "";
    position: absolute;
    top: 50%; left: 50%;
    width: 44px; height: 44px;
    transform: translate(-50%, -50%);
  }

  /* Absolutely positioned controls: grow the element itself. Their offsets
     are anchored to an edge, so a larger box costs nothing. */
  .cart-close { width: 44px; height: 44px; font-size: 1.5rem; }
  .finale-play-btn { min-width: 44px; min-height: 44px; }

  /* Text links that sit on their own line — legal rows, "talk to us", the
     secondary link under each service — are targets, not prose, and were all
     landing at 18-21px tall. Padding rather than min-height so the inline
     baseline is preserved where they sit next to other text. */
  .footer-legal a,
  .finale-legal a,
  .faq-contact-link,
  .service-secondary-link,
  .service-pricing-link,
  .footer-bottom a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .industry-chip { min-height: 44px; display: inline-flex; align-items: center; }
  .finale-baseline .logo, .footer-bottom .logo { min-height: 44px; }
  .cat-selectall-btn { min-height: 44px; }
  .logo-mark { min-height: 44px; }

  /* The site-tour widget injects its own stylesheet with no touch sizing.
     Raising its controls here rather than editing the generated CSS keeps
     the widget's own file untouched. */
  .aitg-ico, .aitg-btn, .aitg-stop, .aitg-cc {
    min-height: 44px !important;
    min-width: 44px !important;
  }

  /* The advisor's Back / Skip / Start-over row sat at 19-27px. These are in
     normal flow next to each other, so growing them for real is better than
     an invisible pseudo-element that would overlap its neighbour. */
  .advisor-nav-btn, .advisor-skip-btn, .advisor-restart-btn, .advisor-apply-btn {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .advisor-nav-btn::after, .advisor-restart-btn::after { content: none; }

  /* Horizontal rails get momentum scrolling and stop swallowing vertical
     swipes at their edges. */
  .compare-table-wrap,
  .cat-filter,
  .reviews-viewport,
  .nd-side {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
}


/* ==========================================================================
   2. <= 900px — the folding point
   ========================================================================== */

@media (max-width: 900px) {

  /* ---- Rhythm ---------------------------------------------------------
     The single highest-impact rule in this file. 96px of padding above AND
     below every section is 1/4 of a phone screen of nothing, twice per
     block. 64px still separates sections clearly at this scale. */
  section { padding: clamp(58px, 9vw, 84px) 0; }
  .section-head { margin-bottom: 34px; max-width: none; }
  .container { padding: 0 24px; }

  /* ---- Type ramp ------------------------------------------------------
     The desktop clamps bottom out at 2.6rem / 2.1rem, which were chosen
     against a 1200px column, not a 390px one. Re-clamped against vw so the
     headline fills the phone's width without breaking mid-word. */
  h1 { font-size: clamp(2.1rem, 7.6vw, 3.4rem); line-height: 1.02; letter-spacing: -0.028em; }
  h2 { font-size: clamp(1.7rem, 5.6vw, 2.4rem); line-height: 1.08; letter-spacing: -0.022em; }
  h3 { font-size: clamp(1.12rem, 3.4vw, 1.35rem); }
  p.lead { font-size: 1.03rem; line-height: 1.62; }

  /* ---- Weight ---------------------------------------------------------
     Halving the blur radius is invisible at this size and roughly quarters
     the work the compositor does per frame — blur cost scales with area. */
  :root { --glass-blur: 12px; --glass-saturate: 140%; }

  /* Decorative full-page blur layers do the most damage for the least
     visual return on a phone. */
  .ambient-bg .glow-orb { filter: blur(46px); opacity: 0.10; }
  .ambient-bg .light-bloom { filter: blur(60px); opacity: 0.16; }
  .ambient-bg .light-streak { display: none; }
  .hero-aurora span { filter: blur(58px); }
  .problem-blob { filter: blur(64px); width: 200px; height: 200px; }
  .blob { filter: blur(60px); }
  .noise-overlay { display: none; }   /* a fixed blend layer over the whole
                                         document forces a full-page repaint
                                         on every scroll frame */

  /* ---- Buttons --------------------------------------------------------
     Two 30px-padded pills side by side overflow a 390px screen. Below they
     go full width and stack, which is also the expected phone pattern. */
  .btn { padding: 14px 24px; font-size: 0.92rem; }
  .hero-actions,
  .cta-actions,
  .service-cta-row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    width: 100%;
    max-width: 380px;
    margin-left: auto;
    margin-right: auto;
  }
  .hero-actions .btn,
  .cta-actions .btn,
  .service-cta-row .btn { width: 100%; justify-content: center; }
}


/* ==========================================================================
   3. <= 860px — mobile navigation
   The markup already had a fullscreen menu, but it relied on `:has()` to
   surface the CTA, left the search button stranded in the bar, had no
   safe-area handling and let the underlying page scroll behind it. Rebuilt
   below as a real drawer.
   ========================================================================== */

@media (max-width: 860px) {

  /* Four columns, not three. .nav-actions and .nav-toggle are separate
     elements and the authored grid only had three tracks, so both were
     assigned `grid-column: 3` and stacked into two rows — which is why the
     mobile header was 113px tall with the hamburger sitting underneath the
     search icon instead of beside it. */
  .nav {
    grid-template-columns: auto 1fr auto auto;
    column-gap: 8px;
    padding: 10px max(14px, var(--safe-r)) 10px max(14px, var(--safe-l));
  }
  .site-header.scrolled .nav { padding-top: 8px; padding-bottom: 8px; }
  .logo-mark { grid-column: 1; }
  .nav-links-wrapper { grid-column: 2; }
  .nav-actions { grid-column: 3; justify-self: end; gap: 2px; align-items: center; }
  .nav-toggle { display: flex; grid-column: 4; justify-self: end; }
  .logo-mark img { height: 32px; }

  /* The header is the drawer's own top edge once open: it has to sit above
     the panel, keep the close button where the hamburger was, and stop
     painting its own surface over the panel's background.

     `position: fixed` while open is not cosmetic. The scroll lock pins <body>
     at a negative offset, and a sticky header inside a pinned body resolves
     to its natural document position — i.e. scrolled off the top of the
     screen, taking the close button with it. Switching to fixed re-anchors it
     to the viewport. backdrop-filter is dropped for the same reason it is
     dropped in JS: it would otherwise establish a containing block. */
  .site-header { padding-top: var(--safe-t); }
  body.nav-open .site-header {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 120;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: none;
    border-bottom-color: transparent;
  }

  /* ---- The panel ------------------------------------------------------
     Fills the screen using --app-vh rather than 100vh so the bottom CTA is
     never parked under the URL bar. Scrolls internally if the menu is
     taller than a short landscape screen. */
  .nav-links-wrapper { position: static; }
  .nav-links {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: calc(var(--app-vh, 1vh) * 100);
    z-index: 99;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-items: stretch;
    gap: 2px;
    margin: 0;
    padding: calc(var(--safe-t) + 88px) 22px calc(var(--safe-b) + 28px);
    overflow-y: auto;
    overscroll-behavior: contain;
    text-align: left;

    background: var(--surface-canvas);
    background-image: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;

    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    transition: opacity 0.28s ease, transform 0.32s cubic-bezier(0.22,1,0.36,1), visibility 0.32s;
  }
  .nav-links::before, .nav-links::after { content: none; }
  .nav-links.open { opacity: 1; visibility: visible; transform: none; }

  /* Menu rows: full-width, generously tall, with a hairline between them so
     the list reads as navigation rather than floating words. */
  .nav-links li { width: 100%; }
  .nav-links li + li { border-top: 1px solid var(--line); }
  .nav-links > li > a:not(.btn) {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    min-height: 60px;
    padding: 14px 6px;
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 6.4vw, 1.9rem);
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--ink);
    background: none;
    border-radius: var(--radius);
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.36s ease, transform 0.36s cubic-bezier(0.22,1,0.36,1), color 0.2s ease;
  }
  /* A chevron on each row: it tells you the row is a target, and it gives
     the eye a right-hand edge to track down. */
  .nav-links > li > a:not(.btn)::after {
    content: "";
    position: static;
    width: 8px; height: 8px;
    flex: 0 0 8px;
    border: 0;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    border-radius: 0;
    background: none;
    opacity: 0.28;
    transform: rotate(-45deg);
    margin-right: 4px;
    transition: opacity 0.2s ease;
  }
  .nav-links > li > a:not(.btn):hover { transform: translateY(0); background: none; }
  .nav-links > li > a:not(.btn):active { color: var(--accent); }
  .nav-links a.active { color: var(--accent); }
  .nav-links a.active::after { opacity: 0.9; transform: rotate(-45deg); display: block; }

  .nav-links.open > li > a:not(.btn) { opacity: 1; transform: none; }
  .nav-links.open li:nth-child(1) a { transition-delay: 0.04s; }
  .nav-links.open li:nth-child(2) a { transition-delay: 0.08s; }
  .nav-links.open li:nth-child(3) a { transition-delay: 0.12s; }
  .nav-links.open li:nth-child(4) a { transition-delay: 0.16s; }
  .nav-links.open li:nth-child(5) a { transition-delay: 0.20s; }
  .nav-links.open li:nth-child(6) a { transition-delay: 0.24s; }

  /* ---- Search + CTA inside the drawer ---------------------------------
     The old rule pinned the CTA to `bottom: 48px` with `position: fixed`,
     which put it over the last menu row on a short screen and under the
     home indicator on a tall one. Both now live in a normal flow block that
     js/layout/mobile.js moves into the panel, so they scroll with the list. */
  .nav-search-btn {
    width: 44px; height: 44px;
    padding: 0;
    display: grid;
    place-items: center;
    border-radius: 50%;
    color: var(--mist);
  }
  .nav-search-btn svg { width: 20px; height: 20px; }
  .nav-search-kbd { display: none; }

  /* Hidden in the bar; re-shown by .nav-drawer-foot inside the panel. */
  .nav-actions .nav-cta { display: none; }

  .nav-drawer-foot {
    display: flex;
    margin-top: auto;
    padding-top: 28px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.4s ease 0.24s, transform 0.4s ease 0.24s;
  }
  .nav-links.open .nav-drawer-foot { opacity: 1; transform: none; }
  .nav-drawer-foot .nav-cta,
  .nav-drawer-foot .btn {
    display: inline-flex;
    position: static;
    width: 100%;
    justify-content: center;
    min-height: 52px;
    font-size: 1rem;
    opacity: 1;
    visibility: visible;
    transform: none;
    margin: 0;
  }
  .nav-drawer-search {
    display: flex !important;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    min-height: 52px;
    padding: 0 18px;
    border-radius: 999px;
    border: 1px solid var(--line-strong);
    background: var(--surface-canvas);
    color: var(--mist);
    font-family: var(--font-mono);
    font-size: 0.88rem;
  }
  .nav-drawer-search svg { width: 18px; height: 18px; }
  /* style.css has its own `@media (max-width: 860px) .nav-links a:not(.btn)`
     rule that sets every anchor in the panel to 1.5rem display type. The
     footer's links live inside .nav-links too, so without this reset the
     mailto line rendered as a 24px headline sitting under the CTA. */
  .nav-drawer-foot a:not(.btn),
  .nav-drawer-contact a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0;
    font-family: var(--font-mono);
    font-size: 0.8rem;
    font-weight: 500;
    letter-spacing: 0;
    color: var(--mist);
    opacity: 1;
    transform: none;
  }
  .nav-drawer-foot a:not(.btn)::after,
  .nav-drawer-contact a::after { content: none; }

  .nav-drawer-contact {
    display: flex !important;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px 18px;
    padding-top: 6px;
    font-family: var(--font-mono);
    font-size: 0.76rem;
    color: var(--mist-dim);
  }

  /* Hamburger sits above the panel and turns into the close control. */
  .nav-toggle { z-index: 120; width: 44px; height: 44px; }
  body.nav-open { overflow: hidden; }

  /* Chrome that must not float over an open drawer. */
  body.nav-open .scroll-progress,
  body.nav-open .cart-dock,
  body.nav-open .aitg-launcher,
  body.nav-open .aitg-bubble,
  body.nav-open .chapter-rail { opacity: 0 !important; pointer-events: none !important; }
}


/* ==========================================================================
   4. <= 640px — phones
   ========================================================================== */

@media (max-width: 640px) {

  .container { padding: 0 max(18px, var(--safe-l)) 0 max(18px, var(--safe-r)); }
  section { padding: clamp(52px, 12vw, 68px) 0; }
  .section-head { margin-bottom: 28px; }

  /* Headings and their standfirst were touching. On desktop the wide measure
     puts visible space between them; at phone width both fill the column and
     the two blocks merge into one wall of text. */
  .section-head h2 + p,
  .section-head h2 + .lead,
  .page-hero h1 + p { margin-top: 12px; }

  /* ---- Cards ----------------------------------------------------------
     34px/30px padding on a 390px screen leaves a 290px measure. 22px keeps
     the card reading as a card while giving the text room. */
  .card,
  .mvv-card,
  .problem-card,
  .service-card,
  .combo-card { padding: 24px 20px; border-radius: var(--radius); }
  .bento-feature { padding: 26px 22px; }
  .cta-banner { padding: 56px 22px; border-radius: 0; }
  .grid-3, .grid-2, .bento, .mvv-statements, .mvv-principle-list, .core-values-grid,
  .services-grid, .services-featured-row, .combo-grid,
  .problem-grid, .form-grid, .service-columns {
    grid-template-columns: 1fr !important;
    gap: 16px;
  }
  .card-icon { width: 42px; height: 42px; margin-bottom: 16px; border-radius: var(--radius); }
  .card-icon svg { width: 21px; height: 21px; }

  /* ---- Hero -----------------------------------------------------------
     Top padding only has to clear the (now shorter) sticky header. */
  .hero {
    padding: calc(var(--safe-t) + 56px) 18px 48px;
    min-height: 0;
  }
  .hero h1 { font-size: clamp(2rem, 8.4vw, 2.9rem); line-height: 1.04; max-width: none; }
  .hero p.lead { margin: 16px auto 24px; font-size: 1rem; }
  .hero-visual { margin-top: 28px; }
  /* Centred only inside the homepage hero, which is a centred layout. The
     inner-page .page-hero is left-aligned, and centring its trust chips under
     left-aligned copy made the block look like it belonged to another page. */
  .hero .hero-trust { justify-content: center; }
  .hero-trust { gap: 8px; }
  .hero-trust span { font-size: 0.72rem; padding: 6px 11px; }

  .hero-visual { justify-content: center; }
  .hero-visual .video-frame { flex: 1 0 100%; }

  /* ---- Hero dashboard -------------------------------------------------
     The live demo stays — it is the hero — but it is given a fixed, honest
     height instead of a 16:10 box, and enough internal scale to be legible.
     `34em` resolved against the frame's inherited 16px was 544px of very
     small UI; 460px at a larger base reads far better. */
  .video-frame { border-radius: var(--radius); }
  /* Taller than it was. The demo opens on Prompt now, and a conversation
     needs vertical room in a way a grid of KPI tiles does not. */
  .video-frame:has(.nd) { aspect-ratio: auto; height: 520px; }
  .hero-visual:has(.nd) { margin-top: 24px; }

  /* The container query in hero-dash.css drops the demo's root to 10px below
     720cqw. Every measurement inside is an em multiple of that root, and most
     are below 1 — so labels landed at 7-8px, which is not small type, it is
     unreadable type. 12.5px puts the smallest label back around 10px and the
     body around 11px.

     Raising the root also means less fits, so the two densest secondary
     panels come out. "Sales by Country" is five rows of 8px numbers and
     "Volume vs Service" is a bar chart whose bars are 2px wide columns you
     are meant to tap. Neither survives the translation to a phone; the KPI
     tiles, the chart and the product table do, and they are the parts that
     actually communicate what the product is. */
  .video-frame:has(.nd) .nd { font-size: 13px; }
  .nd-geo, .nd-volume { display: none; }
  .nd-grid-b { grid-template-columns: 1fr; }
  .nd-hint { font-size: 0.72rem; }

  /* Raising the root fixes most of the demo, but roughly a dozen labels are
     set at 0.72-0.78em and stay under 10px however far the root is pushed.
     Giving those a flat floor is the only way to stop them; the demo already
     abandons pure em scaling on mobile (the container query pins a px root),
     so this is consistent with how it behaves here rather than a break. */
  .nd-kpi-delta,
  .nd-pct,
  .nd-card-sub,
  .nd-th,
  .nd-row-sub,
  .nd-model-sub,
  .nd-user-role,
  .nd-chip,
  .nd-pulse-text,
  .nd-country-val,
  .nd-legend button { font-size: 11px; }
  .nd svg text { font-size: 10.5px; }

  /* A text field under 16px makes iOS zoom the whole page on focus and never
     zoom back — the agent console is the one real input in the demo. */
  .nd-composer input,
  .nd-search input { font-size: 16px; }

  /* ---- Prompt view ------------------------------------------------------
     This is the view the demo now opens on, so it has to work at 393px, and
     as authored it did not: the card head, four suggestion chips and the
     composer between them left the conversation about 40px of height — you
     saw a sliver of the answer's bar chart and none of the words.

     The fixes are all about giving the thread its room back. The subtitle
     goes (the heading already says "Ask the agent"), the chips drop to a
     single non-wrapping row that scrolls sideways, and the thread gets a
     floor so it can never be squeezed below a readable two messages. */
  .nd-prompt { gap: 0.6em; }
  .nd-prompt .nd-card-head { margin-bottom: 0.5em; }
  .nd-prompt .nd-card-sub { display: none; }
  .nd-thread { min-height: 150px; }
  .nd-msg { max-width: 92%; font-size: 0.95em; }

  .nd-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: 2px;
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent 100%);
  }
  .nd-chips::-webkit-scrollbar { display: none; }
  .nd-chip { flex: 0 0 auto; white-space: nowrap; min-height: 38px; }

  .nd-composer { padding: 0.4em 0.4em 0.4em 0.9em; min-height: 48px; }
  .nd-composer input { min-height: 40px; }
  .nd-send { width: 38px; height: 38px; flex: 0 0 38px; }
  .nd-send svg { width: 16px; height: 16px; }

  /* Nav buttons inside the demo are real targets, not decoration. */
  .nd-nav button, .nd-btn, .nd-tab, .nd-legend button { min-height: 40px; }

  /* The view switcher becomes a horizontal rail on mobile. Without a fade the
     fifth tab is simply sliced by the panel edge and reads as a rendering
     fault rather than as "there is more this way". */
  .nd-side {
    padding: 0.5em 0.6em;
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent 100%);
  }

  /* ---- Let the demo's panels stack instead of being crushed -------------
     .nd-grid is `height: 100%` because on desktop it fills a 16:10 frame with
     two explicit fr rows. The container query removes the rows but leaves the
     height, so on a phone three auto-height cards were being squeezed into a
     fixed box — and since .nd-card never clipped, their contents spilled out
     and painted straight over the card below. That is the overlap.

     Letting the grid size to its content and making the view the scroller
     fixes it properly: cards keep their natural height, stack, and the demo
     scrolls inside its frame. overflow:hidden on the card is the belt to that
     braces, so nothing can bleed between panels again. */
  .nd-grid { height: auto; grid-auto-rows: min-content; gap: 0.9em; }
  .nd-card { overflow: hidden; }
  .nd-kpis { flex: none; }
  .nd-visitors { min-height: 190px; }
  .nd-view {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Chained rather than contained: when the demo reaches its last panel the
       page should keep scrolling, or the frame becomes a scroll trap that
       swallows the gesture halfway down the hero. */
    overscroll-behavior-y: auto;
    padding-bottom: 4px;
  }

  .video-play-btn { width: 52px; height: 52px; }
  .video-play-btn svg { width: 19px; height: 19px; }

  /* ---- Client / capability marquees ----------------------------------- */
  .client-marquee { padding: 16px 0 28px; }
  .client-marquee-track { gap: 26px; animation-duration: 18s; }
  .client-marquee-track span { font-size: 0.84rem; }
  .finale-capabilities-track { gap: 22px; }

  /* ---- Story: problem / solution timeline ----------------------------- */
  .problem-thread { display: none; }
  .solution-timeline { gap: 0; }
  /* Narrower number gutter, but the rail stays — the left edge is the whole
     point of this layout and stacking the number above the copy would put
     back the centred version it replaced. */
  .timeline-step { grid-template-columns: 52px 1fr; gap: 16px; padding: 22px 0 26px; }
  .timeline-node-col { width: auto; }
  .timeline-node { font-size: 26px; }
  .timeline-progress-track { display: none; }
  .timeline-step-body { padding-top: 2px; }
  .timeline-step-body h3 { font-size: 20px; margin-bottom: 8px; }
  .timeline-step-body p { font-size: 15px; max-width: none; }

  /* The sticky illustration panel is 420px of decoration between every pair
     of steps on a phone — it pushes the actual copy off-screen. Dropped;
     the numbered steps carry the section on their own. */
  .timeline-visual-wrap { display: none; }
  .timeline-showcase { grid-template-columns: 1fr !important; gap: 0; }

  /* ---- Industries ----------------------------------------------------- */
  .industries-layout { gap: 24px; }
  .industries-stage { max-width: 190px; }
  .industries-chip-row { justify-content: center; gap: 6px; }
  .industry-chip { font-size: 0.76rem; padding: 7px 12px; }
  .industry-desc { font-size: 0.92rem; }

  /* ---- Reviews (already falls back to a swipe rail; tighten it) -------- */
  .reviews-chapter { --panel-x: 10px; }
  .reviews-chapter.is-static .reviews-panel { padding: 40px 0; border-radius: var(--radius); }
  .reviews-head { padding: 0 22px; margin-bottom: 22px; }
  .reviews-chapter.is-static .reviews-track { padding: 22px; gap: 16px; }
  .review-card { padding: 26px 22px 22px; }
  .reviews-chapter.is-static .review-card { flex-basis: min(86vw, 340px); }
  .review-card blockquote { font-size: 1.14rem; line-height: 1.36; }
  .review-quote-mark { font-size: 2.8rem; height: 18px; }

  /* ---- Process (services / about) ------------------------------------- */
  [data-anim="process"] .process-track { padding-left: 34px; gap: 32px; }
  .process-step { padding-right: 0; }
  .step-num { font-size: 0.78rem; }

  /* ---- Work ----------------------------------------------------------- */
  .work-thumb { height: 150px; }
  .filter-row { gap: 8px; margin-bottom: 26px; }
  .filter-chip { font-size: 0.8rem; padding: 9px 14px; }
  .work-body { padding: 20px; }

  /* ---- Forms ----------------------------------------------------------
     16px is not a style choice: any smaller and iOS Safari zooms the page
     on focus and never zooms back out, which is the single most common way
     a mobile form feels broken. */
  .form-field input,
  .form-field select,
  .form-field textarea,
  .site-search-input {
    font-size: 16px;
    padding: 13px 15px;
    min-height: 50px;
    border-radius: var(--radius);
  }
  .form-field select { padding-right: 40px; }
  .form-field textarea { min-height: 120px; }
  .form-field { margin-bottom: 14px; }

  /* Scoped to real page forms. This was written as `form button[type=submit]`
     and the hero demo's chat composer is also a <form> with a submit button —
     so the little round send button was being stretched to the full width of
     the composer as a cyan ellipse, with the text input crushed to nothing
     beside it. Anything inside .nd is the demo's own business. */
  form:not(.nd-composer) .btn[type="submit"],
  form:not(.nd-composer) button[type="submit"]:not(.nd-send) {
    width: 100%;
    justify-content: center;
  }

  /* ---- Finale (homepage close) ----------------------------------------
     Same problem as the inner footer, same treatment. The three flanks —
     Pages, the showreel, Connect — stacked into 1303px. The showreel keeps
     the full width because it is the centrepiece and a 16:9 video in half a
     phone is a postage stamp; the two link columns sit side by side beneath
     it, which is where most of the height was going. */
  .site-finale { margin-top: 28px; }
  /* index.html has no capabilities marquee, so the link columns are the last
     thing in the shell and were butting straight into the legal bar. */
  .finale-shell { border-radius: var(--radius) var(--radius) 0 0; padding: 18px 14px 26px; }
  .finale-hero { padding: 26px 0 4px; }
  .finale-giant { font-size: clamp(1.75rem, 8vw, 2.5rem); line-height: 1.06; max-width: none; }
  .finale-eyebrow { font-size: 0.78rem; margin-bottom: 10px; }

  .finale-flanks {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: 20px 16px;
    margin-top: 18px;
    text-align: left;
  }
  /* finale.css gives the video `order: -1` to float it above the stack; with
     an explicit grid that becomes a placement instead. */
  .finale-video { grid-column: 1 / -1; grid-row: 1; order: 0; margin-bottom: 2px; }
  .finale-flank-left  { grid-column: 1; grid-row: 2; }
  .finale-flank-right { grid-column: 2; grid-row: 2; }

  .finale-flank,
  .finale-flank-left,
  .finale-flank-right { align-items: flex-start; }
  .finale-flank-label { margin-bottom: 6px; }
  .finale-flank-right .finale-flank-label { text-align: left; }
  .finale-links,
  .finale-links-right { align-items: flex-start; gap: 0; }
  /* These are the homepage's only real navigation below the fold, so they
     get the full 44px even though it costs ~30px of footer height. */
  .finale-links a { min-height: 44px; display: inline-flex; align-items: center; font-size: 0.95rem; }
  .finale-links-right a { flex-direction: row; gap: 8px; }
  .finale-links-right a svg { width: 15px; height: 15px; flex-shrink: 0; }

  .finale-capabilities { margin-top: 20px; padding: 18px 0 20px; }
  .finale-baseline {
    flex-direction: column;
    gap: 8px;
    text-align: center;
    padding-top: 14px;
    /* Clearance for the fixed tour launcher, same as .footer-bottom. */
    padding-bottom: calc(70px + var(--safe-b));
  }
  .finale-legal { gap: 18px; flex-wrap: wrap; justify-content: center; }
  .finale-grid-lines { background-size: 60px 60px; opacity: 0.3; }

  /* ---- Footer (inner pages) -------------------------------------------
     Four columns collapsing to one made this 1282px tall — a screen and a
     half of scrolling past link lists to reach the bottom of the page.

     It is now a two-column block that lands in roughly one screen. The
     layout is driven by grid placement rather than by reordering the HTML,
     so the markup and its source order are untouched:

        row 1   brand — logo, one line, socials      (spans both columns)
        row 2   Company        |        Services     (two columns)
        row 3   Contact — laid out as an inline row  (spans both columns)

     Contact is the one that has to span: as a third grid cell it would sit
     alone next to a hole, and its three items read better as a wrapped row
     than as a stack anyway. */
  .site-footer { margin-top: 48px; padding: 40px 0 24px; }

  .footer-grid {
    grid-template-columns: 1fr 1fr !important;
    gap: 22px 18px;
    margin-bottom: 24px;
  }
  .footer-col-brand { grid-column: 1 / -1; }
  .footer-grid > .footer-col:nth-child(2) { grid-column: 1; }
  .footer-grid > .footer-col:nth-child(3) { grid-column: 2; }
  .footer-grid > .footer-col:nth-child(4) { grid-column: 1 / -1; }

  .footer-grid h4, .footer-grid h2 { margin-bottom: 10px; padding-bottom: 8px; font-size: 0.76rem; }
  .footer-grid ul li { margin-bottom: 0; font-size: 0.9rem; }
  .footer-grid ul li a,
  .footer-grid ul li .copy-btn {
    min-height: 36px;
    display: inline-flex;
    align-items: center;
  }

  /* Contact reads across, not down. */
  .footer-grid > .footer-col:nth-child(4) ul {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 20px;
  }

  /* Brand block: logo and socials share a line instead of stacking. */
  .footer-col-brand { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 6px 14px; }
  .footer-col-brand .footer-logo-mark { grid-column: 1; }
  .footer-col-brand .footer-logo-mark img { height: 32px; }
  .footer-col-brand p { grid-column: 1 / -1; margin-top: 0 !important; font-size: 0.85rem !important; }
  .social-row { grid-column: 2; grid-row: 1; margin-top: 0; gap: 5px; }
  .social-row a { width: 42px; height: 42px; display: grid; place-items: center; }
  .footer-logo-mark { min-height: 44px; display: inline-flex; align-items: center; }

  .footer-cta {
    flex-direction: column;
    align-items: stretch;
    text-align: center;
    gap: 14px;
    padding-bottom: 28px;
    margin-bottom: 28px;
  }
  .footer-cta-eyebrow { margin-bottom: 8px; font-size: 0.72rem; }
  .footer-cta-giant { font-size: clamp(1.5rem, 6.6vw, 2rem); }
  .footer-cta-btn { width: 100%; justify-content: center; }

  /* Two centred lines rather than one justified row. Side by side they
     exactly filled 393px, which put "Terms" underneath the floating tour
     launcher in the bottom-right corner. The extra bottom padding is that
     launcher's clearance — it is fixed, so the last row of the page has to
     get out from under it rather than the other way round. */
  .footer-bottom {
    flex-direction: column;
    align-items: center;
    padding-top: 16px;
    gap: 6px;
    text-align: center;
    padding-bottom: calc(70px + var(--safe-b));
  }
  .footer-legal { display: flex; gap: 20px; }

  /* ---- Search overlay -------------------------------------------------- */
  .site-search { padding: calc(var(--safe-t) + 14px) 12px 12px; align-items: stretch; }
  .site-search-panel {
    width: 100%;
    max-width: none;
    max-height: none;
    height: calc((var(--app-vh, 1vh) * 100) - var(--safe-t) - var(--safe-b) - 26px);
    border-radius: var(--radius);
  }
  .site-search-foot { display: none; }
  .site-search-item { padding: 13px 16px; min-height: 56px; }
  .site-search-item-sub { white-space: normal; }

  /* ---- Floating chrome -------------------------------------------------
     Two independent widgets both anchored bottom-right at 26px, one of them
     full-width on mobile: the tour launcher landed on top of the pricing
     cart. They are given separate lanes and lifted clear of the home
     indicator. */
  .aitg-launcher {
    right: max(14px, var(--safe-r)) !important;
    bottom: calc(14px + var(--safe-b)) !important;
    width: 52px !important;
    height: 52px !important;
  }
  /* Sits one slot above the launcher and shares its centre line, so the two
     never overlap. 44px here rather than 48 to keep the stack compact. */
  .back-to-top {
    right: calc(max(14px, var(--safe-r)) + 4px);
    bottom: calc(76px + var(--safe-b));
    width: 44px;
    height: 44px;
  }

  /* On the pricing page the cart is a full-width bar across the bottom, and
     it lands on both of the above. `cart-dock-visible` is set on <body> by
     js/pages/pricing.js only while the bar is showing, so the two buttons step up
     out of its way and drop back down when the cart empties. */
  body.cart-dock-visible .aitg-launcher {
    bottom: calc(86px + var(--safe-b)) !important;
  }
  body.cart-dock-visible .back-to-top {
    bottom: calc(148px + var(--safe-b));
  }
  .aitg-bubble {
    right: max(10px, var(--safe-r)) !important;
    left: max(10px, var(--safe-l)) !important;
    bottom: calc(76px + var(--safe-b)) !important;
    width: auto !important;
    max-width: none !important;
  }
  .aitg-dock {
    left: 50% !important;
    right: auto !important;
    bottom: calc(14px + var(--safe-b)) !important;
    width: calc(100vw - 24px) !important;
    max-width: 420px !important;
  }

  /* Chapter rail and scroll cue are desktop affordances; already hidden,
     restated so a future edit to story.css cannot bring them back. */
  .chapter-rail, .scroll-cue { display: none !important; }

  /* ---- Misc ------------------------------------------------------------ */
  /* Uppercase mono at 0.68rem is 10.9px with 0.08em tracking — it reads as
     texture rather than words at arm's length on a phone. */
  .service-meta-label,
  .finale-flank-label,
  .cart-dock-label,
  .review-role,
  .chapter-num { font-size: 0.74rem; }

  .pull-quote { padding-left: 16px; margin: 24px 0; }
  .stat-grid { gap: 14px; }
  .checklist li { font-size: 0.94rem; }
  .eyebrow { font-size: 0.72rem; margin-bottom: 12px; }
  .section-head:not(.center) > .eyebrow::after { min-width: 20px; margin-left: 12px; }
  .page-hero { padding: calc(var(--safe-t) + 56px) 18px 48px; }
  .page-hero h1 { max-width: none; }
  .page-hero p.lead { margin-top: 14px; }
}


/* ==========================================================================
   5. Pricing page — phones
   The builder is the most interactive surface on the site and the one with
   the most fixed-position furniture, so it gets its own block.
   ========================================================================== */

@media (max-width: 640px) {

  .pricing-builder { padding-bottom: 96px; }   /* clears the cart dock */

  /* Category rail: it is sticky under a sticky header, so its offset has to
     track the shorter mobile header or the two overlap. */
  /* The rail's own background is a gradient that fades to 72% alpha at its
     lower edge, on the assumption that a 14px backdrop blur will finish the
     job. It does not on a phone: the rail is short, the list scrolling under
     it is high-contrast white-on-black, and product names were legible
     straight through the sticky bar. Opaque here — a sticky element with
     content showing through it reads as a rendering fault, not as glass. */
  .cat-filter-wrap {
    top: calc(var(--hdr-h, 58px) + var(--safe-t));
    margin-bottom: 26px;
    gap: 0;
    background: var(--surface-white);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    padding-top: 2px;
  }
  .cat-filter { gap: 16px; scroll-padding-inline: 18px; }
  .cat-chip { font-size: 0.82rem; padding: 12px 2px; white-space: nowrap; }
  .cat-nav { display: none; }   /* the rail is swiped, not paged, on touch */

  /* Longer category names ("Integrations & Automation") push Select-all onto
     its own line, where space-between left it stranded under the icon.
     Pinned to the right edge so a wrapped row still reads as a header. */
  .price-category-head { gap: 8px 10px; }
  .cat-selectall-btn { margin-left: auto; }
  .cat-icon-title { gap: 10px; }
  .price-category-head .cat-icon { width: 34px; height: 34px; border-radius: var(--radius); }
  .price-category-head .cat-icon svg { width: 17px; height: 17px; }
  .price-category-head h3 { font-size: 1.12rem; }
  .price-list { gap: 10px; }
  .price-item { padding: 16px 16px 14px; gap: 4px 12px; border-radius: var(--radius); }
  .price-item .item-name { font-size: 0.96rem; }
  .price-item .item-desc { font-size: 0.79rem; }
  .price-item .item-price { font-size: 1.25rem; margin-top: 12px; padding-top: 10px; }
  .price-item .box { width: 24px; height: 24px; }

  /* Tier selector */
  .tier-step-grid { gap: 16px; }
  .tier-select-bar { gap: 8px; }
  .tier-btn { min-height: 52px; text-align: left; }
  .tier-advisor { padding: 20px 18px; }
  .tier-advisor-title { font-size: 1.05rem; }
  .advisor-option { min-height: 48px; text-align: left; }
  .advisor-controls { flex-wrap: wrap; gap: 8px; }
  .advisor-result.visible { max-height: 520px; }

  /* Comparison table keeps its 640px min-width and scrolls — correct — but
     the affordance has to be obvious, and the first column has to stay
     visible while you swipe. */
  .compare-table { min-width: 560px; font-size: 0.84rem; }
  .compare-table tbody th {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--surface-white);
    font-size: 0.82rem;
    padding: 13px 14px;
    max-width: 150px;
    white-space: normal;
  }
  .compare-table thead th { padding: 18px 10px 12px; }
  .compare-table tbody td { padding: 13px 8px; font-size: 0.8rem; }
  .compare-scroll-hint { display: block; font-size: 0.74rem; }

  /* Cart: bottom sheet + dock */
  /* Phones keep the full-width bar at the BOTTOM. Top-right is right on a
     laptop, but on a phone it would land directly on the sticky category
     rail and cover the chips you are trying to tap — and the bottom edge is
     where a thumb already is. `top: auto` is required: the base rule now
     sets `top`, and an element with both top and bottom set stretches to
     fill the space between them. */
  .cart-dock {
    left: max(12px, var(--safe-l));
    right: max(12px, var(--safe-r));
    top: auto;
    bottom: calc(12px + var(--safe-b));
    padding: 10px 12px 10px 14px;
    gap: 10px;
    justify-content: space-between;
    transform: translateY(18px) scale(0.96);
  }
  .cart-dock.visible { transform: none; }
  .cart-dock-total { font-size: 0.98rem; }
  .cart-dock-cta { padding: 10px 15px; font-size: 0.8rem; white-space: nowrap; }

  .cart-panel {
    left: 0; right: 0; bottom: 0; top: auto;
    width: 100%;
    height: min(88vh, calc((var(--app-vh, 1vh) * 88)));
    max-height: none;
    border-radius: var(--radius) var(--radius) 0 0;
    padding-bottom: calc(20px + var(--safe-b));
    transform: translateY(100%);
  }
  .cart-panel.open { transform: none; }
  .cart-drag-handle { display: block; }

  /* The glass recipe is tuned for a panel floating over a dark page on a big
     screen. As a bottom sheet covering most of a phone it left the catalogue
     headings reading straight through the receipt. Nearly opaque here — this
     is a surface you read numbers off, not a decorative overlay. */
  .cart-panel {
    background:
      linear-gradient(180deg, var(--fill-hover) 0%, var(--fill-hover) 100%),
      rgba(6, 6, 12, 0.97);
  }
  .cart-close { top: 14px; right: 14px; }
  .cart-items { gap: 8px; }
  .cart-actions { flex-direction: column; gap: 8px; }
  .cart-actions .btn { width: 100%; justify-content: center; }
  .receipt-send-row { flex-direction: column; }
  .receipt-send-row .btn-ghost-sm { width: 100%; min-height: 44px; }

  /* FAQ */
  .faq-question { padding: 16px 14px; font-size: 0.95rem; gap: 12px; text-align: left; }
  .faq-answer-inner { padding: 0 14px 16px; font-size: 0.92rem; }
}


/* ==========================================================================
   6. <= 375px — small phones

   Deliberately 375, not 400. An iPhone 14 is 390 and a Pixel is 393, so a
   400px cutoff swept in most of the phones people actually hold and gave
   them the cramped treatment meant for an iPhone SE.
   ========================================================================== */

@media (max-width: 375px) {
  .container { padding: 0 15px; }
  h1 { font-size: clamp(1.85rem, 8.6vw, 2.3rem); }
  h2 { font-size: clamp(1.5rem, 6.4vw, 1.85rem); }
  .card, .mvv-card, .problem-card, .service-card { padding: 20px 17px; }
  .btn { padding: 13px 20px; font-size: 0.88rem; }
  .video-frame:has(.nd) { height: 470px; }
  /* The two-column footer holds even at 320px — the link labels are short
     ("About", "Websites", "Pricing") and a single column here would put the
     scrolling right back. Only the brand row tightens. */
  .footer-col-brand { grid-template-columns: 1fr; justify-items: start; }
  .social-row { grid-column: 1; grid-row: auto; margin-top: 4px; }
  .finale-links a { font-size: 0.9rem; }
  .cart-dock-label { display: none; }
  .nav-links > li > a:not(.btn) { min-height: 54px; font-size: 1.32rem; }
}


/* ==========================================================================
   7. Landscape phones
   A 390x844 phone turned sideways is 844x390 — wide enough to miss every
   max-width query above, but only 390px tall. Vertical padding has to come
   down or a single section fills three screens.
   ========================================================================== */

@media (max-height: 460px) and (orientation: landscape) and (pointer: coarse) {
  section { padding: 44px 0; }
  .hero { padding-top: calc(var(--safe-t) + 40px); padding-bottom: 36px; }
  .hero h1 { font-size: clamp(1.7rem, 4.6vw, 2.4rem); }
  .hero-visual { margin-top: 18px; }
  .video-frame:has(.nd) { height: 300px; }
  .nav-links { padding-top: calc(var(--safe-t) + 68px); }
  .nav-links > li > a:not(.btn) { min-height: 46px; font-size: 1.15rem; }
  .site-search-panel { height: calc((var(--app-vh, 1vh) * 100) - 20px); }
}


/* ==========================================================================
   8. Data saver / reduced motion on mobile
   Users who ask for less motion on a phone are usually also on a device
   where the animations are the reason they asked.
   ========================================================================== */

@media (max-width: 900px) and (prefers-reduced-motion: reduce) {
  .ambient-bg, .hero-aurora, .finale-mesh, .problem-blob, .blob { display: none; }
  .client-marquee-track, .finale-capabilities-track { animation: none; transform: none; }
  .client-marquee, .finale-capabilities { overflow-x: auto; }
}


/* ==========================================================================
   9. Print — a phone's "share as PDF" path ends up here
   ========================================================================== */

@media print {
  .site-header, .nav-links, .cart-dock, .cart-panel, .aitg-launcher,
  .aitg-bubble, .scroll-progress, .chapter-rail, .noise-overlay,
  .ambient-bg, .site-search { display: none !important; }
  body { background: #fff; color: #111; }
  section { padding: 24px 0; }
}
