/* The dashboard.
 *
 * Sits on top of base.css, which owns the design tokens (--bg, --fg, --line,
 * --panel, --soft) and the vendored @font-face rules. Nothing here redeclares a
 * token: the landing page links the same base, and a palette duplicated in two
 * files drifts the moment one is edited.
 *
 * Deliberately plain — tables, panels, one accent — because the product UI is
 * CRUD plus an execution timeline. Every rule here is progressive enhancement
 * away from a page that already works without JavaScript.
 */

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.wrap {
  width: min(1100px, calc(100% - 40px));
  margin: auto;
}

/* --- chrome ---------------------------------------------------------------- */

.topbar {
  border-bottom: 1px solid var(--line);
}

.topbar-inner {
  height: 64px;
  display: flex;
  align-items: center;
  gap: 28px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  letter-spacing: -0.03em;
  flex: none;
}

.mark {
  width: 24px;
  height: 24px;
  object-fit: contain;
  display: block;
}

/* The tab bar fills the space between the brand and the account, so the
   navigation reads as the middle of the header rather than as a group of links
   that happens to be second. */
.tabs {
  display: flex;
  align-items: stretch;
  gap: 22px;
  flex: 1;
  height: 64px;
  font-size: 14px;
}

/* The underline sits on the header's own bottom border: same 1px, moved up by
   the border's width, so the active tab's mark looks continuous with the rule
   the header already draws. */
.tab {
  display: flex;
  align-items: center;
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  margin-bottom: -1px;
}

.tab:hover {
  color: var(--fg);
}

.tab.active {
  color: var(--fg);
  border-bottom-color: var(--fg);
}

.topnav {
  display: flex;
  align-items: center;
  gap: 18px;
  font-size: 14px;
  flex: none;
}

.who {
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* The provider avatar. `object-fit` matters because these are square but not
   always the same size; the border keeps a light avatar from bleeding into the
   dark bar. */
.avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--line);
  display: block;
}

/* Shown when the provider gave no picture, so the slot keeps its shape rather
   than the name jumping left. */
.avatar-fallback {
  display: grid;
  place-items: center;
  background: var(--soft);
  color: var(--muted);
  font: 11px 'DM Mono';
  border: 1px solid var(--line);
  border-radius: 50%;
}

main {
  flex: 1;
  padding: 44px 0 80px;
}

.pagefoot {
  padding: 18px 0 28px;
  color: var(--quiet);
  font-size: 11px;
}

/* --- typography ------------------------------------------------------------ */

h1 {
  font-size: 34px;
  letter-spacing: -0.04em;
  margin: 0 0 10px;
}

h2 {
  font-size: 22px;
  letter-spacing: -0.03em;
  margin: 0 0 8px;
}

h3 {
  font-size: 17px;
  letter-spacing: -0.02em;
  margin: 0 0 4px;
}

.kicker {
  font: 11px 'DM Mono';
  color: var(--quiet);
  text-transform: uppercase;
  letter-spacing: 0.15em;
  margin: 0 0 12px;
}

.lede {
  color: var(--muted);
  line-height: 1.6;
  max-width: 62ch;
  margin: 0 0 20px;
}

.dim {
  color: var(--muted);
}

.mono {
  font-family: 'DM Mono', monospace;
  font-size: 12px;
}

.fineprint {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
  margin: 16px 0 0;
}

.pagehead {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin: 0 0 20px;
}

.pagehead h1 {
  margin-bottom: 4px;
  /* An automation name is user text and may have no break opportunities
     (``PR_review_bot``): without this the unbreakable word holds the head at
     its width and pushes the actions out of the panel, where body's
     overflow-x: hidden clips them out of view. */
  overflow-wrap: anywhere;
}

/* --- panels --------------------------------------------------------------- */

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

.panel.narrow {
  max-width: 520px;
  margin: 60px auto;
}

.panel.accent {
  border-color: var(--edge);
  background: var(--soft);
}

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

/* Centred text with a left-aligned button under it reads as a mistake: the one
   action an empty state offers lines up with the state it is answering. */
.panel.empty .row {
  justify-content: center;
}

/* A panel whose heading and actions sit on one line: the account name on the
   left, what you can do with it on the right. */
.panel-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 14px;
}

.panel-head h3 {
  margin: 0 0 6px;
  /* Same as .pagehead h1: a name without break opportunities must wrap rather
     than push the actions row sideways out of the panel. */
  overflow-wrap: anywhere;
}

.row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* The one next step on a first run: a panel that is a little louder than the
   rest, without being a different component. */
.panel.step {
  border-color: var(--edge);
  background: var(--soft);
}

.panel.step .row {
  margin-top: 4px;
}

/* --- overview -------------------------------------------------------------- */

/* The health strip: four facts in a row, each a dot and three or four words.
   Flex with wrapping rather than a grid, because the number of chips varies
   with what the account has connected and a grid would leave gaps. */
.statusbar {
  list-style: none;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 26px;
  margin: 0 0 16px;
  padding: 11px 16px;
  border: 1px solid var(--line);
  background: var(--panel);
  font-size: 13px;
  color: var(--muted);
  border-radius: var(--r);
}

.statusbar li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* The one pre-attentive signal on the page: a colour read before any word is.
   `box-shadow` rather than `border` so the dot's size is identical in every
   state, which is what lets a row of them be scanned as a column. */
.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--idle);
  flex: none;
}

.dot.ok {
  background: var(--ok-fg);
  box-shadow: 0 0 0 3px var(--ok-glow);
}

.dot.bad {
  background: var(--bad-fg);
  box-shadow: 0 0 0 3px var(--bad-glow);
}

.dot.warn {
  background: var(--warn-fg);
  box-shadow: 0 0 0 3px var(--warn-glow);
}

/* The metric row. Three cards, separated by the page line showing through a
   1px gap rather than by borders, so they read as one strip of figures. */
.kpis {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-bottom: 16px;
  border-radius: var(--r-lg);
  overflow: hidden;
}

.kpi {
  background: var(--panel);
  padding: 18px 18px 16px;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.kpi-label {
  font: 11px 'DM Mono';
  text-transform: uppercase;
  letter-spacing: 0.13em;
  color: var(--quiet);
}

.kpi-value {
  font-size: 36px;
  letter-spacing: -0.045em;
  line-height: 1.05;
  margin: 12px 0 4px;
}

.kpi-detail {
  color: var(--muted);
  font-size: 13px;
}

.kpi-detail.bad {
  color: var(--bad-fg);
}

.kpi-detail.warn {
  color: var(--warn-fg);
}

/* The activity histogram: 14 bars, no axes, no library. `align-items: flex-end`
   makes a height a share of the tallest day, and the floor on a zero day keeps
   a quiet stretch legible instead of blank. */
.spark {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 30px;
  margin-top: auto;
  padding-top: 14px;
}

.spark i {
  flex: 1;
  min-height: 3px;
  background: var(--bar-idle);
  /* A tuned 2px, not the corner scale: these are 6px-wide bar caps. */
  border-radius: 2px;
}

.spark i.ok {
  background: var(--ok-bar);
}

.spark i.bad {
  background: var(--bad-bar);
}

/* The main band: the timeline takes the width, the rail holds the one action
   and the list of connections. */
.split {
  display: grid;
  grid-template-columns: 1.62fr 0.95fr;
  gap: 16px;
  align-items: start;
}

.rail {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

/* The main column of a `.split`, where a page has cards rather than one list:
   the gap is what spaces them, so each card keeps no margin of its own. */
.maincol {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}

/* A card is the panel's smaller sibling: same tokens, a heading rule that runs
   the full width, and no padding around its own children so a list of rows can
   use the whole surface. */
.card {
  border: 1px solid var(--line);
  background: var(--panel);
  min-width: 0;
  border-radius: var(--r-lg);
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.card-meta {
  font: 11px 'DM Mono';
  color: var(--quiet);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}

a.card-meta:hover {
  color: var(--fg);
}

.card-empty {
  color: var(--muted);
  font-size: 13px;
  margin: 0;
  padding: 22px 16px;
}

/* The padded body under a `.card-head`, for a card whose contents are not a
   list that wants the whole surface. */
.card-body {
  padding: 16px;
}

.card-body > :first-child {
  margin-top: 0;
}

.card-body > :last-child {
  margin-bottom: 0;
}

/* The paragraph a `.card-body` opens with: the consequence before the control,
   never after it. */
.card-body p {
  margin: 0 0 14px;
  font-size: 13px;
  line-height: 1.55;
}

/* A card whose contents start with facts and have no head of their own: the
   facts are the whole surface, so their top rule would draw a line under
   nothing. */
.facts:first-child {
  border-top: 0;
}

/* The activity timeline. Four columns: the outcome dot, the provider's mark,
   what happened, and the verdict with its age. A grid rather than flex so the
   column edges line up down the list — that alignment is what makes it
   scannable, and flex would let each row drift with its own content length. */
.timeline {
  list-style: none;
  margin: 0;
  padding: 0;
}

.timeline li {
  display: grid;
  grid-template-columns: 8px 20px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 11px 16px;
  border-bottom: 1px solid var(--hairline);
}

.timeline li:last-child {
  border-bottom: 0;
}

.timeline .mark {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--idle);
}

.timeline .mark.ok {
  background: var(--ok-fg);
}

.timeline .mark.bad {
  background: var(--bad-fg);
}

.mark-provider {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1px solid var(--mark-line);
  background: var(--mark-bg);
  display: grid;
  place-items: center;
  color: var(--link);
  flex: none;
}

.mark-provider.lg {
  width: 26px;
  height: 26px;
}

.timeline-what {
  min-width: 0;
}

.timeline-what a:hover {
  text-decoration: underline;
}

.timeline-what small {
  display: block;
  color: var(--quiet);
  font-size: 12px;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bad-text {
  color: var(--bad-fg);
}

.timeline-verdict {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
}

.timeline .when {
  font: 11px 'DM Mono';
  color: var(--faint);
}

/* The next-step card. Louder than the others on purpose: it is the only place
   on the page that asks the reader to do something. */
.nextstep {
  background: var(--soft);
  border-color: var(--edge);
  padding: 20px 18px;
}

.nextstep h2 {
  margin: 10px 0 10px;
}

.nextstep p {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.55;
  margin: 0 0 16px;
}

/* The three stages, as a path. Same component in the first-run block and here,
   at two sizes — a first run and a returning user are being told the same
   thing about the shape of the product. */
.steps {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 0;
  margin: 0;
  padding: 0;
  font: 11px 'DM Mono';
  color: var(--quiet);
}

.steps .step {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding-right: 14px;
}

.steps .step:after {
  content: '→';
  color: var(--idle);
}

.steps .step:last-child {
  padding-right: 0;
}

.steps .step:last-child:after {
  content: '';
}

/* Done stages are struck through rather than ticked: a tick is a new glyph to
   learn, and the strike reads at a glance in a row of three words. */
.steps .step.done {
  color: var(--faint);
  text-decoration: line-through;
  text-decoration-color: var(--ok-bar);
}

.steps .step.current {
  color: var(--fg);
}

.steps.small {
  margin: 0 0 16px;
}

/* A connector row: the provider's mark, the account, and what it grants. The
   row is the identity; whatever comes after it (permissions, an error, an
   automation's facts) is a footer the row's bottom border separates. */
.connector {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--hairline);
}

.connector:last-child {
  border-bottom: 0;
}

.connector-what {
  min-width: 0;
  flex: 1;
}

.connector-what strong,
.connector-name {
  display: block;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow-wrap: anywhere;
  /* The name is an <h3> on a list of them, so heading navigation finds each
     item; the element's own margins would fight the row's alignment. */
  margin: 0;
}

/* The name is the link to the object, so it is the affordance rather than a
   separate "Open" button being the only way in. */
.connector-name a:hover {
  text-decoration: underline;
}

.connector-what small {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 3px 8px;
  color: var(--quiet);
  font: 11px 'DM Mono';
  margin-top: 4px;
}

/* The actions sit at the end of the identity row on a wide screen, so the mark
   and the name stay left-aligned with every other row and the buttons line up
   in a column down the page. Below 720px the whole row wraps and the actions
   take their own full-width line (see the end of this file). */
.connector-actions {
  margin-left: auto;
  flex: none;
  justify-content: flex-end;
}

/* An action pushed to the end of a connector row, when it is the only one. */
.connector-go {
  margin-left: auto;
  flex: none;
}

/* A connection, as a card. Its row is the identity and its actions the same
   line, rather than a heading, a paragraph and a panel saying the same thing
   three times. */
.connector-card {
  margin-bottom: 16px;
}

.connector-card:last-child {
  margin-bottom: 0;
}

/* A stack is the list itself: the gap between cards is the list's rhythm, so
   each card keeps only the spacing it needs for its own contents. */
.stack {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.stack .connector-card {
  margin-bottom: 0;
}

.connector-card .fineprint {
  padding: 0 16px 16px;
  margin: 12px 0 0;
}

.connector-note {
  border-top: 1px solid var(--hairline);
  padding-top: 14px !important;
}

/* --- facts ---------------------------------------------------------------- */

/* A definition list of what an object is: a label in the machine's voice and
   the value a person reads. Columns rather than a sentence because the same
   three facts have to be comparable down a list, and because a label reads
   faster than prose that spells the same thing out (`docs/design.md` rule 10).
   `auto-fit` lets the columns reflow to whatever width there is. */
.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px 26px;
  margin: 0;
  padding: 14px 16px 16px;
  border-top: 1px solid var(--hairline);
}

.facts > div {
  min-width: 0;
}

.facts dt {
  font: 11px 'DM Mono';
  text-transform: uppercase;
  letter-spacing: 0.13em;
  color: var(--quiet);
}

.facts dd {
  margin: 5px 0 0;
  font-size: 14px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

/* A fact that needs the whole width: a filter list, a long value. */
.facts .span {
  grid-column: 1 / -1;
}

/* The rule belongs to whichever block comes first: a `.card-head` or a
   `.connector` already draws its bottom border, so the facts must not draw a
   second line under it — two 1px rules one pixel apart read as a mistake. */
.card-head + .facts,
.connector + .facts {
  border-top: 0;
}

/* A fact's value and its verdict on one line: the number is the fact, the tag
   is what the number means. */
.facts dd .tag {
  margin-left: 2px;
}

/* --- chips ---------------------------------------------------------------- */

/* A set of short machine values — the permission scopes behind a connection.
   A list rather than a sentence: "contents (read), issues (write)" reads as
   prose and hides the boundaries between the items, which are the thing being
   checked. */
.chips {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
}

.chip {
  font: 11px 'DM Mono';
  color: var(--muted);
  border: 1px solid var(--chip-line);
  padding: 3px 8px;
  border-radius: var(--r-sm);
  white-space: nowrap;
}

.chip b {
  color: var(--fg);
  font-weight: 400;
}

/* A status with its dot: the encoding first, the word beside it. Used wherever a
   state appears in a list, so the dots form a readable column and every state is
   still spelled out (`docs/design.md` rule 12). */
.state {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/* The first-run page: one action, centred, with the rest of the path dimmed
   below it. The user can see where they are going without a sentence saying
   so. */
.firstrun {
  max-width: 620px;
  margin: 40px auto 0;
  text-align: center;
}

.firstrun .steps {
  justify-content: center;
  margin-bottom: 22px;
}

.firstrun h1 {
  font-size: 26px;
  letter-spacing: -0.04em;
}

.firstrun .lede {
  margin: 0 auto 24px;
}

.belt {
  display: grid;
  /* auto-fit rather than a fixed three: the first-run page has two cards left
     and the landing page's belt has four, and both should divide their own
     width evenly instead of leaving a gap where a third would be. */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-top: 56px;
  border-radius: var(--r-lg);
  overflow: hidden;
}

.belt > div {
  background: var(--bg);
  padding: 22px 20px;
  /* Dimmed: these are the stages after the one being asked for, and they should
     be visible without competing with it. */
  opacity: 0.5;
}

.belt h3 {
  margin: 12px 0 8px;
  font-size: 15px;
}

.belt p {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
}

/* The page heading's second line: what the eye lands on before the numbers. */
.pagehead-meta {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font: 11px 'DM Mono';
  color: var(--quiet);
}

/* A list of runs. Four columns — the outcome dot, what triggered it with the
   run's id beneath, the verdict, and when — as a grid so the verdicts line up
   down the list, which is what makes a run history scannable. Same idea as the
   overview's `.timeline`, one column fewer because a run has no provider of its
   own to mark. */
.runs {
  list-style: none;
  margin: 0;
  padding: 0;
}

.runs li {
  display: grid;
  grid-template-columns: 8px 1fr auto auto;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--hairline);
}

.runs li:last-child {
  border-bottom: 0;
}

.runs .run-what {
  min-width: 0;
}

.runs .run-what a:hover {
  text-decoration: underline;
}

.runs .run-what small {
  display: block;
  color: var(--quiet);
  font: 11px 'DM Mono';
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.runs .when {
  font: 11px 'DM Mono';
  color: var(--faint);
  white-space: nowrap;
}

@media (max-width: 900px) {
  .split {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 720px) {
  .kpis {
    grid-template-columns: 1fr;
  }

  /* The verdict column goes under the event rather than shrinking the event to
     nothing beside it. */
  .timeline li {
    grid-template-columns: 8px 20px 1fr;
  }

  .timeline-verdict {
    grid-column: 3;
    flex-direction: row;
    align-items: center;
    gap: 10px;
  }
}

/* --- forms ---------------------------------------------------------------- */

.field {
  display: block;
  margin-bottom: 14px;
}

/* A `<fieldset>` is the element for a group of controls, so a `.field` that
   holds one names itself with a `<legend>` where the others use a `<span>`;
   both get the same label treatment. Fieldsets arrive with a border, padding
   and margins of their own, which are reset here rather than overridden
   per-case. */
fieldset.field {
  border: 0;
  padding: 0;
  margin: 0 0 14px;
  min-inline-size: 0;
}

.field > span,
.field > legend {
  display: block;
  font-size: 12px;
  color: var(--muted);
  margin-bottom: 6px;
  padding: 0;
}

/* A second control inside one field — the free-text half of the repository
   picker, for a value the catalog does not offer — sits under the first rather
   than beside it. They are one filter, and side by side they would read as
   two. */
.field-sub {
  display: block;
  margin-top: 8px;
}

.field-sub > span {
  display: block;
  font-size: 12px;
  color: var(--muted);
  margin-bottom: 6px;
}

/* One control, one style: text inputs, selects and textareas share this box
   (see "Forms" in docs/design.md). The select keeps its native arrow and option
   list — body.dashboard's `color-scheme: light` is what paints those in the
   light palette. */
input[type='text'],
input[type='search'],
input:not([type]),
select,
textarea {
  width: 100%;
  background: var(--field-bg);
  border: 1px solid var(--field-line);
  color: var(--fg);
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  border-radius: var(--r);
}

/* Vertical-only resize: a full-width textarea dragged wider overflows the
   panel it lives in. */
textarea {
  resize: vertical;
}

input[readonly] {
  color: var(--muted);
  background: var(--field-bg-readonly);
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible,
a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* A tick-many group: the repositories an installation offers, as one bordered
   list of label rows. Picking three of forty is the read a checkbox list is
   for, and forty loose checkboxes push the form below the fold — so the list
   scrolls instead, like the field it replaces. */
.choices {
  display: flex;
  flex-direction: column;
  max-height: 240px;
  overflow-y: auto;
  background: var(--field-bg);
  border: 1px solid var(--field-line);
  border-radius: var(--r);
}

.choice {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--hairline);
  cursor: pointer;
}

.choice:last-child {
  border-bottom: 0;
}

.choice:hover {
  background: var(--soft);
}

.choice input {
  flex: none;
}

.choice .mono {
  font-size: 13px;
}

.choice .tag {
  margin-left: auto;
}

.inline-form {
  display: flex;
  align-items: flex-end;
  gap: 14px;
}

.field.grow {
  flex: 1;
  margin-bottom: 0;
}

.button {
  display: inline-block;
  border: 1px solid var(--control);
  background: transparent;
  color: var(--button-fg);
  padding: 11px 18px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  text-decoration: none;
  border-radius: var(--r);
}

.button.primary {
  background: var(--accent-bg);
  border-color: var(--accent-line);
  color: var(--accent-fg);
  font-weight: 600;
}

/* The provider button: the mark and the label on one line, centred. */
.button.github {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

/* A button that is the whole width of its container, for the one action inside
   a narrow card where a left-aligned button would read as a secondary one. */
.button.block {
  display: block;
  width: 100%;
  text-align: center;
}

.github-mark {
  flex: none;
  /* Sit the mark on the text baseline rather than the box centre: the label's
     descenders otherwise push it visually high. */
  margin-top: -1px;
}

.linkish {
  background: none;
  border: 0;
  padding: 0;
  color: var(--link);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  text-decoration: underline;
  border-radius: var(--r-sm);
}

.linkish:hover {
  color: var(--fg);
}

.linkish.danger {
  color: var(--bad-strong);
}

/* --- tables --------------------------------------------------------------- */

.table {
  width: 100%;
  border-collapse: collapse;
  /* Fixed layout so the column widths below are honoured. Without it a long
     value — a webhook URL — expands its column past the panel and pushes the
     last column (Delete) out of view, which is exactly what happened. */
  table-layout: fixed;
  border-radius: var(--r);
}

.table th,
.table td {
  text-align: left;
  padding: 11px 14px 11px 0;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.table th {
  font: 11px 'DM Mono';
  color: var(--quiet);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 400;
}

.table tr:last-child td {
  border-bottom: 0;
}

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A block of prose the user wrote, or a document we are about to store.
   Wrapped, never truncated: instructions are the content of a page, and a long
   line must not push the panel sideways. */
.prose {
  background: var(--code-bg);
  border: 1px solid var(--code-line);
  padding: 14px 16px;
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font: inherit;
  font-size: 14px;
  line-height: 1.6;
  border-radius: var(--r);
}

/* A run's outcome: one sentence the runner wrote, at reading size. A paragraph
   rather than a code block — it is prose, and the code surface on the page is
   reserved for the instructions, which are a document. */
.result {
  margin: 0;
  font-size: 15px;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

/* The agent's brief. The one block on the detail page that reads as prose
   rather than as a labelled value, so it is roomier than a code block: it is
   meant to be read, not copied. */
.instructions {
  margin: 0 16px 16px;
  font-size: 15px;
  line-height: 1.7;
}

/* A run's path: queued, started, finished. Vertical rather than the overview's
   horizontal `.steps`, because a run stage carries a clock time and there is
   room for more stages as the runner lands. The rail down the left is what makes
   it read as one path rather than three facts, and the mark's fill is the same
   pre-attentive signal the `.dot` is everywhere else. */
.flow {
  list-style: none;
  margin: 0;
  padding: 18px 16px 20px;
}

.flow li {
  display: grid;
  grid-template-columns: 12px 1fr auto;
  align-items: center;
  gap: 0 12px;
  padding-bottom: 20px;
}

.flow li:last-child {
  padding-bottom: 0;
}

.flow-mark {
  position: relative;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--ok-fg);
}

/* The connector to the next stage. Drawn from the mark down through the row's
   own bottom padding, so it meets the next mark whatever the row height is. */
.flow li:not(:last-child) .flow-mark::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  width: 1px;
  height: 20px;
  background: var(--line);
  transform: translateX(-50%);
}

/* A stage that has not happened: hollow, and its word is the machine's
   `pending`. An unfilled outline is unmistakably not-done in a way a paler
   filled dot is not, and it needs no colour to say so. */
.flow li.pending .flow-mark {
  background: transparent;
  border: 1px solid var(--idle);
}

.flow li.pending .flow-when {
  color: var(--faint);
}

/* The stage the run is on: the one dot that gets the glow, so a glance finds
   where it is without reading three timestamps. */
.flow li.current .flow-mark {
  box-shadow: 0 0 0 4px var(--ok-glow);
}

.flow-label {
  font-size: 14px;
}

.flow li.pending .flow-label {
  color: var(--quiet);
}

.flow-when {
  color: var(--quiet);
  white-space: nowrap;
}

.flow li.current .flow-when {
  color: var(--fg);
}

/* The spec JSON, behind a disclosure. Monospaced and scrollable: it is the
   machine's view, and wrapping it would make it harder to read, not easier. */
.spec {
  padding: 14px 16px;
  margin: 10px 0 0;
  background: var(--code-bg);
  border: 1px solid var(--code-line);
  overflow-x: auto;
  font-size: 12px;
  line-height: 1.6;
  border-radius: var(--r);
}

/* The message beside a field that was refused. The same red as `.notice.bad`
   because it is the same kind of thing, at the scale of one input. */
.field-error {
  color: var(--bad-fg);
  font-size: 13px;
  margin: -6px 0 16px;
}

.actions {
  text-align: right;
}

.nowrap {
  white-space: nowrap;
}

/* A fixed layout means every cell can overflow; truncate by default and let
   the few that should wrap opt out. */
.table td,
.table th {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- status --------------------------------------------------------------- */

.tag {
  font: 11px 'DM Mono';
  border: 1px solid var(--chip-line);
  padding: 3px 8px;
  color: var(--tag-fg);
  white-space: nowrap;
  border-radius: var(--r-sm);
}

.tag.active,
.tag.accepted,
.tag.connected,
.tag.ok {
  border-color: var(--ok-line);
  color: var(--ok-fg);
}

.tag.disabled,
.tag.error,
.tag.revoked,
.tag.invalid_signature,
.tag.malformed,
.tag.bad,
.tag.failed {
  border-color: var(--bad-line);
  color: var(--bad-fg);
}

/* A caveat rather than a failure: something is queued and nothing has claimed
   it, which is worth showing and is not an error. */
.tag.warn,
.tag.queued {
  border-color: var(--warn-line);
  color: var(--warn-fg);
}

.notice {
  border-left: 2px solid var(--notice-line);
  background: var(--notice-bg);
  padding: 12px 14px;
  margin: 0 0 18px;
  color: var(--notice-fg);
  font-size: 14px;
  line-height: 1.5;
  border-radius: var(--r);
}

.notice.bad {
  border-left-color: var(--bad-notice-line);
  color: var(--bad-notice-fg);
}

.notice.good {
  border-left-color: var(--good-notice-line);
  color: var(--good-notice-fg);
}

details.fineprint summary {
  cursor: pointer;
  color: var(--link);
}

details.fineprint p {
  margin: 8px 0 0;
}

@media (max-width: 720px) {
  .inline-form {
    flex-direction: column;
    align-items: stretch;
  }

  /* A run's verdict and its age move under the trigger instead of being
     squeezed into the width left over. */
  .runs li {
    grid-template-columns: 8px 1fr auto;
    row-gap: 6px;
  }

  .runs .when {
    grid-column: 3;
    grid-row: 2;
    justify-self: end;
  }

  /* The header cannot hold a brand, three tabs and an account on a phone, so
     the tabs move to their own row and the account stays on the first one. */
  .topbar-inner {
    height: auto;
    padding: 14px 0 0;
    flex-wrap: wrap;
    gap: 12px;
  }

  .tabs {
    order: 3;
    flex-basis: 100%;
    height: auto;
    gap: 18px;
  }

  .tab {
    padding-bottom: 10px;
  }

  /* On a phone there is no room for an identity and its actions on one line:
     the actions take their own row, flowing under the name rather than being
     clipped or wrapped into a ragged block beside it. */
  .connector {
    flex-wrap: wrap;
    align-items: flex-start;
  }

  .connector-actions {
    flex-basis: 100%;
    margin-left: 0;
    justify-content: flex-start;
  }

  /* The one action a provider card offers becomes the width of the card, which
     is what it already looks like on a desktop and the only thing on the row. */
  .connector-go {
    flex-basis: 100%;
    margin-left: 0;
    text-align: center;
  }

  .table th:nth-child(2),
  .table td:nth-child(2) {
    display: none; /* the URL is the widest column; it stays available on the row's title */
  }
}
