/* ============================================================================
   Chronos motion layer (v0.4.62.22). Additive, loaded LAST so its tokens and
   polish win the cascade. A single easing + duration set, a scroll-reveal
   system, and a shared press language - all reduced-motion aware. This is
   movement and depth, NOT a reskin: the light/violet identity is untouched, and
   the FOMO flourishes (upgrade pulse, urgent shake, streak flame) are left
   exactly as they are - none of the selectors below target them.
   ============================================================================ */

:root {
    /* Motion tokens - every animation in the layer pulls from these four eases
       and four durations, so the whole app moves with one voice. */
    --e-quart:  cubic-bezier(.25, 1, .5, 1);      /* smooth deceleration */
    --e-expo:   cubic-bezier(.16, 1, .3, 1);      /* the premium, drawn-out ease */
    --e-spring: cubic-bezier(.34, 1.56, .64, 1);  /* gentle overshoot for pops */
    --e-inout:  cubic-bezier(.76, 0, .24, 1);
    --d1: 120ms; --d2: 200ms; --d3: 320ms; --d4: 520ms;

    /* Hover depth kept in the violet family so raising a card reads as "us". */
    --shadow-raise: 0 14px 30px -14px rgba(124, 58, 237, 0.28), 0 4px 10px -6px rgba(17, 24, 39, 0.08);
}

/* ---- scroll reveal -------------------------------------------------------
   html.cm-motion is set by an inline flag in ChronosHead BEFORE first paint,
   so reveal targets start hidden with no flash. Without JS (or if the flag is
   blocked) nothing is hidden and the page renders normally. A failsafe in that
   same inline script reveals everything if chronos-motion.js never runs, so a
   script error can never leave content stuck invisible. */
html.cm-motion [data-reveal] {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity var(--d4) var(--e-expo), transform var(--d4) var(--e-expo);
    transition-delay: calc(var(--cm-i, 0) * 55ms);
    will-change: opacity, transform;
}
html.cm-motion [data-reveal].cm-in {
    opacity: 1;
    transform: none;
}

/* ---- shared press feedback ----------------------------------------------
   Primary action surfaces get a tactile scale-down on press and smooth state
   transitions. Deliberately NOT applied to .upgrade-btn (its pulse owns the
   transform) or urgent/streak animations. */
button.primary,
.primary-fab,
.chip,
.calday,
.lang-picker-item {
    transition: background var(--d2) var(--e-quart),
                color var(--d2) var(--e-quart),
                box-shadow var(--d2) var(--e-quart),
                transform var(--d2) var(--e-spring);
}
button.primary:active:not(:disabled),
.primary-fab:active:not(:disabled) {
    transform: scale(0.97);
}

/* ---- liquid horizon nav --------------------------------------------------
   chronos.com-inspired: the active-tab underline becomes a violet liquid bar
   that springs and stretches between tabs. JS (chronos-motion.js) positions
   .horizon-liquid on the active tab and adds .cm-liquid, which hides the static
   ::after fallback. No JS keeps the original crisp underline; reduced motion
   keeps the bar but drops the travel animation. Identity stays violet + thin. */
.horizon-tabs { position: relative; }
.horizon-liquid {
    position: absolute;
    bottom: -1px; left: 0; width: 0; height: 3px;
    border-radius: 3px;
    background: var(--chronos-violet);
    box-shadow: 0 0 10px rgba(124, 58, 237, 0.55), 0 1px 3px rgba(124, 58, 237, 0.4);
    opacity: 0;
    transition: left var(--d4) var(--e-spring), width var(--d4) var(--e-spring), opacity var(--d2) var(--e-quart);
    pointer-events: none;
    will-change: left, width;
}
.horizon-tabs.cm-liquid .horizon-liquid { opacity: 1; }
.horizon-tabs.cm-liquid .horizon-tab.active::after { opacity: 0; }

/* ---- modal + toast spring enter -----------------------------------------
   These fire when Blazor mounts the element (an @if render == "open"), so a
   modal springs up out of its backdrop and a status toast slides in from the
   bottom edge. Exit stays instant (Blazor removes the node) - deliberately
   simple and safe. Applies to every existing modal via the shared classes. */
.modal-backdrop { animation: cm-fade-in var(--d3) var(--e-quart); }
.modal-card { animation: cm-modal-in var(--d3) var(--e-spring); }
.status-toast { animation: cm-toast-in var(--d3) var(--e-spring); }
@keyframes cm-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes cm-modal-in { from { opacity: 0; transform: translateY(18px) scale(0.96); } to { opacity: 1; transform: none; } }
@keyframes cm-toast-in { from { opacity: 0; transform: translate(-50%, 140%); } to { opacity: 1; transform: translateX(-50%); } }

@media (prefers-reduced-motion: reduce) {
    html.cm-motion [data-reveal] {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }
    .horizon-liquid { transition: opacity var(--d2) linear !important; }
    .modal-backdrop, .modal-card, .status-toast { animation: none !important; }
}
