/* ==========================================================================
   console-motion.css — how the console moves: presses, the sliding highlight
   under tabs and the menu, cards, the save button, copy feedback, dialogs and
   the page's first draw. Every duration and curve is a token from motion.css;
   every colour is the console's own (echo-tokens.css, sadaa.css).

   Loaded right after motion.css, before sadaa.css. A rule here never relies on
   coming later: where an older rule set the same property on the same element,
   that rule was moved onto the tokens where it stands, and the overrides below
   are written one class more specific than the rule they cover.

   Transform and opacity only (and colour fades), never width, height, top,
   left or margin, so nothing is laid out again while it moves. With reduced
   motion every duration is 0.01ms (motion.css) and the press scale is 1.
   ========================================================================== */

/* ---- presses ---------------------------------------------------------------
   A control presses in a little while held and springs back when let go. The
   press uses the quick "appear" curve; the release, the spring. A disabled
   control does not move. Keyboard Enter and Space press it the same way
   (`:active` covers both). Controls whose own sheet sets their transition carry
   the same pair there; these had none. */
:is(.sd-as-fchip, .sd-as-copy__b, .sd-as-seg__b, .sd-hc-seg__b, .sd-cd-seg__b, .sd-bkp-seg__b, .sd-hc-fchip,
    .sd-hc-seeall, .sd-hc-more, .sd-hc-clear, .sd-l3set__tab, .sd-as-tabs a, .sd-iconbtn, .sd-bkp-iconbtn,
    .sd-plan-opt, .sd-l3set__ink, .sd-knx-ink, .sd-knx-suggest__b, .sd-try-end, .sd-rx-end, .sd-toast__x) {
  transition: transform var(--motion-fast) var(--motion-ease-spring),
    background-color var(--motion-fast) var(--motion-ease-standard),
    color var(--motion-base) var(--motion-ease-standard),
    box-shadow var(--motion-fast) var(--motion-ease-standard);
}
:is(.sd-as-fchip, .sd-as-copy__b, .sd-as-seg__b, .sd-hc-seg__b, .sd-cd-seg__b, .sd-bkp-seg__b, .sd-hc-fchip,
    .sd-hc-seeall, .sd-hc-more, .sd-hc-clear, .sd-l3set__tab, .sd-as-tabs a, .sd-iconbtn, .sd-bkp-iconbtn,
    .sd-plan-opt, .sd-l3set__ink, .sd-knx-ink, .sd-knx-suggest__b, .sd-try-end, .sd-rx-end, .sd-toast__x,
    .sd-as-btn, .sd-seg__b, .sd-tabs__b):active:not([disabled]):not([aria-disabled="true"]) {
  transform: scale(var(--motion-press-scale));
  transition-timing-function: var(--motion-ease-out);
}

/* ---- the sliding highlight (motion-kit.js) ----------------------------------
   A strip of tabs, a segmented control or the menu gets one `.sd-motion-ind`
   under its open item. `.is-motion-host` is set as soon as the strip is bound:
   the strip anchors the highlight (UI-SCROLL: an absolute piece is placed
   against its own positioned box, never the page) and isolates it, so the
   highlight paints above the strip's own background and below its items.
   `.is-motion-ind` is set once the highlight is measured and in place, and only
   then is the item's own static highlight hidden: without script, or before
   the first measure, the static one shows and nothing flashes. */
.is-motion-host { position: relative; isolation: isolate; }
.sd-motion-ind {
  position: absolute; inset-block-start: 0; inset-inline-start: 0; z-index: -1;
  display: block; margin: 0; padding: 0; list-style: none; pointer-events: none;
  border-radius: var(--r-full); opacity: 0;
  transition: transform var(--motion-base) var(--motion-ease-standard);
}
.is-motion-ind > .sd-motion-ind { opacity: 1; }

/* A raised pill on a sunk track: the menu and the segmented controls. */
:is(.sd-nav, .sd-seg, .sd-as-seg, .sd-hc-seg, .sd-cd-seg, .sd-bkp-seg) > .sd-motion-ind {
  background: var(--surface); box-shadow: var(--sh-card);
}
.sd-seg > .sd-motion-ind { box-shadow: var(--sh-btn); }
:root[data-theme="dark"] :is(.sd-nav, .sd-as-seg, .sd-hc-seg, .sd-cd-seg, .sd-bkp-seg) > .sd-motion-ind { background: var(--surface-2); }
.sd-nav.is-motion-ind .sd-nav__item.is-current,
:root[data-theme="dark"] .sd-nav.is-motion-ind .sd-nav__item.is-current,
.sd-seg.is-motion-ind .sd-seg__b:not(.sd-seg__b--experimental):is([aria-pressed="true"], [aria-selected="true"], [aria-checked="true"]),
.sd-as-seg.is-motion-ind .sd-as-seg__b:is([aria-pressed="true"], [aria-checked="true"]),
:root[data-theme="dark"] .sd-as-seg.is-motion-ind .sd-as-seg__b:is([aria-pressed="true"], [aria-checked="true"]),
.sd-hc-seg.is-motion-ind .sd-hc-seg__b[aria-checked="true"],
:root[data-theme="dark"] .sd-hc-seg.is-motion-ind .sd-hc-seg__b[aria-checked="true"],
.sd-cd-seg.is-motion-ind .sd-cd-seg__b[aria-pressed="true"],
:root[data-theme="dark"] .sd-cd-seg.is-motion-ind .sd-cd-seg__b[aria-pressed="true"],
.sd-bkp-seg.is-motion-ind .sd-bkp-seg__b:is([aria-selected="true"], [aria-pressed="true"]),
:root[data-theme="dark"] .sd-bkp-seg.is-motion-ind .sd-bkp-seg__b:is([aria-selected="true"], [aria-pressed="true"]) {
  background: transparent; box-shadow: none;
}

/* An ink pill: the assistant's tabs and the settings tabs. The words of the
   open tab turn light as the pill arrives under them. */
:is(.sd-as-tabs > ul, .sd-l3set__tablist) > .sd-motion-ind { background: var(--ink); }
.sd-as-tabs > ul.is-motion-ind a[aria-current="page"],
.sd-l3set__tablist.is-motion-ind .sd-l3set__tab.is-on,
:root[data-theme="dark"] .sd-l3set__tablist.is-motion-ind .sd-l3set__tab.is-on { background: transparent; }

/* An underline: the section tabs (`.sd-tabs`). The highlight is the item's box
   with its bottom edge drawn, where the item's own border sits. */
.sd-tabs > .sd-motion-ind { border-radius: 0; box-shadow: inset 0 -2px 0 var(--echo); }
.sd-tabs.is-motion-ind .sd-tabs__b[aria-selected="true"] { border-bottom-color: transparent; }

/* ---- cards and rows ---------------------------------------------------------
   A card or a row that opens something lifts a pixel under the pointer and
   presses in when clicked. A card that opens nothing does not move. Rows in a
   table only fade their background: a moving table row tears. Hover lifts only
   where there is a pointer that hovers, so a tap on a phone never leaves a card
   floating. */
:is(a.sd-card[href], button.sd-card, .sd-card[role="button"], a.sd-as-card[href], button.sd-as-card,
    a.sd-hc-card[href], .sd-agentcard, .sd-as-page .sd-tier__card, .sd-bkp-callcard, .sd-hc-row) {
  transition: transform var(--motion-fast) var(--motion-ease-spring),
    box-shadow var(--motion-base) var(--motion-ease-standard),
    background-color var(--motion-fast) var(--motion-ease-standard),
    border-color var(--motion-fast) var(--motion-ease-standard);
}
@media (hover: hover) {
  :is(a.sd-card[href], button.sd-card, .sd-card[role="button"], a.sd-as-card[href], button.sd-as-card,
      a.sd-hc-card[href], .sd-agentcard, .sd-as-page .sd-tier__card, .sd-bkp-callcard):hover:not([disabled]) {
    transform: translateY(-1px);
  }
}
:is(a.sd-card[href], button.sd-card, .sd-card[role="button"], a.sd-as-card[href], button.sd-as-card,
    a.sd-hc-card[href], .sd-agentcard, .sd-as-page .sd-tier__card, .sd-bkp-callcard):active:not([disabled]) {
  transform: scale(0.99);
  transition-timing-function: var(--motion-ease-out);
}
.sd-hc-row:active { transform: scale(0.99); transition-timing-function: var(--motion-ease-out); }
:is(.sd-rx-row, .sd-bkp-lrow, .sd-records li.is-clickable, .sd-table tbody tr.is-clickable td, .sd-rp-row td, .sd-rp-row th) {
  transition: background-color var(--motion-fast) var(--motion-ease-standard);
}

/* ---- the page's first draw (motion-kit.js sets data-motion-enter) -----------
   The page's top-level blocks rise into place in at most three steps, 30 ms
   apart, once: only while <html> carries the flag, which comes off a moment
   after the first card arrives. Long lists are never animated row by row. */
:root[data-motion-enter] .sd-shell__col > main.sd-page > * {
  animation: motion-fade-rise-in var(--motion-slow) var(--motion-ease-out) backwards;
}
:root[data-motion-enter] .sd-shell__col > main.sd-page > :nth-child(2) { animation-delay: 30ms; }
:root[data-motion-enter] .sd-shell__col > main.sd-page > :nth-child(n+3) { animation-delay: 60ms; }

/* A tab's content arrives with a short rise when the tab changes (each tab's
   panel is a new element, so this runs once per change, never on a re-render). */
.sd-as-tab, .sd-l3set > :not(.sd-l3set__head) {
  animation: motion-fade-rise-in var(--motion-slow) var(--motion-ease-out) backwards;
}

/* ---- the shell's menus (you, the theme): they grow out of the button that
   opened them, from below for a menu that opens upwards and from above for one
   that opens downwards. */
.sd-menu { animation: motion-scale-in var(--motion-base) var(--motion-ease-out); }
.sd-menu--up { transform-origin: 50% 100%; }
.sd-menu--down { transform-origin: 50% 0; }

/* ---- dialogs, sheets, drawers -------------------------------------------------
   A dialog scales up a little as it fades in and back down as it goes. Its way
   out (`data-leaving`, motion-kit.js usePresence) is inert: focus has already
   gone back and a click lands on the page under it. */
.sd-modal__scrim[data-leaving] {
  pointer-events: none;
  animation: motion-fade-out var(--motion-slow) var(--motion-ease-in) forwards;
}
.sd-modal__scrim[data-leaving] .sd-modal { animation: motion-scale-out var(--motion-slow) var(--motion-ease-in) forwards; }
.sd-sheet-layer[data-leaving] { pointer-events: none; }
.sd-sheet-layer[data-leaving] .sd-sheet__scrim { animation: motion-fade-out var(--motion-slow) var(--motion-ease-in) forwards; }
.sd-sheet-layer[data-leaving] .sd-sheet { animation: motion-fade-sink-out var(--motion-slow) var(--motion-ease-in) forwards; }
.sd-sheet__scrim { animation: motion-fade-in var(--motion-slow) var(--motion-ease-out); }

/* The plan's sheet: from the inline end on a desk, a dialog in the middle, from
   the bottom on a phone. */
.sd-plan-sheet__scrim { animation: motion-fade-in var(--motion-slow) var(--motion-ease-out); }
.sd-plan-sheet--side { animation: motion-slide-in-from-inline-end var(--motion-slow) var(--motion-ease-out); }
.sd-plan-sheet--center { animation: motion-scale-in var(--motion-slow) var(--motion-ease-out); }
@media (max-width: 639px) {
  .sd-plan-sheet--side, .sd-plan-sheet--center { animation-name: motion-fade-rise-in; }
}

/* ---- the save and copy buttons (motion-kit.js SaveButton, CopyButton) ---------
   A button's labels share one grid cell; the ones not showing are invisible (and
   so neither read out nor part of its text), so the button keeps its widest
   label's width and whatever sits beside it never moves. */
.sd-motion-label { display: inline-grid; justify-items: center; }
.sd-motion-label > span, .sd-motion-label::before, .sd-motion-label::after { grid-area: 1 / 1; }
.sd-motion-label::before { content: attr(data-l1); visibility: hidden; }
.sd-motion-label::after { content: attr(data-l2); visibility: hidden; }
:is(.sd-savebtn[data-save-state="saved"], [data-copied="true"]) .sd-motion-label > span {
  animation: motion-fade-in var(--motion-base) var(--motion-ease-out);
}
.sd-savebtn[data-save-state="error"] { animation: motion-shake calc(var(--motion-slow) * 1.6) var(--motion-ease-standard); }
/* An "unsaved changes" bar rises into view when the first change is made. */
.sd-l3set__savebar, .sd-as-savebar { animation: motion-fade-rise-in var(--motion-slow) var(--motion-ease-out); }
/* A bar holding "Saved" for a moment has nothing left to discard or to warn about. */
.sd-l3set__savebar[data-save-state="saved"] :is(.sd-l3set__savet, .sd-btn--ghost),
.sd-as-savebar[data-save-state="saved"] :is(.sd-as-savebar__t, .sd-as-btn--ghost-inv) {
  visibility: hidden;
}

/* ---- a tick that arrives: "Saved", "Copied" ------------------------------------
   Drawn along its own length (pathLength 1). With every animation stopped it is
   simply there. */
.sd-motion-tick { flex: none; animation: motion-pop-in var(--motion-base) var(--motion-ease-spring); }
.sd-motion-tick path { stroke-dasharray: 1; animation: motion-draw-in var(--motion-base) var(--motion-ease-out) backwards; }
