Shared visual system for every Defender module. One source of truth for color, type, motion, and the core primitives that should look identical wherever they appear.
v1 · stableDrop into the top of any embed's <head>. No build step, no npm, no version pinning to manage. Update once at the CDN, propagates everywhere.
Primary actions are slate. Blue and amber are decorative-only — focus rings, status dots, chart accents, never primary buttons.
Inter for everything readable. JetBrains Mono only for values that are data (IPs, MAC addresses, IDs, code, monitor IDs).
Pulsing dots only. Default 9px for section-level loading; 6px small variant for inline use.
.boot-pulse
.boot-pulse.boot-pulse-sm
.stageStaggered fade-up. Mark each child with .stage and an inline style="--d:N" for the stagger index. Reload the page to replay.
Primary = slate, always. "Update" not "Edit". Danger sparingly.
View toggles and range pickers. Default view always on the LEFT.
Semantic colors only. Don't invent new pill colors — pick the closest semantic.
Default card grid: repeat(auto-fill, minmax(280px, 1fr)). Use .card-soft for tinted variants.
Always styled placeholders. Never an empty chart canvas.
Title on the left, actions on the right. Wraps gracefully on narrow iframes.
Field wrappers, labels, inputs, selects, textareas, checkboxes, radios. Required fields use a small amber dot, never an asterisk. Error state is a red left border + .error-text below — never red-flood the whole field.
Section-internal navigation. Use .segmented for binary or 2–3 view toggles; use .tabs when there's a list of distinct sub-views.
Freeform labels (group names, owners, categories). Distinct from .pill which is reserved for status. Tags don't carry a leading dot.
A small standalone colored dot — useful when a full status pill would be visually heavy (e.g. inside a dense table row or next to a label).
One number per tile. Use a .card wrapper plus .kpi contents. Deltas are semantic — up/down — the module decides which direction is good.
For simple data tables. Tabulator remains the right pick for filtering / column reordering / heavy interactivity.
Compact variant for dense readouts:
Label : value pairs. Horizontal by default — use .dl-stack when labels are long or narrow viewports demand it.
Set percentage via style="--p:62" — no unit. Color modifiers map to semantic states.
Use .boot-pulse when you have nothing to show yet. Use skeletons when the page chrome is already laid out and you're waiting for the content shape.
Circle with initials or image. Set background tint via --c. Use a stack for crowded contexts (assignees, recent commenters).
Utility bar between the section header and the content — search, density toggle, group-by, CSV export.
Inline status messages at the top of a section. Use for prolonged states ("Read-only mode — your role can't update monitors"). Use toasts for transient feedback after writes.
Inline side panel — replaces a region of the section rather than overlaying the whole viewport. Sections render inside Glide iframes, so fixed-fullscreen overlays don't behave correctly. The module decides the layout (split, stacked, or animated slide-in within a relative parent).
Anchored panels — the module positions them relative to a trigger. Use .popover for confirm prompts, hints, mini-forms. Use .menu for action lists.
CSS-only — set the message on data-tt. Default direction is up; modifiers are tt-down, tt-left, tt-right.
Transient feedback after writes. Module mounts a .toasts container inside the section (absolute, anchored bottom-right by default) and appends .toast children. Auto-dismiss is the module's responsibility.