/* Dominia — motion. Owner piece: MOTION.
 *
 * Three devices only, each measured off the reference rather than invented:
 *
 *   1. Headlines reveal LINE BY LINE from behind their own mask. inversa.com/origin builds its
 *      headlines as a stack of `.line-mask` / `.line` pairs, which is exactly this.
 *   2. Mono labels resolve out of scrambled characters — caught mid-flight twice on the
 *      reference, "HEATPVXZ" toward HEATMAPS and "EFFICIENCU" toward EFFICIENCY.
 *   3. Plates and stats rise a little as they arrive.
 *
 * Durations come from the reference's own transition census: 1s ease-in-out on 8 elements,
 * 0.2s ease-in-out on 5, 0.25s linear on 3, 0.25s ease-out on 2. Nothing here is faster than
 * 200ms or slower than 900ms, and nothing loops.
 *
 * THE HIDDEN STATE IS ADDED BY SCRIPT, NEVER WRITTEN HERE. js/motion.js writes it inline with
 * GSAP's gsap.from() only once it has decided to animate. If the script (or GSAP) never runs — no JS, an error, prefers-reduced-motion — nothing is ever hidden, and the page
 * reads exactly as it does with the motion finished. A reveal that hides content by default and
 * relies on script to show it is a reveal that eventually ships a blank page to somebody.
 */

/* ---------------------------------------------------------------- line reveal
 *
 * js/motion.js splits each headline with GSAP SplitText into `.hl-line`, each wrapped in its own
 * `.hl-line-mask` (SplitText sets `overflow: clip` on the mask), and slides the lines up from
 * behind it. The durations and curves live in the script now; this sheet only shapes the boxes. */

.hl-line-mask,
.hl-line { display: block; }

/* Descenders (g, y, p) are drawn below the baseline and a tight mask clips them — display leading
   is 0.9 here. The padding buys them room and the equal negative margin gives the space back, so
   line spacing is unchanged from the un-split text. */
.hl-line-mask {
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}

/* ---------------------------------------------------------------- rise
 *
 * Plates and the dossier rise 24px as they arrive. Entirely in js/motion.js (gsap.from), which
 * writes the hidden state inline only once it has decided to animate and clears it afterwards —
 * so there is no armed state in this sheet to leave behind if the script never runs. */

/* ---------------------------------------------------------------- reel
 *
 * The dossier's waitlist count rolls on the hero's odometer (css/hero-video.css). The reel window
 * is 1em tall and .dossier__num sets 0.95 leading, so built as reels the figure stood 1.4px
 * taller and nudged everything below it; the negative margin gives the difference back. */
.dossier__num.odo { margin-block: -0.025em; }

/* ---------------------------------------------------------------- hover
 *
 * The reference's fastest transitions are 0.2s. Ours match. Colour and border only — nothing
 * moves on hover, because a control that shifts under the cursor is a control you can miss. */

.nav__links a,
.footer__links a,
.nav__cta {
  transition: color 200ms ease-out, background-color 200ms ease-out, border-color 200ms ease-out;
}

/* ---------------------------------------------------------------- the buttons
 *
 * The three "Get Early Access" buttons (the hero's .cta, the nav's .nav__cta, Enlist's
 * .btn--primary) share one set of states, on the brand's own timings: --dur-ui for the hover,
 * --dur-micro for the press, both on --ease, and both zero under reduced motion (css/tokens.css).
 *
 * HOVER IS A WALK METER. A 2px line along the bottom edge fills left to right, the meter the
 * claim readouts use for "walked". It is drawn in currentColor, so it is bone on the red buttons
 * and ink on the nav's bone hover, and the label's contrast never moves. A red flood was the
 * first idea and was rejected on the numbers: bone on --claim is 3.83:1, which is exactly why
 * v3 puts buttons on Claim 600 (4.82:1). The control itself does not move — only the line
 * inside it does. Keyboard focus gets the same line.
 *
 * PRESS pulls the glow in and darkens the fill a step: the button is pushed into the page. There
 * was no press state anywhere, and on a phone it is the only feedback a tap gets. */

.hv .cta,
.btn--primary,
.nav__cta { position: relative; }

.hv .cta::before,
.btn--primary::before,
.nav__cta::before {
  content: "";
  position: absolute;
  /* Under the label and aligned to it, not flush on the edge: flush, on Enlist's cream ground, a
     bone line read as the button missing its bottom 2px rather than as a meter. Each button sets
     its own inset from its own padding. The right inset also keeps the line clear of a cut
     corner, which .btn--primary draws with a gradient, not a clip-path (css/surface.css). */
  left: var(--meter-x, 0);
  right: var(--meter-x, 0);
  bottom: var(--meter-y, 0);
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-ui) var(--ease);
  pointer-events: none;
}
.btn--primary { --meter-x: var(--s-6); --meter-y: 9px; }
.hv .cta { --meter-x: 24px; --meter-y: 11px; }
.hv #hv-open .cta { --meter-x: 32px; --meter-y: 13px; }
.nav__cta { --meter-x: var(--s-3); --meter-y: 4px; }
@media (max-width: 759px) { .hv #hv-open .cta { --meter-x: 24px; --meter-y: 12px; } }   /* its phone padding */

@media (hover: hover) {
  .hv .cta:hover::before,
  .btn--primary:hover::before,
  .nav__cta:hover::before { transform: scaleX(1); }

  /* The hero's button had no hover at all. It lifts its glow as Enlist's does: v3's G3 halo is
     22px at 45%, and this is Enlist's 16px drop-shadow at 60% restated as a box-shadow. */
  .hv .cta:hover { box-shadow: 0 0 32px rgba(255, 90, 54, 0.6); }
}
.hv .cta:focus-visible::before,
.btn--primary:focus-visible::before,
.nav__cta:focus-visible::before { transform: scaleX(1); }

.hv .cta {
  transition: box-shadow var(--dur-micro) var(--ease), filter var(--dur-micro) var(--ease);
}
.hv .cta:active {
  box-shadow: 0 0 8px rgba(255, 90, 54, 0.3);
  filter: brightness(0.88);
}
/* One filter list, because filter does not stack: the darkening and the tightened halo together. */
.btn--primary:active { filter: brightness(0.88) drop-shadow(0 0 4px var(--g3-claim)); }
.nav__cta:active { background: var(--bone-2); border-color: var(--bone-2); color: var(--ink); }

/* ---------------------------------------------------------------- the live mark
 *
 * `hero-blink` was referenced by `.hero__hud-live` in css/hero.css and NEVER DEFINED, so the
 * hero's live dot has been a static red square for the whole of this build — an undefined
 * animation name is not an error, it simply does nothing, and `getAnimations()` on that element
 * returned an empty list. Defined here, where motion lives.
 *
 * Not a fade to nothing and not a hard on/off. A dot that vanishes reads as a fault; a dot that
 * snaps reads as a cursor. Holding bright, dropping to a floor and coming back is what a live
 * telemetry mark does, and the 2s ambient beat is the duration this brand already reserves for
 * things that are alive rather than things that are transitioning. */
@keyframes hero-blink {
  0%, 42%   { opacity: 1; }
  56%, 88%  { opacity: 0.22; }
  100%      { opacity: 1; }
}

/* The live marker, per Brand Guidelines v3's attention pulse: a 2000ms loop between 0.6 and 1.0.
   It replaces hero-blink on every "this is live" square. hero-blink is kept for the one thing
   that should blink, the typing caret on the access page (css/monitor.css). */
@keyframes live-pulse {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .beat__live,
  .comms__live,
  .comms__blip,
  .dossier__live { animation: none; }

  /* The log is translated by js/premise.js, which opts out entirely under reduced motion and
     never moves the track at all. What is left to do here is open the window to its content, so
     what would have been a clipped three-line strip becomes one full, still, readable log —
     and drop the mask, which only exists to soften the edges of a thing that is moving. */
  .monitor__log {
    height: auto;
    -webkit-mask-image: none;
            mask-image: none;
  }
  .comms__track { transform: none !important; }
}
