/* AIR-CURTAINS-UI-MOTION-LAYER-01 -- shared motion tokens + reusable
 * primitives for the air-curtains GUI.
 *
 * Kept in its own file rather than folded into air_curtains.css: a second
 * UI task (AIR-CURTAINS-NAV-COLLAPSE-01) is mid-review against that file
 * at the same time this was written, and every template links its own set
 * of stylesheets explicitly (no shared layout template exists to hook a
 * single include into) -- see tasks/AIR-CURTAINS-UI-MOTION-LAYER-01/SPEC.md
 * "Known conflict risk". Link this file from a template's <head> the same
 * way the others already are.
 *
 * Values match tasks/AIR-CURTAINS-UI-MOTION-LAYER-01/SPEC.md "Constraints":
 * short durations, max 4-10px displacement, no transition: all, no
 * overshoot/spring easing.
 */

:root {
    --motion-fast: 140ms;
    --motion-normal: 220ms;
    --motion-slow: 320ms;

    --motion-distance-xs: 4px;
    --motion-distance-sm: 8px;

    --ease-motion-out: cubic-bezier(.2, .8, .2, 1);
    --ease-motion-soft: cubic-bezier(.4, 0, .2, 1);
}

/* Reusable primitive for anything that toggles via a persistent DOM node
 * plus a state attribute, instead of display:none -- the pattern the
 * read-only audit (AUDIT.md) found missing app-wide (tooltips, modals,
 * document-history reveals, accordion panels all currently cut instantly
 * via .style.display / the `hidden` attribute).
 *
 * Usage: put `motion-panel` on the element that appears/disappears, and
 * toggle `data-motion-open="true"/"false"` on it from JS instead of setting
 * .style.display or the `hidden` attribute. The element must stay in the
 * DOM (no display:none, no `hidden`) for the transition to run; that's the
 * whole point.
 */
.motion-panel {
    opacity: 0;
    visibility: hidden;
    transform: translateY(var(--motion-distance-xs)) scale(.98);
    transition:
        opacity var(--motion-normal) var(--ease-motion-out),
        transform var(--motion-normal) var(--ease-motion-out),
        visibility 0s linear var(--motion-normal);
    pointer-events: none;
}

.motion-panel[data-motion-open="true"] {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
    transition-delay: 0s, 0s, 0s;
    pointer-events: auto;
}

/* Same idea, no scale -- for wider panels (accordion bodies, document
 * history) where a scale pop reads as a table row "jumping". Slides in
 * from --motion-distance-sm instead of the tooltip's tighter xs. */
.motion-panel-flat {
    opacity: 0;
    visibility: hidden;
    transform: translateY(var(--motion-distance-sm));
    transition:
        opacity var(--motion-normal) var(--ease-motion-out),
        transform var(--motion-normal) var(--ease-motion-out),
        visibility 0s linear var(--motion-normal);
}

.motion-panel-flat[data-motion-open="true"] {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition-delay: 0s, 0s, 0s;
}

/* Bounded set of transition utilities -- deliberately not `transition: all`
 * (SPEC.md Constraints). Compose the one that matches what's actually
 * changing; do not reach for -fast/-slow ad hoc without a reason noted at
 * the call site. */
.motion-transition-opacity {
    transition: opacity var(--motion-normal) var(--ease-motion-out);
}

.motion-transition-transform {
    transition: transform var(--motion-normal) var(--ease-motion-out);
}

.motion-transition-color {
    transition:
        background-color var(--motion-fast) var(--ease-motion-soft),
        border-color var(--motion-fast) var(--ease-motion-soft);
}

.motion-transition-shadow {
    transition: box-shadow var(--motion-fast) var(--ease-motion-soft);
}

/* Small, bounded state changes -- field errors, button press, inline
 * confirmation. translateY only ever moves --motion-distance-xs (4px). */
.motion-shift-in {
    opacity: 0;
    transform: translateY(var(--motion-distance-xs));
    transition:
        opacity var(--motion-normal) var(--ease-motion-out),
        transform var(--motion-normal) var(--ease-motion-out);
}

.motion-shift-in[data-motion-open="true"] {
    opacity: 1;
    transform: translateY(0);
}

/* SPEC.md Шаг 3 -- single shared tooltip bubble, positioned and toggled by
 * static/air_curtains_motion.js (acTooltipInit). The audit (AUDIT.md
 * section 13 / cross-cutting) found no existing toggle-tooltip component to
 * convert -- only native `title="..."` attributes (no motion possible) and
 * always-visible `.field-hint` static text (not a toggle at all) -- so this
 * is new, not a rewrite of something else. `.motion-panel` supplies the
 * open/close transition; this adds only the visual chrome. */
.ac-tooltip {
    position: fixed;
    z-index: 1000;
    max-width: 280px;
    padding: 6px 10px;
    border-radius: var(--radius, 6px);
    background: var(--ink, #1d2430);
    color: var(--bg, #f6f7f9);
    font-size: 12px;
    line-height: 1.4;
    box-shadow: var(--shadow, 0 12px 40px rgba(0, 0, 0, .25));
}

/* Text only, nothing to click -- stay non-interactive even while open
 * (`.motion-panel[data-motion-open="true"]` otherwise turns pointer-events
 * back on for panels that DO need clicks, e.g. a future dropdown). */
.ac-tooltip[data-motion-open="true"] {
    pointer-events: none;
}

/* SPEC.md Шаг 11 -- reduced motion, scoped to this file's own primitives
 * ONLY (not a blanket `*, *::before, *::after` rule). That blanket form was
 * tried first and reverted: static/pages/air_curtains_project.css already
 * has its own deliberate reduced-motion handling for the "расчёт
 * выполняется" spinner --
 *
 *   @media (prefers-reduced-motion: no-preference) { .spinner div { animation: bounce ... } }
 *   @media (prefers-reduced-motion: reduce)        { .spinner div { animation: pulse  ... } }
 *
 * (see the comment right above those rules, ~air_curtains_project.css:608)
 * -- pulse is itself a deliberately-chosen reduced-motion replacement for
 * bounce, not something that also needs collapsing to 1ms. A global `*`
 * override with `!important` would have clobbered that existing, correct
 * design the moment this file was linked into a page, before any of
 * Шаг 3-12 touched anything. Scoping to our own classes avoids that;
 * anything pre-existing keeps whatever reduced-motion behavior it already
 * has (or doesn't) until a later step deliberately changes it.
 *
 * Also NOT handled here: `element.scrollIntoView({behavior: 'smooth'})`
 * (used in templates/air_curtains_project.html:1764,1781,
 * air_curtains_request_workspace.html:481,1339,
 * air_curtains_requirement_blocks.html:249). Per the scrollIntoView spec, an
 * explicit `behavior` option overrides the CSS `scroll-behavior` property,
 * so a CSS-only rule here cannot satisfy SPEC.md Шаг 11's "никакого
 * автоматического плавного скролла" for those calls -- each needs a
 * `matchMedia('(prefers-reduced-motion: reduce)')` check in JS. Left as a
 * Шаг 11 implementation task, not claimed as done by this file. */
@media (prefers-reduced-motion: reduce) {
    .motion-panel,
    .motion-panel-flat,
    .ac-tooltip,
    .motion-transition-opacity,
    .motion-transition-transform,
    .motion-transition-color,
    .motion-transition-shadow,
    .motion-shift-in {
        transition-duration: 1ms !important;
        transition-delay: 0s !important;
    }
}
