mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
195 lines
6.1 KiB
CSS
195 lines
6.1 KiB
CSS
@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;
|
|
}
|