:root {
  --bg: #0f1115;
  --panel: #171a21;
  --panel-border: #262b35;
  --text: #e6e8ec;
  --text-muted: #8b91a0;
  --accent: #4f8cff;
  --accent-muted: #2a3a5c;
  --ok: #3ecf8e;
  --warn: #e8b339;
  --danger: #e6553b;
  --radius: 8px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  line-height: 1.5;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.app-shell { display: flex; min-height: 100vh; }

nav.sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--panel);
  border-right: 1px solid var(--panel-border);
  padding: 24px 0;
}

nav.sidebar .brand {
  font-weight: 600;
  font-size: 15px;
  padding: 0 20px 20px;
  color: var(--text);
  border-bottom: 1px solid var(--panel-border);
  margin-bottom: 12px;
}

nav.sidebar .brand small { display: block; color: var(--text-muted); font-weight: 400; margin-top: 2px; }

nav.sidebar a {
  display: block;
  padding: 10px 20px;
  color: var(--text-muted);
  font-weight: 500;
}

nav.sidebar a.active, nav.sidebar a:hover {
  color: var(--text);
  background: var(--accent-muted);
  text-decoration: none;
}

/* min-width: 0 overrides the flex-item default of min-width: auto, which
   otherwise refuses to let this column shrink below its content's
   intrinsic width (e.g. the Schedules table) -- this was the actual cause
   of page-level horizontal overflow at ~901-1024px with real table data,
   even though .table-scroll below was already correctly scrolling
   internally. See QA issue #5 regression note below. */
main.content { flex: 1; min-width: 0; padding: 32px 40px; max-width: 1200px; }

h1 { font-size: 22px; margin: 0 0 4px; font-weight: 600; }
h2 { font-size: 16px; margin: 28px 0 12px; font-weight: 600; color: var(--text); }
.subtitle { color: var(--text-muted); margin-bottom: 24px; }

.panel {
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  padding: 20px;
  margin-bottom: 20px;
}

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }

.card {
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  overflow: hidden;
}

.card .thumb {
  height: 110px;
  background: linear-gradient(135deg, #232838, #171a21);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--panel-border);
}

.card .body { padding: 12px 14px; }
.card .title { font-weight: 600; font-size: 13px; margin-bottom: 4px; }
.card .meta { color: var(--text-muted); font-size: 12px; }

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.badge-ok { background: rgba(62,207,142,0.15); color: var(--ok); }
.badge-warn { background: rgba(232,179,57,0.15); color: var(--warn); }
.badge-danger { background: rgba(230,85,59,0.15); color: var(--danger); }
.badge-muted { background: rgba(139,145,160,0.15); color: var(--text-muted); }

/* Long failure-reason badges (e.g.
   NO_ELIGIBLE_RELEASE_AFTER_SEASON_AND_EPISODE_SEARCH) must wrap inside
   their card instead of spilling past its edge -- QA issue #6. */
.badge { white-space: normal; word-break: break-word; max-width: 100%; }
.card .meta { white-space: normal; overflow-wrap: break-word; }

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--panel-border); }
th { color: var(--text-muted); font-weight: 500; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; }

/* Contain a wide table's overflow to a scrollbar *inside* the panel rather
   than letting it push the whole page wider than the viewport -- QA issue
   #5 (Schedules' 9-column table overflowed even at 1024px). The table
   itself keeps its natural width; only this wrapper scrolls. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.form-row { margin-bottom: 14px; }
.form-row label { display: block; margin-bottom: 6px; font-weight: 500; color: var(--text-muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; }
input[type=text], input[type=password], input[type=url], input[type=number], select {
  width: 100%;
  padding: 9px 11px;
  background: #0f1115;
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  color: var(--text);
  font-size: 13px;
}
input:focus, select:focus { outline: 1px solid var(--accent); border-color: var(--accent); }

button, .btn {
  display: inline-block;
  padding: 9px 16px;
  border-radius: 6px;
  border: 1px solid var(--panel-border);
  background: var(--panel);
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
button.primary, .btn.primary { background: var(--accent); border-color: var(--accent); color: #08111f; }
button.danger, .btn.danger { background: var(--danger); border-color: var(--danger); color: #1a0a06; }
button:hover, .btn:hover { filter: brightness(1.1); text-decoration: none; }

.checkbox-row { display: flex; align-items: center; gap: 8px; }
.checkbox-row input { width: auto; }

.banner {
  padding: 14px 16px;
  border-radius: var(--radius);
  border: 1px solid var(--panel-border);
  margin-bottom: 20px;
  font-size: 13px;
}
.banner.warn { border-color: rgba(232,179,57,0.4); background: rgba(232,179,57,0.08); }
.banner.danger { border-color: rgba(230,85,59,0.4); background: rgba(230,85,59,0.08); }
.banner.ok { border-color: rgba(62,207,142,0.4); background: rgba(62,207,142,0.08); }

/* Persistent armed-state banner (base.html, every page) -- QA issue #4: the
   old warning banner only existed while NOT armed and only on the
   Dashboard; once armed there was no page-wide equivalent, only a small
   badge on Settings. This is deliberately louder (solid left border) than
   the plain .banner.danger used for one-off error messages. */
.armed-banner { border-left: 4px solid var(--danger); }

.field-hint { font-size: 12px; margin: -8px 0 14px; min-height: 1.4em; color: var(--text-muted); }
.field-hint-warn { color: var(--warn); }
.field-hint-ok { color: var(--ok); }
.field-hint-danger { color: var(--danger); }

.row-ok { background: rgba(62,207,142,0.06); }
.row-fail { background: rgba(230,85,59,0.06); }

.login-shell { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.login-box { width: 340px; }

.empty-state { color: var(--text-muted); padding: 24px 0; text-align: center; }

.progress-bar { height: 6px; border-radius: 999px; background: var(--panel-border); overflow: hidden; }
.progress-bar .fill { height: 100%; background: var(--accent); }

code, .mono { font-family: "SF Mono", Consolas, monospace; font-size: 12px; }

/* Exact searched/probed container path -- must always wrap and stay fully
   selectable/copyable rather than clip or force horizontal scroll on its
   own (it can legitimately be very long: deep media-library layouts). */
.path-display { display: flex; align-items: flex-start; gap: 8px; }
.path-text { display: inline-block; white-space: normal; overflow-wrap: anywhere; word-break: break-all; max-width: 100%; }
.copy-path-btn { flex-shrink: 0; padding: 3px 8px; font-size: 11px; }

.episode-list { margin: 4px 0 0; padding-left: 18px; font-size: 12px; color: var(--text-muted); }

/* Scanned-files/repair-groups/per-group-item tables (direct public-preview
   follow-up feedback: "The path text in the scanned files and groups is
   horizontal"). The root cause was `table-layout: auto` inside a
   `.table-scroll` (overflow-x: auto) wrapper: auto layout sizes each column
   to its content's max-content width with nothing to stop it, so a browser
   happily grew the Path column arbitrarily wide and let the wrapper scroll
   sideways to it instead of ever actually wrapping -- .path-text's own
   overflow-wrap/word-break rules (above) never even got a chance to apply
   because the column itself was never bounded in the first place.
   `table-layout: fixed` + an explicit <colgroup> bounds every column to a
   fixed share of the table's own (100%-of-container) width regardless of
   content, which is what actually makes long paths wrap in place -- the
   .table-scroll wrapper is kept as a harmless fallback (never triggers once
   nothing overflows) rather than removed outright. */
.run-detail-table { table-layout: fixed; }
.run-detail-table td { overflow-wrap: anywhere; word-break: break-word; }

/* Scanned-files/repair-groups table pagination (independent user-journey
   QA, 2026-09-17, Finding 3's remaining half) -- see _pagination.html. */
.pagination-nav { display: flex; align-items: center; gap: 14px; margin-top: 12px; flex-wrap: wrap; }
.pagination-disabled { color: var(--text-muted); opacity: 0.5; }

/* Repair groups, direct public-preview follow-up feedback ("repair group
   needs to be collapsible per group"): a plain HTML5 <details>/<summary> per
   group -- native keyboard support (Enter/Space toggles) and an implicit,
   browser-computed aria-expanded on <summary> that tracks the parent
   <details>' own `open` attribute, with no custom ARIA/JS wiring needed for
   the disclosure semantics themselves (app/web/static/app.js only preserves
   which groups are open/closed across a live SSE/poll re-render -- see its
   `groups` panelHook). Styled to match .panel's look without doubling up
   its padding against the summary/body's own. */
.repair-group, .scan-item { background: var(--panel); border: 1px solid var(--panel-border); border-radius: var(--radius); margin-bottom: 16px; }
.repair-group > summary, .scan-item > summary {
  list-style: revert;
  cursor: pointer;
  padding: 16px 20px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  /* Comfortably above the ~44px touch-target guideline once padding is
     included -- mobile touch usability, direct public-preview feedback. */
  min-height: 20px;
}
.repair-group > summary:focus-visible, .scan-item > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.repair-group-title, .scan-item-title { font-weight: 600; }
.repair-group-meta, .scan-item-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; color: var(--text-muted); font-size: 12px; }
.repair-group-body, .scan-item-body { padding: 0 20px 20px; }

/* Scanned-file item body fields (Reason/Episodes/Path/Diagnostics & IDs),
   direct public-preview correction, 2026-09-17: "every item in the scanned
   items list" needs exactly ONE disclosure per item, closed by default,
   with ONLY Title and Label visible on its closed summary -- everything
   else moved out of always-visible table cells into this stacked body. */
.scan-item-field { margin-bottom: 12px; }
.scan-item-field:last-child { margin-bottom: 0; }
.scan-item-field-label { display: block; font-weight: 600; color: var(--text-muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 4px; }

details { margin-top: 4px; }
details summary { cursor: pointer; color: var(--accent); font-size: 12px; }
.diagnostics-block { white-space: pre-wrap; overflow-wrap: anywhere; margin: 6px 0; color: var(--text-muted); }

/* Declarative, chronological run log (Checking <path> / outcome / reason) --
   app/pipeline/display.py:run_log_entries. Fixed-height, internally
   scrollable (never lets one run's log stretch the whole page vertically --
   the 2026-09-17 production-report GUI complaint) with its own
   search/severity filter and auto-follow toggle; app/web/static/app.js's
   initRunLogPanel owns the interactive behavior. */
.run-log-toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; font-size: 12px; }
.run-log-toolbar input[type="search"] { flex: 1; min-width: 140px; }
.run-log-follow-label { margin: 0; text-transform: none; font-size: 12px; white-space: nowrap; }
.run-log-scrollbox { max-height: 360px; overflow-y: auto; border: 1px solid var(--panel-border); border-radius: 6px; padding: 8px 10px; }
.run-log { list-style: none; margin: 0; padding: 0; font-size: 12px; }
.run-log li { padding: 6px 0; border-bottom: 1px solid var(--panel-border); }
.run-log li:last-child { border-bottom: none; }
.run-log-time { color: var(--text-muted); margin-right: 8px; }
.run-log-detail { display: block; color: var(--text-muted); overflow-wrap: anywhere; margin-top: 2px; }
.run-log-sev-danger { color: var(--danger); }
.run-log-sev-warn { color: var(--warn); }
.run-log-sev-ok { color: var(--ok); }

/* Instance edit disclosure (Settings) -- a <details> element so the form
   works with JS disabled; kept visually distinct from the always-visible
   row actions. */
.edit-instance-form { margin-top: 10px; padding: 12px; border: 1px solid var(--panel-border); border-radius: 6px; background: rgba(255,255,255,0.02); }

.run-scan-form { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }

/* Responsive: the sidebar was a fixed 220px column that never collapsed,
   so every page overflowed horizontally below ~1024px (worst case, the
   Schedules table, at 1270px even at 1024px viewport) -- QA issue #5.
   The .table-scroll wrapper below was not sufficient on its own: main.content
   also needed `min-width: 0` (see its rule above) to actually let the flex
   item shrink instead of pushing the whole document wider than the
   viewport. Re-verified with real (non-empty, long-tag/long-timezone)
   schedule rows retained through every check at 375/768/1024/1440px --
   zero document-level horizontal overflow at any of them; see
   RELEASE_CANDIDATE.md and evidence/release-1.0.0/. */
@media (max-width: 1024px) {
  main.content { padding: 24px; }
}

@media (max-width: 900px) {
  .app-shell { flex-direction: column; min-height: 0; }
  nav.sidebar {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    padding: 10px 16px;
    border-right: none;
    border-bottom: 1px solid var(--panel-border);
  }
  nav.sidebar .brand {
    border-bottom: none;
    margin-bottom: 0;
    padding: 4px 16px 4px 0;
    flex: 1 1 auto;
  }
  nav.sidebar .brand small { display: none; }
  nav.sidebar a { padding: 8px 12px; }
  nav.sidebar form { padding: 0 !important; margin-left: auto; width: auto !important; }
  nav.sidebar form button { width: auto; }
  main.content { padding: 20px; max-width: 100%; }
}

@media (max-width: 480px) {
  main.content { padding: 14px; }
  h1 { font-size: 19px; }
  .panel { padding: 14px; }
  .grid { grid-template-columns: 1fr; }
  .run-scan-form { flex-direction: column; align-items: stretch; }
  .run-scan-form > div { width: 100%; }
  td, th { padding: 6px 8px; }
}

/* Schedules table, mobile: independent user-journey QA, 2026-09-17,
   Finding 6 -- at 375px this table's own .table-scroll wrapper (866px
   content in a 317px box) hid TIMEZONE/TAGS/COOLDOWN/MODE/FORCE PACK/
   ENABLED/actions behind an internal horizontal scrollbar with no visible
   scrollbar or affordance: a user had to already know to swipe sideways
   INSIDE the table (not the page) to discover whether their own schedule
   was even enabled. Below this width the table becomes one stacked card
   per schedule instead -- every column always visible, nothing to
   discover by touch, and the raw `include_any: [1]` tag-id display (also
   flagged in Finding 1) is no longer additionally hidden by default. Left
   untouched above this width, where the existing horizontal scroll
   already has enough room to not be the practical problem it is at phone
   widths. */
@media (max-width: 700px) {
  .schedules-table thead { display: none; }
  .schedules-table, .schedules-table tbody, .schedules-table tr, .schedules-table td {
    display: block; width: 100%;
  }
  .schedules-table { overflow: visible; }
  .schedules-table tr {
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    margin-bottom: 12px;
    padding: 10px 12px;
  }
  .schedules-table tr:last-child { margin-bottom: 0; }
  .schedules-table td {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    text-align: right;
    border-bottom: 1px solid var(--panel-border);
    padding: 8px 0;
  }
  .schedules-table td:last-child { border-bottom: none; }
  .schedules-table td::before {
    content: attr(data-label);
    font-weight: 600;
    color: var(--text-muted);
    text-align: left;
    flex: 0 0 auto;
  }
  .schedules-table td[data-label="Actions"] { flex-direction: column; align-items: stretch; text-align: left; }
  .schedules-table td[data-label="Actions"]::before { margin-bottom: 6px; }
  .schedules-table td[data-label="Actions"] form { margin-bottom: 6px; }
}

/* Repair-group-item table, mobile: same problem as the Schedules table
   above (a many-column table has no room at phone widths), but a
   label-above-value stacked layout instead of Schedules' label-left/
   value-right flex row -- these columns hold long-form content (full paths,
   diagnostics) that reads better wrapping full-width under its own label
   than squeezed into the right half of a flex row. Direct public-preview
   follow-up feedback covered both the horizontal-path problem (table-layout:
   fixed, above) and mobile touch usability generally. (The scanned-files
   panel stopped being a table entirely in the "one disclosure per item"
   correction -- .scan-item-field's stacked label-above-value layout above
   already reads correctly at any width without a separate mobile override.) */
@media (max-width: 700px) {
  .run-detail-table thead { display: none; }
  .run-detail-table, .run-detail-table tbody, .run-detail-table tr, .run-detail-table td {
    display: block; width: 100%;
  }
  .run-detail-table { overflow: visible; }
  .run-detail-table tr {
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    margin-bottom: 12px;
    padding: 10px 12px;
  }
  .run-detail-table tr:last-child { margin-bottom: 0; }
  .run-detail-table td {
    border-bottom: 1px solid var(--panel-border);
    padding: 8px 0;
  }
  .run-detail-table td:last-child { border-bottom: none; }
  .run-detail-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-weight: 600;
    color: var(--text-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    margin-bottom: 4px;
  }
  .repair-group > summary, .scan-item > summary { padding: 14px 16px; }
  .repair-group-body, .scan-item-body { padding: 0 16px 16px; }
}
