/* ============================================================================
   DIGITT HYPE — assets/css/motion.css
   Visual layer for the motion engine in assets/js/motion.js.
   Loaded AFTER style.css. Tokens come from style.css §01.

   Contract: motion.js applies the classes / custom properties below.
   Anything scroll- or pointer-driven degrades to a visible, static state.
   ----------------------------------------------------------------------------
   01  NO-JS / REDUCED FAILSAFE
   02  REVEAL            [data-reveal] → .is-inview, --reveal-delay
   03  SPLIT TEXT        .dh-split__{inner,l,w,u,m}, --split-stagger/--split-delay, --i
   04  TILT / DEPTH      .dh-tilt.is-tilting, --rx --ry --mx --my --tilt-a, .dh-depth
   05  MAGNETIC          .dh-magnetic, --mag-x --mag-y
   06  PARALLAX          .dh-parallax, --par-y
   07  MARQUEE           .dh-marquee__track, --dh-marquee-dur/-w
   08  STICKY STACK      .dh-stack__card, --stack-top --stack-i --stack-p
   09  SCENE (WebGL/2D)  .dh-scene, .dh-scene__canvas, .dh-scene--static
   10  CUSTOM CURSOR     .dh-cursor{__dot,__ring,__label}
   11  SCROLL PROGRESS   .dh-progress__bar, --dh-progress
   12  PAGE TRANSITION   .dh-wipe, html.is-leaving / .is-loaded
   13  CAROUSEL / TABS / ACCORDION
   14  TYPEWRITER
   ============================================================================ */


/* ============================================================================
   01  NO-JS / REDUCED FAILSAFE
   Nothing here may ever leave content invisible.
   ============================================================================ */

.dh-sr {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Until JS boots, everything is visible. `js` is set on <html> before paint. */
.no-js [data-reveal],
.no-js [data-split],
.no-js [data-parallax],
.no-js [data-sticky-stack] > * {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
}

html.dh-reduced [data-reveal],
html.dh-reduced [data-split] {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
}


/* ============================================================================
   02  REVEAL
   ============================================================================ */

.js [data-reveal] {
    opacity: 0;
    transform: translate3d(0, 26px, 0);
    transition:
        opacity   .85s var(--ease-out) var(--reveal-delay, 0s),
        transform .85s var(--ease-out) var(--reveal-delay, 0s),
        filter    .85s var(--ease-out) var(--reveal-delay, 0s);
    will-change: opacity, transform;
}
.js [data-reveal="left"]  { transform: translate3d(-42px, 0, 0); }
.js [data-reveal="right"] { transform: translate3d(42px, 0, 0); }
.js [data-reveal="scale"] { transform: scale(.92); }
.js [data-reveal="blur"]  { transform: translate3d(0, 20px, 0); filter: blur(12px); }
.js [data-reveal="none"]  { transform: none; }

.js [data-reveal].is-inview {
    opacity: 1;
    transform: none;
    filter: none;
    will-change: auto;
}

/* Group stagger — motion.js writes --reveal-delay onto each child. */
[data-reveal-group] > * { will-change: opacity, transform; }


/* ============================================================================
   03  SPLIT TEXT
   ============================================================================ */

.dh-split { display: block; }
.dh-split__inner { display: block; }
.dh-split__l { display: block; }
.dh-split__w { display: inline-block; white-space: nowrap; }

/* The mask clips its unit; the unit slides up out of it. */
.dh-split__m {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    padding-bottom: .1em;      /* room for descenders inside the clip */
    margin-bottom: -.1em;
}
.dh-split__u {
    display: inline-block;
    transform: translate3d(0, 110%, 0) rotate(4deg);
    opacity: 0;
    transition:
        transform .9s var(--ease-out) calc(var(--split-delay, 0s) + var(--i, 0) * var(--split-stagger, .03s)),
        opacity   .7s var(--ease-out) calc(var(--split-delay, 0s) + var(--i, 0) * var(--split-stagger, .03s));
    will-change: transform, opacity;
}
.dh-split.is-inview .dh-split__u {
    transform: translate3d(0, 0, 0) rotate(0deg);
    opacity: 1;
    will-change: auto;
}
/* Preserve the space between split words */
.dh-split__w + .dh-split__w { margin-left: .26em; }


/* ============================================================================
   04  TILT / DEPTH
   ============================================================================ */

.dh-tilt {
    position: relative;
    transform-style: preserve-3d;
    transition: transform .5s var(--ease-out);
}
.dh-tilt.is-tilting {
    transition: transform .08s linear;
    transform:
        perspective(var(--tilt-perspective, 1000px))
        rotateX(var(--rx, 0deg))
        rotateY(var(--ry, 0deg))
        scale3d(var(--tilt-scale, 1), var(--tilt-scale, 1), 1);
}
.dh-tilt .dh-depth,
.dh-tilt [data-depth] {
    transform: translateZ(calc(var(--depth, 1) * 24px));
    transform-style: preserve-3d;
    transition: transform .5s var(--ease-out);
}
.dh-tilt.is-tilting .dh-depth,
.dh-tilt.is-tilting [data-depth] { transition: transform .08s linear; }

/* Specular sheen — opacity ramps with --tilt-a (0 at rest, 1 at full tilt) */
.dh-sheen {
    position: absolute;
    inset: 0;
    z-index: 4;
    border-radius: inherit;
    pointer-events: none;
    opacity: calc(var(--tilt-a, 0) * .9);
    background: radial-gradient(
        36% 52% at var(--mx, 50%) var(--my, 50%),
        rgba(255,255,255,.20),
        rgba(181,148,251,.08) 42%,
        transparent 70%);
    mix-blend-mode: screen;
    transition: opacity .35s var(--ease-out);
}


/* ============================================================================
   05  MAGNETIC
   ============================================================================ */

.dh-magnetic {
    transform: translate3d(var(--mag-x, 0px), var(--mag-y, 0px), 0);
    transition: transform .45s var(--ease-spring);
    will-change: transform;
}
.dh-magnetic [data-magnetic-inner] {
    display: inline-flex;
    transform: translate3d(calc(var(--mag-x, 0px) * .35), calc(var(--mag-y, 0px) * .35), 0);
    transition: inherit;
}


/* ============================================================================
   06  PARALLAX
   ============================================================================ */

.dh-parallax {
    transform: translate3d(0, var(--par-y, 0px), 0);
    will-change: transform;
}


/* ============================================================================
   07  MARQUEE
   ============================================================================ */

.dh-marquee {
    display: flex;
    overflow: hidden;
    max-width: 100%;
    mask-image: linear-gradient(90deg, transparent, #000 22%, #000 78%, transparent);
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 22%, #000 78%, transparent);
}
.dh-marquee__track {
    display: flex;
    flex: none;
    align-items: center;
    gap: var(--space-8, 64px);
    padding-right: var(--space-8, 64px);
    animation: dh-marquee-run var(--dh-marquee-dur, 40s) linear infinite;
    will-change: transform;
}
.dh-marquee__track > * { flex: none; }
.dh-marquee--rev .dh-marquee__track { animation-direction: reverse; }
.dh-marquee--static .dh-marquee__track { animation: none; }
.dh-marquee:hover .dh-marquee__track,
.dh-marquee:focus-within .dh-marquee__track { animation-play-state: paused; }
/* Client-logo strip: scrolling must never stop, even while a visitor lingers
   to read a logo. Same specificity as the rule above; wins on source order. */
.trusted-logos:hover .dh-marquee__track,
.trusted-logos:focus-within .dh-marquee__track { animation-play-state: running; }

@keyframes dh-marquee-run {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(calc(var(--dh-marquee-w, 100%) * -1), 0, 0); }
}


/* ============================================================================
   08  STICKY STACK
   --stack-p ramps 0→1 as the card is pushed up by the next one.
   ============================================================================ */

.dh-stack { position: relative; }
.dh-stack__card {
    position: sticky;
    top: var(--stack-top, 96px);
    z-index: calc(var(--stack-i, 0) + 1);
    transform: scale(calc(1 - var(--stack-p, 0) * .06)) translate3d(0, calc(var(--stack-p, 0) * -8px), 0);
    transform-origin: 50% 0;
    transition: transform .12s linear;
    will-change: transform;
}
.dh-stack__card::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    background: var(--ink-950, #07050D);
    opacity: calc(var(--stack-p, 0) * .45);
    transition: opacity .12s linear;
}
.dh-stack__card + .dh-stack__card { margin-top: var(--space-5, 24px); }


/* ============================================================================
   09  SCENE — WebGL / 2D canvas background
   ============================================================================ */

.dh-scene { position: relative; isolation: isolate; }
.dh-scene__canvas {
    position: absolute;
    inset: 0;
    z-index: -1;
    width: 100%;
    height: 100%;
    display: block;
    pointer-events: none;
    opacity: 0;
    transition: opacity 1.2s var(--ease-out);
}
.dh-scene__canvas.is-loaded,
.is-loaded .dh-scene__canvas { opacity: 1; }

/* No WebGL / low power / reduced motion → a static brand gradient instead */
.dh-scene--static::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(58% 52% at 22% 18%, rgba(109,40,217,.34), transparent 68%),
        radial-gradient(46% 44% at 82% 30%, rgba(139,92,246,.20), transparent 70%),
        radial-gradient(40% 38% at 68% 92%, rgba(229,160,12,.10), transparent 72%);
}


/* ============================================================================
   10  CUSTOM CURSOR  (pointer:fine only — motion.js gates this)
   ============================================================================ */

.dh-cursor {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 2147483000;
    pointer-events: none;
    opacity: 0;
    transition: opacity .25s var(--ease-out);
}
.dh-cursor.is-visible { opacity: 1; }

.dh-cursor__dot,
.dh-cursor__ring {
    position: absolute;
    top: 0;
    left: 0;
    border-radius: var(--radius-pill, 999px);
    transform: translate3d(-50%, -50%, 0);
    will-change: transform;
}
.dh-cursor__dot {
    width: 6px;
    height: 6px;
    background: var(--gold-400, #F7BE22);
    transition: width .25s var(--ease-spring), height .25s var(--ease-spring), opacity .2s linear;
}
.dh-cursor__ring {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid rgba(181,148,251,.75);
    background: rgba(139,92,246,.06);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    transition:
        width .32s var(--ease-spring),
        height .32s var(--ease-spring),
        background-color .3s var(--ease-out),
        border-color .3s var(--ease-out);
}
.dh-cursor__label {
    font-family: var(--font, sans-serif);
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: #fff;
    opacity: 0;
    transform: scale(.7);
    white-space: nowrap;
    transition: opacity .22s var(--ease-out), transform .28s var(--ease-spring);
}

/* States set from [data-cursor] */
.dh-cursor[data-state="link"] .dh-cursor__ring { width: 52px; height: 52px; background: rgba(139,92,246,.16); }
.dh-cursor[data-state="link"] .dh-cursor__dot  { opacity: 0; }
.dh-cursor[data-state="view"] .dh-cursor__ring,
.dh-cursor[data-state="drag"] .dh-cursor__ring {
    width: 84px;
    height: 84px;
    background: rgba(139,92,246,.85);
    border-color: transparent;
}
.dh-cursor[data-state="view"] .dh-cursor__dot,
.dh-cursor[data-state="drag"] .dh-cursor__dot { opacity: 0; }
.dh-cursor.has-label .dh-cursor__label { opacity: 1; transform: scale(1); }
.dh-cursor.is-down .dh-cursor__ring { transform: translate3d(-50%, -50%, 0) scale(.82); }

/* Hide the native cursor only while ours is mounted and only on fine pointers */
@media (hover: hover) and (pointer: fine) {
    html.dh-cursor-on,
    html.dh-cursor-on a,
    html.dh-cursor-on button,
    html.dh-cursor-on [data-cursor] { cursor: none; }
    /* …but never on text entry, where the caret matters */
    html.dh-cursor-on input,
    html.dh-cursor-on textarea,
    html.dh-cursor-on select,
    html.dh-cursor-on [contenteditable] { cursor: auto; }
}


/* ============================================================================
   11  SCROLL PROGRESS
   ============================================================================ */

.dh-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    z-index: 1100;
    pointer-events: none;
    background: transparent;
}
.dh-progress__bar {
    height: 100%;
    transform-origin: 0 50%;
    transform: scaleX(var(--dh-progress, 0));
    background: linear-gradient(90deg, var(--violet-500, #8B5CF6), var(--gold-400, #F7BE22));
    box-shadow: 0 0 14px rgba(139,92,246,.6);
    will-change: transform;
}


/* ============================================================================
   12  PAGE TRANSITION
   ============================================================================ */

.dh-wipe {
    position: fixed;
    inset: 0;
    z-index: 2147482000;
    pointer-events: none;
    display: grid;
}
.dh-wipe__panel {
    grid-area: 1 / 1;
    background: linear-gradient(135deg, var(--violet-700, #6D28D9), var(--ink-950, #07050D) 65%);
    transform: scaleY(0);
    transform-origin: 50% 100%;
    transition: transform .42s var(--ease-inout);
}
html.is-leaving .dh-wipe__panel { transform: scaleY(1); transform-origin: 50% 100%; }

/* Enter animation — the shell fades up once the document is ready. */
.js main#main { opacity: 0; transform: translate3d(0, 8px, 0); }
.js.is-loaded main#main {
    opacity: 1;
    transform: none;
    transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
}
.no-js main#main, html.dh-reduced main#main { opacity: 1 !important; transform: none !important; }


/* ============================================================================
   13  CAROUSEL / TABS / ACCORDION
   ============================================================================ */

.dh-carousel { position: relative; overflow: hidden; }
.dh-carousel__track {
    display: flex;
    transition: transform .6s var(--ease-out);
    will-change: transform;
}
.dh-carousel__slide { flex: 0 0 100%; min-width: 0; }
.dh-carousel__dot {
    width: 8px;
    height: 8px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-pill, 999px);
    background: var(--ink-600, #2E2054);
    cursor: pointer;
    transition: width .3s var(--ease-out), background-color .3s var(--ease-out);
}
.dh-carousel__dot[aria-selected="true"],
.dh-carousel__dot.is-active { width: 26px; background: var(--violet-500, #8B5CF6); }

/* Accordion panels animate on grid-template-rows so height is automatic. */
.dh-acc__panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows .45s var(--ease-out);
}
.dh-acc__panel > * { overflow: hidden; }
.dh-acc__item.is-open > .dh-acc__panel,
.dh-acc__panel.is-open { grid-template-rows: 1fr; }

.dh-tabpanel[hidden] { display: none; }
.dh-tab[aria-selected="true"] { color: var(--text-1, #F6F3FF); }


/* ============================================================================
   14  TYPEWRITER
   ============================================================================ */

.dh-type { display: inline; }
.dh-type::after {
    content: '';
    display: inline-block;
    width: 3px;
    height: .82em;
    margin-left: 4px;
    vertical-align: baseline;
    background: var(--gold-400, #F7BE22);
    border-radius: 2px;
    animation: dh-caret-blink 1s steps(2, start) infinite;
}
@keyframes dh-caret-blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }


/* ============================================================================
   REDUCED MOTION — hard stop
   ============================================================================ */

@media (prefers-reduced-motion: reduce) {
    .js [data-reveal],
    .dh-split__u {
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
        transition: none !important;
    }
    .dh-tilt, .dh-tilt.is-tilting,
    .dh-magnetic, .dh-parallax,
    .dh-stack__card { transform: none !important; transition: none !important; }
    .dh-stack__card { position: static; }
    .dh-stack__card::after { display: none; }
    .dh-sheen { display: none; }
    .dh-marquee__track { animation: none !important; }
    .dh-cursor, .dh-wipe { display: none !important; }
    html.dh-cursor-on, html.dh-cursor-on * { cursor: auto !important; }
    .dh-scene__canvas { display: none; }
    .dh-type::after { animation: none; }
    .js main#main { opacity: 1 !important; transform: none !important; }
}
