/* GENERATED by scripts/build-tokens.mjs from tokens/*.json — DO NOT EDIT.
   Source of truth: tokens/primitives.json + semantic.json + component.json (DTCG).
   Byte-identical to the shipped v2.3.2 values (golden: tokens/manifest.golden.json). */
/* @abrq/ui theme layer — for host apps that already run Tailwind v4.
   Import order:  @import "tailwindcss";  @import "@abrq/ui/tokens.css";
                  @import "@abrq/ui/theme.css";
   Does NOT import Tailwind or fonts, does NOT set body bg/color/font. */

@theme inline {
  --color-bg: var(--bg);
  --color-surface: var(--surface);
  --color-surface-2: var(--surface-2);
  --color-border: var(--border);
  --color-ink: var(--ink);
  --color-muted: var(--muted);
  --color-primary: var(--primary);
  --color-primary-ink: var(--primary-ink);
  --color-primary-soft: var(--primary-soft);
  --color-accent: var(--accent);
  --color-accent-soft: var(--accent-soft);
  --color-signal: var(--signal);
  --color-warn: var(--warn);
  --color-warn-soft: var(--warn-soft);
  --color-error: var(--error);
  --color-error-soft: var(--error-soft);
  --color-ring: var(--ring);
  --color-skeleton-veil: var(--skeleton-veil);
}
/* tokens/theme.static.css — the hand-authored (non-token) layer appended to the
   generated theme.css by scripts/build-tokens.mjs.

   GOVERNANCE (E3 line-by-line audit, 2026-07-05; E4 motion pass, 2026-07-07):
   - Typography metrics that used to live here as raw literals (label voice,
     tabular numerals, dense-tier sizes) were migrated to the DTCG source in E3
     — this file may reference tokens, never define values the tokens own.
   - The motion/signature values E3 tagged for tokenization (signature durations
     0.4s/1.4s, shimmer easing + veil, Morse rhythm geometry) were migrated to the
     DTCG source in E4 at parity: they now resolve from the --motion-, --ease-,
     --morse-rule- and --skeleton-veil tokens. Zero `disposition:` tags remain —
     the file is fully token-referencing. check-token-purity.sh scans it (no raw hex).
     The lone deliberate literal is the reduced-motion 0.01ms a11y tick, which is
     an event-timing constant, not a design value (see the reduced-motion block). */

/* Colours only — they map a Tailwind key (--color-X) to a distinct token (--X), so no
   self-reference. `inline` is REQUIRED: plain @theme would freeze --color-X: var(--X) at
   :root, so a NESTED re-theme scope (.abrq-invert inside a light page) silently renders
   light — utilities must inline var(--X) so it resolves per element. (Root-level dark
   theming happened to work without it only because [data-theme="dark"] — or the legacy
   `.dark` consumer alias — sits on <html> = :root.)
   Radii/shadows/fonts are consumed in components via arbitrary values
   (e.g. rounded-[var(--radius-lg)], shadow-[var(--shadow-sm)]) so they need no @theme key
   here — which also avoids colliding with a host app's own font/radius theme. */

/* Non-intrusive base (no body clobber). */
[lang="ar"],
[dir="rtl"] {
  font-family: var(--font-arabic);
}
:focus-visible {
  outline: 2px solid var(--ring); /* the brass key — branded focus */
  outline-offset: 2px;
  border-radius: 2px;
}

/* Tabular numerals for data contexts — columns must align (E3; making this the
   DataTable default is wave work). Face comes from --font-numeric-data. */
.tabular {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-numeric-data);
}

/* Mixed-direction text (E5 §6 P4). User-generated strings — pipeline, connector,
   dataset names — routinely mix Arabic and Latin. `plaintext` lets each string
   pick its own base direction from its first strong character, so an Arabic name
   in an LTR page (and a Latin name in an RTL page) reads correctly with no
   hardcoded dir. Alignment follows the resolved direction via logical text-align.
   Exposed through <BidiText> and the `bidiPlaintextClass` export. */
.abrq-bidi-plaintext {
  unicode-bidi: plaintext;
  text-align: start;
}

/* Inline-edge scroll shadow (E7, DataTable). A SYMMETRIC radial fade centred on
   the container edge, so one class serves both edges in both directions — the
   component positions it with logical inset utilities (start/end); no
   [dir=rtl] selector, no physical gradient direction (E5 §6 exit criterion).
   Colour derives from --ink via color-mix, so it tracks the theme. */
.abrq-scroll-shadow {
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--ink) 18%, transparent),
    transparent
  );
}

/* The system's labeling voice: mono tracked caps (section headers, table heads,
   form labels). This — not decoration — is the Telegraph idiom in the chrome.
   Metrics are tokens (E3): size/weight/tracking live in the DTCG source. */
.abrq-label {
  font-family: var(--font-mono);
  font-size: var(--text-label-size);
  font-weight: var(--text-label-weight);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

/* Arabic fallback for the label voice: IBM Plex Mono has no Arabic glyphs, Arabic
   has no uppercase, and positive letter-spacing detaches Arabic joining strokes.
   The label ROLE (small, quiet, structural) carries — set in the Arabic companion
   face, semibold, zero tracking (structurally 0 — generator-validated). */
[dir="rtl"] .abrq-label {
  font-family: var(--font-arabic);
  font-weight: var(--text-label-weight-arabic);
  letter-spacing: var(--tracking-arabic-label);
}

/* ---- Morse-rule signature pattern (E4: geometry tokenized) ------------------
   Dot–dash rule: a divider in the Morse rhythm. Color via currentColor
   (e.g. <div class="abrq-rule text-border" />). Pattern is direction-agnostic.
   The dot/gap/dash rhythm now lives in the DTCG source (--morse-rule-*); the
   cumulative gradient stops are composed with calc() so the geometry has one
   home. Resolved rhythm is unchanged (2/7/15/20px cycle). */
.abrq-rule {
  height: 1px;
  background-image: repeating-linear-gradient(
    90deg,
    currentColor 0,
    currentColor var(--morse-rule-dot),
    transparent var(--morse-rule-dot),
    transparent calc(var(--morse-rule-dot) + var(--morse-rule-gap)),
    currentColor calc(var(--morse-rule-dot) + var(--morse-rule-gap)),
    currentColor calc(var(--morse-rule-dot) + var(--morse-rule-gap) + var(--morse-rule-dash)),
    transparent calc(var(--morse-rule-dot) + var(--morse-rule-gap) + var(--morse-rule-dash)),
    transparent calc(var(--morse-rule-dot) + 2 * var(--morse-rule-gap) + var(--morse-rule-dash))
  );
}

/* ---- G11 (abrq-dip rollout): data-density tier ------------------------------
   Scope class for operational/monitoring surfaces (dense run feeds, audit
   logs, 8–12-column tables). Tightens cell rhythm + data type size. Forms and
   marketing surfaces never use it. Metrics are tokens (E3). */
.abrq-dense th,
.abrq-dense td {
  padding-block: var(--dense-cell-padding);
}
.abrq-dense td {
  font-size: var(--text-dense-size);
}

/* ---- skeleton shimmer (E4: duration + easing + veil tokenized) --------------
   G14 (abrq-dip rollout): skeleton vocabulary. Loading placeholders: flat
   --surface-2 blocks with a subtle one-directional shimmer (NOT a pulse —
   symmetric opacity pulsing reads as the banned motif class). Self-disables
   under prefers-reduced-motion via the global rule. Division of labour:
   empty-region/full-screen loads → MorseBand `loading`; in-place data refresh
   on dense surfaces → skeleton; inline submit → a minimal spinner is tolerated.
   Duration/easing/veil now resolve from the token source at parity. */
.abrq-skeleton {
  position: relative;
  overflow: hidden;
  background: var(--surface-2);
  border-radius: var(--radius);
}
.abrq-skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--skeleton-veil), transparent);
  animation: abrq-shimmer var(--motion-transmit-loop) var(--ease-in-out) infinite;
}
@keyframes abrq-shimmer {
  100% {
    transform: translateX(100%);
  }
}

/* ---- signature motion (E4: duration literals tokenized) ---------------------
   Signature motion: transmission, never pulse. BANNED in this system:
   ECG/heartbeat/vitals waveforms, radar pings, and any animated horizontal
   "trace". Motion = elements lighting in transmission order (left to right),
   or a Morse blink pattern — rhythms of code. The former 0.4s/1.4s literals now
   resolve from --motion-transmit / --motion-transmit-loop at parity. */

/* One-shot: a Morse band "arrives" element by element (delay set per element). */
@keyframes abrq-tx {
  from {
    opacity: 0.15;
  }
  to {
    opacity: 1;
  }
}
.abrq-tx {
  animation: abrq-tx var(--motion-transmit) var(--ease) both;
}

/* Looping: marching transmission, for loading states (delay set per element). */
@keyframes abrq-tx-loop {
  0%,
  15% {
    opacity: 0.15;
  }
  35%,
  60% {
    opacity: 1;
  }
  80%,
  100% {
    opacity: 0.15;
  }
}
.abrq-tx-loop {
  animation: abrq-tx-loop var(--motion-transmit-loop) var(--ease) infinite;
}

/* RETIRED (owner ruling 2026-06-11, abrq-dip rollout): the `.abrq-morse`
   Morse-L live blink. Live indicators are STATIC signal-colour dots — no
   blinking, no pulsing, no flashing of any rhythm. */

/* ---- motion primitives (E4, P4): CSS-first, token-pure, RTL-aware -----------
   The <Fade>/<SlideIn>/<Collapse>/<Stagger> React primitives are thin wrappers
   over these classes — zero runtime deps (ADR-D4). Every duration/easing/distance
   is a token; the reduced-motion neutralizer at the foot of this file collapses
   each to its rest state. Directional motion is LOGICAL: <SlideIn> takes inline-start/inline-end
   and the sign flips under [dir=rtl] via --abrq-slide-from, so there is no
   physical left/right and RTL is correct by construction (E5 inherits these
   already-logical). */

/* Fade — opacity only; the safest reveal (identical under reduced motion). */
@keyframes abrq-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
.abrq-fade-in {
  animation: abrq-fade-in var(--motion) var(--ease-enter) both;
}

/* SlideIn — translate along the INLINE axis + fade. `data-from` picks the logical
   edge; the sign flips under RTL so inline-start is always the reader's leading
   edge. Magnitude is --motion-travel. */
@keyframes abrq-slide-in {
  from {
    opacity: 0;
    transform: translateX(var(--abrq-slide-from, 0));
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}
.abrq-slide-in {
  animation: abrq-slide-in var(--motion) var(--ease-enter) both;
}
.abrq-slide-in[data-from="inline-start"] {
  --abrq-slide-from: calc(-1 * var(--motion-travel));
}
.abrq-slide-in[data-from="inline-end"] {
  --abrq-slide-from: var(--motion-travel);
}
[dir="rtl"] .abrq-slide-in[data-from="inline-start"] {
  --abrq-slide-from: var(--motion-travel);
}
[dir="rtl"] .abrq-slide-in[data-from="inline-end"] {
  --abrq-slide-from: calc(-1 * var(--motion-travel));
}

/* Collapse — height:auto without JS measurement: grid-template-rows 0fr→1fr.
   Toggled by data-open; the single child clips via overflow during the change. */
.abrq-collapse {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--motion) var(--ease-emphasized);
}
.abrq-collapse[data-open="true"] {
  grid-template-rows: 1fr;
}
.abrq-collapse > * {
  overflow: hidden;
  min-height: 0;
}

/* Stagger — children reveal in transmission order. The wrapper sets a per-child
   animation-delay inline (delay = index × step); the animation itself is a class
   above (fade/slide). The reduced-motion neutralizer below zeroes animation-delay
   with `!important`, so the stagger collapses to a single reveal — no JS branch. */

/* ---- reduced-motion: the structural neutralizer, encoded once (E4, P3) -------
   The system's single `prefers-reduced-motion: reduce` layer, kept at the foot as
   the global override. It universally collapses every animation and transition to
   a near-instant no-op, so motion is neutralized to its rest / opacity end-state:
   the signature transmission animations settle fully visible, the shimmer stops,
   the spinner rests, the primitives snap open. Because it targets `*` with
   `!important`, EVERY keyframe/transition in library source (present and future)
   is reachable by it regardless of source order. scripts/check-motion-reduce.sh
   asserts that invariant AND that this block survives into the compiled sheet
   (report-only inventory + a hard compiled-presence guard — the motion analog of
   the purity check).

   FAIL-LOUDLY CARVE-OUT (ADR fail-loudly; PLAN-v3 §5): no data-critical state
   change may depend on motion to be perceived. Audited in E4 — none does: live/
   status is conveyed by signal COLOUR on static dots (owner ruling 2026-06-11,
   `.abrq-morse` retired), never by blink/pulse; the tokenized animations
   (abrq-tx arrival, abrq-tx-loop / shimmer loading) are ambient, not stateful.

   The 0.01ms is a deliberate a11y constant, NOT --motion-instant (0ms): a
   non-zero tick keeps animationend/transitionend firing for JS that unmounts on
   them. It is therefore intentionally not tokenized (it is not a design value). */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0.01ms !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

