/* === INTERACTION DESIGN TOKENS === */
/* Animation, timing, and micro-interaction tokens */

:root {
  /* Timing Functions */
  --blocks-duration-instant: 75ms;
  --blocks-duration-fast: 150ms;
  --blocks-duration-normal: 250ms;
  --blocks-duration-slow: 350ms;
  --blocks-duration-slower: 500ms;
  --blocks-duration-slowest: 750ms;

  /* Custom Easing Functions */
  --blocks-ease-linear: linear;
  --blocks-ease-gentle: cubic-bezier(0.25, 0.1, 0.25, 1);
  --blocks-ease-springy: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  --blocks-ease-confident: cubic-bezier(0.4, 0, 0.2, 1);
  --blocks-ease-bounce: cubic-bezier(0.68, -0.6, 0.32, 1.6);
  --blocks-ease-smooth: cubic-bezier(0.4, 0, 0.6, 1);
  --blocks-ease-snappy: cubic-bezier(0.4, 0, 0.2, 1);

  /* Shadow scale, republished from the semantic layer. This block is a
     MECHANISM, not a mirror of `semantic.css` — it does two things nothing
     else does, and deleting it costs a step:

     1. Tailwind tree-shakes `@theme`: it emits a key only where something
        READS it, and a declaration is not a read. Scan the shipped `dist` with
        Tailwind's own Scanner and the library's markup references xs, sm, md
        and lg — `base` not once. Without these five lines a consumer's `:root`
        carries no `--blocks-shadow-base` at all.
     2. Each `var()` below IS that read, so declaring the alias is what keeps
        the theme key alive in the first place.

     Plain `:root`, so all five are unconditional; the `@media print` reset far
     below stays unlayered and therefore beats both this block and a consumer's
     own `@theme` override. That last part cuts both ways: a consumer who reads
     `--blocks-shadow-md` in their markup and then overrides *that* name in
     their own `@theme` gets silence, because this unlayered block wins. The
     name to override is the scale key, which is what MIGRATION.md and the CSS
     reference both name. */
  --blocks-shadow-xs: var(--blocks-shadow-scale-xs);
  --blocks-shadow-sm: var(--blocks-shadow-scale-sm);
  --blocks-shadow-base: var(--blocks-shadow-scale-base);
  --blocks-shadow-md: var(--blocks-shadow-scale-md);
  --blocks-shadow-lg: var(--blocks-shadow-scale-lg);

  /* Focus Ring */
  --blocks-focus-ring-width: 2px;
  --blocks-focus-ring-offset: 2px;
  --blocks-focus-ring-color: var(--color-primary);
  --blocks-focus-ring: 0 0 0 var(--blocks-focus-ring-width) var(--blocks-focus-ring-color);
  --blocks-focus-ring-inset: inset 0 0 0 var(--blocks-focus-ring-width)
    var(--blocks-focus-ring-color);

  /* Guide highlight (Direction B — D5). The additive ring colour the engine's
     `[data-guide-highlight]` rule (in index.css) paints around a target when a
     `GuideMention` is hovered/focused. Additive `outline` + soft glow, never a
     scrim. Override per app via a `BlocksProvider` style block. */
  --blocks-guide-highlight-ring: var(--color-primary);

  /* Guide spotlight scrim (Phase 6 — D5). The *subtractive* dim the guided
     `Guide` tour paints around the cut-out hole over the active step's target.
     This is the one place the Guide system darkens the surroundings — the
     non-modal Panel/Mention link never does. Mirrors the Dialog backdrop
     (black 50%); override per app via a `BlocksProvider` style block. */
  --blocks-guide-scrim: oklch(0 0 0 / 0.5);

  /* === PRESS CUE (#192) ===
     How far a surface sinks under the pointer while it is held. Four controls
     read it — Button (`active:` and the modelled `pressed` state), Badge's
     remove control, and the Drawer / Dialog close buttons, which are the same
     ghost-Button fold — so a brand retunes that family in one place.

     A token rather than a literal because it is also the only place the sink
     can be switched off without a second, competing declaration: reduced motion
     flattens it to 1 below (the way `--blocks-overlay-panel-scale-start` already
     does for panels), and Button rewrites it to 1 on itself when its `mint` is
     off. Setting it to `1` removes the movement while leaving the paired shadow
     step to report the press.

     Deliberately NOT every `active:scale-*` in the library: the interactive
     Badge and Avatar press to 0.95 and a Table row to 0.995, which are their own
     gestures at their own depths, not this one retuned. Those are literals and
     stay unswitchable until someone gives them tokens of their own. */
  --blocks-press-scale: 0.98;

  /* Transition preset. The lone survivor of a family of unused presets
     (base/transform/shadow/opacity, interaction-*, delay-*, stagger-*) —
     packages/table reads this one. */
  --blocks-transition-colors:
    background-color var(--blocks-duration-fast) var(--blocks-ease-gentle),
    border-color var(--blocks-duration-fast) var(--blocks-ease-gentle),
    color var(--blocks-duration-fast) var(--blocks-ease-gentle);

  /* === OVERLAY ANIMATION TOKENS (XC-11) ===
     Shared enter/exit motion for the panel overlays: Dialog, Drawer,
     ConfirmDialog (via Dialog) and Toast. All four drive Svelte `fly`/`scale`
     transitions, so they read these through the JS mirror in
     `utils/overlay-tokens.ts` (`getOverlayMotion`) — Svelte transitions need
     numeric input. Tooltip runs a deliberately faster CSS opacity fade off its
     own `--blocks-tooltip-*` tokens below; Popover (and Menu through it) runs a
     CSS-native fade/scale off the `--blocks-popover-*` tokens below.

     Override globally with a `BlocksProvider` style block, or per instance via
     the component's `transitionDuration` / `transitionEasing` props.
     `prefers-reduced-motion` below collapses both enter and exit to 1ms and
     removes scale/fly distance — kept in one place so motion reduction is
     consistent across every overlay. */
  --blocks-overlay-enter-duration: 200ms;
  --blocks-overlay-exit-duration: 180ms;
  --blocks-overlay-backdrop-enter-duration: 200ms;
  --blocks-overlay-backdrop-exit-duration: 180ms;
  --blocks-overlay-easing: cubic-bezier(0.83, 0, 0.17, 1); /* quintOut */
  --blocks-overlay-panel-scale-start: 0.96;
  --blocks-overlay-panel-fly-distance: 320px;
  /* 8px, not the 4px this said until 2026-08-18: the token had no readers at all
     while Dialog, Drawer and Sidebar hardcoded `backdrop-blur-sm`, which Tailwind 4
     resolves to 8px. The declared value was never what shipped, so wiring the
     backdrops to the token had to follow the rendering rather than change it. */
  --blocks-overlay-backdrop-blur: 8px;

  /* === TOOLTIP FADE TOKENS (ACC-3 follow-up) ===
     The CSS opacity fade shared by the hover/focus tooltip. Deliberately faster
     than the panel overlays above — a hint should feel instant, not staged — so
     it defaults to the `fast` duration (150ms) + the `confident` easing. That
     easing token is `cubic-bezier(0.4,0,0.2,1)` — exactly Tailwind's implicit
     transition curve, which the fade used before it carried an explicit `ease-*`
     class — so the resting fade is unchanged. Defaulting the duration through
     `--blocks-duration-fast` means `prefers-reduced-motion` below collapses it
     to 1ms for free. Override globally here, or per instance via Tooltip's
     `transitionDuration` / `transitionEasing` props (which set these inline +
     carry a `motion-reduce` guard, since an inline duration can't see the media
     query). */
  --blocks-tooltip-duration: var(--blocks-duration-fast);
  --blocks-tooltip-easing: var(--blocks-ease-confident);

  /* === POPOVER MOTION TOKENS (ACC-3 rest) ===
     The CSS-native enter/exit fade+scale for Popover (and Menu, which passes
     the same motion fragment to its inner Popover). Anchored panels should
     feel snappier than the 200ms modal overlays but calmer than an instant
     toggle, so they share the tooltip's `fast`/`confident` pairing. Enter is
     driven by `@starting-style` (the panel un-hides via `showPopover()`, so a
     plain transition has no before-state); exit relies on
     `transition-behavior: allow-discrete` on `display`/`overlay` to keep the
     panel painted in the top layer while it fades. Both default through
     `--blocks-duration-fast`, so `prefers-reduced-motion` below collapses them
     to 1ms for free. Override globally here, or per instance via Popover's
     `transitionDuration` / `transitionEasing` props (which set these inline +
     carry a `motion-reduce` guard, since an inline duration can't see the
     media query). */
  --blocks-popover-duration: var(--blocks-duration-fast);
  --blocks-popover-easing: var(--blocks-ease-confident);

  /* === COLLAPSE ANIMATION TOKENS (ACC-3) ===
     The CSS-driven grid-template-rows collapse shared by Accordion +
     Collapsible (and their chevron spin). Default to the normal/smooth
     tokens — so `prefers-reduced-motion` below collapses them to 1ms via
     the inherited `--blocks-duration-normal`. Override globally here, or per
     instance via the component's `transitionDuration` / `transitionEasing`
     props (which set these variables inline + carry a `motion-reduce` guard,
     since an inline duration can't see the media query). */
  --blocks-collapse-duration: var(--blocks-duration-normal);
  --blocks-collapse-easing: var(--blocks-ease-smooth);
}

/* ===== TOUCH DEVICE ADAPTATIONS ===== */
@media (pointer: coarse) {
  :root {
    --blocks-touch-target-min: 2.75rem; /* 44px – WCAG 2.5.5 AAA */
    --blocks-touch-spacing: 0.5rem; /* 8px extra gap between targets */
  }
}

@media (pointer: fine) {
  :root {
    /* `0px`, not `0`: a math function rejects the unitless zero, so
       `max(1rem, var(--blocks-touch-target-min))` dropped the whole declaration
       on every fine pointer — measured in Chromium and WebKit. With the unit,
       the same expression yields the 1rem floor there and the touch floor on a
       coarse pointer, which is what a consumer computing a column width or an
       indent from these tokens needs. */
    --blocks-touch-target-min: 0px;
    --blocks-touch-spacing: 0px;
  }
}

/* ===== REDUCED MOTION SUPPORT ===== */
@media (prefers-reduced-motion: reduce) {
  :root {
    /* Reduce all animation durations */
    --blocks-duration-instant: 1ms;
    --blocks-duration-fast: 1ms;
    --blocks-duration-normal: 1ms;
    --blocks-duration-slow: 1ms;
    --blocks-duration-slower: 1ms;
    --blocks-duration-slowest: 1ms;

    /* Collapse overlay enter/exit motion (XC-11) */
    --blocks-overlay-enter-duration: 1ms;
    --blocks-overlay-exit-duration: 1ms;
    --blocks-overlay-backdrop-enter-duration: 1ms;
    --blocks-overlay-backdrop-exit-duration: 1ms;
    --blocks-overlay-panel-scale-start: 1;
    --blocks-overlay-panel-fly-distance: 0px;

    /* Take the sink out of the press cue (#192). The durations above already
       collapse to 1ms, which only makes the movement instant — this removes it.
       The paired shadow step still reports the press. */
    --blocks-press-scale: 1;
  }
}

/* ===== HIGH CONTRAST MODE ===== */
@media (prefers-contrast: more) {
  :root {
    /* Increase contrast ratios — overrides the semantic tokens that
       components actually consume. */
    --color-text-secondary: var(--color-text-primary);
    --color-border-default: var(--color-text-primary);
    --color-border-subtle: var(--color-text-primary);

    /* Make focus indicators more prominent */
    --blocks-focus-ring-width: 3px;
    --blocks-focus-ring-color: var(--color-text-primary);
  }
}

/* ===== PRINT STYLES ===== */
@media print {
  :root {
    /* Optimize for print — overrides the semantic tokens that components
       actually consume. */
    --color-surface-base: white;
    --color-surface-quiet: white;
    --color-surface-elevated: white;
    --color-text-primary: black;
    --color-text-secondary: #333;
    /* Print forces the surfaces white regardless of colour scheme, so every
       intent text role must sit on its LIGHT stop — a page printed from dark
       mode otherwise puts the light-on-dark stops on white paper (measured:
       danger at 2.42:1). Pinned to the stops semantic.css gives the light
       branch, spelled as var() so themes keep re-tinting them. */
    --color-primary-text: var(--color-primary-700);
    --color-secondary-text: var(--color-secondary-600);
    --color-success-text: var(--color-success-600);
    --color-warning-text: var(--color-warning-800);
    --color-danger-text: var(--color-danger-500);
    --color-info-text: var(--color-info-600);
    --color-border-default: #000;
    /* hairline at 8 % alpha disappears under most print drivers — promote
       to a real grey rule for structural trennlinien (rows, dividers). */
    --color-border-hairline: #999;

    /* Remove shadows and effects. UNLAYERED, which is what makes it win: an
       unlayered rule outranks every `@layer` whatever the source order, so
       this beats both the `@theme` block and a consumer's own override of
       the same step. */
    --blocks-shadow-xs: none;
    --blocks-shadow-sm: none;
    --blocks-shadow-base: none;
    --blocks-shadow-md: none;
    --blocks-shadow-lg: none;
  }
}

/* Scroller `emphasis` — lifts whichever item currently sits in the middle of
   the scrollport. Driven by `animation-timeline: view(inline)` (applied by
   scroller.variants.ts), so "50%" is a POSITION, not a moment in time: the
   item is halfway through the scrollport. Nothing here runs on a clock.

   Only the midpoint is declared; 0% and 100% are implicit keyframes taken from
   the element itself, so an item keeps its own resting scale and shadow at the
   edges. Both values are retunable per instance without widening the component
   API (the Tooltip convention).

   Kept small on purpose (plan §3.7 condition 2): anything beyond ~1.05 wobbles
   while scrolling and pulls attention away from reading. `prefers-reduced-motion`
   is handled at the utility (`motion-reduce:[&>*]:[animation:none]`) rather than
   here — dropping only the timeline would hand the animation back to the
   document clock, which is the opposite of what reduced motion asks for. */
@keyframes blocks-scroller-emphasis {
  50% {
    scale: var(--blocks-scroller-emphasis-scale, 1.04);
    box-shadow: var(--blocks-scroller-emphasis-shadow, var(--blocks-shadow-md));
  }
}
