/* ─────────────────────────────────────────────────────────────────────────
   polish.css — micro-interactions + presence layer.

   Pure additions. This file never overrides existing transition declarations;
   it composes through :active / :focus-visible / :hover specificity, or adds
   properties (font-variant-numeric, animation) that aren't set elsewhere.

   Animation Decision Framework (Emil Kowalski):
   - :active press scale 0.97 → seen many times/day → 120ms ease-out, subtle
   - :focus-visible ring → not motion, accessibility + craft
   - tabular-nums → typography only
   - sidebar tab stagger → once per page load (rare) → can delight
   - card hover lift → tens of times/day → subtle, 180ms
   - All motion guarded by prefers-reduced-motion at the bottom
   ───────────────────────────────────────────────────────────────────────── */

/* ── 1. Stronger easing tokens (additive — base.css's --ease-out stays) ── */
:root {
  --ease-out-strong:    cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out-strong: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer:        cubic-bezier(0.32, 0.72, 0, 1);
  --t-press: 120ms;
}

/* ══════════════════════════════════════════════════════════════════════════
   2. PRESS FEEDBACK — Emil's "buttons must feel responsive" rule.
   Any pressable surface gets a 3% scale-down on :active. We compose via
   :active specificity so existing transitions stay intact; we add only
   `transform` (which most rules don't touch).
   ══════════════════════════════════════════════════════════════════════════ */

button:not(:disabled):active,
.btn:not(:disabled):active,
.nav-tab:not(.disabled):active,
.role-card:active,
.dept-card:active,
.user-card:active,
[role="button"]:not([aria-disabled="true"]):active,
.auth-hint:active,
.scope-pill:active,
.v2-pill:active,
.v2c-button:active,
.v2-btn:active,
.tile-action:active,
.v2-lib-tile:active,
.calc-row button:active,
.modal-close:active,
.icon-btn:active {
  transform: scale(0.97);
  transition: transform var(--t-press) var(--ease-out-strong);
}

/* Larger pressables (whole-card targets) want a gentler press */
.dept-card:active,
.role-card:active,
.user-card:active,
.v2-lib-tile:active {
  transform: scale(0.985);
}

/* ══════════════════════════════════════════════════════════════════════════
   3. FOCUS-VISIBLE RINGS — keyboard nav is real UX, not an afterthought.
   Only when the browser knows it's a keyboard interaction (:focus-visible),
   so mouse clicks don't leave a ring behind. Two-layer ring so it reads on
   both dark glass and light theme.
   ══════════════════════════════════════════════════════════════════════════ */

button:focus-visible,
.btn:focus-visible,
.nav-tab:focus-visible,
.role-card:focus-visible,
.dept-card:focus-visible,
.user-card:focus-visible,
[role="button"]:focus-visible,
.auth-hint:focus-visible,
.scope-pill:focus-visible,
.v2c-button:focus-visible,
.v2-btn:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 2px rgba(4, 5, 18, 0.95),
    0 0 0 4px rgba(56, 189, 248, 0.65),
    0 0 18px rgba(56, 189, 248, 0.35);
}

/* Inputs already have their own focus styling — don't double-up */

html[data-theme="light"] button:focus-visible,
html[data-theme="light"] .btn:focus-visible,
html[data-theme="light"] .nav-tab:focus-visible,
html[data-theme="light"] [role="button"]:focus-visible {
  box-shadow:
    0 0 0 2px rgba(255, 255, 255, 0.95),
    0 0 0 4px rgba(2, 132, 199, 0.55),
    0 0 14px rgba(2, 132, 199, 0.20);
}

/* ══════════════════════════════════════════════════════════════════════════
   4. TYPOGRAPHY — tabular numerals so digits don't jiggle when values tick.
   Critical on a 30s-polling sensor dashboard.
   ══════════════════════════════════════════════════════════════════════════ */

.stat-value,
.stat-number,
.stat-room,
.nav-clock-time,
.tile-big-number,
.v2c-bignumber-value,
.metric-value,
.kpi-value,
[data-tabular],
.tile-value,
.harvest-total,
.row-value,
td.numeric,
.cell-numeric {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* ══════════════════════════════════════════════════════════════════════════
   5. CURSOR REFINEMENT — pointer where things click, not-allowed when off.
   ══════════════════════════════════════════════════════════════════════════ */

button:not(:disabled),
.btn:not(:disabled),
[role="button"]:not([aria-disabled="true"]),
.nav-tab,
.role-card,
.dept-card,
.user-card,
.scope-pill,
.v2c-button,
.tile-action {
  cursor: pointer;
}

button:disabled,
.btn:disabled,
[role="button"][aria-disabled="true"],
input:disabled,
textarea:disabled,
select:disabled {
  cursor: not-allowed;
}

/* ══════════════════════════════════════════════════════════════════════════
   6. AMBIENT MOTION — subtle drift on the auth icon's surrounding orbs,
   pulse on the live indicator, breathe on the page background.
   These are decorative and run continuously, so they're long + low-amplitude.
   ══════════════════════════════════════════════════════════════════════════ */

/* LIVE pill — soft halo pulse */
.live-pill,
.live-indicator,
.nav-live {
  position: relative;
}
.live-pill::before,
.live-indicator::before {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  background: radial-gradient(circle, rgba(45, 212, 191, 0.35) 0%, transparent 70%);
  opacity: 0;
  animation: polish-live-halo 2.8s ease-in-out infinite;
  pointer-events: none;
  z-index: -1;
}
@keyframes polish-live-halo {
  0%, 100% { opacity: 0.0; transform: scale(0.96); }
  50%      { opacity: 0.55; transform: scale(1.08); }
}

/* ══════════════════════════════════════════════════════════════════════════
   7. CARD HOVER LIFT — tiny translateY + brighter border. Composes with
   existing hover rules where present.
   ══════════════════════════════════════════════════════════════════════════ */

.dept-card,
.role-card,
.user-card,
.summary-pill {
  transition:
    transform 180ms var(--ease-out-strong),
    box-shadow 200ms var(--ease-out-strong),
    border-color 200ms var(--ease-out-strong);
}
@media (hover: hover) and (pointer: fine) {
  .dept-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.32), 0 0 24px rgba(56, 189, 248, 0.10);
  }
  .summary-pill:hover {
    transform: translateY(-2px);
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   8. MODAL / DRAWER BACKDROP — gentle fade-in. Many modals in this repo
   don't explicitly animate the scrim; this gives them all a 200ms fade.
   ══════════════════════════════════════════════════════════════════════════ */

.modal-backdrop,
.modal-overlay,
.drawer-backdrop,
.dialog-backdrop,
[data-backdrop] {
  animation: polish-backdrop-in 180ms var(--ease-out-strong) both;
}
@keyframes polish-backdrop-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Modals themselves — origin: center (modals are NOT anchored to a trigger) */
.modal,
.dialog,
[role="dialog"]:not([data-no-polish]) {
  transform-origin: center;
}

/* ══════════════════════════════════════════════════════════════════════════
   9. SUBTLE GLASS SHIMMER — for the brand mark on hover. Lots of cards
   already shimmer; this just covers .nav-logo where it didn't.
   ══════════════════════════════════════════════════════════════════════════ */

.nav-logo {
  position: relative;
  overflow: hidden;
  cursor: pointer;
}
.nav-logo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg,
    transparent 30%,
    rgba(255, 255, 255, 0.08) 50%,
    transparent 70%);
  transform: translateX(-100%);
  transition: transform 0.6s var(--ease-out-strong);
  pointer-events: none;
  border-radius: inherit;
}
.nav-logo:hover::after {
  transform: translateX(100%);
}

/* ══════════════════════════════════════════════════════════════════════════
   10. ENTRANCE REVEAL — opt-in via data-reveal="rise|fade|left|right".
   Triggered by js/polish.js via IntersectionObserver. The element starts
   hidden, then gets [data-reveal-in] which transitions to visible.
   ══════════════════════════════════════════════════════════════════════════ */

[data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 460ms var(--ease-out-strong),
    transform 520ms var(--ease-out-strong);
  will-change: opacity, transform;
}
[data-reveal="fade"]  { transform: none; }
[data-reveal="left"]  { transform: translateX(-14px); }
[data-reveal="right"] { transform: translateX(14px); }
[data-reveal="scale"] { transform: scale(0.96); }

[data-reveal][data-reveal-in] {
  opacity: 1;
  transform: none;
}

/* ══════════════════════════════════════════════════════════════════════════
   11. NUMBER COUNT-UP — opt-in via data-countup="<final value>" on any
   element. js/polish.js animates from 0 → value once on mount. The CSS just
   makes sure the digits don't shift layout while ticking.
   ══════════════════════════════════════════════════════════════════════════ */

[data-countup] {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* ══════════════════════════════════════════════════════════════════════════
   12. TAB SWITCH POLISH — fade + tiny lift between tab panels. The existing
   .tab-panel.active rule has a spring keyframe; this just makes the OUTGOING
   panel's exit feel less abrupt by giving inactive panels a 1-frame fade.
   Non-destructive — we keep display:none for layout reasons, so this is
   only visible when JS toggles .active mid-frame.
   ══════════════════════════════════════════════════════════════════════════ */

.tab-panel:not(.active) {
  pointer-events: none;
}

/* ══════════════════════════════════════════════════════════════════════════
   13. SCROLLBAR REFINEMENT — slim, accent-tinted thumb. WebKit only.
   The sidebar already overrides this; here we cover the dept-dashboard
   scroll regions that didn't have one.
   ══════════════════════════════════════════════════════════════════════════ */

.tab-panel ::-webkit-scrollbar,
.tab-content ::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
.tab-panel ::-webkit-scrollbar-track,
.tab-content ::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.02);
}
.tab-panel ::-webkit-scrollbar-thumb,
.tab-content ::-webkit-scrollbar-thumb {
  background: rgba(56, 189, 248, 0.22);
  border-radius: 8px;
  transition: background 150ms ease;
}
.tab-panel ::-webkit-scrollbar-thumb:hover,
.tab-content ::-webkit-scrollbar-thumb:hover {
  background: rgba(56, 189, 248, 0.45);
}

html[data-theme="light"] .tab-panel ::-webkit-scrollbar-thumb,
html[data-theme="light"] .tab-content ::-webkit-scrollbar-thumb {
  background: rgba(2, 132, 199, 0.28);
}
html[data-theme="light"] .tab-panel ::-webkit-scrollbar-thumb:hover,
html[data-theme="light"] .tab-content ::-webkit-scrollbar-thumb:hover {
  background: rgba(2, 132, 199, 0.55);
}

/* ══════════════════════════════════════════════════════════════════════════
   14. TEXT SELECTION — match the accent palette instead of OS default.
   ══════════════════════════════════════════════════════════════════════════ */

::selection {
  background: rgba(56, 189, 248, 0.35);
  color: #fff;
  text-shadow: 0 0 8px rgba(56, 189, 248, 0.4);
}
html[data-theme="light"] ::selection {
  background: rgba(2, 132, 199, 0.28);
  color: #04050f;
  text-shadow: none;
}

/* ══════════════════════════════════════════════════════════════════════════
   15. LOUDER LAYER — explicit "you can see this happening" motion the user
   asked for. Bigger lifts, longer-distance entrances, glow accents on press.
   Still scoped so they don't interfere with functional layout.
   ══════════════════════════════════════════════════════════════════════════ */

/* Strong press feedback (more visible than scale(0.97) — 0.94 actually reads) */
.dept-card:active,
.role-card:active,
.user-card:active,
.harvest-submit-btn:active,
.auth-hint:active,
.dash-add-btn:active,
.scope-pill:active,
.v2c-button:active {
  transform: scale(0.94) !important;
  transition: transform 110ms cubic-bezier(0.23, 1, 0.32, 1) !important;
}

/* Universal hover lift on glass card surfaces.
   Per user 2026-05-30: dashboard tiles (.v2-tile, .v2-lib-tile, .tile)
   excluded — they're drag-rearrangeable surfaces and the lift made every
   hover feel like the tile was about to come loose. Other contexts
   (Overview .stat-card, dept-picker .dept-card, rooms cards) keep the
   subtle lift because they're not draggable. */
@media (hover: hover) and (pointer: fine) {
  .stat-card,
  .alert-group,
  .summary-pill,
  .dept-card,
  .room-card,
  .room-tile,
  .harvest-card,
  .calendar-event-chip {
    transition:
      transform 220ms cubic-bezier(0.23, 1, 0.32, 1),
      box-shadow 240ms cubic-bezier(0.23, 1, 0.32, 1),
      border-color 200ms ease !important;
  }
  .stat-card:hover,
  .alert-group:hover,
  .summary-pill:hover,
  .room-card:hover,
  .room-tile:hover {
    transform: translateY(-4px) !important;
    box-shadow:
      0 14px 40px rgba(0, 0, 0, 0.32),
      0 0 28px rgba(56, 189, 248, 0.18),
      inset 0 1px 0 rgba(255, 255, 255, 0.08) !important;
    border-color: rgba(56, 189, 248, 0.32) !important;
  }
  .dept-card:hover {
    transform: translateY(-6px) scale(1.015) !important;
    box-shadow:
      0 22px 56px rgba(0, 0, 0, 0.42),
      0 0 42px rgba(56, 189, 248, 0.22) !important;
  }
}

/* Cursor-follow ambient glow removed per user request 2026-05-30 —
   `body::before` previously rendered a soft cyan radial tracking
   --polish-cursor-x/y. Kept the JS setup commented out below in both
   polish.js (initCursorGlow) and gsap-polish.js (setupCursorFollower)
   so re-enabling is just three uncomments. */

/* ── Tab-panel mount: bigger crossfade with brief blur so switching feels
   intentional, not jumpy. Composes on top of the existing tab-reveal
   spring keyframe in animations.css. */
.tab-panel.active {
  animation-duration: 0.6s !important;
}
.tab-panel:not(.active) > * {
  filter: blur(0);
}

/* ── Active sidebar row halo: when a tab becomes .active, a quick glow
   ripples out from the left bar. Keyframe runs once each time .active is
   re-applied (i.e. on each tab switch). */
#side-nav-v2 .nav-tab.active {
  animation: sidenav-active-pulse 0.55s cubic-bezier(0.23, 1, 0.32, 1) both !important;
}
@keyframes sidenav-active-pulse {
  0%   { box-shadow:
          inset 1px 0 0 rgba(56, 189, 248, 0.18),
          inset 0 0 0 rgba(56, 189, 248, 0); }
  40%  { box-shadow:
          inset 1px 0 0 rgba(56, 189, 248, 0.50),
          inset 6px 0 30px rgba(56, 189, 248, 0.32),
          0 0 28px rgba(56, 189, 248, 0.18); }
  100% { box-shadow:
          inset 1px 0 0 rgba(56, 189, 248, 0.18),
          inset 0 0 18px rgba(56, 189, 248, 0.06); }
}

/* ── Button shimmer on hover — sweeping highlight across primary buttons.
   Scoped to filled/CTA-looking buttons via class allowlist to avoid lighting
   up every random pill. */
.harvest-submit-btn,
.dash-add-btn,
.auth-hint,
.v2c-button.is-primary,
.btn.primary,
.cta-btn {
  position: relative;
  overflow: hidden;
}
.harvest-submit-btn::before,
.dash-add-btn::before,
.v2c-button.is-primary::before,
.btn.primary::before,
.cta-btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg,
    transparent 35%,
    rgba(255, 255, 255, 0.16) 50%,
    transparent 65%);
  transform: translateX(-120%);
  transition: transform 0.7s cubic-bezier(0.23, 1, 0.32, 1);
  pointer-events: none;
  border-radius: inherit;
}
.harvest-submit-btn:hover::before,
.dash-add-btn:hover::before,
.v2c-button.is-primary:hover::before,
.btn.primary:hover::before,
.cta-btn:hover::before {
  transform: translateX(120%);
}

/* ── Auto-stagger any "row group" — list children get a brief cascade on
   mount via a one-shot animation. data-stagger="N" sets number of children
   to stagger; default 12. JS sets the attribute at scan time. */
[data-stagger-children] > * {
  animation: polish-row-in 0.42s cubic-bezier(0.23, 1, 0.32, 1) both;
}
[data-stagger-children] > *:nth-child(1)  { animation-delay: 0.02s; }
[data-stagger-children] > *:nth-child(2)  { animation-delay: 0.05s; }
[data-stagger-children] > *:nth-child(3)  { animation-delay: 0.08s; }
[data-stagger-children] > *:nth-child(4)  { animation-delay: 0.11s; }
[data-stagger-children] > *:nth-child(5)  { animation-delay: 0.14s; }
[data-stagger-children] > *:nth-child(6)  { animation-delay: 0.17s; }
[data-stagger-children] > *:nth-child(7)  { animation-delay: 0.20s; }
[data-stagger-children] > *:nth-child(8)  { animation-delay: 0.23s; }
[data-stagger-children] > *:nth-child(9)  { animation-delay: 0.26s; }
[data-stagger-children] > *:nth-child(10) { animation-delay: 0.29s; }
[data-stagger-children] > *:nth-child(11) { animation-delay: 0.32s; }
[data-stagger-children] > *:nth-child(12) { animation-delay: 0.35s; }
@keyframes polish-row-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Body bg subtle breathing aurora — replaces the dead-feeling flat bg
   with a slow, drifting two-color radial that adds presence without
   pulling attention. Behind everything (z-index: -1, fixed). */
body::after {
  content: '';
  position: fixed;
  inset: -40%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(45% 35% at 18% 22%, rgba(56, 189, 248, 0.07) 0%, transparent 60%),
    radial-gradient(40% 30% at 78% 78%, rgba(167, 139, 250, 0.06) 0%, transparent 60%),
    radial-gradient(30% 25% at 80% 20%, rgba(45, 212, 191, 0.05) 0%, transparent 60%);
  animation: polish-aurora 22s ease-in-out infinite alternate;
  opacity: 0.85;
}
@keyframes polish-aurora {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
  50%  { transform: translate3d(-3%, 2%, 0) rotate(0.4deg); }
  100% { transform: translate3d(2%, -2%, 0) rotate(-0.4deg); }
}
html[data-theme="light"] body::after {
  background:
    radial-gradient(45% 35% at 18% 22%, rgba(2, 132, 199, 0.05) 0%, transparent 60%),
    radial-gradient(40% 30% at 78% 78%, rgba(79, 70, 229, 0.04) 0%, transparent 60%),
    radial-gradient(30% 25% at 80% 20%, rgba(13, 148, 136, 0.04) 0%, transparent 60%);
}

/* ══════════════════════════════════════════════════════════════════════════
   16. REDUCED MOTION — Emil's rule: keep opacity, drop transforms. The
   global rule in animations.css already kills durations; we add transform:
   none on our additive rules so reduced-motion users get instant snaps.
   ══════════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  button:active,
  .btn:active,
  .nav-tab:active,
  .role-card:active,
  .dept-card:active,
  [role="button"]:active,
  .v2c-button:active,
  .v2-lib-tile:active {
    transform: none !important;
  }
  .live-pill::before,
  .live-indicator::before {
    animation: none !important;
  }
  .nav-logo::after {
    display: none !important;
  }
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
  .dept-card:hover,
  .summary-pill:hover,
  .stat-card:hover,
  .room-card:hover,
  .room-tile:hover {
    transform: none !important;
  }
  body::before,
  body::after {
    animation: none !important;
    display: none !important;
  }
  [data-stagger-children] > * {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  #side-nav-v2 .nav-tab.active {
    animation: none !important;
  }
}
