/* ============================================================
   EMPIRE OS — Motion foundation (motion.css)
   ------------------------------------------------------------
   A tasteful, GPU-cheap motion layer that sits ON TOP of the
   base design system. Pure CSS: transitions, keyframes, and
   linear() spring easings — NO runtime animation library.

   Loaded LAST (after layout.css) so it cascades over existing
   component styles without editing them. Everything here is:
     • additive (namespaced `--mo-*` tokens, `.mo-*` utilities)
     • transform/opacity/color/background/border only — never
       animating width/height/top/left/margin (no layout thrash)
     • fully neutralized under prefers-reduced-motion (bottom).

   How to apply on a surface (for later per-view polish passes):
     - Reveal a list/grid:  add `.mo-stagger` to the container and
       `style="--i:N"` (0-based) to each child, OR just use the
       nth-child fallback (works up to 16 items with no --i).
     - Reveal one element:  `.mo-enter` (slide-up+fade),
       `.mo-fade` (opacity only), or `.mo-pop` (scale-in).
     - Interactive affordance: add `.mo-tap` for a satisfying
       press, `.mo-lift` for a hover raise (both opt-in; core
       buttons/cards already get polish globally below).
   ============================================================ */

:root {
  /* ---- Duration scale (short by design) ---------------------------- */
  --mo-dur-1: 120ms;  /* micro:   hover tint, icon color, tap feedback   */
  --mo-dur-2: 200ms;  /* base:    most interactions, focus ring          */
  --mo-dur-3: 320ms;  /* entrance:card/list reveals, drawer/panel        */
  --mo-dur-4: 480ms;  /* overlay: modal/backdrop, large emphasis moments */
  --mo-stagger-step: 42ms; /* per-item offset for .mo-stagger cascades   */

  /* ---- Named easings ----------------------------------------------- */
  /* Standard: quick, symmetric-ish ease for micro-interactions.        */
  --mo-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  /* Emphasized / decelerate: enters fast, settles slow — for content
     arriving on screen (the house --ease-smooth, kept in sync).        */
  --mo-ease-emphasized: cubic-bezier(0.22, 1, 0.36, 1);

  /* ---- linear() SPRING curves (generated, damped oscillator) -------- */
  /* SMOOTH spring — critically damped (ζ≈1.0, ω≈7), NO overshoot.
     Use for overlay/content entrances that should feel alive but calm. */
  --mo-spring-smooth: linear(
    0, 0.0487, 0.1558, 0.2826, 0.4082, 0.5221, 0.6204, 0.7023,
    0.7689, 0.8222, 0.8641, 0.8968, 0.922, 0.9414, 0.9561, 0.9672,
    0.9756, 0.9819, 0.9866, 0.9901, 1
  );
  /* SUBTLY BOUNCY spring — underdamped (ζ≈0.72, ω≈8), ~3.8% overshoot.
     Tasteful settle, not cartoonish. Use for pops / affirmative moments.*/
  --mo-spring-bouncy: linear(
    0, 0.0472, 0.1597, 0.3028, 0.4523, 0.5927, 0.7152, 0.8159,
    0.8943, 0.9521, 0.992, 1.0174, 1.0316, 1.0376, 1.0381, 1.035,
    1.0301, 1.0244, 1.0187, 1.0136, 1.0092, 1.0057, 1.003, 1.0011, 1
  );
}

/* ============================================================
   1. REUSABLE ENTER ANIMATIONS  (keyframes + utility classes)
   Content-only opacity + transform. Safe to drop on any element.
   ============================================================ */
@keyframes mo-fade-in    { from { opacity: 0; } to { opacity: 1; } }
@keyframes mo-slide-up   { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes mo-scale-in   { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: none; } }

.mo-fade  { animation: mo-fade-in  var(--mo-dur-3) var(--mo-ease-emphasized) both; }
.mo-enter { animation: mo-slide-up var(--mo-dur-3) var(--mo-spring-smooth)   both; }
.mo-pop   { animation: mo-scale-in var(--mo-dur-3) var(--mo-spring-bouncy)   both; }

/* Index-based stagger helper. Preferred: set `style="--i:N"` (0-based)
   on each child so the cascade scales to any list length. Falls back to
   nth-child offsets (1..16) when --i is not provided. */
.mo-stagger > * {
  animation: mo-slide-up var(--mo-dur-3) var(--mo-ease-emphasized) both;
  animation-delay: calc(var(--i, 0) * var(--mo-stagger-step));
}
.mo-stagger[data-i-auto] > *:nth-child(1)  { --i: 0; }
.mo-stagger[data-i-auto] > *:nth-child(2)  { --i: 1; }
.mo-stagger[data-i-auto] > *:nth-child(3)  { --i: 2; }
.mo-stagger[data-i-auto] > *:nth-child(4)  { --i: 3; }
.mo-stagger[data-i-auto] > *:nth-child(5)  { --i: 4; }
.mo-stagger[data-i-auto] > *:nth-child(6)  { --i: 5; }
.mo-stagger[data-i-auto] > *:nth-child(7)  { --i: 6; }
.mo-stagger[data-i-auto] > *:nth-child(8)  { --i: 7; }
.mo-stagger[data-i-auto] > *:nth-child(9)  { --i: 8; }
.mo-stagger[data-i-auto] > *:nth-child(10) { --i: 9; }
.mo-stagger[data-i-auto] > *:nth-child(11) { --i: 10; }
.mo-stagger[data-i-auto] > *:nth-child(12) { --i: 11; }
.mo-stagger[data-i-auto] > *:nth-child(13) { --i: 12; }
.mo-stagger[data-i-auto] > *:nth-child(14) { --i: 13; }
.mo-stagger[data-i-auto] > *:nth-child(15) { --i: 14; }
.mo-stagger[data-i-auto] > *:nth-child(16) { --i: 15; }

/* ============================================================
   2. OPT-IN INTERACTION UTILITIES
   ============================================================ */
/* Satisfying press — firm, never a collapse. */
.mo-tap { transition: transform var(--mo-dur-1) var(--mo-ease-standard); }
.mo-tap:active { transform: scale(0.97); }

/* Hover raise — transform only (no layout, no heavy shadow animation). */
.mo-lift { transition: transform var(--mo-dur-2) var(--mo-spring-smooth); will-change: transform; }
.mo-lift:hover { transform: translateY(-2px); }
.mo-lift:active { transform: translateY(0) scale(0.995); }

/* ============================================================
   3. GLOBAL INTERACTION POLISH on EXISTING selectors
   Layered on top so components.css / layout.css stay untouched.
   Only fills gaps (missing easing, missing press) and refines
   overlay entrances with the smooth spring. Restrained — Linear/
   Vercel, not bouncy toys.
   ============================================================ */

/* Rail nav items: give the color/bg change the house easing (base uses
   the browser default `ease`) and add a barely-there press. */
.rail-item {
  transition:
    color var(--mo-dur-1) var(--mo-ease-standard),
    background-color var(--mo-dur-1) var(--mo-ease-standard);
}
.rail-item:active { transform: scale(0.985); }

/* Buttons already transition + press; keep their timing but ensure the
   press reads as a spring-y settle on release for the primary CTA. */
.btn:active,
.btn-icon:active { transform: scale(0.97); }

/* Chips / tags used as interactive filters: smooth their color/bg swaps
   and add a press when they are actually clickable. */
.tag {
  transition:
    color var(--mo-dur-1) var(--mo-ease-standard),
    background-color var(--mo-dur-1) var(--mo-ease-standard),
    border-color var(--mo-dur-1) var(--mo-ease-standard);
}
.tag[role="button"]:active,
button.tag:active,
a.tag:active { transform: scale(0.96); }

/* Inputs / selects / textareas: smooth focus-ring + border transitions
   (base declares the transition; this just aligns the easing globally). */
.input, .textarea, .select {
  transition:
    border-color var(--mo-dur-2) var(--mo-ease-standard),
    background-color var(--mo-dur-2) var(--mo-ease-standard),
    box-shadow var(--mo-dur-2) var(--mo-ease-standard);
}

/* Overlays — upgrade the entrance easing to the SMOOTH spring so modals
   and the shared right drawer arrive with life but no jank. Base already
   defines the transform/opacity transition + .in state; we only retime. */
.modal {
  transition:
    transform var(--mo-dur-4) var(--mo-spring-smooth),
    opacity var(--mo-dur-3) var(--mo-ease-emphasized);
}
.drawer {
  transition:
    transform var(--mo-dur-4) var(--mo-spring-smooth),
    opacity var(--mo-dur-3) var(--mo-ease-emphasized);
}

/* ============================================================
   4. ROUTE / VIEW TRANSITION
   The router already toggles `#view.view-enter` on real navigation
   (after `body.nav-ready`). Retime that single container entrance
   with the smooth spring + a gentle rise for a premium view swap.
   No router edit required — this only restyles the existing hook.
   A standalone `.mo-view-enter` class is also exposed for any other
   container that wants the same treatment.
   ============================================================ */
@keyframes mo-view-enter { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* NOTE: intentionally does NOT target `#view.view-enter`. The route/view swap is
   owned by layout.css (`eos-view-enter`, a crisp 120ms fade) — a longer springy
   translate here made every tab switch read like a full reload. This class is
   left as an opt-in utility for any OTHER container that wants the spring. */
.mo-view-enter {
  animation: mo-view-enter var(--mo-dur-3) var(--mo-spring-smooth) both;
}

/* ============================================================
   4b. THE MOTION SPEC (P5-05)
   ------------------------------------------------------------
   Five purposes. Every animated thing in either product is one of
   them, and each one has exactly one duration and one easing. If a
   new interaction doesn't fit a row, it isn't a new row — it's the
   wrong interaction.

     PURPOSE          DURATION            EASING                  APPLIES TO
     ─────────────────────────────────────────────────────────────────────────
     Micro-feedback   --mo-dur-1  120ms   --mo-ease-standard      hover, press,
                                                                  checkbox, toggle
     Transition       --mo-dur-2  200ms   --mo-ease-standard      modal in/out,
                                                                  tab switch, popover
     Entrance         --mo-dur-3  320ms   --mo-ease-emphasized    drawer, sheet, page
     Celebration      --mo-dur-3  320ms   --mo-spring-bouncy      deal won, agreement
                                                                  signed, habit done
     Ambient          --mo-dur-4  480ms   --mo-ease-standard      brand recolour,
                                                                  build cascade

   THE HARD RULES
   1. Spring easing is for SUCCESS ONLY. Never for navigation, never for
      chrome. A bouncy menu feels cheap; a bouncy "deal won" feels earned.
      That is what `.celebrate` is for, and it is the only bouncy thing.
   2. Nothing animates longer than --mo-dur-4 (480ms) except the one-time
      build cascade. A status loop (spinner, skeleton, typing dots) is not
      an animation in this sense — it reports, it doesn't decorate.
   3. Everything animates FROM WHERE IT CAME FROM. A drawer slides from the
      right edge. A popover scales from its trigger's corner, which is why
      `.popover` sets `transform-origin` off its measured placement rather
      than from the middle of the screen.
   4. prefers-reduced-motion is honoured globally (section 5 below).
   5. Never animate on first paint. Content appears; it does not perform.
      `.rise` / `#view.view-enter` fire on ROUTE CHANGE only — the router
      gates them behind `body.nav-ready` for exactly this reason.
   ============================================================ */

/* CELEBRATION — the one bouncy thing, and the only correct use of the
   underdamped spring. Add `.celebrate` for one beat when something the
   person worked for actually lands. */
.celebrate { animation: mo-celebrate var(--mo-dur-3) var(--mo-spring-bouncy) both; }
@keyframes mo-celebrate { 0% { transform: scale(0.9); } 60% { transform: scale(1.04); } 100% { transform: none; } }

/* RULE 1, applied. Two pieces of chrome were using the bouncy spring:
   the switch knob (micro-feedback) and the bulk-action bar (an entrance).
   Both are retimed onto the rows they belong to, so "springy" once again
   means "something good happened" rather than "something moved". */
.toggle::after,
.toggle[data-tip]::after {
  transition: left var(--mo-dur-1) var(--mo-ease-standard),
              background-color var(--mo-dur-1) var(--mo-ease-standard);
}
.selbar { animation: selbar-in var(--mo-dur-3) var(--mo-ease-emphasized); }

/* RULE 3, applied. A popover grows out of the edge nearest its trigger —
   placeFloating() stamps data-placement, so the origin can follow it. */
.popover { transform-origin: top left; transition: opacity var(--mo-dur-2) var(--mo-ease-standard), transform var(--mo-dur-2) var(--mo-ease-standard); }
.popover[data-placement="top"] { transform-origin: bottom left; }

/* ============================================================
   4c. DATA DISPLAY RULES (P5-10)
   ------------------------------------------------------------
   1 · NUMBERS TABULAR-ALIGN. A figure that changes must not shift the
       glyphs around it. Every place a number is shown on its own — a
       metric, a count, a badge, a duration, a currency — is lining and
       tabular by default. Prose keeps proportional figures.
   2 · DATES ARE MACHINE-READABLE. A rendered date is a <time datetime>
       so it can be copied, parsed and read out. `fmt.timeTag()` in ui.js
       is the one way to emit one.
   3 · TEXT NEVER TRUNCATES MID-WORD. `.ellip` cuts at the box with a real
       ellipsis and keeps the full value in `title`. Nothing slices a
       string to a character count.
   4 · A SPINNER IS NEVER CENTRED IN AN EMPTY BOX. If the shape of what is
       loading is known, show that shape (`.skeleton`). A centred spinner
       says "wait" and nothing else.
   ============================================================ */
:where(
  .kpi-value, .kpi-delta, .badge, .badge-soft, .tag, .chip, .u-chip,
  .drawer-tab-badge, .tab__count, .ring span, .notif-dot, .ip-count,
  .selbar-count, .table .num, kbd, time, [data-num], .num, .mono
) { font-variant-numeric: tabular-nums lining-nums; }

/* Rule 4. A `.skeleton` block is the loading state; `.loading-center` is
   the shape it replaces and is deliberately given no styling of its own,
   so anything still using it stands out in review rather than shipping. */
.skeleton-row { height: 1em; border-radius: var(--r-xs); }
.skeleton-row + .skeleton-row { margin-top: var(--sp-2); }

/* ============================================================
   5. ACCESSIBILITY — prefers-reduced-motion (NON-NEGOTIABLE)
   Neutralize everything above: kill animations, remove transforms,
   collapse transition/animation timings to a hair. Opacity-only
   cross-fades are still allowed (they don't cause vestibular issues)
   but durations are minimized so the UI feels instant.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  /* Global clamp (mirrors base.css / layout.css — kept here so motion.css
     is self-contained and safe even if loaded standalone). */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Strip motion from the utilities/enter animations entirely so nothing
     translates or scales — just render in place. */
  .mo-fade, .mo-enter, .mo-pop,
  .mo-stagger > *,
  body.nav-ready #view.view-enter,
  .mo-view-enter { animation: none !important; }

  .celebrate { animation: none !important; }
  .mo-lift { will-change: auto; }
  .mo-lift:hover,
  .mo-tap:active,
  .mo-lift:active,
  .rail-item:active,
  .btn:active, .btn-icon:active,
  .tag[role="button"]:active, button.tag:active, a.tag:active { transform: none !important; }
}
