/* R5 secondary region: terms.html, purchase-success.html, 404.html and the shared footer horizon.
   Every selector goes through an .orb-sec-* hook. No !important. Colours are style.css :root tokens
   or their rgba forms (--ai-cyan 0,212,255; --ai-magenta 255,0,255; --electric-purple 153,69,255;
   --ai-orange 255,107,0; --deep-purple-bg #0a0015; --grid-purple #1a0033). Image paths resolve from
   assets/sentient/secondary/ to images/sentient/; every image has a CSS fallback beneath it. */

/* ---- 1. Orb engine hosts ------------------------------------------------------------------ */
.orb-sec-orb { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.orb-sec-bubble { position: absolute; top: 0; left: 0; border-radius: 50%; }
.orb-sec-orb.is-live .orb-sec-bubble { will-change: transform, opacity; }
/* an orb face drawn inside a host: image on top of a CSS halo so a missing file still reads as an orb */
.orb-sec-orb[data-orb-face]::before {
  content: ''; position: absolute; left: 50%; bottom: 0; z-index: 1;
  width: var(--orb-sec-face, 64px); height: var(--orb-sec-face, 64px); margin-left: calc(var(--orb-sec-face, 64px) / -2);
  border-radius: 50%;
  background: var(--orb-sec-face-img, none) center / contain no-repeat,
    radial-gradient(circle at 36% 30%, rgba(150, 238, 255, 0.9), rgba(0, 212, 255, 0.45) 45%, rgba(153, 69, 255, 0.35) 70%, rgba(153, 69, 255, 0) 100%);
  box-shadow: 0 0 28px rgba(0, 212, 255, 0.45), 0 0 60px rgba(255, 0, 255, 0.22);
}
/* No mascot face on the decorative orbs. The character is drawn art with a job to do, and putting
   it in every footer horizon turned it into wallpaper. These stay as light: the orb glow without a
   face. The data-orb-face hooks remain so the states are still addressable, and they now differ by
   treatment alone. */
.orb-sec-orb[data-orb-face] { --orb-sec-face-img: none; }
.orb-sec-lost-orb {
  mix-blend-mode: screen;
  -webkit-mask-image: radial-gradient(circle at 50% 47%, #000 56%, rgba(0, 0, 0, 0) 76%);
  mask-image: radial-gradient(circle at 50% 47%, #000 56%, rgba(0, 0, 0, 0) 76%);
}
.orb-sec-orb[data-orb-face="idle"]::before {
  transform: scale(0.97);
  filter: saturate(0.92) brightness(0.96);
}
.orb-sec-orb[data-orb-face="resting"]::before {
  transform: scale(0.9) rotate(-4deg);
  filter: saturate(0.68) brightness(0.82);
  opacity: 0.82;
  box-shadow: 0 0 18px rgba(0, 212, 255, 0.28), 0 0 40px rgba(255, 0, 255, 0.12);
}

/* ---- 2. Foreground plane (design plan 4.5) ------------------------------------------------- */
.orb-sec-plane {
  position: relative; isolation: isolate;
  background: rgba(10, 0, 21, var(--orb-sec-tint, 0.72));
  border: 1px solid rgba(0, 212, 255, 0.25); border-radius: 16px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(255, 0, 255, 0.06) inset;
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .orb-sec-plane.is-glass { -webkit-backdrop-filter: blur(16px) saturate(1.3); backdrop-filter: blur(16px) saturate(1.3); }
}
@media (max-width: 767px) { .orb-sec-plane.is-glass { -webkit-backdrop-filter: none; backdrop-filter: none; } }

/* ---- 3. Motion toggle (label is constant; aria-pressed carries the state) ------------------ */
.orb-sec-toggle {
  display: inline-flex; align-items: center; gap: 0.55rem;
  font-family: 'JetBrains Mono', 'Share Tech Mono', 'Share Tech Mono Fallback', monospace; font-size: 0.78rem; letter-spacing: 0.5px; text-transform: uppercase;
  color: var(--ai-cyan); background: rgba(0, 212, 255, 0.06); border: 1px solid rgba(0, 212, 255, 0.45); border-radius: 999px;
  padding: 0.5rem 1.1rem; min-width: 10.5rem; line-height: 1.25; justify-content: center; cursor: pointer; transition: background 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;
}
.orb-sec-toggle::before { content: ''; width: 0.6rem; height: 0.6rem; border-radius: 50%; background: var(--ai-cyan); box-shadow: 0 0 8px var(--ai-cyan); }
.orb-sec-toggle:hover, .orb-sec-toggle:focus-visible { box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.2); outline: none; }
.orb-sec-toggle[aria-pressed="true"] { color: var(--light-gray); border-color: rgba(255, 0, 255, 0.5); background: rgba(255, 0, 255, 0.08); }
.orb-sec-toggle[aria-pressed="true"]::before { background: var(--ai-magenta); box-shadow: none; }
html:not([data-motion-js]) .orb-sec-toggle { display: none; }   /* inert without JS, so hidden */

/* ---- 4. Footer horizon (index, echorb, forge via patch; terms directly) --------------------- */
.orb-sec-footer {
  position: relative; isolation: isolate; overflow: clip;
  background: transparent; padding: 4.5rem 0 6.5rem; border-top: 1px solid rgba(255, 0, 255, 0.2);   /* 6.5rem below: room for the 64px orb on the horizon line */
}
.orb-sec-footer[data-page="forge"] { border-top-color: rgba(255, 107, 0, 0.2); }
.orb-sec-horizon {
  position: absolute; left: -10%; right: -10%; bottom: 0; height: 220px; z-index: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 70% 100% at 50% 100%, rgba(0, 212, 255, 0.28), rgba(0, 212, 255, 0) 70%),
    radial-gradient(ellipse 60% 100% at 30% 100%, rgba(255, 0, 255, 0.18), rgba(255, 0, 255, 0) 70%);
  opacity: 0.55; transform: translateY(24px);
  transition: opacity 0.9s ease, transform 0.9s ease;
}
.orb-sec-footer.is-lit .orb-sec-horizon { opacity: 1; transform: none; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    html:not([data-motion="still"]) .orb-sec-horizon {
      transition: none; animation: orb-sec-rise linear both; animation-timeline: view(); animation-range: entry 0% entry 90%;
    }
  }
}
@keyframes orb-sec-rise { from { opacity: 0.55; transform: translateY(24px); } to { opacity: 1; transform: none; } }
.orb-sec-horizon-orb { position: absolute; inset: auto; left: 50%; bottom: 12px; width: 200px; height: 96px; margin-left: -100px; overflow: visible; --orb-sec-face: 64px; }
.orb-sec-footer .container { position: relative; z-index: 1; }
.orb-sec-footer .orb-sec-plane { display: inline-block; max-width: 100%; padding: 1.25rem 1.75rem; }
.orb-sec-footer .orb-sec-toggle { margin-top: 1rem; }
.orb-sec-footer::before { z-index: 2; }   /* keep style.css's shine line above the horizon */

/* ---- 5. terms.html: frame the frozen legal text -------------------------------------------- */

/* The world behind the legal text. Giovanni chose world 20 from four options, and asked that it
   stay showing while you scroll: "can we keep the background showing even while scrolling through
   the terms". So it is a FIXED layer rather than a background on the page, which matters because
   this document is over 16,000px tall. A scrolling background would have run out almost at once and
   background-attachment: fixed is the one thing iOS has never handled reliably, so a fixed element
   is the version that actually works on a phone.

   A still, not planes. The other pages move their worlds because you are travelling past them. Here
   you are reading, and a parallax under a terms and conditions page is decoration fighting the
   document. Nothing about this layer moves, so it needs no motion gate.

   Cut at 1280, per the standing note for terms, 404 and purchase-success. The art only ever shows
   in the margins beside the frame, which keeps its own 0.80 backing, so the body text measures
   16.6:1 against a 4.5 floor with this behind it. */
.orb-sec-world,
.orb-sec-world-scrim {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.orb-sec-world {
  background: url(../../../images/world-terms/terms-bg-sm.webp) center bottom / cover no-repeat;
}
@media (min-width: 768px) {
  .orb-sec-world {
    background-image: url(../../../images/world-terms/terms-bg-lg.webp);
  }
}
/* The art is a night scene already; this only settles it far enough back that the frame reads as
   the foreground and the margins do not compete with the column. */
.orb-sec-world-scrim {
  background: linear-gradient(180deg, rgba(10, 0, 21, 0.86), rgba(10, 0, 21, 0.72) 45%, rgba(10, 0, 21, 0.90));
}
/* Everything the visitor reads sits above it. */
/* Everything the visitor reads sits above it. Written out per page rather than with :has(), which
   would have been neater and also a single point of failure: where :has() is not honoured the
   content loses its stacking context and the world paints over the page. The three pages that
   carry a world are named, so nothing depends on a selector being supported. */
.orb-sec-page[data-page="terms"] .orb-sec-frame,
.orb-sec-page[data-page="terms"] > nav,
.orb-sec-page[data-page="terms"] > footer,
.orb-sec-page[data-page="404"] > nav,
.orb-sec-page[data-page="404"] > .nf-wrap,
.orb-sec-page[data-page="404"] > footer,
.orb-sec-page[data-page="success"] > nav,
.orb-sec-page[data-page="success"] > .orb-sec-success,
.orb-sec-page[data-page="success"] > footer { position: relative; z-index: 1; }

/* The footer's two top rules go, exactly as they did on echorb once its footer sat over the world.
   They were never wrong before: this page had a flat background until now, and a hairline against
   flat dark is a divider doing its job. With the world behind it, the same 1px border and the same
   animated shine from style.css draw a lit wire straight across the hills. Measured on the finished
   page at 1440x900: a single row 64.7 luma above its neighbours at y 585. */
.orb-sec-page[data-page="terms"] footer.orb-sec-footer { border-top: 0; }
.orb-sec-page[data-page="terms"] footer.orb-sec-footer::before { content: none; }

.orb-sec-glow {
  position: absolute; left: 0; right: 0; top: 0; height: 60vh; z-index: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 60% 55% at 50% 0%, rgba(0, 212, 255, 0.16), rgba(0, 212, 255, 0) 70%),
    radial-gradient(ellipse 45% 40% at 85% 10%, rgba(255, 0, 255, 0.12), rgba(255, 0, 255, 0) 70%);
}
.orb-sec-frame {
  --orb-sec-tint: 0.80;
  position: relative; z-index: 1;
  /* 50rem, on Giovanni's "go wider". The old value was 42rem and its comment claimed 76 characters
     of Inter, which is simply not what it rendered: measured off the line boxes, 42rem gave a
     median of 57 characters per line at 1440 and 1920. I had repeated that 76 back to him as the
     reason not to widen it, which was wrong, and the number was wrong in the source before that.

     Measured, not estimated: a Range over each paragraph, counting DISTINCT line-box tops rather
     than client rects, because these paragraphs are full of inline <strong> and one rect per
     fragment undercounts the line badly. 104 paragraphs sampled.

     Still rem rather than ch or a percentage, which was the sound half of the original reasoning:
     it does not shift when the web font swaps in, so there is no layout jump. */
  width: min(50rem, 100% - 1.5rem); margin: 2rem auto 3rem;
  padding: clamp(1.25rem, 4vw, 3rem);
  overflow-wrap: anywhere;
}
.orb-sec-frame .terms-header { position: relative; padding-bottom: 1.5rem; margin-bottom: 1.5rem; border-bottom: 1px solid rgba(0, 212, 255, 0.2); }
.orb-sec-frame .terms-header p { margin-bottom: 0.25rem; }
.orb-sec-frame .terms-header h1 { font-size: clamp(1.5rem, 5vw, 2rem); margin: 0.5rem 0 1rem; }   /* 2rem keeps the title on one line in Orbitron inside the 42rem frame (no wrap shift on font swap) */
/* .orb-sec-orb-terms removed with its element: Giovanni, "remove the odd orbs from the terms page". */
.orb-sec-frame h2 { color: var(--ai-orange); letter-spacing: 3px; font-size: 1.05rem; margin: 2.5rem 0 1rem; }
.orb-sec-frame a { color: var(--ai-cyan); }
/* No hover sweep on the legal headings. style.css gives every h1, h2 and h3 a ::before that is a
   2px cyan rule parked at translateX(-100%) and swept across on hover. Parked means OUTSIDE the
   heading, and nothing here clips it. Worse, these headings are not positioned, so the rule
   resolves against .orb-sec-frame instead and parks a frame width to its left: a 2px cyan line
   drawn across the empty margin beside every one of the eighteen headings on this page. Measured
   at 1440x900, rows 308 and 487 sat 182 luma above the background either side of the frame.

   This is the same fault style.css already fixed once, for .section-title, in its own words "the
   unwanted line beside headers". These headings are not .section-title, so they never got it. */
.orb-sec-frame h1::before,
.orb-sec-frame h2::before,
.orb-sec-frame h3::before { content: none; }
.orb-sec-frame .social-links a { color: var(--ai-cyan); }

/* ---- 6. purchase-success.html --------------------------------------------------------------- */
.orb-sec-page[data-page="success"] { background: linear-gradient(180deg, #0a0015 0%, #1a0033 100%); }
/* The sentient-hero art is gone from here, on Giovanni's "have them share this world": this page
   is the only one of the three that HAD art rather than none, so sharing world 20 replaces it
   rather than filling a gap. What is kept is the dark gradient, which now does the scrim's job, so
   this page carries no .orb-sec-world-scrim of its own and does not end up doubly dimmed. */
.orb-sec-page .orb-sec-success {
  width: 100%; min-width: 0;
  background: linear-gradient(180deg, rgba(10, 0, 21, 0.72), rgba(10, 0, 21, 0.9)),
    linear-gradient(135deg, rgba(0, 212, 255, 0.05), rgba(0, 0, 0, 0.55));
}
/* the page's fluid wash held as one static frame (25% keyframe): the orb field is the only time-based layer */
.orb-sec-page .orb-sec-success::before { animation-delay: -5s; animation-play-state: paused; }
@media (min-width: 768px) {
  /* held frame sized in viewport units: a content-height change no longer resizes the full-viewport wash (layout-shift score) */
  .orb-sec-page .orb-sec-success::before { top: -50vh; bottom: auto; height: 200vh; }
}
/* 320 clip fix: the container and card must shrink with the viewport */
.orb-sec-success .success-container { width: 100%; min-width: 0; max-width: min(800px, 100%); padding: clamp(1rem, 4vw, 3rem); }
.orb-sec-success .success-card { min-width: 0; padding: clamp(1.25rem, 4vw, 2.5rem); }
.orb-sec-success .success-card h1 { font-size: clamp(1.6rem, 7vw, 2.5rem); overflow-wrap: anywhere; }
/* Item 12: purchase-success.html defines its own dataFlow keyframes, which animate `left` from
   -100% to 100%. style.css:1535 puts `animation: dataFlow` on .data-stream itself, so since the
   cec684d repair the paragraph slid out of its card: at 320 it laid out from -206 to 38 against a
   card at 16 to 304 and was clipped, freezing under reduce as an unreadable 22px fragment. The
   paragraph stays put; only its ::after sweep may move, and not when motion is reduced. */
.orb-sec-page[data-page="success"] .data-stream {
  animation: none;
  position: relative;
  left: auto;
  right: auto;
  width: 100%;
  max-width: 100%;
}
.orb-sec-mascot { position: relative; isolation: isolate; margin: 0 auto; max-width: 320px; }
.orb-sec-mascot .orb-sec-orb { inset: -1rem 0; }
.orb-sec-mascot .echorb-mascot { position: relative; z-index: 1; aspect-ratio: 1 / 1; }   /* excited_echorb.png is square: reserve its box before it loads */
.orb-sec-success .orb-sec-toggle { align-self: center; }

/* ---- 7. 404.html: the lost orb ------------------------------------------------------------- */
.orb-sec-lost { position: fixed; inset: 0; z-index: 1; }
.orb-sec-scrim { position: relative; z-index: 2; width: 100%; }   /* fixed column width: pseudo-elements sized from it do not shift when fonts swap */
.orb-sec-scrim::before {
  content: ''; position: absolute; inset: -8% -9%; z-index: -1; border-radius: 50%;
  background: radial-gradient(ellipse 55% 50% at 50% 55%, rgba(10, 0, 21, 0.88), rgba(10, 0, 21, 0) 78%);
}
.orb-sec-lost-orb {
  display: block; width: 180px; height: 180px; margin: -0.5rem auto 0.25rem;
  filter: drop-shadow(0 0 24px rgba(0, 212, 255, 0.55));
  animation: orb-sec-drift 7s ease-in-out infinite;
}
.orb-sec-lost-orb.is-fallback { border-radius: 50%; box-shadow: 0 0 40px rgba(0, 212, 255, 0.5), 0 0 90px rgba(255, 0, 255, 0.25); }
@keyframes orb-sec-drift { 0%, 100% { transform: translateY(0) rotate(-3deg); } 50% { transform: translateY(-10px) rotate(3deg); } }
@media (max-width: 767px) { .orb-sec-lost-orb { width: 140px; height: 140px; } }
.orb-sec-page[data-page="404"] .nf-actions .orb-sec-toggle { font-size: 0.82rem; }

/* ---- 8. Still composition: identical under the OS setting and the site toggle -------------- */
/* Design, not an off switch: every engine renders one frame (JS); the horizon sits at rest at full
   strength; the success page's shimmer, pulse, float and sweep hold their first frame; the lost orb
   holds its drop-shadow; the footer shine holds. */
@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="full"]) .orb-sec-horizon { transition: none; animation: none; opacity: 1; transform: none; }
  html:not([data-motion="full"]) .orb-sec-footer::before { animation-play-state: paused; }
  html:not([data-motion="full"]) .orb-sec-lost-orb { animation: none; }
  html:not([data-motion="full"]) .orb-sec-page .success-card::before,
  html:not([data-motion="full"]) .orb-sec-page .hero-shimmer,
  html:not([data-motion="full"]) .orb-sec-page .success-icon,
  html:not([data-motion="full"]) .orb-sec-page .echorb-mascot,
  html:not([data-motion="full"]) .orb-sec-page .data-stream,
  html:not([data-motion="full"]) .orb-sec-page .data-stream::after { animation: none; left: 0; transform: none; }
  html:not([data-motion="full"]) .orb-sec-page .success-icon i { animation: none; }
  html:not([data-motion="full"]) .orb-sec-toggle, html:not([data-motion="full"]) .orb-sec-plane { transition: none; }
}
html[data-motion="still"] .orb-sec-horizon { transition: none; animation: none; opacity: 1; transform: none; }
html[data-motion="still"] .orb-sec-footer::before { animation-play-state: paused; }
html[data-motion="still"] .orb-sec-lost-orb { animation: none; }
html[data-motion="still"] .orb-sec-page .success-card::before,
html[data-motion="still"] .orb-sec-page .hero-shimmer,
html[data-motion="still"] .orb-sec-page .success-icon,
html[data-motion="still"] .orb-sec-page .echorb-mascot,
html[data-motion="still"] .orb-sec-page .data-stream,
html[data-motion="still"] .orb-sec-page .data-stream::after { animation: none; left: 0; transform: none; }
html[data-motion="still"] .orb-sec-page .success-icon i { animation: none; }
html[data-motion="still"] .orb-sec-toggle, html[data-motion="still"] .orb-sec-plane { transition: none; }
