/* theme — ten colour tokens in two sets. The default set is light; a browser
   that reports a dark OS swaps in the dark set through the media query. The
   two data-theme rules below are what the header's toggle writes, and an
   attribute selector on :root outweighs the bare :root both sets above use, so
   the reader's pick wins over the OS whichever way the OS is set. The values
   are the mockup's, unchanged.

   color-scheme rides along with each set. It is what tells the browser which
   way to paint the things we do not style — form controls, scrollbars, the
   canvas behind the page — and without it a light page keeps dark inputs. */
:root { color-scheme: light; --bg: #eceef2; --surface: #fafbfc; --line-subtle: #8c929e; --line: #767d8b; --line-quote: #6c7382; --accent: #2f5bd0; --text: #1a1d24; --text-muted: #4d5462; --text-problem: #a3242a; --focus: #a13a00; }
@media (prefers-color-scheme: dark) {
:root { color-scheme: dark; --bg: #191c22; --surface: #22262e; --line-subtle: #69717f; --line: #7d8698; --line-quote: #8d97aa; --accent: #9ec0ff; --text: #e8ebf0; --text-muted: #c5cbd6; --text-problem: #ffa8a3; --focus: #ffd47a; }
}
:root[data-theme="light"] { color-scheme: light; --bg: #eceef2; --surface: #fafbfc; --line-subtle: #8c929e; --line: #767d8b; --line-quote: #6c7382; --accent: #2f5bd0; --text: #1a1d24; --text-muted: #4d5462; --text-problem: #a3242a; --focus: #a13a00; }
:root[data-theme="dark"] { color-scheme: dark; --bg: #191c22; --surface: #22262e; --line-subtle: #69717f; --line: #7d8698; --line-quote: #8d97aa; --accent: #9ec0ff; --text: #e8ebf0; --text-muted: #c5cbd6; --text-problem: #ffa8a3; --focus: #ffd47a; }

/* scale — the tokens that do not change with the theme, and the page's own
   font. --text-base sits on :root as font-size, so 1rem is 16.5px here and
   every rem below — spacing, max-width, heading defaults — rises with it. */
:root { --space-1: .25rem; --space-2: .5rem; --space-3: .75rem; --space-4: 1rem; --space-5: 1.25rem; --space-6: 2rem; --space-7: 3rem; --font-sans: ui-sans-serif, system-ui, sans-serif; --text-sm: 15px; --text-base: 16.5px; --weight-normal: normal; --radius-control: .5rem; --radius-surface: .75rem; --border: 1px; --border-accent: 2px; --border-quote: 3px; --busy-opacity: .6; font-family: var(--font-sans); font-size: var(--text-base); background: var(--bg); color: var(--text); }

/* base — element defaults, and the page's own width and rhythm. Every <p> on
   these screens is secondary text, which is where .caveat, .empty and .read-at
   get their colour from; their own rules carry no colour. */
body { margin: 0; }
main { max-width: 70rem; margin: 0 auto; padding: var(--space-7) var(--space-6); }
p { color: var(--text-muted); }
/* app.js moves focus to runs-heading and failure-heading after a swap, so where
   focus landed has to be visible: without a mark the reader is told the answer
   arrived and not where. The browser default is whatever the browser picked for
   this background and is not measured. :focus-visible, not :focus, so a mouse
   click on a button does not draw the ring. */
:focus-visible { outline: var(--border-accent) solid var(--focus); outline-offset: var(--border-accent); }

/* app-header */
header { display: flex; gap: var(--space-4); align-items: baseline; padding: var(--space-5) var(--space-6); border-bottom: var(--border) solid var(--line-subtle); }
header span { color: var(--text-muted); }
.environments { margin-left: auto; font-size: var(--text-sm); }
.session { margin-left: auto; }
a.session { color: var(--text); }
/* Placement only, the way .panel-head .btn is: the theme button is last in
   every header and sits at the far end. On the two screens that already push
   something there it follows that thing across the header's own gap instead of
   splitting the free space with it, which is what two auto margins would do. */
.theme-toggle { margin-left: auto; }
.environments + .theme-toggle, .session + .theme-toggle { margin-left: 0; }

/* button — every <button> on these screens carries .btn, so one rule answers
   all of them. Placement stays with the component that places it: see
   .panel-head .btn below. */
.btn { font: inherit; color: inherit; background: none; border: var(--border) solid var(--line); border-radius: var(--radius-control); padding: var(--space-1) var(--space-3); cursor: pointer; }

/* card-grid and card */
.domains { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: var(--space-4); margin-top: var(--space-6); }
.domain { padding: var(--space-5); border: var(--border) solid var(--line); border-radius: var(--radius-surface); background: var(--surface); }
.domain h2 { margin: 0 0 var(--space-3); }
.domain span { display: block; margin-top: var(--space-4); font-size: var(--text-sm); }
.is-disabled { color: var(--text-muted); }

/* panel */
.panel { margin-top: var(--space-6); padding: var(--space-5); border: var(--border) solid var(--line); border-radius: var(--radius-surface); background: var(--surface); }
.panel-head { display: flex; align-items: baseline; gap: var(--space-4); }
.panel-head h2 { margin: 0; }
/* Placement only: the head's button sits at the far end. Every button does not
   get this, which is why it is scoped to the head and not folded into .btn. */
.panel-head .btn { margin-left: auto; }

/* tabs — trigger switch */
.triggers { display: flex; gap: var(--space-3); margin: var(--space-4) 0; }
.triggers a { color: var(--text-muted); text-decoration: none; border-bottom: var(--border-accent) solid transparent; }
.triggers a[aria-current] { color: var(--text); border-bottom-color: var(--accent); }

/* filter-form — window and page size */
.window { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: baseline; margin-top: var(--space-6); }
.window input { font: inherit; color: inherit; background: var(--bg); border: var(--border) solid var(--line); border-radius: var(--radius-control); padding: var(--space-1) var(--space-2); }
.window span { color: var(--text-muted); font-size: var(--text-sm); }

/* data-table — one table per screen, so the element selectors stay */
table { width: 100%; border-collapse: collapse; margin-top: var(--space-4); }
th, td { text-align: left; padding: var(--space-2); border-bottom: var(--border) solid var(--line-subtle); font-size: var(--text-sm); }
th { color: var(--text-muted); font-weight: var(--weight-normal); }

/* key-value — one dl per screen, same reason */
dl { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-1) var(--space-4); margin: var(--space-4) 0; }
dt { color: var(--text-muted); }

/* plain-list */
.pipelines ul { list-style: none; padding: 0; }
.pipelines li { padding: var(--space-2) 0; border-bottom: var(--border) solid var(--line-subtle); }
.failures { list-style: none; padding: 0; }
.failures li { padding: var(--space-3) 0; border-bottom: var(--border) solid var(--line-subtle); }
.failures span { display: inline-block; margin-right: var(--space-4); color: var(--text-muted); font-size: var(--text-sm); }

/* code — the pipeline row is the only place a <code> is styled. The old
   `.run code` matched nothing: .run holds an h3, a dl and a button. */
.pipelines code { color: var(--text-muted); font-size: var(--text-sm); }

/* note — secondary sentences. Colour comes from p above, except .problem. */
.caveat { border-left: var(--border-quote) solid var(--line-quote); padding-left: var(--space-4); }
.empty, .read-at { color: var(--text-muted); }
.read-at { font-size: var(--text-sm); }
.problem { color: var(--text-problem); }

/* busy — htmx puts this on the element that started a request, for as long as
   it is in flight. Without a rule for it a refresh looks like nothing happened
   until the answer lands, and a DE read is budgeted at 3 seconds. No new
   colour — the element is dimmed, not repainted. */
.htmx-request { opacity: var(--busy-opacity); cursor: progress; }
