/*
 * @kungal/ui-tokens — KunUI design tokens (framework-agnostic).
 *
 * This file is the single source of truth for KunUI's visual language:
 * the semantic color scales, the radius buckets, the z-index layering,
 * and the animation keyframes. It contains ZERO framework code and ZERO
 * component classes — it is pure CSS custom properties + Tailwind v4
 * `@theme` declarations, so it can be consumed identically by a Vue app,
 * a React app, or plain HTML.
 *
 * USAGE — import it AFTER Tailwind in your app's entry stylesheet:
 *
 *   @import 'tailwindcss';
 *   @import '@kungal/ui-tokens/css';            // this file
 *   @source '../node_modules/@kungal/ui-vue';  // scan whichever KunUI render
 *                                            // layer you use (vue/react)
 *
 * Deliberately NOT included here (they are consumer-/package-specific):
 *   - `@import 'tailwindcss'`  → the consuming app owns its Tailwind import
 *   - `@source` directives     → each render-layer package declares its own
 */

@custom-variant dark (&:is(.kun-dark-mode *));

/* Semantic color palette — generated (OKLCH, contrast-verified). See
 * scripts/gen-tokens.mjs. Imported here so its @theme + @layer base merge in. */
@import './palette.generated.css';

:root {
  /* Global alpha applied to "glassy" semantic surfaces (background +
   * default-100). Lower = more see-through. Apps may override in :root. */
  --kun-global-opacity: 0.7;

  /* Opacity of the RAISED surface (`content1`) — cards, popovers, dropdowns,
   * inputs, modal, drawer. Default 1 = fully opaque (the clean elevation look).
   * A site with a background image (e.g. a galgame page) can make every surface
   * frosted at once by lowering this and adding a blur, with NO component changes:
   *   :root { --kun-surface-opacity: 0.7; --kun-backdrop-filter: blur(12px); }
   * (Surfaces ship `backdrop-filter: none` by default — set --kun-backdrop-filter
   * to opt into true frosted glass rather than plain see-through.) */
  --kun-surface-opacity: 1;

  /* Backdrop-filter for raised glass surfaces (Card / Modal), consumed via the
   * `kun-backdrop` utility. Default `none` so NO backdrop-filter is emitted:
   * backdrop-filter: blur() is the #1 cause of mobile scroll jank, and at the
   * default opaque / zero-blur it produced no visual effect anyway. A glass site
   * opts in for every surface at once, e.g. `--kun-backdrop-filter: blur(12px)`
   * (pair with a lowered --kun-surface-opacity). */
  --kun-backdrop-filter: none;

  /* The code face: `.kun-prose code` and `kbd`. kun_ui_tokens carries it as
   * KunFontFamilies.mono, so an app sets code in the same stack. */
  --kun-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
}

/* Opt-in frosted-glass backdrop for raised surfaces. At the default `none` it
 * emits `backdrop-filter: none` (free — no compositing layer, no blur pass);
 * set --kun-backdrop-filter to enable glass on every surface that uses it. */
@utility kun-backdrop {
  -webkit-backdrop-filter: var(--kun-backdrop-filter, none);
  backdrop-filter: var(--kun-backdrop-filter, none);
}

@theme {
  --color-black: #000;
  --color-white: #fff;

  /* Border radius — 5 buckets every KunUI component references.
   *
   * Each scalable bucket multiplies its base by --kun-radius-scale (default 1),
   * so a single RUNTIME knob drives every KunUI corner at once, live and with no
   * re-render:
   *   :root { --kun-radius-scale: 0 }     → square corners everywhere
   *   :root { --kun-radius-scale: 1.5 }   → 50% rounder everywhere
   * This is the robust override path: --kun-radius-scale is a NEW consumer-owned
   * variable the calc() reads, so it never fights Tailwind's own :root
   * --radius-kun-* declarations (those win the cascade if you try to override
   * them directly, which is the usual "my :root override does nothing" trap).
   * `none` and `full` deliberately don't scale — a square stays square, a pill
   * stays a pill.
   *
   * Tailwind v4 @theme auto-generates rounded-kun-none / -sm / -md / -lg / -full;
   * the framework-agnostic class map lives in @kungal/ui-core (kunRoundedClasses). */
  --radius-kun-none: 0;
  --radius-kun-sm: calc(0.375rem * var(--kun-radius-scale, 1)); /* 6px  */
  --radius-kun-md: calc(0.75rem * var(--kun-radius-scale, 1)); /* 12px — HeroUI-style default control radius */
  --radius-kun-lg: calc(1rem * var(--kun-radius-scale, 1)); /* 16px — containers / floating panels */
  --radius-kun-full: 9999px;

  /* z-index layering — floating UI must stack predictably so a popover
   * opened inside a modal (or from a sticky topbar) is always visible.
   * Tier rule: a floating element always sits above the layer that
   * triggered it.  sticky < modal < popover < alert < message.
   * The band sits very high (9000+) to win against app-side legacy
   * headers that use z-50/100/9999. */
  --z-kun-sticky: 30;
  --z-kun-modal: 9000;
  --z-kun-popover: 9300;
  --z-kun-alert: 9700;
  --z-kun-message: 9999;

  /* Motion — one easing set + duration scale so every component shares a
   * rhythm. Asymmetric by design: decelerate on enter, accelerate on exit
   * (ease in as it arrives, snap away as it leaves). Curves from Material 3;
   * `emphasized` is the snappy "premium settle" (Radix/Vaul). The --ease-kun-*
   * names also generate Tailwind `ease-kun-*` utilities. */
  --ease-kun-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-kun-out: cubic-bezier(0, 0, 0, 1); /* enter / decelerate */
  --ease-kun-in: cubic-bezier(0.3, 0, 1, 1); /* exit / accelerate */
  --ease-kun-emphasized: cubic-bezier(0.16, 1, 0.3, 1);
  --kun-dur-fast: 150ms; /* hover, selection, micro-interactions */
  --kun-dur-base: 250ms; /* component enter / in-screen transitions */
  --kun-dur-slow: 350ms; /* larger surfaces */
  --kun-dur-exit: 180ms; /* exits run ~30% shorter than enters */

  /* Elevation scale — ONE shadow per tier so every floating surface of the same
   * kind shares an elevation instead of picking shadow-md/lg/2xl ad hoc. These
   * are a Tailwind `--shadow-*` namespace, so `shadow-kun-sm|md|lg` utilities are
   * generated and compose with `ring-*` (both feed --tw-shadow). Tiers:
   *   sm → tooltips / small hints
   *   md → popovers, dropdowns, menus, select & date lists, toasts
   *   lg → modals, drawers (the highest surfaces) */
  --shadow-kun-sm: 0 1px 5px -2px rgb(0 0 0 / 0.08);
  --shadow-kun-md:
    0 3px 10px -4px rgb(0 0 0 / 0.07), 0 6px 18px -6px rgb(0 0 0 / 0.1);
  --shadow-kun-lg:
    0 6px 18px -8px rgb(0 0 0 / 0.11), 0 12px 36px -12px rgb(0 0 0 / 0.16);

  /* Animations */
  --animate-shake: shake 1s ease-in-out;
  --animate-bounceInDown: bounceInDown 1s ease-in-out;
  --animate-tada: tada 1s ease-in-out;
  --animate-bounce: bounce 1s ease-in-out;
  --animate-fadeInUp: fadeInUp 0.5s ease-in-out;
  --animate-fadeOutDown: fadeOutDown 0.5s ease-in-out;
  --animate-swing: swing 1s ease-in-out;
  --animate-bounceInRight: bounceInRight 0.5s ease-in-out;

  @keyframes shake {
    0%,
    100% {
      transform: translateX(0);
    }
    6% {
      transform: translateX(-6px) rotateY(-9deg);
    }
    18% {
      transform: translateX(5px) rotateY(7deg);
    }
    31% {
      transform: translateX(-3px) rotateY(-5deg);
    }
    43% {
      transform: translateX(2px) rotateY(3deg);
    }
    50% {
      transform: translateX(0);
    }
  }

  @keyframes bounceInDown {
    0% {
      opacity: 0;
      transform: translateY(-500px);
    }
    60% {
      opacity: 1;
      transform: translateY(30px);
    }
    80% {
      transform: translateY(-10px);
    }
    100% {
      transform: translateY(0);
    }
  }

  @keyframes tada {
    0% {
      transform: scale(1);
    }
    10%,
    20% {
      transform: scale(0.9) rotate(-3deg);
    }
    30%,
    50%,
    70%,
    90% {
      transform: scale(1.1) rotate(3deg);
    }
    40%,
    60%,
    80% {
      transform: scale(1.1) rotate(-3deg);
    }
    100% {
      transform: scale(1) rotate(0);
    }
  }

  @keyframes bounce {
    0%,
    20%,
    50%,
    80%,
    100% {
      transform: translateY(0);
    }
    40% {
      transform: translateY(-30px);
    }
    60% {
      transform: translateY(-15px);
    }
  }

  /* animate.css: https://github.com/animate-css/animate.css */
  @keyframes fadeInUp {
    from {
      opacity: 0;
      transform: translate3d(0, 100%, 0);
    }
    to {
      opacity: 1;
      transform: translate3d(0, 0, 0);
    }
  }

  @keyframes fadeOutDown {
    from {
      opacity: 1;
    }
    to {
      opacity: 0;
      transform: translate3d(0, 100%, 0);
    }
  }

  @keyframes swing {
    20% {
      transform: rotate3d(0, 0, 1, 15deg);
    }
    40% {
      transform: rotate3d(0, 0, 1, -10deg);
    }
    60% {
      transform: rotate3d(0, 0, 1, 5deg);
    }
    80% {
      transform: rotate3d(0, 0, 1, -5deg);
    }
    to {
      transform: rotate3d(0, 0, 1, 0deg);
    }
  }

  @keyframes bounceInRight {
    from,
    60%,
    75%,
    90%,
    to {
      animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    }
    from {
      opacity: 0;
      transform: translate3d(3000px, 0, 0) scaleX(3);
    }
    60% {
      opacity: 1;
      transform: translate3d(-25px, 0, 0) scaleX(1);
    }
    75% {
      transform: translate3d(10px, 0, 0) scaleX(0.98);
    }
    90% {
      transform: translate3d(-5px, 0, 0) scaleX(0.995);
    }
    to {
      transform: translate3d(0, 0, 0);
    }
  }
}

/* Explicit z-index utilities — Tailwind v4's @theme auto-generation does
 * NOT cover the --z-* namespace (only --color / --radius / --spacing /
 * --font etc.), so `class="z-kun-popover"` silently no-ops without these
 * @utility blocks. They are the load-bearing piece of the z-index system,
 * not the @theme declarations above.
 *
 * Each value derefs the @theme variable (so a consumer's
 * `:root { --z-kun-modal: ... }` override still propagates) WITH a literal
 * fallback. The fallback is load-bearing, NOT cosmetic: Tailwind v4 only emits
 * a @theme variable to :root when its tree-shaker considers it "used", and a
 * custom @utility referencing the var does not reliably count as usage across
 * consumer builds/versions. When it's dropped, `z-index: var(--z-kun-popover)`
 * resolves to var(<undefined>) → no z-index → the layer stacks at `auto` and
 * gets covered by any positioned element (carousels, sticky headers, …). The
 * fallback guarantees a real z-index even when the variable never reaches
 * :root. Keep the fallbacks in sync with the @theme declarations above. */
@utility z-kun-sticky {
  z-index: var(--z-kun-sticky, 30);
}
@utility z-kun-modal {
  z-index: var(--z-kun-modal, 9000);
}
@utility z-kun-popover {
  z-index: var(--z-kun-popover, 9300);
}
@utility z-kun-alert {
  z-index: var(--z-kun-alert, 9700);
}
@utility z-kun-message {
  z-index: var(--z-kun-message, 9999);
}

/* How much viewport width an open overlay took away when it hid the page
 * scrollbar. `useBodyScrollLock` writes the live value onto <html> while a
 * Modal/Drawer/Lightbox/CommandPalette is open and removes it on close; this
 * declaration is the unlocked resting value so a consumer never has to reason
 * about the variable being absent.
 *
 * It is 0 whenever nothing was actually removed — overlay scrollbars, or a page
 * that reserves its own `scrollbar-gutter: stable`. Otherwise it is the
 * scrollbar width, and the initial containing block really did grow, so a
 * `position: fixed` element that is right-anchored or centred needs it. Apply
 * it as a MARGIN, not folded into the anchor: an invalid var() substitution
 * makes the whole declaration invalid at computed-value time, and a dropped
 * margin merely loses the compensation where a dropped `left` sends the element
 * to its static position.
 *
 *   margin-right: var(--kun-scrollbar-width, 0px);
 *
 * Plain :root + a literal fallback at every use, same reasoning as the z-index
 * and border blocks: a @theme variable can be tree-shaken out of a consumer's
 * build. */
:root {
  --kun-scrollbar-width: 0px;
}

/* Canonical neutral border — the SINGLE source of truth for every structural
 * hairline (inputs, cards, dividers, popovers, tabs, tables…). Defaults to the
 * `default-100` step — a very light hairline that just delineates a surface
 * without framing it — which already flips light↔dark, so one utility stays
 * consistent across modes AND
 * components — no more per-component `border-default/20` + `dark:border-…`
 * juggling that only coincidentally matched. Retheme every border at once by
 * overriding `--color-kun-border` (set it in `.kun-dark-mode` too if you give
 * it a fixed, non-flipping value). Plain :root + literal fallback on the
 * utility → never tree-shaken (same reasoning as the z-index / motion blocks).
 *
 * `border-kun` sets border-COLOR only; pair it with a width class
 * (`border` / `border-b` / `border-t` / `border-l`). Conditional `border-danger-*`
 * / `focus:border-*` still win (apply `border-kun` only in the non-error branch
 * so two plain border-color utilities never fight over source order). */
:root {
  --color-kun-border: oklch(var(--default-100));
}
@utility border-kun {
  border-color: var(--color-kun-border, oklch(var(--default-100)));
}

/* Duration utilities bound to the motion scale, so component transitions route
 * through the same `--kun-dur-*` tokens as the overlay enter/leave animations
 * instead of hardcoding `duration-150/200/300`. Literal fallback (the var is
 * mirrored to :root below) keeps them robust if the token is ever tree-shaken.
 * Tiers: fast = hover/selection/micro; base = component enter; exit = leave
 * (asymmetric, ~30% shorter); slow = larger surfaces / fades. */
@utility duration-kun-fast {
  transition-duration: var(--kun-dur-fast, 150ms);
}
@utility duration-kun-base {
  transition-duration: var(--kun-dur-base, 250ms);
}
@utility duration-kun-slow {
  transition-duration: var(--kun-dur-slow, 350ms);
}
@utility duration-kun-exit {
  transition-duration: var(--kun-dur-exit, 180ms);
}

/* Motion tokens, mirrored into a plain :root so they ALWAYS reach the document.
 *
 * Exact same tree-shaking trap as the z-index fallbacks above: Tailwind v4 only
 * emits an @theme variable to :root when its scanner sees it "used", and these
 * are read ONLY via `var(--kun-dur-base)` / `var(--ease-kun-out)` inside
 * component <style> blocks and inline styles — which Tailwind never scans. The
 * duration tokens have no utility namespace at all, so @theme drops every one
 * of them in a normal consumer build; the component transitions then resolve to
 * `var(<undefined>)`, the whole `transition` shorthand is invalidated, and the
 * Modal / Drawer / FadeCard / Tab-indicator / toast animations silently vanish.
 * This plain :root (not @theme → never tree-shaken) guarantees a real value in
 * every build. The easings are ALSO kept in @theme above — that is what
 * generates the `ease-kun-*` utilities — so keep the two lists in sync. */
:root {
  --ease-kun-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-kun-out: cubic-bezier(0, 0, 0, 1);
  --ease-kun-in: cubic-bezier(0.3, 0, 1, 1);
  --ease-kun-emphasized: cubic-bezier(0.16, 1, 0.3, 1);
  --kun-dur-fast: 150ms;
  --kun-dur-base: 250ms;
  --kun-dur-slow: 350ms;
  --kun-dur-exit: 180ms;
}

