/* ── iOS — the system idiom is an OPACITY dim on touch-down, not a ripple. Pairs with the
   existing components.css .btn:active{transform:scale(.97)} (additive, GPU-only). ───────── */
@media (prefers-reduced-motion: no-preference) {
  html[data-os="ios"] .btn:active,
  html[data-os="ios"] .pill:active,
  html[data-os="ios"] .chip:active,
  html[data-os="ios"] [data-ripple]:active { opacity: .6; }
}

@media (max-width: 767px) {
  html[data-os="ios"] nav.bnav {
    background:linear-gradient(180deg,rgba(255,255,255,.13),rgba(255,255,255,.052)),color-mix(in oklch,var(--surface,#14161d) 72%,transparent);
    border-top:1px solid rgba(255,255,255,.14);
    box-shadow:0 -1px 0 rgba(255,255,255,.055) inset,0 -18px 44px rgba(0,0,0,.34);
    -webkit-backdrop-filter:blur(24px) saturate(1.55);
    backdrop-filter:blur(24px) saturate(1.55);
  }
  html[data-os="ios"] nav.bnav a.on{background:rgba(255,255,255,.13);box-shadow:inset 0 0 0 1px rgba(255,255,255,.11)}
  html[data-os="ios"] nav.bnav a.on::before{top:3px;background:linear-gradient(90deg,var(--accent,#8b7cf6),color-mix(in oklch,var(--info,#60a5fa) 72%,var(--accent,#8b7cf6)))}
}

/* ── Android — Material ripple. The host needs a clip + positioning context; scoped to Android so it
   never affects iOS/web. Only .btn / [data-ripple] are hosts (they size their own ≥44px target without
   a ::before hit-expander, so overflow:hidden can't shrink a touch target). An element's OWN outset
   box-shadow is not clipped by its own overflow:hidden, so the .btn glow survives. ─────────────────── */
html[data-os="android"] .btn,
html[data-os="android"] [data-ripple] { position: relative; overflow: hidden; }

.plat-ripple {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  background: currentColor;
  opacity: .22;
  transform: scale(0);
  will-change: transform, opacity;
}
@media (prefers-reduced-motion: no-preference) {
  .plat-ripple { animation: plat-ripple-go var(--dur-slow, 380ms) var(--ease-out, ease-out) forwards; }
}
@keyframes plat-ripple-go { to { transform: scale(2.2); opacity: 0; } }

/* In-app "Reduce motion" toggle also kills the ripple (platform.js already skips spawning it under
   reduced-motion; this is belt-and-suspenders for an already-mounted span). */
html.reduce-motion .plat-ripple { animation: none !important; display: none; }

/* ── Signature motion (Phase 6) — additive, GPU-friendly, gated by BOTH reduced-motion paths. ───────── */

/* Directional value-flash: a one-shot glow when a number changes (Platform.flash(el,dir)). text-shadow
   works on inline number spans (transform/scale does not) and never reflows. pos=gain, neg=loss. */
@media (prefers-reduced-motion: no-preference) {
  .plat-flash-pos { animation: plat-flash-pos var(--dur-slow, 380ms) var(--ease-out, ease-out) 1; }
  .plat-flash-neg { animation: plat-flash-neg var(--dur-slow, 380ms) var(--ease-out, ease-out) 1; }
}
@keyframes plat-flash-pos { 0% { text-shadow: none } 30% { text-shadow: 0 0 14px var(--pos) } 100% { text-shadow: none } }
@keyframes plat-flash-neg { 0% { text-shadow: none } 30% { text-shadow: 0 0 14px var(--neg) } 100% { text-shadow: none } }
html.reduce-motion .plat-flash-pos, html.reduce-motion .plat-flash-neg { animation: none !important; }

/* Native <dialog> spring entrance — every modal/sheet (Display prefs, new-goal, account pickers) now
   springs up like a native sheet instead of hard-popping. translateY+opacity only (no scale → no text
   blur, no layout shift); --ease-spring gives the subtle overshoot. ::backdrop fades in with it. The
   `both` fill resolves to transform:none, so fixed-position children inside a dialog are unaffected after. */
@media (prefers-reduced-motion: no-preference) {
  dialog[open] { animation: plat-dialog-in var(--dur-base, 200ms) var(--ease-spring, var(--ease-out, ease-out)) both; }
  dialog[open]::backdrop { animation: plat-backdrop-in var(--dur-base, 200ms) var(--ease-out, ease-out) both; }
}
@keyframes plat-dialog-in { from { opacity: 0; transform: translateY(12px) } to { opacity: 1; transform: none } }
@keyframes plat-backdrop-in { from { opacity: 0 } to { opacity: 1 } }
html.reduce-motion dialog[open], html.reduce-motion dialog[open]::backdrop { animation: none !important; }

/* ── Distinct adaptive desktop (Phase 7) — cursor-era refinements on the live data-pointer/data-hover
   hooks (set by platform.js). SCOPED to >=768px AND fine pointer so the mobile experience (and the e2e
   at <=767px, where the app hides the scrollbar) is byte-identical — this is why the earlier global
   scrollbar override was wrong. The multi-column SDUI grid + sidebar nav + cmdK palette already ship;
   this adds what keys off a real cursor: an on-brand scrollbar, a hover-lift, and a hover-reveal utility. */
@media (min-width: 768px) and (hover: hover) and (pointer: fine) {
  /* On-brand thin scrollbar for mouse users — WebKit + Firefox. (Touch keeps the hidden/overlay bar.) */
  html[data-pointer="fine"] { scrollbar-color: var(--line-strong) transparent; scrollbar-width: thin; }
  html[data-pointer="fine"] ::-webkit-scrollbar { width: 11px; height: 11px; }
  html[data-pointer="fine"] ::-webkit-scrollbar-thumb {
    background: var(--line-strong); border-radius: var(--r-pill);
    border: 3px solid transparent; background-clip: padding-box;
  }
  html[data-pointer="fine"] ::-webkit-scrollbar-thumb:hover { background: var(--ink-faint); }

  /* Card hover-lift — a desktop-only "alive under the cursor" affordance touch UIs cannot have.
     GPU-only (transform/box-shadow), reduced-motion-gated below. */
  html[data-hover] .card { transition: transform var(--dur-fast, 120ms) var(--ease-out, ease-out), box-shadow var(--dur-base, 200ms) var(--ease-out, ease-out); }

  /* Hover-reveal utility — secondary actions hide until hover/focus on desktop (keyboard-reachable via
     :focus-within); on touch (<=767px / coarse) this rule never applies, so mobile never loses them. */
  html[data-hover] .hover-reveal { opacity: 0; transition: opacity var(--dur-fast, 120ms) var(--ease-out, ease-out); }
  html[data-hover] *:hover > .hover-reveal,
  html[data-hover] .hover-reveal:focus-within { opacity: 1; }
}
@media (min-width: 768px) and (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  html[data-hover] .card:hover { transform: translateY(-2px); box-shadow: var(--shadow-3, 0 14px 40px rgba(0,0,0,.5)); }
}
/* In-app reduce-motion kills the hover-lift (mirrors base.css). */
html.reduce-motion .card { transition: none !important; }
html.reduce-motion[data-hover] .card:hover { transform: none !important; }
