/* ============================================================================
   19. Vitrine system utilities
   ----------------------------------------------------------------------------
   The signature "Vitrine" vocabulary from the reference platform, added as a
   shared layer the app shell + resource pages consume: the mono micro-label
   (every eyebrow/header/count), the mono-tabular data face (money, counts,
   ids, timestamps), the glass surface grammar (translucent panes vs opaque
   floating chrome), the radius/shadow scales, and the entrance-motion set.
   All opt-in classes — nothing existing re-keys.
   ========================================================================== */

/* ---- 19a. Motion + interaction tokens ----------------------------------- */

:root {
  --ta-ease: cubic-bezier(0.16, 0.84, 0.44, 1);
  --ta-t: 140ms;
  /* The radius scale itself lives in tokens.css, derived from one --ta-radius
     base exactly as the reference derives its --radius-* steps. Only the `md`
     alias belongs here: it names the control step for call sites that read as
     "medium" rather than as "base". */
  --ta-r-md: var(--ta-r);
  /* Real depth: soft, offset, tinted toward the deep field hue so a shadow
     reads as ambient occlusion rather than soot. Every step is two layers — a
     tight contact shadow plus a wide ambient one; one layer alone reads as a
     drop shadow from 2010. Values are the reference's --shadow-* scale. */
  --ta-shadow-xs: 0 1px 2px oklch(0.25 0.02 262 / 0.05);
  --ta-shadow-sm: 0 1px 2px oklch(0.25 0.02 262 / 0.05),
    0 2px 8px -2px oklch(0.25 0.02 262 / 0.06);
  --ta-shadow: 0 2px 4px -1px oklch(0.25 0.02 262 / 0.05),
    0 8px 20px -6px oklch(0.25 0.02 262 / 0.09);
  --ta-shadow-lg: 0 4px 8px -2px oklch(0.25 0.02 262 / 0.06),
    0 16px 40px -12px oklch(0.25 0.02 262 / 0.13);
  --ta-shadow-xl: 0 6px 12px -3px oklch(0.25 0.02 262 / 0.07),
    0 24px 56px -16px oklch(0.25 0.02 262 / 0.17);
  /* Glass surfaces: translucent panes over the ambient field. */
  --ta-glass: oklch(1 0 0 / 0.55);
  --ta-glass-strong: oklch(1 0 0 / 0.72);
  --ta-glass-solid: oklch(0.99 0.002 260 / 0.86);
  --ta-glass-rim: oklch(1 0 0 / 0.65);
  /* Floating chrome (menus, dialogs, sheets) is OPAQUE — reads AT, not
     through the field. */
  --ta-popover: #ffffff;
  /* The tenant wash painted by `hue_brand_style` when an accent hue is set;
     a single radial near the top, never repeated. */
  --ta-wash: rgba(58, 109, 240, 0.08);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --ta-glass: oklch(0.27 0.015 262 / 0.45);
    --ta-glass-strong: oklch(0.27 0.015 262 / 0.62);
    --ta-glass-solid: oklch(0.22 0.012 262 / 0.86);
    --ta-glass-rim: oklch(1 0 0 / 0.13);
    --ta-popover: #1a1e26;
    --ta-wash: rgba(91, 140, 255, 0.12);
    --ta-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --ta-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --ta-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.25);
    --ta-shadow-lg: 0 2px 4px rgba(0, 0, 0, 0.5), 0 18px 40px -14px rgba(0, 0, 0, 0.6);
    --ta-shadow-xl: 0 4px 8px rgba(0, 0, 0, 0.55), 0 32px 72px -18px rgba(0, 0, 0, 0.7);
  }
}

:root[data-theme="dark"] {
  --ta-glass: oklch(0.27 0.015 262 / 0.45);
  --ta-glass-strong: oklch(0.27 0.015 262 / 0.62);
  --ta-glass-solid: oklch(0.22 0.012 262 / 0.86);
  --ta-glass-rim: oklch(1 0 0 / 0.13);
  --ta-popover: #1a1e26;
  --ta-wash: rgba(91, 140, 255, 0.12);
  --ta-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --ta-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --ta-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.25);
  --ta-shadow-lg: 0 2px 4px rgba(0, 0, 0, 0.5), 0 18px 40px -14px rgba(0, 0, 0, 0.6);
  --ta-shadow-xl: 0 4px 8px rgba(0, 0, 0, 0.55), 0 32px 72px -18px rgba(0, 0, 0, 0.7);
}

/* A pinned light theme wins over a dark system. */
:root[data-theme="light"] {
  --ta-glass: oklch(1 0 0 / 0.55);
  --ta-glass-strong: oklch(1 0 0 / 0.72);
  --ta-glass-solid: oklch(0.99 0.002 260 / 0.86);
  --ta-glass-rim: oklch(1 0 0 / 0.65);
  --ta-popover: #ffffff;
  --ta-wash: rgba(58, 109, 240, 0.08);
  --ta-shadow-xs: 0 1px 2px oklch(0.25 0.02 262 / 0.05);
  --ta-shadow-sm: 0 1px 2px oklch(0.25 0.02 262 / 0.05),
    0 2px 8px -2px oklch(0.25 0.02 262 / 0.06);
  --ta-shadow: 0 2px 4px -1px oklch(0.25 0.02 262 / 0.05),
    0 8px 20px -6px oklch(0.25 0.02 262 / 0.09);
  --ta-shadow-lg: 0 4px 8px -2px oklch(0.25 0.02 262 / 0.06),
    0 16px 40px -12px oklch(0.25 0.02 262 / 0.13);
  --ta-shadow-xl: 0 6px 12px -3px oklch(0.25 0.02 262 / 0.07),
    0 24px 56px -16px oklch(0.25 0.02 262 / 0.17);
}

/* The tenant wash joins the ambient field on the fixed page backdrop. */
body {
  background:
    radial-gradient(1200px 620px at 78% -14%, var(--ta-wash), transparent 62%),
    radial-gradient(1100px 620px at 84% -12%, var(--ta-ambient-a), transparent 62%),
    radial-gradient(900px 520px at -8% 24%, var(--ta-ambient-b), transparent 55%),
    radial-gradient(1200px 700px at 50% 112%, var(--ta-ambient-c), transparent 60%),
    var(--ta-bg);
}

/* Landing pages (the public marketing shell) sit on a clean white field —
   the reference look. The ambient wash stays on the in-app shell. Dark mode
   keeps the dark field instead of forcing white, so landing text (which uses
   the same light/dark tokens as everything else) stays readable. */
body:has(> main.spa-landing) {
  background: #fff;
}

@media (prefers-color-scheme: dark) {
  body:has(> main.spa-landing) {
    background: var(--ta-bg);
  }
}

/* ---- 19b. Type signatures ----------------------------------------------- */

/* The reference's single most load-bearing style: 11px mono, uppercase,
   letter-spaced, muted — eyebrows, table headers, section labels, counts. */
.mono-label {
  font-family: var(--ta-mono);
  font-size: 0.6875rem;
  line-height: 1.4;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ta-muted);
  font-weight: 400;
  /* The label often sits directly above a figure it belongs to (a count, a
     timestamp); tabular digits keep the two aligned on the same grid. */
  font-variant-numeric: tabular-nums;
}

/* Mono + tabular figures — money, counts, ids, timestamps. */
.data {
  font-family: var(--ta-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.875rem;
}

.data-lg {
  font-family: var(--ta-mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.5rem;
  font-weight: 500;
}

/* ---- 19c. Glass surfaces ------------------------------------------------ */

.glass-card,
.glass-panel,
.glass-tile {
  background: var(--ta-glass-strong);
  border: 1px solid var(--ta-border);
  border-radius: var(--ta-r-lg);
  box-shadow: inset 0 1px 0 var(--ta-glass-rim), var(--ta-shadow-sm);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
}

.glass-card {
  padding: 1.25rem;
}

/* The shared Card primitive (`data-slot="card"`, components/ui/card.tsx) wears
   the same pane material from here — the `bg-card` utility supplies the fill,
   this rule adds what no utility sets: the blur, the rim, the lift. Mirrors
   the reference's `[data-slot="card"]` rule in app.css. PARITY B14. */
[data-slot="card"] {
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
  box-shadow: inset 0 1px 0 var(--ta-glass-rim), var(--ta-shadow-sm);
}

/* Nested glass steps down to a flat surface — no blur on blur. */
.glass-card .glass-card,
.glass-panel .glass-panel,
.glass-card [data-slot="card"],
[data-slot="card"] [data-slot="card"] {
  background: var(--ta-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
}

/* Floating chrome: opaque, reads AT the field. */
.glass-overlay {
  background: var(--ta-popover);
  border: 1px solid var(--ta-border);
  border-radius: var(--ta-r-lg);
  box-shadow: inset 0 1px 0 var(--ta-glass-rim), var(--ta-shadow-lg);
}

/* ---- 19d. Entrance motion ----------------------------------------------- */

/* Pure CSS entrance set, staggered by `--enter-i` (set inline per element or
   via the `.enter-stack` nth-child cascade below). An item's beat is its index
   times `--enter-step`; timing is the Instrument load — 560ms on the system
   curve, ~70ms apart in reading order, settled by ~1.2s. Slow enough to read
   as settling, fast enough to feel alive. Reduced motion collapses every one
   to a still frame. */

.enter-rise,
.enter-fade,
.enter-pop,
.enter-slide,
.enter-stack>* {
  animation-duration: var(--enter-dur, 560ms);
  animation-timing-function: var(--enter-ease, var(--ta-ease));
  /* `backwards`, not `both`: every `to` frame below IS the element's natural
     resting style, so forwards-filling buys nothing and costs a lot — a
     filling `transform: none` computes to the identity matrix, which makes
     the element a containing block for `position: fixed` descendants for the
     rest of the page's life. That silently trapped the create slide-over
     inside its table card (and would trap any fixed overlay in an entering
     block). Backwards still holds the `from` frame through the stagger
     delay, so the entrance is unchanged. */
  animation-fill-mode: backwards;
  animation-delay: calc(var(--enter-i, 0) * var(--enter-step, 70ms));
}

.enter-rise {
  animation-name: enter-rise;
}

.enter-fade {
  animation-name: enter-fade;
}

.enter-pop {
  animation-name: enter-pop;
}

.enter-slide {
  animation-name: enter-slide;
}

/* Container cascade: children of `.enter-stack` rise one after the other with
   no per-child wiring — use it when the container's children ARE the list (a
   page's block stack, a nav group). Past the twelfth child the delay stops
   growing so a long page still arrives in one gesture. `:where()` zeroes the
   specificity so a child that names its own motion keeps it. */
:where(.enter-stack)>* {
  animation-name: enter-rise;
}

/* Navbars are global chrome, not content: they stay put while the content
   below cascades in (matches old/, where the topbar never animates). */
.enter-stack>nav {
  animation: none;
}

.enter-stack>*:nth-child(1) {
  --enter-i: 0;
}

.enter-stack>*:nth-child(2) {
  --enter-i: 1;
}

.enter-stack>*:nth-child(3) {
  --enter-i: 2;
}

.enter-stack>*:nth-child(4) {
  --enter-i: 3;
}

.enter-stack>*:nth-child(5) {
  --enter-i: 4;
}

.enter-stack>*:nth-child(6) {
  --enter-i: 5;
}

.enter-stack>*:nth-child(7) {
  --enter-i: 6;
}

.enter-stack>*:nth-child(8) {
  --enter-i: 7;
}

.enter-stack>*:nth-child(9) {
  --enter-i: 8;
}

.enter-stack>*:nth-child(10) {
  --enter-i: 9;
}

.enter-stack>*:nth-child(11) {
  --enter-i: 10;
}

.enter-stack>*:nth-child(n + 12) {
  --enter-i: 11;
}

@keyframes enter-rise {
  from {
    opacity: 0;
    transform: translateY(6px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes enter-fade {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes enter-pop {
  from {
    opacity: 0;
    transform: scale(0.96);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes enter-slide {
  from {
    opacity: 0;
    transform: translateX(-8px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {

  .enter-rise,
  .enter-fade,
  .enter-pop,
  .enter-slide,
  .enter-stack>* {
    animation-duration: 0.01ms;
    animation-delay: 0ms;
  }
}