/* * Uptime design system: reference stylesheet. * * This is the stylesheet the published component previews use. It is a * reference for sizes, spacing and states, not a file to import into * apps/web. Every value comes from docs/design/tokens.json, exposed as CSS * custom properties of the same name (--ink, --space-4, --radius-sm) and * --font-display / --font-body / --font-mono for the families. * * Classes starting with .is- (is-hover, is-focus, is-active, is-open) only * freeze a state for the previews. The app uses the real pseudo-classes. */ /* ── Base ───────────────────────────────────────────── */ body { margin: 0; padding: 16px; background: var(--paper); color: var(--ink); font-family: var(--font-body); font-size: 16px; line-height: 24px; } .ut-row { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; } .ut-stack { display: grid; gap: var(--space-3); } .ut-label { font-family: var(--font-mono); font-size: 12px; line-height: 16px; font-weight: 500; color: var(--muted); } .ut-data { font-family: var(--font-mono); font-size: 13px; line-height: 20px; font-variant-numeric: tabular-nums; } .ut-figure { font-family: var(--font-mono); font-size: 20px; line-height: 24px; font-weight: 500; font-variant-numeric: tabular-nums; } .ut-muted { color: var(--muted); } .ut-icon { flex: none; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; } /* ── Button ─────────────────────────────────────────── */ .ut-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); box-sizing: border-box; height: var(--control-md); padding: 0 14px; border: 1px solid transparent; border-radius: var(--radius-control); background: transparent; color: var(--ink); font: 500 14px/20px var(--font-body); white-space: nowrap; cursor: pointer; user-select: none; transition: background-color 120ms, border-color 120ms, color 120ms, box-shadow 120ms, transform 80ms; } .ut-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; } .ut-btn:active:not([disabled]), .ut-btn.is-active { transform: translateY(1px); } .ut-btn--primary { background: var(--ink); color: var(--paper); box-shadow: inset 0 1px 0 var(--control-highlight), var(--shadow-control); } .ut-btn--primary:hover, .ut-btn--primary.is-hover { background: var(--ink-soft); } .ut-btn--primary:active:not([disabled]), .ut-btn--primary.is-active { box-shadow: inset 0 1px 0 var(--control-highlight); } .ut-btn--secondary { background: var(--surface); border-color: var(--rule-strong); box-shadow: var(--shadow-control); } .ut-btn--secondary:hover, .ut-btn--secondary.is-hover { background: var(--paper); border-color: var(--ink-soft); } .ut-btn--secondary:active:not([disabled]), .ut-btn--secondary.is-active { background: var(--sunken); box-shadow: none; } .ut-btn--quiet { color: var(--accent); } .ut-btn--quiet:hover, .ut-btn--quiet.is-hover { background: var(--sunken); color: var(--accent-hover); } .ut-btn--danger { background: var(--down); color: var(--on-down); box-shadow: inset 0 1px 0 var(--control-highlight), var(--shadow-control); } .ut-btn--danger:hover, .ut-btn--danger.is-hover { background: color-mix(in oklab, var(--down) 86%, var(--ink)); } .ut-btn--sm { height: var(--control-sm); padding: 0 10px; gap: 6px; font-size: 13px; } .ut-btn--icon { width: var(--control-md); padding: 0; } .ut-btn--sm.ut-btn--icon { width: var(--control-sm); } .ut-btn .ut-kbd { margin-left: var(--space-1); } .ut-btn--primary .ut-kbd { border-color: var(--control-highlight); color: var(--paper); opacity: 0.7; } .ut-btn[disabled] { opacity: 0.45; cursor: not-allowed; box-shadow: none; } .ut-btn[aria-busy="true"] { cursor: progress; } .ut-spinner { flex: none; width: 14px; height: 14px; box-sizing: border-box; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: ut-spin 700ms linear infinite; } @keyframes ut-spin { to { transform: rotate(360deg); } } .ut-kbd { display: inline-block; padding: 0 5px; border: 1px solid var(--rule-strong); border-radius: var(--radius-xs); font-family: var(--font-mono); font-size: 11px; line-height: 16px; color: var(--muted); } /* Segmented control: one choice from two to five, such as a time range. */ .ut-segmented { display: inline-flex; gap: 2px; padding: 2px; border-radius: var(--radius-control); background: var(--sunken); box-shadow: var(--shadow-inset); } .ut-segmented__item { height: calc(var(--control-sm) - 4px); padding: 0 10px; border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--ink-soft); font: 500 13px/1 var(--font-body); cursor: pointer; transition: background-color 120ms, color 120ms, box-shadow 120ms; } .ut-segmented__item:hover { color: var(--ink); } .ut-segmented__item:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; } .ut-segmented__item[aria-pressed="true"], .ut-segmented__item[aria-checked="true"] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-control); } /* ── Field ──────────────────────────────────────────── */ .ut-field { display: grid; gap: 6px; min-width: 0; } .ut-field__label { font-size: 14px; line-height: 20px; font-weight: 600; } .ut-field__optional { margin-left: 6px; font-weight: 400; color: var(--muted); } .ut-input, .ut-input-group { box-sizing: border-box; width: 100%; height: var(--control-md); border: 1px solid var(--rule-strong); border-radius: var(--radius-control); background: var(--surface); box-shadow: var(--shadow-inset); color: var(--ink); font: 400 14px/20px var(--font-body); transition: border-color 120ms, box-shadow 120ms; } .ut-input { padding: 0 12px; } .ut-input::placeholder, .ut-input-group input::placeholder { color: var(--muted); opacity: 1; } .ut-input:hover, .ut-input-group:hover, .ut-input.is-hover { border-color: var(--ink-soft); } .ut-input:focus, .ut-input.is-focus, .ut-input-group:focus-within, .ut-input-group.is-focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 0 0 4px var(--focus-halo); } .ut-input--mono, .ut-input-group--mono input { font-family: var(--font-mono); font-size: 13px; font-variant-numeric: tabular-nums; } .ut-input-group { display: flex; align-items: stretch; overflow: hidden; } .ut-input-group input { flex: 1; min-width: 0; padding: 0 12px; border: 0; background: transparent; color: inherit; font: inherit; outline: none; } .ut-affix { display: flex; align-items: center; padding: 0 10px; background: var(--paper); color: var(--muted); font-family: var(--font-mono); font-size: 13px; white-space: nowrap; } .ut-affix--prefix { border-right: 1px solid var(--rule); } .ut-affix--suffix { border-left: 1px solid var(--rule); } .ut-affix--icon { padding: 0 0 0 10px; background: transparent; } .ut-affix--icon + input { padding-left: 8px; } .ut-field__hint { font-size: 13px; line-height: 18px; color: var(--muted); } .ut-field__error { display: flex; gap: 6px; align-items: baseline; font-size: 13px; line-height: 18px; color: var(--down); } .ut-field__error::before { content: ""; flex: none; width: 8px; height: 8px; border-radius: var(--radius-xs); background: var(--down); } .ut-field--error .ut-input, .ut-field--error .ut-input-group, .ut-field--error .ut-select { border-color: var(--down); } .ut-field--error .ut-input:focus, .ut-field--error .ut-input.is-focus, .ut-field--error .ut-input-group:focus-within { border-color: var(--down); box-shadow: 0 0 0 1px var(--down), 0 0 0 4px var(--down-halo); } .ut-input:disabled, .ut-input-group.is-disabled { border-color: var(--rule); background: var(--sunken); box-shadow: none; color: var(--muted); cursor: not-allowed; } /* ── Select trigger ─────────────────────────────────── */ .ut-select { display: flex; align-items: center; gap: var(--space-2); box-sizing: border-box; width: 100%; height: var(--control-md); padding: 0 8px 0 12px; border: 1px solid var(--rule-strong); border-radius: var(--radius-control); background: var(--surface); box-shadow: var(--shadow-control); color: var(--ink); font: 400 14px/20px var(--font-body); text-align: left; cursor: pointer; transition: border-color 120ms, box-shadow 120ms, background-color 120ms; } .ut-select:hover, .ut-select.is-hover { border-color: var(--ink-soft); } .ut-select:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 0 0 4px var(--focus-halo); } .ut-select[aria-expanded="true"], .ut-select.is-open { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 0 0 4px var(--focus-halo); } .ut-select__value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ut-select__placeholder { color: var(--muted); } .ut-select__prefix { color: var(--muted); } .ut-select__lead { display: inline-flex; flex: none; align-items: center; } .ut-select__count { flex: none; padding: 0 6px; border-radius: var(--radius-full); background: var(--accent-tint); color: var(--accent); font-family: var(--font-mono); font-size: 12px; line-height: 20px; font-variant-numeric: tabular-nums; } .ut-select__chevron { color: var(--muted); transition: transform 120ms; } .ut-select[aria-expanded="true"] .ut-select__chevron, .ut-select.is-open .ut-select__chevron { color: var(--accent); } .ut-select--sm { width: auto; height: var(--control-sm); padding: 0 6px 0 10px; font-size: 13px; } /* ── Open menu (listbox) ────────────────────────────── */ .ut-popover-anchor { position: relative; display: grid; gap: 4px; } .ut-menu { display: grid; gap: 1px; box-sizing: border-box; min-width: 220px; max-width: 360px; max-height: 340px; overflow-y: auto; padding: 4px; border: 1px solid var(--rule); border-radius: var(--radius-md); background: var(--surface); box-shadow: var(--shadow-overlay); transform-origin: top left; animation: ut-pop 120ms cubic-bezier(0.16, 1, 0.3, 1); } @keyframes ut-pop { from { opacity: 0; transform: translateY(-4px) scale(0.98); } } .ut-menu__search { position: sticky; top: -4px; z-index: 1; display: flex; align-items: center; gap: var(--space-2); height: var(--control-md); margin: -4px -4px 4px; padding: 0 12px; border-bottom: 1px solid var(--rule); background: var(--surface); color: var(--muted); } .ut-menu__search input { flex: 1; min-width: 0; border: 0; background: transparent; color: var(--ink); font: 400 14px/20px var(--font-body); outline: none; } .ut-menu__group { padding: 8px 8px 4px; color: var(--muted); font-size: 12px; line-height: 16px; font-weight: 600; } .ut-menu__sep { height: 1px; margin: 4px -4px; background: var(--rule); } .ut-option { display: flex; align-items: center; gap: 10px; min-height: var(--option); padding: 0 8px; border-radius: var(--radius-sm); color: var(--ink-soft); font-size: 14px; line-height: 20px; cursor: pointer; } .ut-option:hover, .ut-option[data-active], .ut-option.is-hover { background: var(--sunken); color: var(--ink); } .ut-option[aria-selected="true"] { color: var(--ink); font-weight: 500; } .ut-menu--single .ut-option[aria-selected="true"] { background: var(--accent-tint); } .ut-option__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ut-option__meta { color: var(--muted); font-family: var(--font-mono); font-size: 12px; font-weight: 400; font-variant-numeric: tabular-nums; } .ut-option__check { visibility: hidden; color: var(--accent); } .ut-option[aria-selected="true"] .ut-option__check { visibility: visible; } .ut-option[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; } .ut-option__code { width: 44px; flex: none; color: var(--muted); font-family: var(--font-mono); font-size: 12px; } .ut-checkbox { display: grid; place-items: center; flex: none; box-sizing: border-box; width: 16px; height: 16px; border: 1px solid var(--rule-strong); border-radius: var(--radius-sm); background: var(--surface); box-shadow: var(--shadow-inset); color: var(--on-accent); } .ut-checkbox svg { visibility: hidden; width: 12px; height: 12px; stroke-width: 2; } .ut-option[aria-selected="true"] .ut-checkbox, .ut-checkbox.is-checked { border-color: var(--accent); background: var(--accent); box-shadow: inset 0 1px 0 var(--control-highlight); } .ut-option[aria-selected="true"] .ut-checkbox svg, .ut-checkbox.is-checked svg { visibility: visible; } .ut-menu__footer { position: sticky; bottom: -4px; display: flex; align-items: center; justify-content: space-between; margin: 4px -4px -4px; padding: 6px 6px 6px 12px; border-top: 1px solid var(--rule); background: var(--surface); color: var(--muted); font-size: 13px; } .ut-menu__empty { padding: 12px 8px; color: var(--muted); font-size: 14px; } @media (pointer: coarse) { .ut-btn, .ut-input, .ut-input-group, .ut-select { height: var(--control-touch); } .ut-input, .ut-input-group, .ut-select, .ut-menu__search input { font-size: 16px; } .ut-option { min-height: var(--control-touch); } } /* ── Status mark ────────────────────────────────────── */ .ut-status { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; line-height: 18px; } .ut-glyph { flex: none; display: inline-block; width: 10px; height: 10px; box-sizing: border-box; } .ut-glyph--up { border-radius: 50%; background: var(--up); } .ut-glyph--degraded { background: var(--degraded); clip-path: polygon(50% 0, 100% 100%, 0 100%); } .ut-glyph--down { border-radius: var(--radius-xs); background: var(--down); } .ut-glyph--unknown { border: 2px solid var(--unknown); border-radius: 50%; } .ut-glyph--paused { border-left: 3px solid var(--muted); border-right: 3px solid var(--muted); width: 9px; } .ut-status--up { color: var(--up); } .ut-status--degraded { color: var(--degraded); } .ut-status--down { color: var(--down); } .ut-status--unknown, .ut-status--paused { color: var(--muted); } .ut-status--chip { height: 24px; padding: 0 10px 0 8px; border-radius: var(--radius-full); } .ut-status--chip.ut-status--up { background: var(--up-tint); } .ut-status--chip.ut-status--degraded { background: var(--degraded-tint); } .ut-status--chip.ut-status--down { background: var(--down-tint); } .ut-status--chip.ut-status--unknown, .ut-status--chip.ut-status--paused { background: var(--sunken); } /* ── Badge ──────────────────────────────────────────── */ .ut-badge { display: inline-flex; align-items: center; gap: 6px; height: 22px; padding: 0 8px; border: 1px solid var(--rule); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); font-size: 12px; font-weight: 500; } .ut-badge::before { content: ""; width: 8px; height: 8px; border-radius: var(--radius-xs); background: var(--badge-color); } /* ── Uptime strip ───────────────────────────────────── */ .ut-strip { display: grid; gap: 6px; min-width: 0; } .ut-strip__days { display: flex; gap: 2px; height: 28px; } .ut-strip--compact .ut-strip__days { height: 20px; } .ut-day { flex: 1 1 0; min-width: 2px; border-radius: var(--radius-xs); background: var(--up); } .ut-day--soft { background: var(--up-soft); } .ut-day--degraded { background: var(--degraded); } .ut-day--down { background: var(--down); } .ut-day--none { background: var(--sunken); box-shadow: inset 0 0 0 1px var(--rule); } .ut-strip__axis { display: flex; justify-content: space-between; align-items: baseline; } /* ── Region grid ────────────────────────────────────── */ .ut-regions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; overflow: hidden; border: 1px solid var(--rule); border-radius: var(--radius-md); background: var(--rule); } .ut-region { display: grid; gap: 6px; padding: var(--space-3) var(--space-4); background: var(--surface); } .ut-region__top { display: flex; justify-content: space-between; align-items: center; } .ut-region__name { font-size: 12px; color: var(--muted); } .ut-dots { display: inline-grid; grid-template-columns: repeat(9, 8px); gap: 3px; align-items: center; } .ut-dots .ut-glyph { width: 8px; height: 8px; } /* ── Monitor row ────────────────────────────────────── */ .ut-board { overflow: hidden; border: 1px solid var(--rule); border-radius: var(--radius-md); background: var(--surface); } .ut-board__head, .ut-monitor { display: grid; grid-template-columns: 96px minmax(0, 1.5fr) 105px minmax(0, 1.3fr) 72px 64px; gap: var(--space-4); align-items: center; padding: 0 var(--space-4); } .ut-board__head { height: 32px; border-bottom: 1px solid var(--rule); background: var(--sunken); } .ut-monitor { min-height: 56px; border-bottom: 1px solid var(--rule); color: inherit; text-decoration: none; transition: background-color 120ms; } .ut-monitor:last-child { border-bottom: 0; } .ut-monitor:hover { background: var(--sunken); } .ut-monitor:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; } .ut-monitor__name { display: grid; gap: 2px; min-width: 0; } .ut-monitor__title { display: flex; gap: var(--space-2); align-items: center; font-size: 15px; font-weight: 600; line-height: 20px; } .ut-monitor__url { overflow: hidden; color: var(--muted); text-overflow: ellipsis; white-space: nowrap; } .ut-num { text-align: right; } /* ── Side navigation ────────────────────────────────── */ .ut-nav { display: grid; align-content: start; gap: 2px; box-sizing: border-box; width: 224px; min-height: 100%; padding: var(--space-4) var(--space-3); border-right: 1px solid var(--rule); background: var(--sunken); } .ut-wordmark { padding: 0 10px var(--space-3); font-family: var(--font-display); font-size: 20px; font-weight: 600; letter-spacing: -0.01em; } .ut-nav__search { display: flex; justify-content: space-between; align-items: center; height: 32px; margin-bottom: var(--space-3); padding: 0 8px 0 10px; border: 1px solid var(--rule-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--muted); font-size: 13px; } .ut-nav__group { padding: var(--space-3) 10px var(--space-1); } .ut-nav__item { display: flex; justify-content: space-between; align-items: center; height: 32px; padding: 0 10px; border-radius: var(--radius-sm); color: var(--ink-soft); font-size: 14px; text-decoration: none; } .ut-nav__item:hover { background: var(--surface); color: var(--ink); } .ut-nav__item:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; } .ut-nav__item[aria-current="page"] { background: var(--accent-tint); color: var(--ink); font-weight: 600; } .ut-count { font-family: var(--font-mono); font-size: 11px; font-variant-numeric: tabular-nums; color: var(--muted); } .ut-count--down { padding: 1px 6px; border-radius: var(--radius-full); background: var(--down-tint); color: var(--down); font-weight: 500; } /* ── Panel and dialog ───────────────────────────────── */ .ut-panel { overflow: hidden; border: 1px solid var(--rule); border-radius: var(--radius-md); background: var(--surface); } .ut-panel__head { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--rule); } .ut-panel__body { padding: var(--space-4); } .ut-title-md { margin: 0; font-family: var(--font-display); font-size: 22px; font-weight: 600; line-height: 28px; } .ut-scrim { display: grid; place-items: center; padding: var(--space-6); background: var(--overlay); } .ut-dialog { display: grid; gap: var(--space-3); box-sizing: border-box; width: 100%; max-width: 440px; padding: var(--space-6); border: 1px solid var(--rule); border-radius: var(--radius-md); background: var(--surface); box-shadow: var(--shadow-overlay); } .ut-dialog p { margin: 0; color: var(--ink-soft); } .ut-dialog__actions { display: flex; justify-content: flex-end; gap: var(--space-2); padding-top: var(--space-2); } /* ── Latency trace ──────────────────────────────────── */ .ut-trace { display: block; width: 100%; height: auto; } .ut-trace .grid { stroke: var(--rule); stroke-width: 1; } .ut-trace .axis { fill: var(--muted); font-family: var(--font-mono); font-size: 10px; } .ut-trace .line { fill: none; stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; } .ut-trace .s1 { stroke: var(--series-1); } .ut-trace .s2 { stroke: var(--series-2); } .ut-trace .s3 { stroke: var(--series-3); } .ut-trace .end1 { fill: var(--series-1); } .ut-trace .end2 { fill: var(--series-2); } .ut-trace .end3 { fill: var(--series-3); } .ut-trace .area { fill: var(--series-1); opacity: 0.08; } .ut-trace .incident { fill: var(--down-tint); } .ut-legend { display: flex; flex-wrap: wrap; gap: var(--space-4); } .ut-legend__item { display: inline-flex; align-items: center; gap: 6px; } .ut-legend__key { width: 12px; height: 2px; border-radius: 1px; } @media (prefers-reduced-motion: reduce) { .ut-btn, .ut-monitor, .ut-input, .ut-input-group, .ut-select, .ut-segmented__item { transition: none; } .ut-menu { animation: none; } .ut-spinner { animation-duration: 2s; } }