/* DataTrail — control-plane panel component layer.
 *
 * Third token tier. `ui/design-tokens.css` owns the palette (tier 1) and the semantic intent
 * (tier 2); this file owns the component-scoped tokens (tier 3) and the components that consume
 * them. Nothing here reads the raw palette directly, and no component below hard-codes a colour,
 * radius, duration or control height — every visual value resolves through a token, so a rebrand
 * touches the palette only and a dark mode would touch the semantic tier only.
 *
 * Why this file exists at all: the admin panel emitted `.os-cp-btn`, `.os-cp-section`,
 * `.os-cp-form` and several badge tones that no stylesheet defined, so those controls rendered as
 * raw browser defaults — `border: 2px outset`, square corners, grey `rgb(107,107,107)`. Measured in
 * a real browser, not assumed.
 *
 * Scope is deliberately narrow: every rule is nested under `.os-cp-shell` (or an explicit
 * control-plane class), so this layer cannot reach the reference-fidelity screens whose geometry is
 * pixel-gated.
 */

.os-cp-shell {
  /* ---- tier 3: component-scoped tokens, all derived from the semantic tier ---- */
  --cp-surface: var(--surface-primary);
  --cp-surface-sunken: var(--surface-secondary);
  --cp-surface-hover: var(--surface-hover);
  --cp-surface-selected: var(--surface-selected);
  --cp-fg: var(--text-primary);
  --cp-fg-muted: var(--text-secondary);
  --cp-fg-subtle: var(--text-muted);
  --cp-border: var(--border-default);
  --cp-border-subtle: var(--border-subtle);
  --cp-border-strong: var(--border-strong);
  --cp-accent: var(--action-primary);
  --cp-accent-hover: var(--action-primary-hover);
  --cp-accent-soft: var(--action-primary-soft);
  --cp-danger: var(--status-danger);
  --cp-danger-soft: var(--raw-red-50);
  --cp-success: var(--status-success);
  --cp-success-soft: var(--raw-green-50);
  --cp-warning: var(--status-warning);
  --cp-warning-soft: var(--raw-amber-50);

  --cp-radius-control: var(--radius-md);
  --cp-radius-surface: var(--radius-lg);
  --cp-radius-pill: 999px;

  /* WCAG 2.2 target size is 24px; controls here sit well above it so a pointer, a touch and a
     switch user all get a comfortable target. */
  --cp-control-height: var(--control-sm);
  --cp-control-padding-x: var(--space-3);
  --cp-gap: var(--space-3);
  --cp-section-padding: var(--space-4);

  --cp-motion: var(--motion-fast);
  --cp-ease: var(--ease-standard);
  --cp-shadow-control: var(--shadow-control);
  --cp-shadow-surface: var(--shadow-xs);
}

/* ------------------------------------------------------------------ sections
   A section is the panel's unit of meaning: one heading, one explanation, one set of controls. */
.os-cp-shell .os-cp-section {
  display: grid;
  gap: var(--cp-gap);
  align-content: start;
  padding: var(--cp-section-padding);
  border: 1px solid var(--cp-border);
  border-radius: var(--cp-radius-surface);
  background: var(--cp-surface);
  box-shadow: var(--cp-shadow-surface);
}

.os-cp-shell .os-cp-section > h3 {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  color: var(--cp-fg);
}

.os-cp-shell .os-cp-section > p {
  margin: 0;
  max-width: 78ch;                       /* long explanations stay readable rather than full-bleed */
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--cp-fg-muted);
}

.os-cp-shell .os-cp-section > p.muted { color: var(--cp-fg-subtle); }

/* ------------------------------------------------------------------ buttons
   One button component, four intents. Every intent carries the full interaction-state set the
   design system requires: default / hover / active / focus-visible / disabled. */
.os-cp-shell .os-cp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--cp-control-height);
  padding: 0 var(--cp-control-padding-x);
  border: 1px solid var(--cp-border);
  border-radius: var(--cp-radius-control);
  background: var(--cp-surface);
  color: var(--cp-fg);
  font: var(--weight-semibold) var(--text-sm) / 1 var(--font-sans);
  text-decoration: none;                 /* the row's "open" control is an anchor, not a button */
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--cp-shadow-control);
  transition: background-color var(--cp-motion) var(--cp-ease),
              border-color var(--cp-motion) var(--cp-ease),
              color var(--cp-motion) var(--cp-ease);
}

.os-cp-shell .os-cp-btn:hover:not(:disabled):not([aria-disabled='true']) {
  background: var(--cp-surface-hover);
  border-color: var(--cp-border-strong);
}

.os-cp-shell .os-cp-btn:active:not(:disabled) { background: var(--cp-surface-sunken); }

.os-cp-shell .os-cp-btn.primary {
  background: var(--cp-accent);
  border-color: var(--cp-accent);
  color: var(--text-inverse);
}
.os-cp-shell .os-cp-btn.primary:hover:not(:disabled) {
  background: var(--cp-accent-hover);
  border-color: var(--cp-accent-hover);
}

.os-cp-shell .os-cp-btn.danger { color: var(--cp-danger); border-color: var(--cp-border); }
.os-cp-shell .os-cp-btn.danger:hover:not(:disabled) {
  background: var(--cp-danger-soft);
  border-color: var(--cp-danger);
}

.os-cp-shell .os-cp-btn.ghost { background: transparent; border-color: transparent; box-shadow: none; }
.os-cp-shell .os-cp-btn.ghost:hover:not(:disabled) { background: var(--cp-surface-hover); }

/* Disabled must read as unavailable without dropping below AA contrast — a control the user cannot
   use still has to be legible enough to explain itself. */
.os-cp-shell .os-cp-btn:disabled,
.os-cp-shell .os-cp-btn[aria-disabled='true'] {
  background: var(--cp-surface-sunken);
  border-color: var(--cp-border);
  color: var(--cp-fg-subtle);
  cursor: not-allowed;
  box-shadow: none;
}

/* ------------------------------------------------------------------ forms */
.os-cp-shell .os-cp-form {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--cp-gap);
  padding: var(--space-3);
  border: 1px solid var(--cp-border-subtle);
  border-radius: var(--cp-radius-control);
  background: var(--cp-surface-sunken);
}

.os-cp-shell .os-cp-form label {
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--cp-fg-muted);
}

.os-cp-shell .os-cp-form input,
.os-cp-shell .os-cp-form select {
  min-height: var(--cp-control-height);
  min-width: 12ch;
  padding: 0 var(--space-2);
  border: 1px solid var(--cp-border);
  border-radius: var(--cp-radius-control);
  background: var(--cp-surface);
  color: var(--cp-fg);
  font: var(--weight-medium) var(--text-sm) / 1 var(--font-sans);
}

.os-cp-shell .os-cp-form input:hover,
.os-cp-shell .os-cp-form select:hover { border-color: var(--cp-border-strong); }

/* A field the server rejected explains itself next to the field, not only in a banner. */
.os-cp-shell .os-cp-form [aria-invalid='true'] {
  border-color: var(--cp-danger);
  background: var(--cp-danger-soft);
}

.os-cp-shell .os-cp-field-error {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--cp-danger);
}

/* ------------------------------------------------------------------ badges
   Status is never carried by colour alone: each tone pairs with its own text, and the dot is a
   redundant shape cue for anyone who cannot separate the hues. */
.os-cp-shell .os-cp-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--cp-radius-pill);
  background: var(--cp-surface-sunken);
  color: var(--cp-fg-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: .04em;
  white-space: nowrap;
}

.os-cp-shell .os-cp-badge::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: var(--cp-radius-pill);
  background: currentColor;
  flex: none;
}

/* The label is near-black on every tone, and the DOT carries the hue.
   Tinting the text to match its background is the usual way status pills are built and it fails AA
   badly here — measured on this palette: green 2.21:1, amber 2.00:1, red 4.44:1, blue 4.47:1, all
   under the 4.5 needed at this size. Moving the hue to the dot keeps the tones just as
   distinguishable while making colour redundant rather than load-bearing, which is what the
   accessibility rule is actually asking for. */
.os-cp-shell .os-cp-badge.green { background: var(--cp-success-soft); color: var(--cp-fg); }
.os-cp-shell .os-cp-badge.green::before { background: var(--cp-success); }
.os-cp-shell .os-cp-badge.amber { background: var(--cp-warning-soft); color: var(--cp-fg); }
.os-cp-shell .os-cp-badge.amber::before { background: var(--cp-warning); }
.os-cp-shell .os-cp-badge.red { background: var(--cp-danger-soft); color: var(--cp-fg); }
.os-cp-shell .os-cp-badge.red::before { background: var(--cp-danger); }
.os-cp-shell .os-cp-badge.blue { background: var(--cp-accent-soft); color: var(--cp-fg); }
.os-cp-shell .os-cp-badge.blue::before { background: var(--cp-accent); }
.os-cp-shell .os-cp-badge.grey { background: var(--cp-surface-sunken); color: var(--cp-fg-muted); }

/* ------------------------------------------------------------------ states
   The state matrix the design system requires: idle / loading / empty / error / permission.
   Each is a visible, explained surface rather than a blank area the user has to interpret. */
.os-cp-shell .os-cp-state {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  padding: var(--space-8) var(--space-4);
  border: 1px dashed var(--cp-border-strong);
  border-radius: var(--cp-radius-control);
  background: var(--cp-surface-sunken);
  text-align: center;
}

.os-cp-shell .os-cp-state b {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--cp-fg);
}

.os-cp-shell .os-cp-state span {
  max-width: 56ch;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--cp-fg-muted);
}

.os-cp-shell .os-cp-state.error {
  border-style: solid;
  border-color: var(--cp-danger);
  background: var(--cp-danger-soft);
}
.os-cp-shell .os-cp-state.error b { color: var(--cp-danger); }

.os-cp-shell .os-cp-state.locked { border-style: solid; border-color: var(--cp-border); }

/* Loading: a real skeleton, so the layout does not jump when the data lands. */
.os-cp-shell .os-cp-skeleton {
  display: grid;
  gap: var(--space-2);
}

.os-cp-shell .os-cp-skeleton i {
  display: block;
  height: var(--space-5);
  border-radius: var(--cp-radius-control);
  background: linear-gradient(90deg, var(--cp-surface-sunken) 25%, var(--cp-surface-hover) 37%, var(--cp-surface-sunken) 63%);
  background-size: 400% 100%;
  animation: os-cp-shimmer 1.4s ease infinite;
}

@keyframes os-cp-shimmer {
  from { background-position: 100% 50%; }
  to { background-position: 0 50%; }
}

/* Motion explains; it is never the only signal. With reduced motion the shimmer becomes a static
   tone, so the skeleton still reads as "not real content yet". */
@media (prefers-reduced-motion: reduce) {
  .os-cp-shell .os-cp-skeleton i { animation: none; background: var(--cp-surface-sunken); }
  .os-cp-shell .os-cp-btn { transition: none; }
}

/* ------------------------------------------------------------------ run table */
.os-cp-shell .os-cp-runs { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }

.os-cp-shell .os-cp-runs th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--cp-border);
  background: var(--cp-surface-sunken);
  color: var(--cp-fg-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: .04em;
  text-align: left;
  white-space: nowrap;
}

.os-cp-shell .os-cp-runs td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--cp-border-subtle);
  color: var(--cp-fg);
  vertical-align: middle;
}

.os-cp-shell .os-cp-runs tbody tr:hover { background: var(--cp-surface-hover); }
.os-cp-shell .os-cp-runs td.numeric { font-variant-numeric: tabular-nums; }

.os-cp-shell .os-cp-runs code {
  font: var(--weight-medium) var(--text-xs) / 1.4 var(--font-mono);
  color: var(--cp-fg-muted);
}

.os-cp-shell .os-cp-run-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }

/* ------------------------------------------------------------------ responsive
   Below the md breakpoint the form stacks and the table scrolls in its own container, so the panel
   never forces the page itself to scroll sideways. */
.os-cp-shell .os-cp-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

@media (max-width: 768px) {
  .os-cp-shell .os-cp-form { flex-direction: column; align-items: stretch; }
  .os-cp-shell .os-cp-form label,
  .os-cp-shell .os-cp-form .os-cp-btn { width: 100%; }
  .os-cp-shell .os-cp-section { padding: var(--space-3); }
}

/* ------------------------------------------------------------------ accessibility helpers */
.os-cp-shell .os-cp-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* A busy region stays readable but signals that its content is being replaced. */
.os-cp-shell [aria-busy='true'] { cursor: progress; }

/* ------------------------------------------------------------------ dry-run preview
   The preview is the moment the operator decides whether to spend ~50 seconds and tens of
   megabytes, so it is given real visual weight: the numbers lead, and the fact that nothing is
   written is stated on the surface rather than implied. */
.os-cp-shell .os-cp-preview {
  display: grid;
  gap: var(--cp-gap);
  padding: var(--cp-section-padding);
  border: 1px solid var(--cp-accent);
  border-radius: var(--cp-radius-control);
  background: var(--cp-accent-soft);
}

.os-cp-shell .os-cp-preview > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.os-cp-shell .os-cp-preview > header b {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--cp-fg);
}

.os-cp-shell .os-cp-preview .os-cp-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: var(--space-2);
}

.os-cp-shell .os-cp-fact {
  display: grid;
  /* The panel's existing `.os-cp-facts > div` rule sets a two-column template for its OTHER use
     (a definition list). These tiles are children of the same container, so without an explicit
     single column the label lands in a second column pushed outside a 120px tile — rendered,
     measurable, and invisible. Setting the template here is what keeps the label under its number. */
  grid-template-columns: 1fr;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--cp-border-subtle);
  border-radius: var(--cp-radius-control);
  background: var(--cp-surface);
}

.os-cp-shell .os-cp-fact b {
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  color: var(--cp-fg);
  font-variant-numeric: tabular-nums;   /* counts line up when the preview is re-run */
}

.os-cp-shell .os-cp-fact small {
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--cp-fg-muted);
}

.os-cp-shell .os-cp-preview p {
  margin: 0;
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--cp-fg-muted);
}

.os-cp-shell .os-cp-preview code {
  font: var(--weight-medium) var(--text-xs) / 1.4 var(--font-mono);
  color: var(--cp-fg);
}
