/* =====================================================================
   Olympus design system: components (v1.0, 29 October 2026)
   Requires tokens.css. Roles only: no raw colour values in this file.
   ===================================================================== */

/* ---------------------------------------------------------------- base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html, body { margin: 0; }
body {
  background: var(--canvas); color: var(--ink-1);
  font: var(--text-body); letter-spacing: var(--tracking-tight);
  font-feature-settings: "cv11", "ss01", "ss03"; /* Inter: single-storey a off, open digits, round quotes */
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  min-height: 100vh; min-height: 100dvh;
}
h1, h2, h3, h4, p, ul, ol, dl, dd, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
button, input, select, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
button { cursor: pointer; }
[hidden] { display: none !important; }
::selection { background: var(--accent-fill); color: var(--ink-on-accent); }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; border-radius: var(--r-sm); }
.num, .tnum { font-variant-numeric: tabular-nums; }
.mono { font: var(--text-mono); letter-spacing: 0; }
.muted { color: var(--ink-3); }
.ink-2 { color: var(--ink-2); }
.sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: fixed; left: var(--sp-4); top: -100px; z-index: 100; padding: var(--sp-2) var(--sp-4);
  background: var(--surface-2); border-radius: var(--r-md); box-shadow: var(--shadow-2); color: var(--ink-1);
}
.skip-link:focus { top: var(--sp-4); }
.icon { width: 16px; height: 16px; flex: none; stroke: currentColor; fill: none; stroke-width: 1.75;
  stroke-linecap: round; stroke-linejoin: round; }
.icon-20 { width: 20px; height: 20px; }

/* ---------------------------------------------------------------- brand mark */
.brand-mark { flex: none; display: block; }
.brand-mark .mk-tile { fill: var(--mark-tile); }
.brand-mark .mk-peak-hi { stop-color: var(--mark-peak-hi); }
.brand-mark .mk-peak-lo { stop-color: var(--mark-peak-lo); }
.brand-mark .mk-far-hi { stop-color: var(--mark-far-hi); }
.brand-mark .mk-far-lo { stop-color: var(--mark-far-lo); }
.brand-mark .mk-snow { fill: var(--mark-snow); opacity: 0.9; }
.brand-mark .mk-sun { fill: var(--mark-sun); }
.brand-mark .mk-horizon { stroke: var(--mark-horizon); stroke-width: 1; opacity: 0.5; }

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  height: 36px; padding: 0 var(--sp-4); border-radius: var(--r-md); border: 1px solid transparent;
  font: var(--text-body); font-weight: 500; white-space: nowrap; user-select: none;
  transition: background-color var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out);
}
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: 0.55; cursor: default; }
.btn-primary { background: var(--accent-fill); color: var(--ink-on-accent); box-shadow: var(--shadow-1), var(--highlight); }
.btn-primary:hover:not(:disabled) { background: var(--accent-fill-hover); }
.btn-secondary { background: var(--surface-1); border-color: var(--line-input); color: var(--ink-1); }
.btn-secondary:hover:not(:disabled) { background: var(--surface-2); }
.btn-ghost { background: transparent; color: var(--ink-2); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--ink-1); }
.btn-lg { height: 44px; padding: 0 var(--sp-5); font-size: 0.9375rem; border-radius: var(--r-lg); }
.btn-block { width: 100%; }
.btn-icon { width: 36px; padding: 0; }
.btn .spinner { width: 16px; height: 16px; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent;
  animation: spin 700ms linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.link-btn { background: none; border: 0; padding: 0; color: var(--accent); font-weight: 500; text-align: left; }
.link-btn:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (pointer: coarse) {
  .btn, .btn-icon { min-height: var(--target); }
  .btn-icon { min-width: var(--target); }
}

/* ---------------------------------------------------------------- fields */
.field { display: grid; gap: var(--sp-2); }
.field-label { font: var(--text-caption); color: var(--ink-2); }
.input {
  width: 100%; height: 44px; padding: 0 var(--sp-3); border-radius: var(--r-md);
  background: var(--surface-1); border: 1px solid var(--line-input); color: var(--ink-1);
  font-size: 1rem; /* 16 px keeps iOS from zooming */
  transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
.input::placeholder { color: var(--ink-3); }
.input:hover { border-color: var(--ink-3); }
.input:focus-visible { outline: none; border-color: var(--focus-ring); box-shadow: 0 0 0 3px var(--accent-wash); }
.input[aria-invalid="true"] { border-color: var(--crit); }
.input-code { font: 500 1.375rem/1 var(--font-mono); letter-spacing: 0.4em; text-align: center; height: 52px; }
.search {
  position: relative; display: flex; align-items: center; min-width: 0;
}
.search .icon { position: absolute; left: 10px; color: var(--ink-3); pointer-events: none; }
.search .input { height: 36px; padding-left: 32px; font-size: 0.875rem; }
.search .kbd { position: absolute; right: 8px; pointer-events: none; }
@media (pointer: coarse) { .search .input { height: var(--target); font-size: 1rem; } }
.select {
  height: 36px; padding: 0 28px 0 var(--sp-3); border-radius: var(--r-md); appearance: none;
  background: var(--surface-1); border: 1px solid var(--line-input); color: var(--ink-1); font-size: 0.875rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%), linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: calc(100% - 14px) 50%, calc(100% - 10px) 50%; background-size: 4px 4px; background-repeat: no-repeat;
}
@media (pointer: coarse) { .select { height: var(--target); font-size: 1rem; } }

/* ---------------------------------------------------------------- segmented control (radio group) */
.segmented {
  display: inline-flex; padding: 2px; gap: 2px; border-radius: var(--r-md);
  background: var(--surface-3); border: 1px solid var(--line);
}
.segmented button {
  display: inline-flex; align-items: center; gap: var(--sp-2); height: 30px; padding: 0 var(--sp-3);
  border: 0; border-radius: var(--r-sm); background: transparent; color: var(--ink-2); font-weight: 500; font-size: 0.8125rem;
  transition: background-color var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.segmented button:hover { color: var(--ink-1); }
.segmented button[aria-checked="true"], .segmented button[aria-pressed="true"] {
  background: var(--surface-1); color: var(--ink-1); box-shadow: var(--shadow-1), 0 0 0 1px var(--line-input);
}
@media (pointer: coarse) { .segmented button { min-height: 40px; } }

/* ---------------------------------------------------------------- chips, tags, kbd */
.chip {
  display: inline-flex; align-items: center; gap: 6px; height: 22px; padding: 0 8px; border-radius: var(--r-pill);
  font: var(--text-caption); white-space: nowrap; background: var(--quiet-wash); color: var(--quiet-ink);
}
.chip .glyph { width: 10px; height: 10px; }
.chip-ok { background: var(--ok-wash); color: var(--ok-ink); }
.chip-warn { background: var(--warn-wash); color: var(--warn-ink); }
.chip-crit { background: var(--crit-wash); color: var(--crit-ink); }
.chip-quiet { background: var(--quiet-wash); color: var(--quiet-ink); }
.chip-outline { background: transparent; color: var(--ink-2); box-shadow: inset 0 0 0 1px var(--line-strong); }
.chip-mono { font: var(--text-mono); letter-spacing: 0; }
.tag-demo {
  display: inline-flex; align-items: center; gap: 6px; height: 22px; padding: 0 8px; border-radius: var(--r-pill);
  font: var(--text-caption); color: var(--warn-ink); background: var(--warn-wash); box-shadow: inset 0 0 0 1px var(--warn); gap: 0.3em;
}
.kbd {
  display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 5px;
  border-radius: var(--r-xs); font: 500 0.6875rem/1 var(--font-sans); color: var(--ink-3);
  background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line-strong);
}
@media (pointer: coarse) { .kbd { display: none; } }

/* ---------------------------------------------------------------- status glyphs (shape + colour, never colour alone)
   ok = filled circle · late = triangle · failed = diamond · quiet = hollow ring. Drawn as inline SVG by js/ui/icons.js. */
.glyph { width: 10px; height: 10px; flex: none; }
.glyph-ok { color: var(--ok); }
.glyph-warn { color: var(--warn); }
.glyph-crit { color: var(--crit); }
.glyph-quiet { color: var(--quiet); }

/* heartbeat: live pulse when fresh */
.beat { display: inline-flex; align-items: center; gap: var(--sp-2); white-space: nowrap; }
.beat-dot { position: relative; width: 8px; height: 8px; flex: none; }
.beat-dot::before { content: ""; position: absolute; inset: 0; border-radius: 50%; background: currentColor; }
.beat-ok { color: var(--ok-ink); }
.beat-ok .beat-dot { color: var(--ok); }
.beat-ok .beat-dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%; background: var(--ok);
  animation: pulse var(--pulse-period) var(--ease-out) infinite;
}
@keyframes pulse { 0% { transform: scale(1); opacity: 0.55; } 70%, 100% { transform: scale(3); opacity: 0; } }
.beat-warn { color: var(--warn-ink); } .beat-warn .beat-dot { color: var(--warn); }
.beat-crit { color: var(--crit-ink); } .beat-crit .beat-dot { color: var(--crit); }
.beat-quiet { color: var(--ink-3); }
.beat-quiet .beat-dot::before { background: transparent; box-shadow: inset 0 0 0 1.5px var(--quiet); }
.beat-warn .beat-dot::before { border-radius: 1px; clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.beat-crit .beat-dot::before { border-radius: 1px; transform: rotate(45deg) scale(0.85); }

/* ---------------------------------------------------------------- cards and stat tiles */
.card {
  background: var(--surface-1); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-1), var(--highlight);
}
.card-pad { padding: var(--sp-5); }
.card-link { display: block; color: inherit; transition: border-color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out); }
.card-link:hover { text-decoration: none; border-color: var(--line-strong); background: var(--surface-2); }
.tile { display: grid; gap: var(--sp-2); padding: var(--sp-4) var(--sp-5); min-width: 0; }
.tile-label { display: flex; align-items: center; gap: var(--sp-2); font: var(--text-caption); color: var(--ink-3); }
.tile-value { font: var(--text-stat); letter-spacing: var(--tracking-display); color: var(--ink-1); white-space: nowrap; }
.tile-value small { font: var(--text-body); color: var(--ink-3); letter-spacing: var(--tracking-tight); margin-left: 4px; }
.tile-sub { font: var(--text-body-sm); color: var(--ink-2); min-width: 0; }
.tile-ok .tile-value { color: var(--ok-ink); }
.tile-warn .tile-value { color: var(--warn-ink); }
.tile-crit .tile-value { color: var(--crit-ink); }

/* ---------------------------------------------------------------- meter (cost vs idle target)
   Track spans 0 → 1.5 × target; the target is a tick at 2/3. Over target turns the fill critical. */
.meter { display: grid; gap: 6px; min-width: 0; }
.meter-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); }
.meter-value { font-variant-numeric: tabular-nums; font-weight: 500; color: var(--ink-1); }
.meter-target { font: var(--text-caption); font-weight: 400; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.meter-track { position: relative; height: 6px; border-radius: var(--r-pill); background: var(--meter-track); overflow: visible; }
.meter-fill {
  position: absolute; left: 0; top: 0; bottom: 0; border-radius: var(--r-pill); background: var(--viz-single);
  width: var(--fill, 0%); transition: width var(--dur-3) var(--ease-out);
}
.meter-tick { position: absolute; top: -3px; bottom: -3px; width: 2px; border-radius: 1px; background: var(--viz-target); left: var(--at, 66.6%); }
.meter-over .meter-fill { background: var(--crit); }
.meter-over .meter-value { color: var(--crit-ink); }
.meter-none .meter-fill { display: none; }

/* ---------------------------------------------------------------- outcome strip (24 h of job outcomes)
   One column per hour on a single baseline. A tick rising above the line is an hour with OK runs; a tick
   dropping below it is an hour with a failure (an hour can have both). Position and colour both carry the
   outcome, so it reads in greyscale and for colour-blind users. */
.strip { position: relative; display: grid; grid-template-columns: repeat(24, minmax(0, 1fr)); height: 24px; min-width: 120px; }
.strip::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--line-strong); }
.strip-col { position: relative; }
.strip-col.has-ok::before, .strip-col.has-fail::after {
  content: ""; position: absolute; left: 50%; width: 3px; margin-left: -1.5px; border-radius: 1.5px;
}
.strip-col.has-ok::before { bottom: calc(50% + 1px); height: 38%; background: var(--ok); }
.strip-col.has-fail::after { top: calc(50% + 1px); height: 46%; background: var(--crit); }
.strip-legend { display: flex; justify-content: space-between; font: var(--text-micro); color: var(--ink-3); margin-top: 4px; }
.strip-empty { display: flex; align-items: center; height: 24px; color: var(--ink-3); font: var(--text-body-sm); }

/* ---------------------------------------------------------------- data table */
.table-wrap { overflow-x: auto; border-radius: var(--r-lg); }
.table { width: 100%; border-collapse: separate; border-spacing: 0; font: var(--text-body-sm); }
.table thead th {
  position: sticky; top: 0; z-index: 1; text-align: left; font: var(--text-caption); color: var(--ink-3);
  padding: 0 var(--sp-3); height: 36px; background: var(--surface-1); border-bottom: 1px solid var(--line); white-space: nowrap;
}
.table th.num, .table td.num { text-align: right; }
.table td, .table tbody th, .table tfoot th { padding: var(--sp-3); border-bottom: 1px solid var(--line); vertical-align: middle; color: var(--ink-1); }
.table tbody th, .table tfoot th { text-align: left; font-weight: 500; }
.table tbody tr:last-child td, .table tbody tr:last-child th { border-bottom: 0; }
.table tbody tr { transition: background-color var(--dur-1) var(--ease-out); }
.table tbody tr.row-link { cursor: pointer; }
.table tbody tr.row-link:hover, .table tbody tr.row-link:focus-within { background: var(--surface-2); }
.table .row-anchor { color: inherit; font-weight: 500; }
.table .row-anchor:hover { text-decoration: none; }
.table .row-anchor:focus-visible { outline-offset: 4px; }
.sort-btn {
  display: inline-flex; align-items: center; gap: 4px; height: 28px; margin: 0 -6px; padding: 0 6px; border: 0; border-radius: var(--r-sm);
  background: none; font: inherit; color: inherit;
}
.sort-btn:hover { color: var(--ink-1); background: var(--surface-2); }
.sort-btn .icon { width: 12px; height: 12px; opacity: 0; transition: opacity var(--dur-1), transform var(--dur-2) var(--ease-out); }
th[aria-sort] .sort-btn { color: var(--ink-1); }
th[aria-sort] .sort-btn .icon { opacity: 1; }
th[aria-sort="descending"] .sort-btn .icon { transform: rotate(180deg); }
.table caption { text-align: left; }

/* ---------------------------------------------------------------- menus, popovers, dialog (command palette) */
.popover {
  position: absolute; z-index: 40; min-width: 220px; padding: var(--sp-1); border-radius: var(--r-lg);
  background: var(--surface-2); box-shadow: var(--shadow-3);
  animation: pop-in var(--dur-2) var(--ease-out);
}
@keyframes pop-in { from { opacity: 0; transform: translateY(-4px) scale(0.98); } }
.menu-item {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; min-height: 36px; padding: 0 var(--sp-3);
  border: 0; border-radius: var(--r-md); background: none; color: var(--ink-1); text-align: left; font-size: 0.875rem;
}
.menu-item:hover, .menu-item:focus-visible { background: var(--surface-3); outline: none; }
.menu-item .icon { color: var(--ink-3); }
.menu-sep { height: 1px; margin: var(--sp-1) 0; background: var(--line); }
.menu-head { padding: var(--sp-2) var(--sp-3); font: var(--text-caption); color: var(--ink-3); }
@media (pointer: coarse) { .menu-item { min-height: var(--target); } }

.dialog {
  padding: 0; border: 0; border-radius: var(--r-xl); background: var(--surface-2); color: var(--ink-1);
  box-shadow: var(--shadow-3); width: min(640px, calc(100vw - 32px)); max-height: min(520px, calc(100dvh - 96px));
  margin: 12vh auto auto; overflow: hidden;
}
.dialog[open] { display: flex; flex-direction: column; animation: dialog-in var(--dur-2) var(--ease-out); }
.dialog::backdrop { background: var(--scrim); backdrop-filter: blur(2px); animation: fade-in var(--dur-2) var(--ease-out); }
@keyframes dialog-in { from { opacity: 0; transform: translateY(-8px) scale(0.985); } }
@keyframes fade-in { from { opacity: 0; } }
.palette-input-row { display: flex; align-items: center; gap: var(--sp-3); padding: 0 var(--sp-4); border-bottom: 1px solid var(--line); }
.palette-input-row .icon { color: var(--ink-3); width: 18px; height: 18px; }
.palette-input { flex: 1; height: 56px; border: 0; background: transparent; font-size: 1rem; color: var(--ink-1); min-width: 0; }
.palette-input:focus-visible { outline: none; }
.palette-list { overflow-y: auto; padding: var(--sp-2); }
.palette-group { padding: var(--sp-2) var(--sp-3) var(--sp-1); font: var(--text-caption); color: var(--ink-3); }
.palette-item {
  display: flex; align-items: center; gap: var(--sp-3); min-height: 40px; padding: 0 var(--sp-3); border-radius: var(--r-md);
  cursor: pointer; color: var(--ink-1);
}
.palette-item .icon { color: var(--ink-3); }
.palette-item .hint { margin-left: auto; color: var(--ink-3); font: var(--text-body-sm); }
.palette-item[aria-selected="true"] { background: var(--accent-wash); }
.palette-item[aria-selected="true"] .icon { color: var(--accent); }
.palette-empty { padding: var(--sp-8) var(--sp-4); text-align: center; color: var(--ink-3); }
.palette-foot { display: flex; gap: var(--sp-4); padding: var(--sp-2) var(--sp-4); border-top: 1px solid var(--line); font: var(--text-caption); color: var(--ink-3); }
.palette-foot span { display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 719px) { .dialog { margin-top: var(--sp-4); max-height: calc(100dvh - 32px); } .palette-foot { display: none; } }

/* ---------------------------------------------------------------- states: skeleton, empty, error, offline */
.skeleton {
  display: block; border-radius: var(--r-sm); background: var(--skeleton-a);
  background-image: linear-gradient(90deg, var(--skeleton-a) 0, var(--skeleton-b) 40%, var(--skeleton-a) 80%);
  background-size: 200% 100%; animation: shimmer 1400ms linear infinite; color: transparent;
}
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
.sk-line { height: 12px; }
.sk-title { height: 18px; width: 40%; }
.sk-stat { height: 28px; width: 60%; }

.state {
  display: grid; justify-items: center; gap: var(--sp-3); padding: var(--sp-12) var(--sp-6); text-align: center;
}
.state-art { width: 56px; height: 56px; display: grid; place-items: center; border-radius: var(--r-xl);
  background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); color: var(--ink-3); }
.state-art .icon { width: 24px; height: 24px; }
.state-ok .state-art { color: var(--ok); background: var(--ok-wash); box-shadow: none; }
.state-crit .state-art { color: var(--crit); background: var(--crit-wash); box-shadow: none; }
.state-title { font: var(--text-title-2); }
.state-body { max-width: 44ch; color: var(--ink-2); }

.banner {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface-1); border: 1px solid var(--line); color: var(--ink-1); font: var(--text-body-sm);
}
.banner .icon { flex: none; }
.banner-crit { background: var(--crit-wash); border-color: transparent; color: var(--crit-ink); }
.banner-warn { background: var(--warn-wash); border-color: transparent; color: var(--warn-ink); }
.banner .btn { margin-left: auto; }

.status-msg { min-height: 20px; font: var(--text-body-sm); color: var(--ink-2); }
.status-msg.error { color: var(--crit-ink); }
.status-msg.success { color: var(--ok-ink); }

/* ---------------------------------------------------------------- tooltip (charts) */
.tooltip {
  position: fixed; z-index: 60; pointer-events: none; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md);
  background: var(--surface-2); box-shadow: var(--shadow-2); font: var(--text-body-sm); color: var(--ink-2);
  min-width: 140px; max-width: 260px;
}
.tooltip strong { color: var(--ink-1); font-weight: 600; font-variant-numeric: tabular-nums; }
.tooltip .tt-row { display: flex; align-items: center; gap: var(--sp-2); }
.tooltip .tt-key { width: 10px; height: 2px; border-radius: 1px; flex: none; }
.tooltip .tt-row strong { margin-left: auto; padding-left: var(--sp-3); }

/* ---------------------------------------------------------------- motion helpers */
.enter { animation: enter var(--dur-3) var(--ease-out) both; }
@keyframes enter { from { transform: translateY(6px); } }
.settle { animation: settle var(--dur-3) var(--ease-out) both; }
@keyframes settle { from { transform: translateY(5px); } }
/* Motion never hides content: transform only, so a paused animation (background tab, screenshot, thumbnail) still shows everything. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
  .beat-ok .beat-dot::after { display: none; }
  .skeleton { animation: none; }
}
@media (forced-colors: active) {
  .strip-col.has-ok::before, .strip-col.has-fail::after, .meter-fill, .meter-tick, .beat-dot::before { background: CanvasText; forced-color-adjust: none; }
  .chip, .tag-demo { border: 1px solid CanvasText; }
}
