/* =====================================================================
   YOLANI OLIVAS: MOTION LAYER
   Additive only. Loads AFTER style.css. Nothing here is required for the
   site to function: every effect degrades to the static base if JS or a
   CDN fails, and all of it is silenced under prefers-reduced-motion.
   Palette + type inherit the base tokens (--ink, --paper, --serif, --ease).
   ===================================================================== */

/* ---------------------------------------------------------------------
   1. PAGE TRANSITION COVER
   A single full-bleed panel that wipes over the screen on exit and off
   the screen on enter. Present in the DOM before first paint (injected by
   an inline head snippet) so there is never a flash of unstyled content.
   --------------------------------------------------------------------- */
.page-cover {
  position: fixed; inset: 0; z-index: 9999;
  background: var(--ink);
  display: grid; place-items: center;
  transform: translateY(0);
  will-change: transform;
  pointer-events: none;
}
.page-cover__mark {
  font-family: var(--serif); color: var(--paper);
  font-size: clamp(1.4rem, 4vw, 2.2rem); letter-spacing: .01em;
  opacity: 0; transform: translateY(8px);
}
.page-cover__mark b { font-weight: 600; }
/* Enter: cover starts down over the page, then slides up and away. */
html.js .page-cover { transform: translateY(0); transition: transform .8s var(--ease); }
html.pt-ready .page-cover { transform: translateY(-100%); }
/* Exit: JS adds .pt-leaving, cover slides down to fully cover, then nav. */
html.pt-leaving .page-cover { transform: translateY(0); transition: transform .55s var(--ease); }
html.pt-leaving .page-cover__mark {
  opacity: 1; transform: translateY(0);
  transition: opacity .4s var(--ease) .12s, transform .4s var(--ease) .12s;
}
/* No-JS / reduced motion: never let the cover trap the page. */
html:not(.js) .page-cover { display: none; }
@media (prefers-reduced-motion: reduce) {
  .page-cover { display: none !important; }
}

/* ---------------------------------------------------------------------
   2. CUSTOM CURSOR
   A precise dot plus a lagging ring. Only switches on for fine pointers
   once JS confirms it is running (html.cursor-on). Native cursor stays
   until then, so a JS failure never leaves the user cursorless.
   --------------------------------------------------------------------- */
.cursor { position: fixed; top: 0; left: 0; z-index: 9998; pointer-events: none; }
.cursor__dot,
.cursor__ring {
  position: fixed; top: 0; left: 0; border-radius: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none; will-change: transform;
}
.cursor__dot { width: 6px; height: 6px; background: var(--ink); }
.cursor__ring {
  width: 38px; height: 38px; border: 1px solid var(--ink);
  transition: width .3s var(--ease), height .3s var(--ease),
              background-color .3s var(--ease), border-color .3s var(--ease),
              opacity .3s var(--ease);
  mix-blend-mode: normal;
}
/* Grow + fill on interactive targets. */
html.cursor-hot .cursor__ring {
  width: 58px; height: 58px;
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}
html.cursor-hot .cursor__dot { opacity: .4; }
/* Over dark sections the cursor inverts to stay visible. */
html.cursor-invert .cursor__dot { background: var(--paper); }
html.cursor-invert .cursor__ring { border-color: var(--paper); }
html.cursor-invert.cursor-hot .cursor__ring { background: color-mix(in srgb, var(--paper) 12%, transparent); }
/* Hide the native cursor only once ours is live and only on fine pointers.
   Everything uses the custom cursor EXCEPT iframes (they're a separate
   document with their own native cursor) and form fields (need the caret).
   This also removes the "double cursor" over inline prototype controls. */
@media (hover: hover) and (pointer: fine) {
  html.cursor-on,
  html.cursor-on *:not(iframe):not(input):not(textarea):not(select):not([contenteditable="true"]) { cursor: none; }
  html.cursor-on iframe { cursor: auto; }
}
.cursor { display: none; }
@media (hover: hover) and (pointer: fine) {
  html.cursor-on .cursor { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .cursor { display: none !important; }
  html.cursor-on, html.cursor-on a, html.cursor-on button { cursor: auto !important; }
}

/* ---------------------------------------------------------------------
   3. SCROLL PROGRESS BAR (in the nav)
   A hairline that fills left-to-right with scroll depth.
   --------------------------------------------------------------------- */
.scroll-prog {
  position: fixed; top: 0; left: 0; height: 2px; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background: var(--ink); z-index: 101; will-change: transform;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) { .scroll-prog { display: none; } }

/* ---------------------------------------------------------------------
   4. MAGNETIC BUTTONS
   The element translates toward the cursor; an inner span counter-shifts
   slightly for depth. Pure transform, GPU-friendly.
   --------------------------------------------------------------------- */
[data-magnetic] { will-change: transform; }
[data-magnetic] > * { display: inline-block; will-change: transform; }

/* ---------------------------------------------------------------------
   5. HERO ENHANCEMENTS
   a) blur-to-focus on the rising headline lines (adds to the base rise)
   b) a hairline that draws across under the statement
   c) a faint aura that tracks the cursor behind the headline
   --------------------------------------------------------------------- */
html.js .reveal-line > span { filter: blur(10px); }
html.js .reveal-line.mo-in > span,
html.js .reveal-line > span { animation-name: lineUpBlur; }
@keyframes lineUpBlur {
  0%   { transform: translateY(125%); filter: blur(10px); }
  60%  { filter: blur(0); }
  100% { transform: translateY(0);    filter: blur(0); }
}
/* underline draw beneath the hero statement */
.hero__rule {
  height: 2px; width: 100%; max-width: 0; background: var(--ink);
  margin-top: clamp(1.2rem, 3vw, 2rem);
  transition: max-width 1.1s var(--ease) .5s;
}
html.pt-ready .hero__rule.draw { max-width: min(360px, 60%); }
/* cursor-tracking aura */
.hero { isolation: isolate; }
.hero__aura {
  position: absolute; z-index: -1; top: 0; left: 0;
  width: 520px; height: 520px; border-radius: 50%;
  background: radial-gradient(circle at center,
              color-mix(in srgb, var(--ink) 9%, transparent) 0%,
              transparent 62%);
  transform: translate(-50%, -50%); opacity: 0;
  transition: opacity .6s var(--ease); pointer-events: none; will-change: transform;
  filter: blur(8px);
}
html.pt-ready .hero__aura { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  html.js .reveal-line > span { filter: none; animation-name: lineUp; }
  .hero__aura { display: none; }
  .hero__rule { max-width: min(360px, 60%); transition: none; }
}
/* touch devices (esp. mobile Safari) can strand an animated blur() and leave
   the headline permanently fuzzy. Skip the blur there; keep the rise. */
@media (hover: none), (pointer: coarse) {
  html.js .reveal-line > span { filter: none !important; animation-name: lineUp; }
}

/* ---------------------------------------------------------------------
   6. CASE PHONE "SETTLE"
   The device previews start slightly lifted + rotated and settle flat as
   they scroll into view (driven by GSAP; these are just the will-change
   hints and a no-JS safe default).
   --------------------------------------------------------------------- */
.frame--device .phone, .frame .phone { will-change: transform; }
[data-settle] { will-change: transform, opacity; }

/* ---------------------------------------------------------------------
   7. SIGNATURE MOMENT: LIVE AGENT NETWORK
   Replaces the static homepage arch-mini with an animated command center:
   four agent clusters feeding pulses into a central daily brief.
   Built as layered SVG + DOM; JS animates the pulses. Reduced motion shows
   the same diagram, static.
   --------------------------------------------------------------------- */
.agent-net {
  position: relative; width: 100%; height: 100%;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; box-shadow: 0 22px 46px -28px rgba(23,21,15,.3);
  display: block;
}
.agent-net__svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.agent-net__link { fill: none; stroke: var(--line); stroke-width: 1.2; }
.agent-net__pulse { fill: var(--ink); }
.agent-net__node {
  fill: #fff; stroke: var(--ink); stroke-width: 1.4;
  transition: r .3s var(--ease), fill .3s var(--ease);
}
.agent-net__node.hot { fill: var(--ink); }
.agent-net__core { fill: var(--ink); }
.agent-net__ripple { fill: none; stroke: var(--ink); stroke-width: 1.2; opacity: 0; }
.agent-net__cname {
  font-family: var(--sans); font-size: 11.5px; font-weight: 700;
  letter-spacing: .01em; fill: var(--ink);
}
.agent-net__label {
  font-family: var(--sans); font-size: 9.5px; font-weight: 600;
  letter-spacing: .06em; fill: var(--ink-faint);
}
.agent-net__brief {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: var(--night); color: #fff; padding: 11px 14px;
  font-size: 12px; font-weight: 700; letter-spacing: .01em;
  display: flex; align-items: center; gap: 8px;
}
.agent-net__brief .live {
  width: 7px; height: 7px; border-radius: 50%; background: #fff;
  box-shadow: 0 0 0 0 rgba(255,255,255,.7); animation: netLive 2s infinite;
}
@keyframes netLive {
  0% { box-shadow: 0 0 0 0 rgba(255,255,255,.6); }
  70% { box-shadow: 0 0 0 7px rgba(255,255,255,0); }
  100% { box-shadow: 0 0 0 0 rgba(255,255,255,0); }
}
@media (prefers-reduced-motion: reduce) {
  .agent-net__brief .live { animation: none; }
}

/* ---------------------------------------------------------------------
   8. MICRO: reveal-on-scroll polish for elements JS tags with .mo-lift
   --------------------------------------------------------------------- */
html.js [data-mo-lift] { opacity: 0; transform: translateY(30px); }
html.js [data-mo-lift].mo-in { opacity: 1; transform: none;
  transition: opacity .9s var(--ease), transform .9s var(--ease); }
@media (prefers-reduced-motion: reduce) {
  html.js [data-mo-lift] { opacity: 1 !important; transform: none !important; }
}
