/* ==========================================================================
   Shardhan Consultants firm site: motion.css (from the product site; FIRM: marquee pause)
   Owner: FOUNDATION. Page agents must NOT edit this file.

   Principles
   - Content is visible by default. Nothing here hides content unless JS has
     confirmed motion is enabled (html.motion-on) AND a helper has bound the
     element (it adds .is-armed). Page code animates FROM hidden states with
     gsap.from()/set() inside SD.mm, so a failed CDN or a reverted context
     always leaves the finished, readable DOM.
   - Motion off = prefers-reduced-motion OR html.motion-off (footer toggle,
     localStorage "sd-motion"="off"). Every CSS animation/transition is reduced
     to its end state.
   - Animate transform / opacity / clip-path only.
   ========================================================================== */

/* 1. Reveal hooks --------------------------------------------------------
   [data-reveal]            fade-rise (SD.reveal)
   [data-reveal="stagger"]  children rise in sequence (items: [data-reveal-item] or direct children)
   [data-split]             SplitText masked line reveal (SD.reveal)
   [data-draw]              scaleX line draw for .rule / any line element
   [data-count]             odometer counter (SD.counter)
   The hidden state is applied by GSAP inline styles, not by CSS, so these
   attributes are safe without JS. The only CSS pre-state is for .is-armed. */
html.motion-on [data-draw].is-armed { transform: scaleX(0); }
html.motion-on [data-draw].is-drawn { transform: scaleX(1); transition: transform 1100ms var(--ease-out); }

/* SplitText masks: keep descenders visible */
.split-mask { padding-bottom: .08em; margin-bottom: -.08em; }

/* 2. Utility transitions used by page code (toggle a class, CSS animates) */
.fx-fade { transition: opacity var(--dur-4) var(--ease-out); }
.fx-rise { transition: transform var(--dur-5) var(--ease-out), opacity var(--dur-4) var(--ease-out); }
.fx-wipe { clip-path: inset(0 0 0 0); transition: clip-path var(--dur-5) var(--ease-in-out); }
.fx-wipe.is-pre { clip-path: inset(0 100% 0 0); }

/* Ink-dot pulse (single pulse, never flashing) */
@keyframes sd-inkdot { 0% { box-shadow: 0 0 0 0 rgba(224,120,42,.55); } 100% { box-shadow: 0 0 0 10px rgba(224,120,42,0); } }
.ink-pulse { animation: sd-inkdot 1.6s var(--ease-out) 1; }

/* Stamp land (maker/checker): add .is-stamped */
@keyframes sd-stamp { 0% { transform: scale(1.6) rotate(-14deg); opacity: 0; } 60% { opacity: 1; } 100% { transform: scale(1) rotate(-6deg); opacity: 1; } }
.stamp.is-stamped { animation: sd-stamp 420ms var(--ease-stamp) both; }

/* Marquee (CSS base loop; core.js swaps to a GSAP velocity-reactive loop and adds .is-js) */
@keyframes sd-marquee { to { transform: translate3d(calc(-50% - var(--marquee-gap) / 2), 0, 0); } }
html.motion-on .marquee:not(.is-js) .marquee__track { animation: sd-marquee var(--marquee-dur) linear infinite; }
html.motion-on .marquee:not(.is-js)[data-marquee-reverse] .marquee__track { animation-direction: reverse; }
html.motion-on .marquee.is-paused .marquee__track,
html.motion-on .marquee:not(.is-js):hover .marquee__track, html.motion-on .marquee:not(.is-js):focus-within .marquee__track { animation-play-state: paused; }

/* Live-status blip for mocks ("syncing", "live") */
@keyframes sd-blip { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
.blip { width: 7px; height: 7px; border-radius: 50%; background: var(--mint); display: inline-block; }
html.motion-on .blip { animation: sd-blip 2.4s ease-in-out infinite; }

/* 3. Motion OFF: finished states ----------------------------------------- */
html.motion-off *, html.motion-off *::before, html.motion-off *::after {
  animation-duration: .001ms !important;
  animation-iteration-count: 1 !important;
  animation-delay: 0s !important;
  transition-duration: .001ms !important;
  transition-delay: 0s !important;
  scroll-behavior: auto !important;
}
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-force) *, html:not(.motion-force) *::before, html:not(.motion-force) *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
/* Marquee when paused: a calm, wrapped list; the duplicate group is removed */
html.motion-off .marquee, html.no-js .marquee { mask-image: none; -webkit-mask-image: none; }
html.motion-off .marquee__track, html.no-js .marquee__track { width: auto; flex-wrap: wrap; transform: none !important; }
html.motion-off .marquee__track, html.no-js .marquee__track { max-width: calc(var(--container-wide) + var(--gutter) * 2); margin-inline: auto; padding-inline: var(--gutter); }
html.motion-off .marquee__group, html.no-js .marquee__group { flex: 1 1 auto; flex-wrap: wrap; row-gap: .75rem; }
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-force) .marquee { mask-image: none; -webkit-mask-image: none; }
  html:not(.motion-force) .marquee__track { width: auto; flex-wrap: wrap; transform: none !important; max-width: calc(var(--container-wide) + var(--gutter) * 2); margin-inline: auto; padding-inline: var(--gutter); }
  html:not(.motion-force) .marquee__group { flex: 1 1 auto; flex-wrap: wrap; row-gap: .75rem; }
  html:not(.motion-force) .marquee__group[aria-hidden="true"] { display: none; }
}
html.motion-off .marquee__group[aria-hidden="true"] { display: none; }
html.motion-off .ledger-field canvas { display: none; }
html.motion-off .ledger-field__fallback { opacity: 1 !important; }
html.motion-off [data-draw] { transform: none !important; }
html.motion-off .blip { animation: none; }

/* 4. Cross-document View Transitions (Chromium 126+, Safari 18.2+) -------
   Persistent header: .site-header has view-transition-name: site-header.
   Page swap: a "ledger-line wipe" — the new page is revealed as ruled rows
   that thicken from hairlines while a solid edge sweeps down. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
@property --vt-sweep { syntax: "<percentage>"; inherits: false; initial-value: 0%; }
@property --vt-row { syntax: "<length>"; inherits: false; initial-value: 0px; }

@keyframes sd-vt-old { to { opacity: 0; transform: translateY(-14px); } }
@keyframes sd-vt-new {
  0%   { --vt-sweep: -12%; --vt-row: 0px; }
  70%  { --vt-row: 26px; }
  100% { --vt-sweep: 112%; --vt-row: 26px; }
}
::view-transition-old(root) { animation: sd-vt-old 360ms var(--ease-in) both; }
::view-transition-new(root) {
  animation: sd-vt-new 620ms var(--ease-in-out) both;
  -webkit-mask-image:
    linear-gradient(180deg, #000 calc(var(--vt-sweep) - 10%), transparent var(--vt-sweep)),
    repeating-linear-gradient(180deg, #000 0 var(--vt-row), transparent var(--vt-row) 26px);
  mask-image:
    linear-gradient(180deg, #000 calc(var(--vt-sweep) - 10%), transparent var(--vt-sweep)),
    repeating-linear-gradient(180deg, #000 0 var(--vt-row), transparent var(--vt-row) 26px);
}
::view-transition-group(site-header) { animation-duration: 420ms; animation-timing-function: var(--ease-out); z-index: 10; }
::view-transition-old(site-header), ::view-transition-new(site-header) { animation: none; mix-blend-mode: normal; }
/* Shared-element hooks page agents may use: give an element on both pages the
   same view-transition-name (e.g. .vt-hero-media { view-transition-name: hero-media; }). */
::view-transition-group(*) { animation-timing-function: var(--ease-out); }
html.motion-off::view-transition-group(*), html.motion-off::view-transition-old(*), html.motion-off::view-transition-new(*) { animation: none !important; }

/* Safety net (integration QA): keyboard focus always lands on something visible. If a scrubbed or
   not-yet-played animation has left a focused control (or any of its ancestors) transparent, show it. */
main :has(:focus-visible), main :focus-visible { opacity: 1 !important; visibility: visible !important; }
