/* Motion and finish. Loaded last; additive only.
   Rules of the house: motion says something about state (arrived, pressed, live, ringing) or it is not here.
   Entrances are <= 180 ms, end at opacity 1 / transform none, and never gate interaction. Looping animation is kept to
   small indicators. Everything that loops or enters sits inside prefers-reduced-motion: no-preference; base.css also
   flattens every animation and transition under prefers-reduced-motion: reduce. */

:root {
  --ease-out: cubic-bezier(.2, .7, .2, 1);
  --ease-io: cubic-bezier(.45, 0, .25, 1);
  --btn-edge: inset 0 1px 0 rgba(255, 255, 255, .045), 0 1px 1px rgba(0, 0, 0, .28);
  --lift: 0 8px 18px -12px rgba(0, 0, 0, .7);
}
:root[data-theme="light"] {
  --btn-edge: 0 1px 1px rgba(21, 25, 28, .07);
  --lift: 0 8px 18px -12px rgba(21, 25, 28, .35);
}

/* ---------- type: figures line up, copy breaks well ---------- */
.call-timer, .cl-timer, .tile-t, .wrapbar-n, .mdock-t, .recorder-t,
.total-v, .stat-v, .cl-stat-v, .mynum-v, .side-num-v, .wb-v, .wb-n, .wb-c, .wb-t, .wb-fv, .wb-clock,
.livecall-t, .holdt, .cd, .offer-cd, .count, .badge, .seg-n, .lb-v, .act-sum strong, .tbl .r {
  font-variant-numeric: tabular-nums;
}
h1, h2, .home-hi, .cl-name, .empty-t, .blocked-t, .kbd-hint, .offer-keys { text-wrap: balance; }
.page-t p, .empty-d, .set-lead, .auth-lead, .auth-foot, .modal-msg, .field-h, .banner-b, .alert-m, .walert p,
.switch-l, .cl-idle-h p, .pf-head p, .help-setup-b p, .help-faq dd { text-wrap: pretty; }

/* ---------- buttons: a physical edge at rest, flat when pressed ---------- */
.btn { transition: background-color var(--t), border-color var(--t), color var(--t), box-shadow var(--t), transform 70ms var(--ease-out); }
.btn:where(:not(.ghost):not(.star):not(:disabled)) { box-shadow: var(--btn-edge); }
.btn:active:not(:disabled) { box-shadow: none; transition-duration: 40ms; }
.btn.lg:active:not(:disabled), .btn.xl:active:not(:disabled), .cl-save:active:not(:disabled), .cl-start:active:not(:disabled),
.incoming-a .btn:active:not(:disabled) { transform: translateY(.5px) scale(.985); }
.tile-mode, .mon-btns .btn { box-shadow: none; }
.link, .link-strong, .cp-back { transition: color var(--t), text-decoration-color var(--t); }
.chip:active, .qd-chip:active, .seg-b:active, .qr-opt:active { transform: translateY(.5px); }
.seg-b, .chip, .qd-chip, .qr-opt, .mdock-mode, .teach-act { transition: background-color var(--t), border-color var(--t), color var(--t), transform 70ms var(--ease-out); }
.mdock-mode:active:not(:disabled) { transform: scale(.985); }

/* ---------- fields ---------- */
.input, .otp-b { transition: border-color var(--t), background-color var(--t); }
.check-box, .opt-dot { transition: background-color var(--t), border-color var(--t); }
.opt-dot::after { transition: background-color var(--t); }
.switch-k { transition: transform 140ms var(--ease-out), background-color var(--t); }

/* ---------- rows and lists: hover arrives at once, leaves softly ---------- */
.tbl tbody tr, .rc-row, .ms-row, .fav, .tp-row, .opt, .menu-i, .snip-i, .pal-i, .set-tab, .nav-i, .linekey, .cl-list,
.log-l, .tl-r, .lrn-sel { transition: background-color 160ms ease-out, color var(--t), box-shadow var(--t); }
.tbl tbody tr:hover, .rc-row:hover, .ms-row:hover, .fav:hover, .tp-row:hover, .opt:hover, .menu-i:hover, .snip-i:hover,
.set-tab:hover, .nav-i:hover, .linekey:hover, .cl-list:hover, .log-l:hover, .tl-r:hover { transition-duration: 40ms; }
.ms-row:hover { background: var(--raised); }
.nav-i .ic, .tab, .tab-l, .dtab, .rc-call { transition: color var(--t), background-color var(--t), border-color var(--t); }
.tbl tr.selected td:first-child, .tbl tr.selected th:first-child { box-shadow: inset 2px 0 0 var(--info); }
.lamp, .tile-dot, .cdot, .qdot, .pill, .tag, .ltag, .xbadge, .cstat::before { transition: background-color 160ms ease-out, border-color 160ms ease-out, color 160ms ease-out; }

/* cards that are links lift a hair; plain cards only sharpen their border */
.scard { transition: border-color var(--t), box-shadow 140ms ease-out, transform 140ms var(--ease-out); }
.scard:hover { box-shadow: var(--lift); transform: translateY(-1px); }
.scard:active { transform: none; box-shadow: none; }
.lh, .wb-tile, .set-s, .qform { transition: border-color var(--t); }
.lh:hover { border-color: var(--line-2); }

/* ---------- key pad: instant down, slow release (the key "lets go") ---------- */
.key { transition: background-color 260ms ease-out, transform 140ms var(--ease-out); }
.key:active, .key.down { transition-duration: 30ms; }
.key-d { transition: color 260ms ease-out; }
.key:active .key-d, .key.down .key-d { transition-duration: 30ms; }
.auth-key { transition: color 320ms ease-out; }
.auth-key:hover { color: var(--ink-3); transition-duration: 60ms; }
.auth-key:nth-child(5):hover { color: var(--ink-2); }

/* ---------- meters and bars: glide, never jump ---------- */
.meter i, .lvl-bar i { transition: background-color 90ms linear; }
.cl-bar i, .wb-bar i, .lb-bar i, .scard-bar i { transition: width 280ms var(--ease-out), background-color 160ms ease-out; }
.ring-arc, .ring-over { transition: stroke-dasharray 320ms var(--ease-out), stroke 160ms ease-out; }
.ratio-a { transition: width 240ms var(--ease-out); }

/* ---------- call display: the edge is the status light ----------
   The coloured edge is an inset shadow (views.css). A 3px strip in the display's own colour sits on top of it and fades
   in and out, so the edge appears to breathe without repainting the display. Tempo carries the state:
   in call = slow and calm, dialling = steady pulse, ringing = the double beat of a phone, held = still. */
.display::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--sunken); opacity: 0; pointer-events: none;
}
.display { transition: box-shadow 180ms ease-out; }
@media (min-width: 861px) { .cl-band { position: relative; } }
.cl-band::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; border-radius: 7px 0 0 0;
  background: var(--sunken); opacity: 0; pointer-events: none;
}

/* ---------- incoming call: the top edge rings ---------- */
.incoming { position: relative; }
.incoming:not(.offer)::before {
  content: ""; position: absolute; left: 0; right: 0; top: -3px; height: 3px;
  border-radius: 5px 5px 0 0; background: var(--raised); opacity: 0; pointer-events: none;
}
.incoming-pulse { transform-origin: 50% 15%; }

@media (prefers-reduced-motion: no-preference) {
  /* ----- entrances ----- */
  @keyframes view-in { from { opacity: 0; transform: translateY(4px); } }
  @keyframes fade-in { from { opacity: 0; } }
  @keyframes pop-in { from { opacity: 0; transform: translateY(5px); } }
  @keyframes drop-in { from { opacity: 0; transform: translateY(-6px); } }
  @keyframes menu-in { from { opacity: 0; transform: translateY(-3px); } }
  @keyframes side-in { from { opacity: 0; transform: translateX(10px); } }
  @keyframes sheet-in { from { opacity: 0; transform: translateY(14px); } }
  @keyframes check-in { from { transform: scale(.5); } }
  @keyframes mark-in { from { transform: scaleY(.3); opacity: 0; } }
  @keyframes under-in { from { transform: scaleX(.3); opacity: 0; } }

  /* a new screen: pages rise 4px; the full-height work surfaces (dialer, call list) only fade, so nothing can
     overflow the outlet for the length of the animation */
  .outlet > .page, .bare-outlet > * { animation: view-in 160ms var(--ease-out); }
  .outlet > :not(.page) { animation: fade-in 140ms ease-out; }
  .auth-body { animation: view-in 180ms var(--ease-out); }
  /* the key pad behind the form is drawn in from its top-left corner (decoration only; nothing here is clickable) */
  .auth-key { --kc: 0ms; --kr: 0ms; animation: fade-in 180ms ease-out backwards; animation-delay: calc(var(--kc) + var(--kr)); }
  .auth-key:nth-child(3n+2) { --kc: 45ms; }
  .auth-key:nth-child(3n) { --kc: 90ms; }
  .auth-key:nth-child(n+4) { --kr: 45ms; }
  .auth-key:nth-child(n+7) { --kr: 90ms; }
  .auth-key:nth-child(n+10) { --kr: 135ms; }

  /* dialogs move, they never scale: anything measured or clicked inside them is true-sized from the first frame */
  .modal-layer { animation: fade 140ms ease-out; }
  .modal { animation: rise 150ms var(--ease-out); }
  .modal.sz-sm, .modal.sz-md { animation: pop-in 150ms var(--ease-out); }
  .modal.pal { animation: drop-in 140ms var(--ease-out); }
  .modal-layer[data-kind="drawer"] .modal { animation: slide 160ms var(--ease-out); }
  .menu, .snip { animation: menu-in 110ms var(--ease-out); }
  .incoming { animation: side-in 160ms var(--ease-out); }
  .toast, .xfer-ok { animation-timing-function: var(--ease-out); }
  .tile { animation: view-in 160ms var(--ease-out); }
  .check input:checked + .check-box .ic { animation: check-in 120ms var(--ease-out); }
  .pal-i[aria-selected="true"]::before { transform-origin: 50% 50%; animation: mark-in 120ms var(--ease-out); }
  .tab-l[aria-current="page"]::after { animation: under-in 160ms var(--ease-out); }
  .dtab { transition: color var(--t), border-color 160ms ease-out; }

  @media (max-width: 860px) {
    .incoming { animation-name: sheet-in; }
  }
  @media (max-width: 720px) {
    .modal, .modal.sz-sm, .modal.sz-md, .modal-layer[data-kind="drawer"] .modal { animation: sheet-in 170ms var(--ease-out); }
    .modal.pal { animation: drop-in 140ms var(--ease-out); }
  }

  /* ----- live ----- */
  @keyframes edge-breathe { 0%, 100% { opacity: 0; } 50% { opacity: .62; } }
  @keyframes edge-pulse { 0%, 100% { opacity: 0; } 50% { opacity: .85; } }
  /* brr-brr … brr-brr: two beats, then a rest */
  @keyframes edge-ring { 0%, 8%, 16%, 26%, 100% { opacity: 0; } 12% { opacity: .9; } 34%, 90% { opacity: .42; } }
  @keyframes bell { 0%, 34%, 100% { transform: rotate(0); } 5%, 23% { transform: rotate(-16deg); } 11%, 29% { transform: rotate(14deg); } 17% { transform: rotate(-10deg); } }
  @keyframes rec { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
  @keyframes ping { from { box-shadow: 0 0 0 0 color-mix(in srgb, var(--edge) 55%, transparent); } to { box-shadow: 0 0 0 6px transparent; } }
  @keyframes attn { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
  @keyframes skel { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

  .display[data-mode="active"]::after, .cl-band[data-mode="active"]::after { animation: edge-breathe 3.2s var(--ease-io) infinite; }
  .display[data-mode="dialing"]::after, .cl-band[data-mode="dialing"]::after, .cl-band[data-mode="pending"]::after { animation: edge-pulse 1.1s var(--ease-io) infinite; }
  .display[data-mode="ringing"]::after { animation: edge-ring 2.4s linear infinite; }

  .incoming:not(.offer)::before { animation: edge-ring 2.4s linear infinite; }
  .incoming:not(.offer) .incoming-pulse, .display[data-mode="ringing"] .call-state .ic, .pill[data-s="ringing"] .ic {
    animation: bell 2.4s ease-in-out infinite; transform-origin: 50% 15%;
  }

  .rec-dot { animation: rec 1.8s var(--ease-io) infinite; }
  .cx-flag[data-k="rec"] .rec-dot { animation: none; }
  .tile[data-state="ringing"] .tile-dot { animation: ping 1.4s ease-out infinite; }
  .pill[data-s="error"] .ic, .home-line .lamp[data-s="error"] { animation: attn 1.8s var(--ease-io) infinite; }

  /* loading rows: a slow swell, each row a beat behind the one above */
  .skel-row { animation: skel 1.5s var(--ease-io) infinite; }
  .skel-row:nth-child(2) { animation-delay: .12s; }
  .skel-row:nth-child(3) { animation-delay: .24s; }
  .skel-row:nth-child(4) { animation-delay: .36s; }
  .skel-row:nth-child(n+5) { animation-delay: .48s; }
}
