/*
  TAG Solutions — SHARED portfolio layer.
  Loaded AFTER /main_style.css on the hub and on every lane page.
  Inherits the full design system (:root vars, .btn, .option-card, .pill,
  .reveal, #bg-canvas particles, #cursor-glow, scanlines, reduced-motion).

  Structure:
    1. Lane theme tokens        (accent swap per lane; particles/glow follow --accent)
    2. Normal-flow layout       (.pro-page / .pro-flow — the .section-absolute trap fix)
    3. Topbar helpers
    4. Scroll progress + floating CTA
    5. Lane hero / stats
    6. Demo blocks + stage shells
    7. Handle grid (job cards)
    8. Process row  (migrated, shared)
    9. Engage note + deliverables + stack chips  (migrated, shared)
   10. Cross-nav
   11. Lane foot
   12. Motion utilities (split / shimmer / cascade / page-enter / view-transitions)
   13. ONE consolidated prefers-reduced-motion block
*/

/* ============================ 1. Lane themes ============================ */

body[data-theme="solutions"]  { --accent: var(--blue); --accent2: #66c2ff; }
body[data-theme="lane-web"]    { --accent: #38b6ff; --accent2: #66c2ff; }
body[data-theme="lane-dash"]   { --accent: #46e6a8; --accent2: #7df2c8; }
body[data-theme="lane-auto"]   { --accent: #ffd17d; --accent2: #ffe3a8; }
body[data-theme="lane-sheets"] { --accent: #7bdff2; --accent2: #a8dadc; }
body[data-theme="lane-ai"]     { --accent: #b18cff; --accent2: #cdb4ff; }
body[data-theme="lane-games"]  { --accent: #ff5e8a; --accent2: #ff8fb0; }

/* ====================== 2. Normal-flow layout ==========================
   main_style.css puts .section at position:absolute inside #app{overflow:hidden}
   — lane pages must NOT use that. .pro-page unlocks real document scrolling and
   .pro-flow is the normal-flow content column offset below the fixed topbar. */

/* Border-box reset, scoped to the portfolio pages.
   main_style.css sets box-sizing per-element rather than globally, so any
   `width:100%` element that also has padding overflows its parent — that was
   clipping .engage-note's right padding on every lane at 375px. Scoped to
   .pro-page so the creative site's layout is untouched. */
.pro-page *,
.pro-page *::before,
.pro-page *::after { box-sizing: border-box; }

html:has(body.pro-page) { height: auto; overflow-x: hidden; }

body.pro-page {
  height: auto;
  min-height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
}

.pro-flow {
  position: relative;
  z-index: 5;
  width: 100%;
  max-width: 1160px;
  margin: 0 auto;
  padding: calc(var(--topbar-h) + 1.6rem) 1.25rem 4rem;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: clamp(3rem, 7vw, 5.5rem);
}

.pro-flow > section { scroll-margin-top: calc(var(--topbar-h) + 1.2rem); }

/* ========================= 3. Topbar helpers =========================== */

/* Anchors styled as buttons must never carry the default underline.
   (.btn / .nav-btn live in main_style.css where they were authored for <button>.) */
a.btn,
a.nav-btn,
.topbar a { text-decoration: none; }

.brand-link { text-decoration: none; color: var(--text); }

.brand-sub {
  font-weight: 650;
  color: color-mix(in srgb, var(--accent) 78%, var(--text));
  letter-spacing: 0.4px;
}

.creative-link { text-decoration: none; }

.topbar-mid {
  display: inline-flex;
  gap: 0.4rem;
  align-items: center;
}

.top-actions { display: flex; gap: 0.55rem; align-items: center; }

/* Narrow screens: brand + two labelled nav buttons overflow the bar and clip.
   Collapse the nav buttons to icon-only and drop the "/ Solutions" suffix. */
@media (max-width: 620px) {
  .top-actions .nav-btn span { display: none; }
  .top-actions .nav-btn { padding: 0 0.72rem; }
  .top-actions .nav-btn i { font-size: 1rem; }
}

@media (max-width: 430px) {
  .brand-sub { display: none; }
  .brand-text { font-size: 0.95rem; }
  .topbar { padding: 0 0.75rem; }
}

/* =================== 3b. Native form controls (dark) ==================
   Selects/inputs are painted by the OS, not by us. Two things were wrong:
   1) no `color-scheme`, so the browser assumed a LIGHT page and drew the
      <select> popup light;
   2) the closed control uses a translucent white background, which the popup
      resolves against white — giving near-white options under near-white
      text, i.e. an unreadable dropdown.
   Fix: declare the dark scheme, and set explicit <option> colours for
   browsers that honour author styling on the popup list. */

.pro-page { color-scheme: dark; }

.pro-page select option,
.pro-page select optgroup {
  background-color: #12141f;
  color: #f2f2ff;
}

/* Demo surfaces that are deliberately LIGHT must keep light native controls,
   otherwise their inputs render dark inside a white mock. */
.demo-web.light,
.inv-paper { color-scheme: light; }

.demo-web.light select option {
  background-color: #ffffff;
  color: #14192b;
}

/* ==================== 4. Scroll progress + floating CTA ================= */

.scroll-progress {
  position: fixed;
  top: var(--topbar-h);
  left: 0;
  right: 0;
  height: 3px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--accent), var(--accent2));
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 45%, transparent);
  z-index: 9;
  will-change: transform;
  pointer-events: none;
}

.floating-cta {
  position: fixed;
  right: 1.15rem;
  bottom: 1.15rem;
  z-index: 8;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  height: 48px;
  padding: 0 1.15rem;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 800;
  letter-spacing: 0.2px;
  color: #fff;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 92%, #fff 0%), color-mix(in srgb, var(--accent2) 90%, #000 0%));
  border: 1px solid color-mix(in srgb, var(--accent) 75%, rgba(255,255,255,0.2));
  box-shadow: 0 18px 60px rgba(0,0,0,0.4), 0 0 34px color-mix(in srgb, var(--accent) 30%, transparent);
  opacity: 0;
  transform: translateY(16px) scale(0.96);
  pointer-events: none;
  transition: opacity 300ms ease, transform 300ms cubic-bezier(.2,.9,.2,1);
}

.floating-cta.show {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

.floating-cta:hover { transform: translateY(-2px) scale(1.02); }

@media (max-width: 480px) {
  .floating-cta {
    left: 0.7rem;
    right: 0.7rem;
    bottom: 0.7rem;
    justify-content: center;
    height: 50px;
    border-radius: 14px;
  }
  /* The bar spans the full width down here, so reserve room for it —
     otherwise it permanently covers the last rows of page content. */
  .pro-flow { padding-bottom: 6.5rem; }
}

/* ========================== 5. Lane hero / stats ======================= */

.lane-hero {
  text-align: center;
  padding-top: 0.5rem;
}

.lane-kicker {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 34%, rgba(255,255,255,0.12));
  background: color-mix(in srgb, var(--accent) 10%, rgba(255,255,255,0.03));
  color: color-mix(in srgb, var(--accent) 85%, var(--text));
  font-weight: 750;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 0.72rem;
  margin-bottom: 1.35rem;
}

.lane-kicker i { font-size: 0.78rem; }

.lane-title {
  font-size: clamp(2.3rem, 5.4vw, 3.5rem);
  line-height: 1.06;
  margin: 0 auto;
  max-width: 16ch;
  letter-spacing: 0.4px;
  background: linear-gradient(90deg, var(--text), color-mix(in srgb, var(--accent) 42%, var(--text)));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 0 40px color-mix(in srgb, var(--accent) 12%, transparent);
}

/* Split-text safety — REQUIRED, do not remove.
   splitText() wraps each word in an inline-block .pw span. Inline-block children
   do NOT participate in an ancestor's `background-clip: text`, so they inherit the
   parent's transparent text-fill with no gradient of their own and paint as
   INVISIBLE (only a .shimmer word, which carries its own gradient, survives).
   Fix: give every word the same *vertical* ramp. Because it runs top-to-bottom and
   all words share a line height, the gradient is identical per word and the line
   still reads as one continuous fill. */
.lane-title.is-split .pw:not(.shimmer) {
  background-image: linear-gradient(180deg, var(--text), color-mix(in srgb, var(--accent) 30%, var(--text)));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

.lane-sub {
  margin: 1.15rem auto 0;
  max-width: 62ch;
  color: var(--muted);
  line-height: 1.6;
  font-size: 1.05rem;
}

.lane-pills {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin: 1.6rem auto 0;
  max-width: 720px;
}

.lane-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  align-items: center;
  margin-top: 1.9rem;
}

.lane-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.8rem;
  width: 100%;
  max-width: 940px;
  margin: 0 auto;
}

.lane-stat {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 1rem 1.15rem;
  border-radius: var(--radius-sm);
  background: var(--card);
  border: 1px solid var(--border);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.lane-stat i {
  font-size: 1.15rem;
  color: color-mix(in srgb, var(--accent) 82%, #fff);
  filter: drop-shadow(0 0 14px color-mix(in srgb, var(--accent) 26%, transparent));
  margin-top: 0.1rem;
}

.lane-stat strong { display: block; font-size: 0.98rem; letter-spacing: 0.01em; }
.lane-stat span { display: block; color: var(--muted); font-size: 0.83rem; margin-top: 0.15rem; line-height: 1.4; }

/* ---------------------- Make the `hidden` attribute win ----------------------
   The browser's `[hidden] { display: none }` comes from the UA stylesheet, so
   ANY author rule that sets `display` on the same element silently defeats it —
   the element stays on screen while `el.hidden === true` reports hidden. That
   shipped: the web lane's #dw-toast is `display: flex`, so "Message sent — demo
   only" sat permanently over the coaches section of the NovaFit demo, scrolling
   along with it, having never been triggered.

   Individual lanes had been patching this one class at a time (.dc-suggest,
   .scr-config, .dd-updated …). This makes it structural instead: if JS says
   hidden, it is hidden, whatever a component rule says. `!important` is
   deliberate and is the same approach normalize.css takes — a component that
   needs to animate itself out should drive opacity/visibility, not `hidden`. */
.pro-page [hidden] { display: none !important; }

/* ------------------ Centred pill rows: drop the legacy margin ------------------
   main_style.css:615 gives every .pill a trailing `margin-right: 0.4rem`, left
   over from when pills sat in inline text runs. Our pill rows are flex
   containers that already own their spacing via `gap`, so that margin survives
   only on the LAST pill — as dead space on the right and nowhere else. A row
   set to justify-content:center therefore centres the pills *plus* that phantom
   trailing margin, landing the visible row 3.17px left of true centre. 0.4rem
   is 6.34px, and half of it is exactly the offset measured on the hub's
   .trust-pills and on .lane-pills / .stack-chips across all six lanes.

   Scoped to the known flex rows rather than blanket-resetting .pro-page .pill,
   so a pill dropped into a sentence keeps its inline spacing. */
.pro-page :is(.lane-pills, .stack-chips, .trust-pills) > .pill { margin-right: 0; }

/* ------------------- Micro-badge scale (one value, one place) -------------------
   Pill-shaped badges inside demo chrome kept drifting: the automation lane had
   six different vertical paddings rendering near-identical labels from 15.6px
   to 22.4px tall, and the ai lane had five more. The class NAMES are page-local
   (.dp-h-badge, .dc-source, .ds-badge …), so each lane still has to apply the
   scale itself — but it applies these tokens rather than retyping the numbers,
   which is what let them drift apart in the first place. */
:root {
  --badge-pad: 0.2rem 0.55rem;
  --badge-lh: 1.35;
}

/* ---------------- Optical icon alignment (page furniture) ----------------
   Font Awesome glyphs have wildly different intrinsic widths (fa-bolt is
   narrow, fa-arrows-rotate is wide), so an icon+label pair renders its label
   at a different x for every icon. In a stacked list that reads as ragged
   text with no obvious cause. Boxing each glyph to a fixed em width with the
   glyph centred inside gives every row one shared left edge.

   `em`, not `rem`, so the box tracks whatever font-size the context sets.
   Deliberately NOT applied inside .demo-stage — demo chrome is its own visual
   world and several demos rely on tight inline icons. Lane page.css files must
   not restate this; if a lane needs a different width, it is a shared-layer
   decision, not a local one. */
.lane-stat i,
.proof-list li i,
.handle-card h3 i,
.engage-note h3 i,
.process-step h3 i,
.stack-chip i,
.xnav-dir i,
.btn i,
.nav-btn i {
  flex: none;
  width: 1.25em;
  text-align: center;
}

/* ==================== 6. Demo blocks + stage shells ==================== */

.demo-block { width: 100%; }

.demo-intro {
  max-width: 820px;
  margin: 0 auto 1.5rem;
  text-align: center;
}

.demo-num {
  display: inline-block;
  font-weight: 900;
  font-size: 0.8rem;
  letter-spacing: 0.22em;
  color: color-mix(in srgb, var(--accent) 70%, var(--muted));
  margin-bottom: 0.7rem;
}

.demo-intro h2 {
  font-size: clamp(1.6rem, 3.4vw, 2.15rem);
  margin: 0;
  letter-spacing: 0.3px;
}

.demo-intro p {
  margin: 0.7rem auto 0;
  max-width: 60ch;
  color: var(--muted);
  line-height: 1.55;
}

.proof-list {
  list-style: none;
  margin: 1.15rem auto 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.1rem;
  justify-content: center;
  max-width: 780px;
}

.proof-list li {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: color-mix(in srgb, var(--text) 82%, var(--muted));
  font-size: 0.88rem;
  font-weight: 600;
}

.proof-list li i {
  color: color-mix(in srgb, var(--accent) 82%, #fff);
  font-size: 0.82rem;
}

/* Shared stage shell (migrated) */
.demo-stage {
  position: relative;
  /* Hard containment for demo internals. Demos stack their own popovers,
     drawers and overlays; isolate guarantees none of those z-indexes can ever
     paint above the page's own chrome (topbar 10, floating CTA 8), no matter
     what the demo author picks or how the reveal animation changes the
     element's own stacking properties. */
  isolation: isolate;
  border-radius: var(--radius);
  background: var(--card);
  border: 1px solid var(--border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 18px 60px rgba(0,0,0,0.36);
  overflow: hidden;
  max-width: 1000px;
  margin: 0 auto;
  width: 100%;
}

.browser-frame { }

.browser-chrome {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.6rem 0.9rem;
  background: rgba(0,0,0,0.35);
  border-bottom: 1px solid rgba(255,255,255,0.08);
}

.browser-chrome .dot {
  width: 11px;
  height: 11px;
  border-radius: 999px;
  display: inline-block;
}
.browser-chrome .dot.red { background: #ff5f57; }
.browser-chrome .dot.yellow { background: #febc2e; }
.browser-chrome .dot.green { background: #28c840; }

.browser-chrome .url-bar {
  flex: 1;
  margin-left: 0.6rem;
  padding: 0.28rem 0.8rem;
  border-radius: 8px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.08);
  color: var(--muted);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.demo-caption {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  justify-content: center;
  max-width: 1000px;
  margin: 0.9rem auto 0;
  padding: 0 0.5rem;
  color: var(--muted);
  font-size: 0.82rem;
  line-height: 1.5;
  text-align: center;
}

.demo-caption i { color: color-mix(in srgb, var(--accent) 70%, var(--muted)); }
.demo-caption b { color: color-mix(in srgb, var(--accent) 80%, var(--text)); font-weight: 750; }

/* ========================= 7. Handle grid ============================= */

.handle-grid {
  display: grid;
  /* Always 6 cards — cap at 3 columns so they land as a clean 3x2 block.
     auto-fit produced 4 columns at desktop, leaving an orphan row of 2. */
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1rem;
  width: 100%;
  max-width: 1050px;
  margin: 0 auto;
}

@media (min-width: 820px) {
  .handle-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.handle-card {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--card);
  border: 1px solid var(--border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 16px 50px rgba(0,0,0,0.3);
  padding: 1.3rem 1.35rem 1.4rem;
  transition: transform 240ms ease, border-color 240ms ease, box-shadow 240ms ease;
}

.handle-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, rgba(255,255,255,0.07), transparent 40%);
  opacity: 0.6;
  pointer-events: none;
}

.handle-card:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--accent) 50%, rgba(255,255,255,0.16));
  box-shadow: 0 22px 70px rgba(0,0,0,0.42), 0 0 34px color-mix(in srgb, var(--accent) 13%, transparent);
}

.handle-card .hc-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  font-size: 1.2rem;
  color: color-mix(in srgb, var(--accent) 85%, #fff);
  background: color-mix(in srgb, var(--accent) 14%, rgba(255,255,255,0.04));
  border: 1px solid color-mix(in srgb, var(--accent) 26%, rgba(255,255,255,0.1));
  margin-bottom: 0.9rem;
}

.handle-card h3 {
  margin: 0 0 0.4rem;
  font-size: 1.08rem;
  letter-spacing: 0.01em;
}

.handle-card p {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.5;
}

.handle-card .hc-tag {
  display: inline-block;
  margin-top: 0.85rem;
  font-size: 0.74rem;
  font-weight: 750;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 75%, var(--muted));
}

/* ========================= 8. Process row (migrated) ================== */

.process-row {
  width: 100%;
  max-width: 1050px;
  margin: 0 auto;
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.process-step {
  position: relative;
  flex: 1 1 240px;
  max-width: 320px;
  border-radius: var(--radius);
  background: var(--card);
  border: 1px solid var(--border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 18px 60px rgba(0,0,0,0.34);
  padding: 1.4rem 1.3rem 1.3rem;
  text-align: center;
}

.ps-num {
  position: absolute;
  top: 0.8rem;
  right: 1rem;
  font-size: 2rem;
  font-weight: 900;
  color: color-mix(in srgb, var(--accent) 26%, transparent);
  line-height: 1;
}

.process-step .icon {
  font-size: 1.7rem;
  color: color-mix(in srgb, var(--accent) 80%, #fff);
  filter: drop-shadow(0 0 16px color-mix(in srgb, var(--accent) 22%, transparent));
}

.process-step h3 { margin: 0.7rem 0 0.4rem; font-size: 1.08rem; }
.process-step p { margin: 0; color: var(--muted); font-size: 0.88rem; line-height: 1.5; }

.process-arrow {
  align-self: center;
  color: color-mix(in srgb, var(--accent) 65%, var(--muted));
  font-size: 1.1rem;
  opacity: 0.8;
}

@media (max-width: 700px) {
  .process-arrow { transform: rotate(90deg); flex-basis: 100%; text-align: center; }
  .process-step { max-width: none; }
}

/* ============= 9. Engage note + deliverables + stack chips ============ */

.engage-note {
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  border-radius: var(--radius);
  background: var(--card);
  border: 1px solid var(--border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 18px 60px rgba(0,0,0,0.3);
  padding: 1.6rem 1.7rem;
  text-align: center;
}

.engage-note h3 {
  margin: 0 0 0.6rem;
  font-size: 1.2rem;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}

.engage-note h3 i { color: color-mix(in srgb, var(--accent) 82%, #fff); }

.engage-note p {
  margin: 0 auto;
  max-width: 64ch;
  color: var(--muted);
  line-height: 1.6;
  font-size: 0.95rem;
}

.engage-note p strong { color: color-mix(in srgb, var(--accent) 72%, var(--text)); }

.engage-note .stack-chips { margin-top: 1.15rem; justify-content: center; }

.deliverables {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
}

.deliverables .pill { padding: 0.42rem 0.85rem; font-size: 0.88rem; }

.stack-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}

.stack-chips .pill {
  gap: 0.4rem;
  padding: 0.38rem 0.75rem;
  font-size: 0.84rem;
}

/* ============================ 10. Cross-nav =========================== */

.cross-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
}

.xnav-card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  border-radius: var(--radius);
  background: var(--card);
  border: 1px solid var(--border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 16px 50px rgba(0,0,0,0.3);
  padding: 1.25rem 1.35rem;
  text-decoration: none;
  color: var(--text);
  transition: transform 220ms ease, border-color 220ms ease, box-shadow 220ms ease;
}

.xnav-card .xnav-dir {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 78%, var(--muted));
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.xnav-card.next { text-align: right; }
.xnav-card.next .xnav-dir { justify-content: flex-end; }

.xnav-card .xnav-name {
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: 0.01em;
}

.xnav-card .xnav-desc { color: var(--muted); font-size: 0.85rem; line-height: 1.45; }

.xnav-card:hover {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--accent) 55%, rgba(255,255,255,0.16));
  box-shadow: 0 22px 70px rgba(0,0,0,0.42), 0 0 34px color-mix(in srgb, var(--accent) 14%, transparent);
}

.xnav-all {
  grid-column: 1 / -1;
  text-align: center;
  margin-top: 0.2rem;
}

.xnav-all a {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: color-mix(in srgb, var(--accent) 80%, var(--text));
  text-decoration: none;
  font-weight: 750;
  font-size: 0.92rem;
}

.xnav-all a:hover { text-decoration: underline; }

@media (max-width: 560px) {
  .cross-nav { grid-template-columns: 1fr; }
}

/* ============================ 11. Lane foot =========================== */

.lane-foot {
  text-align: center;
  width: 100%;
  max-width: 820px;
  margin: 0 auto;
}

.lane-foot h2 {
  font-size: clamp(1.7rem, 3.6vw, 2.3rem);
  margin: 0;
  letter-spacing: 0.4px;
  background: linear-gradient(90deg, var(--text), color-mix(in srgb, var(--accent) 42%, var(--text)));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.lane-foot p { margin: 0.7rem auto 1.5rem; max-width: 56ch; color: var(--muted); line-height: 1.55; }

.lane-foot .micro { display: block; margin-top: 2.4rem; font-size: 0.85rem; }

/* ====================== 12. Motion utilities ========================== */

/* Split-text: JS wraps words in .pw spans and adds .is-split to the target. */
.pw { display: inline-block; will-change: transform, opacity; }

[data-split].is-split .pw {
  opacity: 0;
  animation: splitIn 0.62s cubic-bezier(.2,.9,.2,1) forwards;
  animation-delay: calc(var(--i, 0) * 55ms);
}

@keyframes splitIn {
  from { opacity: 0; transform: translateY(0.7em) rotateX(-38deg); }
  to   { opacity: 1; transform: none; }
}

/* Shimmer sweep on an accent word */
.shimmer {
  background: linear-gradient(
    100deg,
    color-mix(in srgb, var(--accent) 88%, var(--text)) 20%,
    #ffffff 40%,
    color-mix(in srgb, var(--accent2) 88%, var(--text)) 60%
  );
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: shimmerSweep 4.5s linear infinite;
}

@keyframes shimmerSweep {
  0%   { background-position: 180% 0; }
  100% { background-position: -80% 0; }
}

/* Cascade stagger — parent is a .reveal; children fade up in sequence */
.cascade > * {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.5s ease, transform 0.5s ease;
  transition-delay: calc(var(--i, 0) * 70ms);
}

.cascade.in > * { opacity: 1; transform: none; }

/* Magnetic buttons compose translate with any transform-based hover */
.magnetic { translate: var(--mx, 0) var(--my, 0); }

/* Page enter (fallback when View Transitions are unsupported) */
@supports not (view-transition-name: root) {
  body.pro-page .pro-flow { animation: pageFadeUp 520ms cubic-bezier(.2,.9,.2,1) both; }
}

@keyframes pageFadeUp {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* Cross-document View Transitions (progressive enhancement) */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: vtOut 200ms ease both; }
::view-transition-new(root) { animation: vtIn 320ms cubic-bezier(.2,.9,.2,1) both; }

@keyframes vtOut { to { opacity: 0; transform: translateY(-8px); } }
@keyframes vtIn  { from { opacity: 0; transform: translateY(10px); } }

/* ================= 13. Consolidated reduced motion ==================== */

@media (prefers-reduced-motion: reduce) {
  .scroll-progress { display: none; }
  .floating-cta { transition: none; }
  [data-split].is-split .pw { opacity: 1; animation: none; }
  .shimmer { animation: none; }
  .cascade > * { opacity: 1; transform: none; transition: none; }
  .magnetic { translate: none; }
  body.pro-page .pro-flow { animation: none; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ================= 14. No-JS safety net ==============================
   .reveal / .cascade start at opacity:0 and are revealed by an
   IntersectionObserver in pro.js. With scripting unavailable that observer
   never runs and the page would render blank. Force everything visible. */
@media (scripting: none) {
  .reveal,
  .cascade > *,
  [data-split].is-split .pw { opacity: 1 !important; transform: none !important; }
  .scroll-progress { display: none; }
}

/* ---- and the same net for JS that is enabled but BROKEN ----
   `scripting: none` only covers JS switched off. It does nothing for the more
   likely failure: pro.js 404s, or one syntax error stops it parsing. Then
   scripting is "enabled", the observer never runs, and all seven pages render
   blank — measured at 24/24 reveals invisible, headline included.

   pro.js adds `pro-js` to <html> on its very first line, so the hidden state
   below only applies once the runtime is actually present. No pro.js, no
   hiding: the visitor gets a static but complete page instead of an empty one.
   Keep this rule and that line together — removing either re-arms the trap. */
html:not(.pro-js) .reveal,
html:not(.pro-js) .cascade > *,
html:not(.pro-js) [data-split] .pw {
  opacity: 1 !important;
  transform: none !important;
}
html:not(.pro-js) .scroll-progress { display: none; }
