@import './tokens.css';

/*
 * IBM Plex, self-hosted via @fontsource — offline/PWA safe, never a CDN
 * (docs/architecture/09 §3.1). Sans: 400 body, 600 emphasis/headings, 300 for
 * large display only. Mono: 400 editor/code, 500 for emphasis. Keep weights
 * minimal — add one only when a surface needs it.
 *
 * The family-level import pulls every script subset (latin, latin-ext, cyrillic,
 * greek, vietnamese). We keep them all: user data — snippet names, dataset
 * values, chart labels — can be in any language, and Plex must render it rather
 * than fall back to system-ui. @font-face `unicode-range` means the browser only
 * *downloads* the subset a glyph needs, so the unused subsets cost nothing at
 * runtime; they only add to the offline precache, which is the price of working
 * internationally offline. Vite bundles the woff2 and Workbox precaches them
 * (woff2 is in the PWA globPatterns — see vite.config.ts).
 */
@import '@fontsource/ibm-plex-sans/300.css';
@import '@fontsource/ibm-plex-sans/400.css';
@import '@fontsource/ibm-plex-sans/600.css';
@import '@fontsource/ibm-plex-mono/400.css';
@import '@fontsource/ibm-plex-mono/500.css';

* {
  box-sizing: border-box;
}

html,
body,
#app {
  height: 100%;
  margin: 0;
}

body {
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  /* Plex "requires space to breathe" — keep body line-height generous (doc §3.1). */
  line-height: 1.45;
  color: var(--text);
  background: var(--bg);
  /* Repaint chrome on theme flip; neutralized under reduced-motion below. */
  transition:
    background var(--dur-moderate) var(--ease),
    color var(--dur-moderate) var(--ease);
}

/*
 * Shared keyboard focus ring — always visible, accessibility is non-negotiable
 * (doc §4, principle 4). Components may override the offset (e.g. inset on
 * fields) but should not remove it.
 */
:where(button, input, select, textarea, a, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/*
 * Field baseline (arch 09 §4) — the quiet field: a fill one step off its surface
 * plus a bottom border only, no box. The fill comes from the contextual --field
 * token (elevated surfaces set `--field: var(--field-02)` on their container,
 * the same mechanism as --control-hover-fill); the underline is --border-strong,
 * which meets 3:1 non-text contrast in both themes. Declared once here at zero
 * specificity (:where) so modules add only their idiosyncrasies — width, mono
 * font, padding — never a competing border recipe. Monaco's internal widgets
 * (find/replace inputs) keep their own styling and are excluded.
 */
:where(
  input:not([type]),
  input[type='text'],
  input[type='search'],
  input[type='number'],
  input[type='url'],
  textarea
):where(:not(.monaco-editor *)) {
  font: inherit;
  color: var(--text);
  background: var(--field);
  border: none;
  border-block-end: var(--border-width) solid var(--border-strong);
  border-radius: var(--radius);
}

:where(input, textarea)::placeholder {
  color: var(--text-placeholder);
}

/* On a field the ring hugs the box — an offset ring reads as a second border
   where there is no longer a box to anchor it. */
:where(
    input:not([type]),
    input[type='text'],
    input[type='search'],
    input[type='number'],
    input[type='url'],
    textarea
  ):where(:not(.monaco-editor *)):focus-visible {
  outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/*
 * Chart tooltip (vega-tooltip). The renderer disables vega-tooltip's bundled
 * stylesheet (chart-renderer `disableDefaultStyle`), so the look is ours: an
 * elevated surface matching the popover recipe (--layer-01 + border + shadow,
 * square corners), in Plex, with the data laid out as a quiet key/value table.
 * vega-tooltip appends one `#vg-tooltip-element` to <body> and positions it
 * inline; these rules supply everything the default sheet did — position,
 * visibility toggle, z-index — plus the visual styling. Tokens cascade from
 * <html data-theme>, so the tooltip follows the active theme without a class.
 */
#vg-tooltip-element {
  visibility: hidden;
  position: fixed;
  /* Cursor-following overlay: the topmost ephemeral layer. Must clear the feature
     modal (900) that hosts the Chart Builder preview, toasts (1100), and an open
     select (2000) — none of which it ever needs to sit beneath. */
  z-index: 2100;
  padding: var(--space-3) var(--space-4);
  background: var(--layer-01);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1.3;
  color: var(--text);
}

#vg-tooltip-element.visible {
  visibility: visible;
}

/* Title — shown when a tooltip channel resolves to a single labeled value. */
#vg-tooltip-element h2 {
  margin: 0 0 var(--space-2);
  font-size: 12px;
  font-weight: 600;
}

#vg-tooltip-element table {
  border-spacing: 0;
}

#vg-tooltip-element td {
  padding: var(--space-1) 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Field name: quiet, right-aligned against its value. */
#vg-tooltip-element td.key {
  max-width: 150px;
  padding-inline-end: var(--space-3);
  text-align: right;
  color: var(--text-secondary);
}

/* Value: primary text; tabular figures keep numeric columns aligned. */
#vg-tooltip-element td.value {
  display: block;
  max-width: 300px;
  max-height: 7em;
  text-align: left;
  font-variant-numeric: tabular-nums;
}

/*
 * Visually-hidden but available to assistive tech — the standard sr-only recipe.
 * Used for polite `aria-live`/`role="status"` announcements whose visible
 * confirmation lives elsewhere (e.g. Copy Reference shows "Copied" on the button
 * for sighted users; this announces it to a screen reader). See
 * docs/architecture/10 → Toast copy (the "toast only what can't be seen" rule).
 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
