/* Dashboard styles. Every color, size, radius and space comes from tokens.css,
   which loads first. No raw color literals here: tests/test_design_tokens.py
   fails on them. Rules and tables: DESIGN-TOKENS.md.

   Three weights: 400 for body and table text, 500 for labels, buttons and nav,
   600 for page and section headings and the big numbers. Surfaces follow the
   Figma Reporting screen (42:112): a canvas page, surface-1 panels with a
   hairline and a 12px radius, 8px controls, no shadows. */

* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: var(--type-body-weight);
  font-size: var(--type-body-size);
  line-height: var(--type-body-leading);
  letter-spacing: var(--type-body-tracking);
  color: hsl(var(--foreground));
  background: hsl(var(--background));
}
/* Page title: display-md. Section title: headline. */
h1 {
  font-size: var(--type-display-md-size);
  font-weight: var(--type-display-md-weight);
  line-height: var(--type-display-md-leading);
  letter-spacing: var(--type-display-md-tracking);
  margin: var(--space-md) 0 var(--space-lg);
}
h2 {
  font-size: var(--type-headline-size);
  font-weight: var(--type-headline-weight);
  line-height: var(--type-headline-leading);
  letter-spacing: var(--type-headline-tracking);
  margin: var(--space-xl) 0 var(--space-md);
}
strong, b, summary, legend { font-weight: var(--weight-medium); }
button, input, select, textarea {
  font-family: inherit;
  letter-spacing: inherit;
}
/* Code, commit SHAs and IDs: JetBrains Mono. */
code, kbd, samp, pre {
  font-family: var(--font-mono);
  font-weight: var(--type-mono-weight);
  letter-spacing: var(--type-mono-tracking);
}
code, kbd, samp { font-size: 0.93em; }
.mono {
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  font-weight: var(--type-mono-weight);
  letter-spacing: var(--type-mono-tracking);
}
/* Links are primary: 5.0:1 on the canvas, 4.7 on surface-1. Primary on
   surface-2 is 4.4:1, so no link sits on surface-2. Dark uses a lighter purple
   (tokens.css). */
a { color: hsl(var(--link)); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Focus: a 2px ring on every interactive element. */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, summary:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
}

/* Status dot. One rule draws it, each class below only sets --dot. The text
   beside it stays ink or ink-subtle. */
:is(td, span).positive::before,
:is(td, span).negative::before,
[class*="status-"]::before,
.pill[class*="stop-"]::before,
.flag::before,
.verdict::before,
td.oee-cell::before,
.toast::before {
  content: "";
  display: inline-block;
  width: var(--space-xs);
  height: var(--space-xs);
  margin-right: var(--space-xs);
  border-radius: var(--radius-pill);
  background: var(--dot, hsl(var(--status-inactive)));
  vertical-align: middle;
  position: relative;
  top: -1px;
}
[class*="status-"] { white-space: nowrap; }
.positive { --dot: hsl(var(--status-success)); }
.negative { --dot: hsl(var(--status-error)); }
.status-success, .status-succeeded { --dot: hsl(var(--status-success)); }
.status-failed, .status-timed_out { --dot: hsl(var(--status-error)); }
.status-skipped, .status-no_op, .status-closed {
  --dot: hsl(var(--status-inactive));
  color: hsl(var(--muted-foreground));
}
.status-dispatched, .status-open { --dot: hsl(var(--status-info)); }
.status-running, .status-reverted { --dot: hsl(var(--status-warning)); }
.status-merged { --dot: hsl(var(--primary)); }
/* QA verdicts (a run's) and criterion results (a QA report's). */
.status-passed, .status-pass { --dot: hsl(var(--status-success)); }
.status-fail, .status-error { --dot: hsl(var(--status-error)); }
.status-blocked, .status-interrupted { --dot: hsl(var(--status-warning)); }
.status-needs_input { --dot: hsl(var(--status-info)); }

/* ---- App shell (shell B; Figma Left nav 113:3, Overview 11:3) ----
   The sidebar sits on the app fill (surface-1) and the page in a canvas panel
   beside it, inset 8px top, right and bottom, with 12px corners and a hairline.
   Cross-fade between pages (View Transitions API); the sidebar is its own
   transition group, so it stays still while the page fades. Browsers without
   support, and people who ask for reduced motion, get a plain page load. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
.shell {
  background: hsl(var(--card));
  display: grid;
  grid-template-columns: var(--sidebar) minmax(0, 1fr);
  min-height: 100vh;
}
.panel {
  min-width: 0;
  margin: var(--shell-inset) var(--shell-inset) var(--shell-inset) 0;
  background: hsl(var(--background));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
}

/* Sidebar: nav items 32px, padding 0 8, icon to label 10, radius md. Labels
   ink-muted, icons ink-subtle; hover surface-2; active surface-3 with ink. */
.sidebar {
  view-transition-name: sidebar;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  width: var(--sidebar);
  padding: var(--space-sm);
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  background: hsl(var(--card));
}
.sidebar-head {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: var(--nav-item);
  padding: 0 var(--space-xxs) var(--space-sm) var(--space-nav-y);
}
.sidebar-brand {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  color: hsl(var(--foreground));
  text-decoration: none;
  font-size: var(--type-body-lg-size);
  font-weight: var(--type-body-lg-weight);
  letter-spacing: var(--type-body-lg-tracking);
}
.sidebar-brand:hover { text-decoration: none; }
.sidebar-brand .brand-mark { height: var(--avatar); width: auto; display: block; }
.sidebar-nav { display: flex; flex-direction: column; gap: var(--space-xs); }
.nav-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxxs);
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-nav-icon);
  width: 100%;
  min-height: var(--nav-item);
  padding: 0 var(--space-xs);
  border: 0;
  border-radius: var(--radius-md);
  background: none;
  color: hsl(var(--ink-muted));
  font: inherit;
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-leading);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.nav-item .icon { color: hsl(var(--muted-foreground)); }
.nav-item:hover { background: hsl(var(--muted)); text-decoration: none; }
.nav-item[aria-current="page"] { background: hsl(var(--surface-3)); color: hsl(var(--foreground)); }
.nav-item[aria-current="page"] .icon { color: hsl(var(--foreground)); }
.nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-section {
  padding: var(--space-nav-y) var(--space-xs);
  margin-top: var(--space-xs);
  color: hsl(var(--muted-foreground));
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
}
.icon { width: var(--icon-sm); height: var(--icon-sm); flex: none; }

/* Panel top bar: breadcrumbs on the left, 56px, hairline under it. */
.panel-topbar {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: var(--topbar-height);
  padding: 0 var(--space-md) 0 var(--space-lg);
  border-bottom: 1px solid hsl(var(--border));
}
.crumbs-nav { flex: 1; min-width: 0; }
.crumbs {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--type-body-sm-size);
}
.crumbs li { display: flex; align-items: center; gap: var(--space-xs); min-width: 0; }
.crumbs a {
  display: inline-flex;
  align-items: center;
  min-height: var(--nav-item);
  color: hsl(var(--muted-foreground));
  white-space: nowrap;
}
.crumbs a:hover { color: hsl(var(--foreground)); }
.crumbs .icon { color: hsl(var(--muted-foreground)); }
.crumbs [aria-current="page"] {
  color: hsl(var(--foreground));
  font-weight: var(--weight-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.icon-button {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: var(--nav-item);
  height: var(--nav-item);
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: none;
  color: hsl(var(--muted-foreground));
  cursor: pointer;
}
.icon-button:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }
.menu-button, .drawer-close, .scrim { display: none; }

/* Sidebar foot: the theme toggle and the account menu, under a hairline. */
.sidebar-foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-xxxs);
  padding-top: var(--space-sm);
  border-top: 1px solid hsl(var(--border));
}
/* Theme toggle: cycles automatic, light, dark (static/theme.js). The icon shows
   the current state. */
.theme-toggle svg { display: none; }
:root:not([data-theme]) .theme-toggle .icon-auto,
:root[data-theme="light"] .theme-toggle .icon-light,
:root[data-theme="dark"] .theme-toggle .icon-dark { display: block; }

/* Account menu: avatar, name and role; opens a panel above it with the email,
   role, the access link and "Sign out". */
.user-menu { position: relative; }
.user-menu summary { gap: var(--space-xs); list-style: none; }
.user-menu summary::-webkit-details-marker { display: none; }
.user-menu[open] summary { background: hsl(var(--muted)); }
.user-menu .avatar { width: var(--avatar); height: var(--avatar); }
.user-text { display: flex; flex-direction: column; min-width: 0; line-height: var(--type-caption-leading); }
.user-name {
  color: hsl(var(--foreground));
  font-weight: var(--weight-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user-role { color: hsl(var(--muted-foreground)); font-size: var(--type-caption-size); }
.user-menu-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + var(--space-xs));
  z-index: 20;
  display: flex;
  flex-direction: column;
  padding: var(--space-xs);
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-md);
}
.user-menu-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xxs);
  padding: var(--space-xs) var(--space-sm) var(--space-sm);
  margin-bottom: var(--space-xxs);
  border-bottom: 1px solid hsl(var(--border));
}
.user-menu-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm);
  width: 100%;
}
.user-menu-name { font-weight: var(--weight-medium); }
.user-menu-role {
  flex-shrink: 0;
  font-size: var(--type-caption-size);
  color: hsl(var(--muted-foreground));
}
.user-menu-email { font-size: var(--type-caption-size); color: hsl(var(--muted-foreground)); overflow-wrap: anywhere; }
.user-menu-panel a,
.user-menu-panel button {
  display: block;
  width: 100%;
  margin: 0;
  padding: var(--space-xs) var(--space-sm);
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: hsl(var(--foreground));
  font: inherit;
  font-size: var(--type-body-sm-size);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.user-menu-panel a:hover,
.user-menu-panel button:hover { background: hsl(var(--muted)); }
.user-menu-panel form { margin: 0; }

/* View tabs (project page): pills, 36px, the current one on surface-2. */
.tabs {
  display: flex;
  gap: var(--space-xs);
  overflow-x: auto;
  margin: 0 0 var(--space-lg);
  padding: 0 0 var(--space-sm);
  list-style: none;
  border-bottom: 1px solid hsl(var(--border));
  scrollbar-width: none;
}
.tab {
  display: inline-flex;
  align-items: center;
  min-height: var(--tab-height);
  padding: var(--space-nav-y) var(--space-md);
  border-radius: var(--radius-pill);
  color: hsl(var(--muted-foreground));
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  line-height: var(--type-button-leading);
  white-space: nowrap;
}
.tab:hover { color: hsl(var(--foreground)); background: hsl(var(--card)); text-decoration: none; }
.tab[aria-current="page"] { background: hsl(var(--muted)); color: hsl(var(--foreground)); }

/* Under 900px the sidebar is a drawer over a scrim, opened by the menu button. */
@media (max-width: 899px) {
  body.drawer-open { overflow: hidden; }
  .shell { grid-template-columns: minmax(0, 1fr); }
  .panel { margin: var(--shell-inset); }
  .sidebar {
    position: fixed;
    z-index: 30;
    left: 0;
    top: 0;
    bottom: 0;
    width: min(var(--sidebar), 85vw);
    border-right: 1px solid hsl(var(--border));
    transform: translateX(-100%);
    visibility: hidden;
    /* Visibility must change immediately: interpolating it can reject focus
       while the drawer's opening animation is still at its first frame. */
    transition: transform var(--duration-base) ease;
  }
  .drawer-open .sidebar { transform: none; visibility: visible; }
  .scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 29;
    border: 0;
    padding: 0;
    background: hsl(var(--overlay));
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--duration-base) ease;
  }
  .drawer-open .scrim { opacity: var(--opacity-scrim); pointer-events: auto; }
  .menu-button, .drawer-close { display: inline-grid; }
  .panel-topbar { padding-left: var(--space-xs); }
}
/* Phones: the panel loses its inset and corners. */
@media (max-width: 699px) {
  .panel { margin: 0; border: 0; border-radius: 0; min-height: 100vh; }
  .panel-topbar { padding-right: var(--space-xs); }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar, .scrim { transition: none; }
}

/* ---- Layout ---- */
.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: var(--space-lg);
}
.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-lg);
}
.page-header h1 { margin: 0; }
.page-title-aside {
  font-size: var(--type-body-sm-size);
  font-weight: var(--type-body-sm-weight);
  letter-spacing: var(--type-body-sm-tracking);
}
.month-selector {
  display: flex;
  gap: var(--space-sm);
  align-items: center;
  font-size: var(--type-button-size);
}
.month-selector span { font-weight: var(--type-button-weight); }

/* Phones: page edges line up with the top bar. The title takes the headline
   size and the row above it; the month selector or back link sits below,
   left-aligned, on one line. */
@media (max-width: 640px) {
  .container { padding: var(--space-md); }
  h1 {
    font-size: var(--type-headline-size);
    line-height: var(--type-headline-leading);
    letter-spacing: var(--type-headline-tracking);
  }
  .page-header {
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: var(--space-xs) var(--space-md);
  }
  .page-header h1 { flex: 1 1 100%; }
  .page-header > :not(h1) { white-space: nowrap; }
}

/* Stat tiles: surface-1, a hairline, 12px corners and 20px padding, as on the
   Reporting screen. A good or bad value adds a 3px rule on the left edge in the
   status color. */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-md);
  margin-bottom: var(--space-lg);
}
.card {
  background: hsl(var(--card));
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  padding: calc(var(--space-md) + var(--space-xxs));
}
.card:is(.positive, .negative) { border-left: 3px solid var(--dot); }
.card-label {
  font-size: var(--type-body-sm-size);
  color: hsl(var(--muted-foreground));
  margin-bottom: var(--space-xs);
}
.card-value {
  font-size: var(--type-display-md-size);
  font-weight: var(--type-display-md-weight);
  line-height: var(--type-display-md-leading);
  letter-spacing: var(--type-display-md-tracking);
}
/* The line under a value is a detail, caption size. */
.card-value ~ .card-label {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  margin: var(--space-xs) 0 0;
}

/* ---- Tables ---- */
/* Every table sits in a scroll box. On a phone a wide table scrolls inside it
   and the page keeps its width. The gap below the table lives here. Positioned,
   so a .visually-hidden label in a cell is clipped with the table. */
.table-scroll {
  position: relative;
  overflow-x: auto;
  margin-bottom: var(--space-lg);
}
/* Canvas, a hairline and 12px corners, with a surface-1 header row (Figma 45:547). */
.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: hsl(var(--background));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  overflow: hidden;
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-leading);
  letter-spacing: var(--type-body-sm-tracking);
}
.data-table th, .data-table td {
  text-align: left;
  padding: var(--space-sm) var(--space-md);
  border-bottom: 1px solid hsl(var(--border));
}
.data-table th {
  font-size: var(--type-caption-size);
  font-weight: var(--type-caption-weight);
  line-height: var(--type-caption-leading);
  color: hsl(var(--muted-foreground));
  background: hsl(var(--surface-1));
}
.data-table tr:last-child td { border-bottom: none; }
.data-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.data-table td.num { white-space: nowrap; }
.data-table td.mono, .data-table span.mono { color: hsl(var(--ink-muted)); white-space: nowrap; }
.data-table small { font-size: var(--type-caption-size); }
/* A run table under Pull Requests lists the same work run by run, up to 200
   rows. It scrolls inside a box of fixed height, with its header row in view,
   so the page below it stays in reach. The box carries the frame, so the frame
   stays whole while the rows scroll. clip, not the table's hidden: hidden
   would make the table the box the header sticks to. */
.table-window {
  max-height: var(--table-window);
  overflow-y: auto;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
}
.table-window .data-table { overflow: clip; border: none; border-radius: 0; }
.table-window .data-table thead th { position: sticky; top: 0; z-index: 1; }

/* ---- Panels: charts, OEE, forms ---- */
.chart-section {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  margin-bottom: var(--space-lg);
}
/* A panel title is body-lg, as on the Reporting screen. */
.chart-section h2, .oee-header h2 {
  margin: 0 0 var(--space-md);
  font-size: var(--type-body-lg-size);
  font-weight: var(--type-body-lg-weight);
  line-height: var(--type-body-lg-leading);
  letter-spacing: var(--type-body-lg-tracking);
}
/* Fixed-height box per chart (Chart.js maintainAspectRatio is off, see
   chart-theme.js). The page height then does not depend on when a chart is
   drawn: charts are created after the font loads (RoseyChart.ready), and an
   aspect-ratio canvas would grow the page when it appears. */
.chart-box { position: relative; height: var(--chart-height); }

/* ---- Forms ---- */
.settings-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  max-width: 760px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  margin-bottom: var(--space-lg);
}
.settings-form fieldset {
  /* fieldsets default to min-width:min-content, which let a long <option> or
     inline <code> stretch the whole section past the form. Pin it so flex
     children shrink to the form width instead. */
  min-width: 0;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  padding: var(--space-md) var(--space-lg) var(--space-lg);
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}
.settings-form legend {
  font-size: var(--type-button-size);
  color: hsl(var(--muted-foreground));
  padding: 0 var(--space-xxs);
}
.settings-form label {
  display: flex;
  flex-direction: column;
  gap: var(--space-xxs);
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  color: hsl(var(--foreground));
  min-width: 0;
}
.settings-form .checkbox-label {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-xs);
}
.settings-form .checkbox-label input { width: auto; margin-top: var(--space-xxs); accent-color: hsl(var(--primary)); }
/* Phones: a wrapping label no longer squeezes the checkbox. Scoped to phones so
   the desktop baselines keep the slightly narrower box they show today. */
@media (max-width: 640px) {
  .settings-form .checkbox-label input { flex: none; }
}
/* The agents a project uses: one card per agent, its checkbox, name and what it does.
   A checked card takes the primary outline, so the choice reads at a glance. */
.settings-form .agents-choice { display: flex; flex-direction: column; gap: var(--space-xxs); }
.settings-form .agents-choice p { margin: 0; }
.settings-form .agents-heading {
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  color: hsl(var(--foreground));
}
.settings-form .agent-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-sm);
  margin-top: var(--space-xs);
}
.settings-form .agent-option {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-md);
  background: hsl(var(--card));
  cursor: pointer;
}
.settings-form .agent-option:hover { border-color: hsl(var(--input)); }
.settings-form .agent-option:has(input:checked) { border-color: hsl(var(--primary)); }
.settings-form .agent-option:has(input:focus-visible) { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; }
.settings-form .agent-option input {
  flex: none;
  width: auto;
  margin-top: var(--space-xxs);
  accent-color: hsl(var(--primary));
}
.settings-form .agent-option-text { display: flex; flex-direction: column; gap: var(--space-xxs); min-width: 0; }
.settings-form .agent-option-name { font-size: var(--type-button-size); font-weight: var(--type-button-weight); }
.settings-form .agent-option-desc,
.settings-form .agent-option-note {
  font-size: var(--type-caption-size);
  font-weight: var(--type-caption-weight);
  line-height: var(--type-caption-leading);
  color: hsl(var(--muted-foreground));
}
/* Warning fails AA as text (DESIGN-TOKENS.md rule 7): ink text after a warning dot. */
.settings-form .agent-option-note { color: hsl(var(--foreground)); }
.settings-form .agent-option-note::before {
  content: "";
  display: inline-block;
  width: var(--space-xs);
  height: var(--space-xs);
  margin-right: var(--space-xxs);
  border-radius: var(--radius-pill);
  background: hsl(var(--status-warning));
}

/* Text inputs and selects are 44px (Figma Text Input 3:404). Checkboxes and
   radios keep their own size, so they stay level with their labels. */
.settings-form input:not([type="checkbox"], [type="radio"], [type="hidden"]),
.settings-form select { min-height: var(--input-height); }
/* Inputs: canvas with an ink-tertiary outline, 3.2:1 (Figma's hairline is 1.3:1). */
.settings-form input,
.settings-form select,
.settings-form textarea {
  width: 100%;
  min-width: 0;
  padding: var(--space-xs) var(--space-sm);
  border: 1px solid hsl(var(--input));
  border-radius: var(--radius-md);
  font-size: var(--type-body-sm-size);
  font-weight: var(--type-body-sm-weight);
  color: hsl(var(--foreground));
  background: hsl(var(--background));
}
/* ink-tertiary is for placeholders and disabled text only, never content. */
.settings-form ::placeholder { color: hsl(var(--ink-tertiary)); }
.settings-form textarea {
  resize: vertical;
  min-height: calc(var(--space-xl) + var(--space-xs)); /* not --input-height */
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  line-height: var(--type-mono-leading);
  letter-spacing: var(--type-mono-tracking);
}
.settings-form code, .settings-form pre {
  background: hsl(var(--muted));
  padding: 0 var(--space-xxs);
  border-radius: var(--radius-xs);
}
.settings-form pre {
  margin: 0;
  padding: var(--space-sm);
  overflow-x: auto;
  font-size: var(--type-mono-size);
  line-height: var(--type-mono-leading);
}
/* A long URL in a form hint breaks instead of sticking out. */
.settings-form small code { overflow-wrap: anywhere; }
/* Guard: inline <code> inside a flex-column <label> would otherwise become a
   full-width stretched flex item. Keep it inline-sized. */
.settings-form label code { align-self: flex-start; width: auto; }
.settings-form p { margin: 0; }
.settings-form p small,
.settings-form small {
  color: hsl(var(--muted-foreground));
  font-size: var(--type-caption-size);
  font-weight: var(--type-caption-weight);
  line-height: var(--type-caption-leading);
}
.settings-form .form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--space-md);
}
.settings-form .form-row > label { margin: 0; }
/* Primary button: a primary fill with white text, 5.0:1. */
.settings-form button,
.google-btn {
  align-self: flex-start;
  min-height: var(--control-height);       /* Figma Button 3:387 */
  margin-top: var(--space-xxs);
  padding: var(--space-xs) var(--space-md);
  background: hsl(var(--primary));
  color: hsl(var(--on-primary));
  border: 1px solid hsl(var(--primary));
  border-radius: var(--radius-md);
  cursor: pointer;
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  line-height: var(--type-button-leading);
  transition: background 150ms ease;
}
.settings-form button:hover,
.google-btn:hover {
  background: hsl(var(--button-hover));
  border-color: hsl(var(--button-hover));
  text-decoration: none;
}
/* Secondary: surface-1 with a control outline. Destructive: the same, with a
   danger outline and dot. */
.settings-form button.secondary,
.settings-form button.danger,
.turn-controls button {
  background: hsl(var(--card));
  color: hsl(var(--foreground));
  border-color: hsl(var(--input));
}
.settings-form button.secondary:hover,
.settings-form button.danger:hover,
.turn-controls button:hover { background: hsl(var(--muted)); }
.settings-form button.danger { border-color: hsl(var(--danger)); }
.settings-form button.danger::before {
  content: "";
  display: inline-block;
  width: var(--space-xs);
  height: var(--space-xs);
  margin-right: var(--space-xs);
  border-radius: var(--radius-pill);
  background: hsl(var(--danger));
}
/* Projects on the same runner are bold in the copy: medium weight and ink
   against the ink-subtle of the rest. */
.batch-nearby ul {
  margin: var(--space-xs) 0;
  padding-left: var(--space-lg);
  font-size: var(--type-body-sm-size);
  color: hsl(var(--muted-foreground));
}
.batch-nearby strong { color: hsl(var(--foreground)); }
.jira-test {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
}
.jira-test button { margin-top: 0; }
.jira-test .positive, .jira-test .negative { font-size: var(--type-body-sm-size); }
/* The ✓ and ✗ say pass or fail by shape, in the foreground color, so there is
   no dot. */
.jira-test .positive::before, .jira-test .negative::before { content: none; }
.htmx-indicator {
  opacity: 0;
  transition: opacity 150ms ease;
  color: hsl(var(--muted-foreground));
  font-size: var(--type-body-sm-size);
}
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
.run-panel {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  padding: var(--space-md) var(--space-lg);
  margin-bottom: var(--space-md);
}
.run-panel summary { cursor: pointer; font-size: var(--type-body-sm-size); }
.run-panel[open] summary { margin-bottom: var(--space-md); }
.run-panel .settings-form { padding: 0; margin: 0; border: none; border-radius: 0; }

/* ---- Login ---- */
.login-page {
  max-width: 420px;
  margin: var(--space-xxl) auto;
  padding: var(--space-xxl) var(--space-xl);
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  text-align: center;
}
/* Phones: the card keeps a gap at each edge, as wide as the top bar's padding. */
@media (max-width: 640px) {
  .login-page { margin: var(--space-xxl) var(--space-md); }
}
.login-page .brand-mark { height: 56px; width: auto; }
.login-page h1 { margin-top: var(--space-md); }
.login-page .brand-sub {
  font-size: var(--type-body-sm-size);
  font-weight: var(--type-body-sm-weight);
  letter-spacing: var(--type-body-sm-tracking);
  color: hsl(var(--muted-foreground));
}
.google-btn {
  display: inline-flex;
  align-items: center;
  margin-top: var(--space-lg);
  padding: var(--space-sm) var(--space-lg);
}

/* ---- Toasts ---- */
#toast-container {
  position: fixed;
  top: var(--space-md);
  right: var(--space-md);
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
.toast {
  padding: var(--space-sm) var(--space-lg);
  border-radius: var(--radius-md);
  font-size: var(--type-body-sm-size);
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
  outline: 1px solid hsl(var(--popover-border));
  animation: toast-in 300ms ease;
  max-width: 400px;
  word-break: break-word;
}
.toast-success { --dot: hsl(var(--status-success)); }
.toast-error { --dot: hsl(var(--status-error)); }
.toast-out { opacity: 0; transition: opacity 400ms ease; }
@keyframes toast-in {
  from { opacity: 0; transform: translateX(var(--space-md)); }
  to   { opacity: 1; transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }

/* ---- Run detail: session viewer ---- */
.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  align-items: center;
  margin-bottom: var(--space-md);
}
/* Pills are for status only. Other metadata gets a tag with 6px corners. */
.pill {
  display: inline-block;
  padding: var(--space-xxs) var(--space-xs);
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-sm);
  background: hsl(var(--background));
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: hsl(var(--foreground));
  white-space: nowrap;
}
.pill[class*="status-"], .pill[class*="stop-"] {
  border-radius: var(--radius-pill);
  padding: var(--space-xxs) var(--space-sm);
}
a.pill { color: hsl(var(--link)); }
a.pill:hover { border-color: hsl(var(--link)); text-decoration: none; }
/* Run stop reasons. max_turns is a budget problem, not a code problem: it gets
   the warning dot so it is not mistaken for a genuine failure. */
.pill.stop-max_turns { --dot: hsl(var(--status-warning)); }
.pill.stop-error { --dot: hsl(var(--status-error)); }
.pill.stop-completed { --dot: hsl(var(--status-success)); }
.handoff-note { margin-bottom: var(--space-lg); }
/* Project page: why dispatch is paused. Ink text on a status band, as statuses
   are drawn; the band's color says how bad. */
.dispatch-banner {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-left: 3px solid var(--band);
  border-radius: var(--radius-lg);
  padding: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-lg);
  font-size: var(--type-body-sm-size);
  --band: hsl(var(--status-error));
}
.dispatch-banner-info { --band: hsl(var(--status-info)); }
.dispatch-banner-warning { --band: hsl(var(--status-warning)); }
.dispatch-banner-error { --band: hsl(var(--status-error)); }
/* What made a run fail: ink text on a danger rule, as statuses are drawn. */
.run-error {
  border-left: 3px solid hsl(var(--danger));
  padding-left: var(--space-sm);
}
/* QA run page (qa_detail.html). */
.qa-criterion { margin-bottom: var(--space-lg); }
.qa-evidence { display: flex; flex-wrap: wrap; gap: var(--space-md); margin-top: var(--space-sm); }
.qa-evidence figure { margin: 0; }
.qa-evidence img, .qa-evidence video {
  display: block;
  max-width: 100%;
  max-height: 420px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-sm);
}
.qa-evidence figcaption { font-size: var(--type-caption-size); color: hsl(var(--muted-foreground)); }
.note-text {
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: inherit;
  font-size: var(--type-body-sm-size);
  letter-spacing: var(--type-body-sm-tracking);
}
.muted { color: hsl(var(--muted-foreground)); font-size: var(--type-body-sm-size); }
.turn-controls {
  display: flex;
  gap: var(--space-xs);
  margin-bottom: var(--space-md);
}
.turn-controls button {
  min-height: var(--control-height);
  padding: var(--space-xxs) var(--space-sm);
  border: 1px solid hsl(var(--input));
  border-radius: var(--radius-md);
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  cursor: pointer;
}
/* A turn is a tile: surface-1, a hairline, and a 3px rule in its phase color. */
.turn {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-left: 3px solid var(--band);
  border-radius: var(--radius-lg);
  padding: var(--space-md) var(--space-lg);
  margin-bottom: var(--space-sm);
  --band: hsl(var(--status-inactive));
}
.turn.phase-tool { --band: hsl(var(--status-info)); }
.turn.phase-text { --band: hsl(var(--status-inactive)); }
.turn.phase-final { --band: hsl(var(--status-success)); }
.turn.has-error { --band: hsl(var(--status-error)); }
.turn-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  font-size: var(--type-body-sm-size);
}
.turn-head .turn-usage {
  margin-left: auto;
  color: hsl(var(--muted-foreground));
  font-size: var(--type-caption-size);
  white-space: nowrap;
}
.turn details { margin-top: var(--space-xs); }
.turn details summary {
  cursor: pointer;
  font-size: var(--type-body-sm-size);
  color: hsl(var(--muted-foreground));
}
.turn-prose {
  white-space: pre-wrap;
  word-break: break-word;
  font-size: var(--type-body-sm-size);
  letter-spacing: var(--type-body-sm-tracking);
  margin: var(--space-xxs) 0 0;
  max-height: 420px;
  overflow: auto;
}
.turn-thinking .turn-prose { color: hsl(var(--muted-foreground)); }
.turn-tool { margin-top: var(--space-sm); }
.turn-tool .tool-name { font-size: var(--type-body-sm-size); font-weight: var(--weight-medium); }
.tool-json {
  margin: var(--space-xxs) 0 0;
  padding: var(--space-sm) var(--space-md);
  background: hsl(var(--muted));
  border-radius: var(--radius-md);
  font-size: var(--type-mono-size);
  line-height: var(--type-mono-leading);
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 420px;
  overflow: auto;
}
.result-meta { margin-top: var(--space-md); }
tr.row-link { cursor: pointer; }
/* Surface-1, so links in a hovered row stay at 4.7:1. */
tr.row-link:hover td { background: hsl(var(--surface-1)); }

/* ---- Code reviews (project page, review detail) ---- */
.agent-filter {
  margin: 0 0 var(--space-md);
  font-size: var(--type-body-sm-size);
  color: hsl(var(--muted-foreground));
}
.agent-filter strong { color: hsl(var(--foreground)); }
.review-summary { margin: calc(-1 * var(--space-xs)) 0 var(--space-md); }
.review-toggle {
  margin-left: var(--space-xs);
  padding: 0;
  border: none;
  background: none;
  color: hsl(var(--link));
  font: inherit;
  font-size: var(--type-body-sm-size);
  cursor: pointer;
}
.review-count { margin-left: var(--space-xs); }
.review-table tr.review-run td { background: hsl(var(--surface-1)); }
.review-table tr.review-run td:first-child { padding-left: var(--space-xl); }
.review-table tr.review-run:last-child td { border-bottom: 1px solid hsl(var(--border)); }
/* Section rows of the detail table: labels, medium and ink. */
.review-detail th {
  padding-top: var(--space-md);
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  color: hsl(var(--foreground));
}
.review-detail tr:first-child th { padding-top: var(--space-sm); }
.review-detail td:first-child { color: hsl(var(--muted-foreground)); width: 40%; }
/* Phones: a long value, such as the reviewer run id, wraps inside its cell. */
@media (max-width: 640px) {
  .review-detail td { overflow-wrap: anywhere; }
}

/* ---- Pull Requests (project page, app/pr_view.py) ---- */
.pr-summary { margin: calc(-1 * var(--space-xs)) 0 var(--space-xxs); }
.pr-summary strong { color: hsl(var(--foreground)); }
.pr-caption { margin: 0 0 var(--space-sm); font-size: var(--type-caption-size); }
/* Filters are tabs, so they take the pill shape. */
.pr-filters { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin-bottom: var(--space-md); }
.pr-filters button {
  padding: var(--space-xxs) var(--space-sm);
  border: 1px solid hsl(var(--input));
  border-radius: var(--radius-pill);
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  font-size: var(--type-caption-size);
  font-weight: var(--type-button-weight);
  cursor: pointer;
}
.pr-filters button:hover { background: hsl(var(--muted)); }
.pr-filters button[aria-pressed="true"] {
  background: hsl(var(--foreground));
  border-color: hsl(var(--foreground));
  color: hsl(var(--background));
}
.pr-table td { vertical-align: top; }
.pr-table tr.pr-row { cursor: pointer; }
.pr-table tr.pr-row:hover td { background: hsl(var(--surface-1)); }
/* Each PR is its own tbody, so the rule under the last row of every tbody but
   the table's last comes back. */
.pr-table tbody:not(:last-child) tr:last-child > * { border-bottom: 1px solid hsl(var(--border)); }
.pr-table tbody:last-child tr.pr-row:has(+ tr.pr-detail[hidden]) td { border-bottom: none; }
.pr-cell { min-width: 300px; }
.pr-title { margin-left: var(--space-xxs); }
.pr-cell .pill { margin-left: var(--space-xxs); }
.pr-note {
  margin-top: var(--space-xxs);
  font-size: var(--type-caption-size);
  color: hsl(var(--muted-foreground));
}
.pr-group-row th {
  padding-top: var(--space-md);
  background: hsl(var(--background));
  font-weight: var(--weight-medium);
  color: hsl(var(--foreground));
}
.pr-group-row .muted { font-size: inherit; }
/* A ticket key, linked to its tracker: a tag, so it reads apart from the PR
   number beside it. */
.ticket-key {
  display: inline-block;
  margin-right: var(--space-xxs);
  padding: 0 var(--space-xxs);
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--type-caption-size);
  line-height: var(--type-body-sm-leading);
  white-space: nowrap;
}
a.ticket-key:hover { border-color: hsl(var(--link)); text-decoration: none; }
.pr-ticket-line { margin: 0 0 var(--space-sm); }
.pr-group-toggle {
  margin-left: var(--space-xs);
  padding: 0;
  border: none;
  background: none;
  color: hsl(var(--link));
  font: inherit;
  cursor: pointer;
}
.pr-review { white-space: nowrap; }
/* The other columns, as one line under the title. Phones only. */
.pr-meta { display: none; }
.pr-toggle {
  display: block;
  margin-top: var(--space-xs);
  padding: 0;
  border: none;
  background: none;
  color: hsl(var(--link));
  font: inherit;
  font-size: var(--type-body-sm-size);
  cursor: pointer;
}
/* Why a PR needs a look. The dot says which kind of reason: what a person
   decided, where Rosey struggled, where the reviewer and a person disagree,
   or a verdict nobody gave. */
.flags { display: flex; flex-wrap: wrap; gap: var(--space-xxs); margin-top: var(--space-xs); }
.flag {
  display: inline-block;
  padding: 0 var(--space-xs);
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-sm);
  background: hsl(var(--background));
  font-size: var(--type-caption-size);
  line-height: var(--type-body-sm-leading);
  white-space: nowrap;
}
.flag-human { --dot: hsl(var(--status-error)); }
.flag-rosey { --dot: hsl(var(--status-warning)); }
.flag-split { --dot: hsl(var(--primary)); }
.flag-verdict { --dot: hsl(var(--status-inactive)); }
.verdict { white-space: nowrap; }
.verdict-yes { --dot: hsl(var(--status-success)); }
.verdict-no { --dot: hsl(var(--status-error)); }
.verdict-likely { --dot: hsl(var(--status-inactive)); color: hsl(var(--muted-foreground)); }
/* The details: the cell spans the table, and its body is as wide as the scroll
   box and sticks to its left edge, so on a phone it reads without scrolling
   sideways. */
.pr-scroll { container-type: inline-size; }
/* clip, not the table's hidden: hidden makes the table the scroll box the
   body sticks to, and the table never scrolls. */
.pr-table { overflow: clip; }
.pr-table tr.pr-detail > td { padding: 0; background: hsl(var(--surface-1)); }
.pr-detail-body {
  position: sticky;
  left: 0;
  box-sizing: border-box;
  /* Less the table's 1px borders, or the body would widen the table. */
  width: calc(100cqw - 2px);
  padding: var(--space-md);
}
.pr-sides {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
.pr-side {
  min-width: 0;
  padding: var(--space-sm) var(--space-md);
  background: hsl(var(--background));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
}
.pr-side h3, .pr-detail-label {
  margin: 0 0 var(--space-xs);
  font-size: var(--type-caption-size);
  font-weight: var(--weight-medium);
  line-height: var(--type-caption-leading);
  color: hsl(var(--muted-foreground));
}
.pr-quote {
  margin: var(--space-xs) 0;
  padding-left: var(--space-sm);
  border-left: 2px solid hsl(var(--hairline-strong));
  white-space: pre-line;
  overflow-wrap: anywhere;
}
.pr-side .pill-row { gap: var(--space-xxs); margin: var(--space-xs) 0 0; }
.pr-verdict-line { margin: 0; }
.pr-comment { margin: var(--space-xs) 0 0; overflow-wrap: anywhere; }
/* The timeline: one line per event on a rule, each marked by who acted.
   Builder is primary and Code Reviewer ink-muted, as in the cost chart. */
.pr-timeline {
  list-style: none;
  margin: 0 0 0 var(--space-xxs);
  padding: 0;
  border-left: 2px solid hsl(var(--border));
}
.pr-event {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 0 var(--space-sm);
  align-items: baseline;
  padding: var(--space-xxs) 0 var(--space-xxs) var(--space-md);
}
.pr-event::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--space-xxs) - 1px);
  top: calc(var(--space-xxs) + 0.45em);
  box-sizing: border-box;
  width: var(--space-xs);
  height: var(--space-xs);
  border: 2px solid var(--marker);
  border-radius: var(--radius-pill);
  background: hsl(var(--surface-1));
}
.actor-builder { --marker: hsl(var(--chart-1)); }
.actor-reviewer { --marker: hsl(var(--chart-4)); }
.actor-qa { --marker: hsl(var(--chart-2)); }
.actor-human { --marker: hsl(var(--status-info)); }
.actor-milestone { --marker: hsl(var(--status-inactive)); }
.actor-milestone::before { background: var(--marker); }
.pr-when { color: hsl(var(--ink-muted)); white-space: nowrap; }
.pr-cost {
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  color: hsl(var(--ink-muted));
  white-space: nowrap;
  text-align: right;
}
.pr-detail-foot { margin: var(--space-sm) 0 0; font-size: var(--type-caption-size); }
.pr-orphans .table-scroll { margin: var(--space-sm) 0 0; }
@media (max-width: 640px) {
  .pr-table .pr-col { display: none; }
  .pr-cell { min-width: 0; }
  .pr-meta {
    display: block;
    margin-top: var(--space-xxs);
    font-size: var(--type-caption-size);
    color: hsl(var(--muted-foreground));
  }
  .pr-meta .verdict, .pr-meta [class*="status-"] { color: hsl(var(--foreground)); }
  .pr-sides { grid-template-columns: 1fr; }
  .pr-event { grid-template-columns: 1fr auto; }
  .pr-when { grid-column: 1 / -1; }
}


/* ---- OEE panel (app/oee.py, templates/_oee.html) ---- */
.oee-panel {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  margin-bottom: var(--space-lg);
}
.oee-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
}
/* Four tiles of the same width, as on the Reporting screen: the composite takes
   one column, the three factors the other three. */
.oee-body {
  display: grid;
  grid-template-columns: 1fr 3fr;
  gap: var(--space-md);
  align-items: stretch;
}
@media (max-width: 720px) { .oee-body { grid-template-columns: 1fr; } }
.oee-factors {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--space-md);
}
/* A tile: surface-1, a hairline, and a 3px rule in its band color. */
.oee-composite, .oee-factor {
  border: 1px solid hsl(var(--border));
  border-left: 3px solid var(--band);
  border-radius: var(--radius-lg);
  /* 20px, as on the Reporting screen. The label leaves room for the (i) icon. */
  padding: calc(var(--space-md) + var(--space-xxs));
  background: hsl(var(--card));
  /* anchor for the (i) icon */
  position: relative;
}
/* Calculation hint, pinned top-right of each block. Padding-right on the block
   keeps long labels from running under it. */
.oee-info {
  position: absolute;
  /* matches the block's padding-top so the icon sits on the label's line */
  top: calc(var(--space-md) + var(--space-xxs));
  right: calc(var(--space-md) + var(--space-xxs));
  display: inline-flex;
  color: hsl(var(--muted-foreground));
  cursor: help;
  border-radius: 50%;
}
.oee-info svg { width: 15px; height: 15px; display: block; }
.oee-info:hover, .oee-info:focus { color: hsl(var(--foreground)); }
/* Popover: right-anchored so it can't run off the page from a right-hand tile,
   and above the sibling tiles it overlaps. No ancestor clips it. */
.oee-info-bubble {
  display: none;
  position: absolute;
  top: var(--space-lg);
  right: calc(-1 * var(--space-xxs));
  z-index: 20;
  width: max-content;
  max-width: min(26rem, 80vw);
  padding: var(--space-sm);
  background: hsl(var(--popover));
  color: hsl(var(--popover-foreground));
  outline: 1px solid hsl(var(--popover-border));
  border-radius: var(--radius-md);
  font-size: var(--type-caption-size);
  font-weight: var(--type-caption-weight);
  line-height: var(--type-caption-leading);
  text-align: left;
  white-space: normal;
  cursor: default;
}
.oee-info:hover .oee-info-bubble,
.oee-info:focus .oee-info-bubble,
.oee-info:focus-within .oee-info-bubble { display: block; }
/* The composite is the leftmost block, so a right-anchored bubble opens off the
   left edge of the page. Anchor it left and let it open rightward over the
   factor tiles instead. */
.oee-composite .oee-info-bubble { left: calc(-1 * var(--space-xxs)); right: auto; }
/* Label, then the value right under it, then the detail pinned to the bottom,
   on the same line as the factor tiles' details. */
.oee-composite { display: flex; flex-direction: column; }
.oee-composite .oee-factor-detail { margin-top: auto; }
.oee-composite-value, .oee-factor-value {
  font-size: var(--type-display-md-size);
  font-weight: var(--type-display-md-weight);
  line-height: var(--type-display-md-leading);
  letter-spacing: var(--type-display-md-tracking);
}
.oee-factor-label {
  font-size: var(--type-body-sm-size);
  color: hsl(var(--muted-foreground));
  margin-bottom: var(--space-xs);
  padding-right: var(--space-lg);
}
.oee-factor { display: flex; flex-direction: column; }
/* Detail line pinned to the bottom of its block, so the explanatory text sits on
   one baseline across all four regardless of how many lines each one wraps to.
   The question + detail travel together as the bottom text block, so the auto
   margin goes on the question, the first of the pair. */
.oee-factor .oee-factor-question { margin-top: auto; }
.oee-factor-question {
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  line-height: var(--type-button-leading);
  padding-top: var(--space-xs);
}
.oee-factor-detail {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: hsl(var(--muted-foreground));
  margin-top: var(--space-xs);
}
/* Inline with the value it qualifies, on the value's baseline; wraps beneath it
   only when the tile is too narrow for both. */
.oee-factor-valuerow {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  column-gap: var(--space-xs);
}
.oee-capped { color: hsl(var(--muted-foreground)); font-size: var(--type-caption-size); line-height: var(--type-caption-leading); }
/* Bands: >=85% on target, >=80% acceptable, below that off target. The band
   shows as the left rule or dot. The numbers stay ink. */
.oee-good { --band: hsl(var(--status-success)); --dot: hsl(var(--status-success)); }
.oee-ok { --band: hsl(var(--status-warning)); --dot: hsl(var(--status-warning)); }
.oee-poor { --band: hsl(var(--status-error)); --dot: hsl(var(--status-error)); }
.oee-unknown { --band: hsl(var(--status-inactive)); --dot: hsl(var(--status-inactive)); }
.oee-unknown .oee-composite-value, .oee-unknown .oee-factor-value { color: hsl(var(--muted-foreground)); }
/* Human intervention and Rosey share: a label column, then the values, left
   aligned under a hairline. */
.oee-intervention {
  display: flex;
  column-gap: var(--space-lg);
  row-gap: var(--space-xxs);
  flex-wrap: wrap;
  align-items: baseline;
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid hsl(var(--border));
  font-size: var(--type-body-sm-size);
}
.oee-intervention + .oee-intervention {
  margin-top: var(--space-sm);
  padding-top: 0;
  border-top: none;
}
.oee-intervention-label {
  flex: 0 0 160px;
  font-size: var(--type-body-sm-size);
  color: hsl(var(--muted-foreground));
}
/* The factor-tile icon is absolutely positioned to the tile's top-right corner;
   in the intervention row there is no tile to corner it in, so it rides inline
   after the label text instead. The bubble opens up and to the right: this row
   is the last thing in the panel, so a downward bubble would hang off the
   bottom, and a right-anchored one off the left edge. */
/* The headline number of the share row. The rest of the row qualifies it. */
.oee-share-value { color: hsl(var(--foreground)); }
.oee-intervention-label .oee-info {
  position: relative;
  top: auto;
  right: auto;
  margin-left: var(--space-xxs);
  vertical-align: middle;
}
.oee-intervention-label .oee-info-bubble {
  top: auto;
  bottom: var(--space-lg);
  left: calc(-1 * var(--space-xxs));
  right: auto;
}
td.oee-unknown::before { content: none; }
.oee-excluded-note { margin: calc(-1 * var(--space-md)) 0 var(--space-lg); }
/* Footnote marker on internal project names; outside the <a> so it doesn't
   pick up the link colour or underline. */
.oee-excluded-mark { margin-left: var(--space-xxs); }
/* Internal projects (counts_toward_oee = 0): greyed across every column, dots
   included, so the row reads as excluded at a glance. */
tr.oee-internal td,
tr.oee-internal td a { color: hsl(var(--muted-foreground)); }
tr.oee-internal td::before { --dot: hsl(var(--status-inactive)); }

/* ---- Access page (ROS-269) ---- */
.access-intro { max-width: 760px; margin-top: 0; }
.access-notice {
  max-width: 760px;
  padding: var(--space-sm) var(--space-md);
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg);
  background: hsl(var(--card));
  font-size: var(--type-body-sm-size);
}
.access-table { max-width: 760px; }
.access-table code {
  background: hsl(var(--muted));
  padding: 0 var(--space-xxs);
  border-radius: var(--radius-xs);
}
/* Person cell: Google avatar, then name over email. */
.person { display: flex; align-items: center; gap: var(--space-sm); }
.person-name { font-weight: var(--weight-medium); }
.avatar {
  flex: none;
  width: 28px; height: 28px;
  border-radius: 50%;
  object-fit: cover;
}
.avatar-initial {
  display: inline-flex; align-items: center; justify-content: center;
  background: hsl(var(--muted));
  color: hsl(var(--muted-foreground));
  font-size: var(--type-eyebrow-size);
  font-weight: var(--type-eyebrow-weight);
}
.person-text { display: flex; flex-direction: column; min-width: 0; }
.person-email { color: hsl(var(--muted-foreground)); font-size: var(--type-caption-size); }
/* Several people in one cell: a project's admins (ROS-33). */
.person-list { display: flex; flex-direction: column; gap: var(--space-sm); }
.data-table .row-action { width: 1%; text-align: right; white-space: nowrap; }
.data-table .row-action form { margin: 0; }
/* Compact secondary button for actions inside a table row. */
.btn-small {
  padding: var(--space-xxs) var(--space-sm);
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--input));
  border-radius: var(--radius-md);
  font-size: var(--type-caption-size);
  font-weight: var(--type-button-weight);
  cursor: pointer;
}
.btn-small:hover { background: hsl(var(--muted)); }
.settings-form .inline-field { display: flex; gap: var(--space-sm); align-items: stretch; }
.settings-form .inline-field input { flex: 1; }
.settings-form .inline-field button { margin-top: 0; white-space: nowrap; }
/* Phones: keep who and what, drop the audit columns, stack the add form. */
@media (max-width: 640px) {
  .access-table .hide-narrow { display: none; }
  .person-email { overflow-wrap: anywhere; }
  .access-table th, .access-table td { padding-left: var(--space-sm); padding-right: var(--space-sm); }
  .settings-form .inline-field { flex-direction: column; }
  .settings-form .inline-field button { align-self: stretch; }
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* "≥" before a cost that is a floor: its title says what that means. */
.floor-mark { cursor: help; }

/* ---- Disabled (DESIGN-TOKENS.md, "Disabled") ----
   The whole control at --opacity-disabled, ink-tertiary text, no hover change.
   The background and border stay as they are, so hover rules are undone by
   reading the same tokens as the resting state. */
button:disabled, input:disabled, select:disabled, textarea:disabled,
label:has(:disabled) {
  opacity: var(--opacity-disabled);
  cursor: not-allowed;
}
button:disabled, input:disabled, select:disabled, textarea:disabled {
  color: hsl(var(--ink-tertiary)); /* disabled text, allowed by rule 10 */
}
.settings-form button:disabled:hover,
.google-btn:disabled:hover {
  background: hsl(var(--primary));
  border-color: hsl(var(--primary));
}
.settings-form button.secondary:disabled:hover,
.settings-form button.danger:disabled:hover,
.turn-controls button:disabled:hover { background: hsl(var(--card)); }
.btn-small:disabled:hover,
.pr-filters button:disabled:hover { background: hsl(var(--background)); }
.nav-item:disabled:hover { background: none; }
.user-menu-panel button:disabled:hover { background: none; }
.settings-form .agent-option:has(:disabled):hover { border-color: hsl(var(--border)); }
label:has(:disabled) input:disabled { opacity: 1; } /* the label already fades */

/* ---- Touch targets (DESIGN-TOKENS.md, "Touch targets") ----
   On a coarse pointer every control is at least --tap (44px) tall. Icon-only
   buttons are also 44px wide. Checkboxes keep their size: their label is the target. */
@media (pointer: coarse) {
  button,
  input:not([type="checkbox"], [type="radio"], [type="hidden"]),
  select,
  .nav-item,
  .user-menu-panel a,
  .user-menu-panel button,
  .crumbs a,
  .sidebar-brand,
  .tab,
  .month-selector a,
  a.pill,
  .google-btn {
    min-height: var(--tap);
  }
  .month-selector a,
  a.pill { display: inline-flex; align-items: center; }
  .icon-button { width: var(--tap); height: var(--tap); }
}

/* ---- Charts (dashboard-charts.md) ---- */
/* A line under a panel title: what the chart counts, and the numbers it adds up to. */
.chart-caption {
  margin: calc(-1 * var(--space-xs)) 0 var(--space-md);
  color: hsl(var(--muted-foreground));
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-leading);
}
/* Title and a button group on one line; the group wraps under it on a phone. */
.chart-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
.chart-head h2 { margin: 0; }
/* Button group (no reload): secondary buttons side by side, the pressed one on
   surface-4 with ink text. */
.segmented { display: inline-flex; }
.segment {
  min-height: var(--control-height);
  padding: var(--space-xs) var(--space-md);
  background: hsl(var(--card));
  color: hsl(var(--foreground));
  border: var(--border-width) solid hsl(var(--input));
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  line-height: var(--type-button-leading);
  cursor: pointer;
}
.segment:first-child { border-radius: var(--radius-md) 0 0 var(--radius-md); }
.segment:last-child { border-radius: 0 var(--radius-md) var(--radius-md) 0; margin-left: calc(-1 * var(--border-width)); }
.segment:hover { background: hsl(var(--muted)); }
.segment[aria-pressed="true"] { background: hsl(var(--surface-4)); }
/* Headline trend tiles (Figma 42:112): label, value, change, a small line, detail. */
.trend-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--trend-tile-min)), 1fr));
  gap: var(--space-md);
}
.trend-tile {
  display: flex;
  flex-direction: column;
  background: hsl(var(--background));
  border: var(--border-width) solid hsl(var(--border));
  border-radius: var(--radius-lg);
  padding: calc(var(--space-md) + var(--space-xxs));
}
.trend-tile .card-label { margin-bottom: var(--space-xxs); }
.trend-value {
  font-size: var(--type-headline-size);
  font-weight: var(--type-headline-weight);
  line-height: var(--type-headline-leading);
  letter-spacing: var(--type-headline-tracking);
}
.trend-change, .trend-detail {
  color: hsl(var(--muted-foreground));
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
}
.trend-change { margin-top: var(--space-xxs); }
.trend-spark { position: relative; height: var(--sparkline-height); margin: var(--space-xs) 0; }
.trend-detail { margin-top: auto; }
/* A legend drawn as HTML, for a chart that colors bars by sign. */
.chart-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  margin: var(--space-sm) 0 0;
  color: hsl(var(--muted-foreground));
  font-size: var(--type-caption-size);
}
.chart-legend .key {
  width: var(--chart-marker);
  height: var(--chart-marker);
  border-radius: var(--radius-pill);
}
.chart-legend .key ~ .key { margin-left: var(--space-xs); }
.key-under { background: hsl(var(--diverging-n2)); }
.key-over { background: hsl(var(--diverging-p2)); }
.chart-data { margin-top: var(--space-md); font-size: var(--type-body-sm-size); }
.chart-data summary { cursor: pointer; }
.chart-data a { display: inline-flex; align-items: center; }
.chart-footnote { margin-top: var(--space-sm); margin-bottom: 0; }
@media (pointer: coarse) {
  .segment, .chart-data summary, .chart-data a { min-height: var(--tap); }
}
