/* Skein's own layer on top of the brand pack.
 *
 * RULE, from design D10: tokens only. `var(--mgd-ink)`, never `#201e1d`. If a
 * value is needed that the pack does not name, the pack is where it gets named
 * - a literal here is a fork of the brand with extra steps.
 *
 * The pack supplies type, colour, rules, buttons, cards, tags and a grid
 * helper. It does not supply application chrome, which is what this file is:
 * the shell, the cards, the forms, the modal, and the progress display.
 */

/* ── Which ground we are on ─────────────────────────────────────────────────
 * The pack names its per-ground pairs in full: --mgd-muted and
 * --mgd-muted-on-ink, --mgd-ok and --mgd-ok-on-ink, and so on. Correct for a
 * pack, awkward for a consumer: every component would have to be written twice
 * or know which ground it is sitting on.
 *
 * So the choice is made ONCE, here, and everything below asks for a role. Dark
 * is the default because that is what this application is read on; the light
 * block exists so `.mgd-on-ink` coming off <body> is the only change needed,
 * rather than a rewrite of every rule that mentions a colour.
 *
 * These are indirections, not new values. Every one of them resolves to a pack
 * token, so D10 still holds - there is no literal in this file.
 */
:root {
  --edge: var(--mgd-ink);
  /* What sits ON --edge when it is used as a fill. Paired, because "invert it"
     is two values and getting one of them from --edge alone is not possible. */
  --edge-text: var(--mgd-ground);
  /* An opaque panel: the modal needs one, because an element in the top layer
     with a transparent background shows the page through it. */
  --panel: var(--mgd-white);
  --quiet: var(--mgd-muted);
  --hair: var(--mgd-hairline);
  --good: var(--mgd-ok);
  --warn: var(--mgd-caution);
  --attn: var(--mgd-attention);
  --idle: var(--mgd-dormant);
}

/* This rule READS the pack's ground class; it does not restyle it. Everything
   in here is either one of Skein's own custom properties or the colour-scheme
   hint below, so the pack's own .mgd-on-ink declarations are untouched. */
.mgd-on-ink {
  --edge: var(--mgd-ground);
  --edge-text: var(--mgd-ink);
  --panel: var(--mgd-ink);
  --quiet: var(--mgd-muted-on-ink);
  --hair: var(--mgd-hairline-on-ink);
  --good: var(--mgd-ok-on-ink);
  --warn: var(--mgd-caution-on-ink);
  --attn: var(--mgd-attention-on-ink);
  --idle: var(--mgd-dormant-on-ink);

  /* Native controls are drawn by the browser, not styled by the page, so the
     browser needs telling. This covers the controls themselves. It does NOT
     cover a <select>'s dropdown list — see the root rule below. */
  color-scheme: dark;
}

/* The dropdown list is painted from the ROOT element's colour scheme, not the
   select's.
   Measured: with color-scheme: dark on both <body> and the <select>, the
   computed value on <html> was still `normal` and the popup rendered white with
   our near-white option text on it. Unreadable, and invisible from the page's
   own computed styles — the select itself looked completely correct.
   :has() rather than a bare `html { color-scheme: dark }`, so the root still
   follows the one class on <body> and going light stays a one-line change. */
:root:has(body.mgd-on-ink) {
  color-scheme: dark;
}

/* ── The shell ──────────────────────────────────────────────────────────────
 * Grid, not flex, and named areas rather than implicit order.
 *
 * The shell is a fixed two-dimensional structure - a header of whatever height
 * its contents need, then everything else - so `grid-template-rows: auto 1fr`
 * states it in one line: `auto` is "as tall as the header is", `1fr` is "all
 * the space that is left". min-height:100dvh (not vh) so a short page still
 * fills a mobile viewport without the address bar causing a scroll.
 *
 * Flex would reach the same picture, but only by nesting and by every child
 * agreeing about flex-grow. Grid puts the layout in the parent, where a layout
 * belongs; the children say which region they are in and nothing about size.
 */
.shell {
  display: grid;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    'masthead'
    'main';
  min-height: 100dvh;
}

.shell__masthead {
  grid-area: masthead;
  /* The 2px rule under the header is the pack's separator, not a shadow.
     Nothing in this brand is rounded and nothing floats. */
  border-bottom: var(--mgd-rule) solid var(--edge);
}

.shell__main {
  grid-area: main;
}

/* One measure for every band, so the header contents and the page contents
 * line up on the same left edge.
 *
 * No max-width. It had one at 1100px, which left half of a wide monitor empty
 * and made the list look like a phone layout that had been stretched. The
 * thing a max-width is FOR is line length, and nothing here is a wide
 * paragraph: the cards below cap their own measure at about 500px, and the one
 * place prose runs long uses .measure. So the page spans, and readability is
 * handled where the reading happens.
 *
 * clamp() on the horizontal padding rather than a media query: 20px of gutter
 * on a phone, growing to 56px on a desktop, with no breakpoint deciding it.
 */
.wrap {
  width: 100%;
  padding: var(--mgd-space-4) clamp(var(--mgd-space-4), 3vw, var(--mgd-space-6));
}

.shell__masthead .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--mgd-space-4);
  flex-wrap: wrap;
}

.masthead__brand {
  display: flex;
  align-items: center;
  gap: var(--mgd-space-3);
  text-decoration: none;
}

/* The lockup is the pack's type component, not an image — see AppShell.tsx for
   why. .mgd-lockup--sm sets its own 24px, so nothing is needed here; the
   cursor block is sized in em off that, so overriding the size would rescale
   the whole thing correctly if it ever needs to. */

.masthead__product {
  /* Skein is the product; MGD is the maker. The pack's label role is the
     smaller, tracked, uppercase treatment - correct for a secondary mark. */
  border-left: var(--mgd-rule) solid var(--hair);
  padding-left: var(--mgd-space-3);
}

.masthead__who {
  display: flex;
  align-items: center;
  gap: var(--mgd-space-3);
}

/* ── Stacks ─────────────────────────────────────────────────────────────────
 * A vertical rhythm helper. `gap` on a grid rather than margins on children:
 * margins collapse, double up between siblings, and leave a stray one at the
 * end of a list. A gap only exists between things.
 */
.stack {
  display: grid;
  gap: var(--mgd-space-4);
}

.stack--tight {
  gap: var(--mgd-space-2);
}

/* ── Page furniture ─────────────────────────────────────────────────────── */
.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--mgd-space-4);
  flex-wrap: wrap;
}

.page-head__actions {
  display: flex;
  gap: var(--mgd-space-3);
  flex-wrap: wrap;
}

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

.mono {
  font-family: var(--mgd-font-mono);
}

/* The one place a measure is still needed, now that .wrap has none: prose that
   would otherwise run the full width of a monitor. */
.measure {
  max-width: 68ch;
}

/* A code name is an identifier, so it is set in mono and boxed like one. */
.code-name {
  font-family: var(--mgd-font-mono);
  font-size: var(--mgd-size-label);
  border: var(--mgd-rule) solid var(--hair);
  padding: 0 var(--mgd-space-1);
}

/* ── States ─────────────────────────────────────────────────────────────────
 * Loading and empty are states, not decorations, and each says what it is
 * rather than showing a spinner that says nothing.
 */
.state {
  padding: var(--mgd-space-6) 0;
  color: var(--quiet);
}

.state--error {
  /* Not red TEXT. --mgd-red measures 3.76:1 on the light ground and 3.95:1 on
     ink, so at body size it fails AA on both — which mgd-brand 1.4.0 corrected
     after declaring otherwise for three releases. The red carries the meaning
     as a 2px rule, which is chrome and only needs 3:1, and the words stay at
     full contrast. */
  color: inherit;
  border-left: var(--mgd-rule) solid var(--mgd-red);
  padding-left: var(--mgd-space-4);
}

/* ── The sign-in page ───────────────────────────────────────────────────────
 * The one place a single centred column is right - one statement, one action,
 * no navigation - and the pack has an explicit opt-in for exactly that case.
 * `.mgd-centred` goes on the band container, never on <body>, which is what
 * stops a page ending up half-centred. See mgd-brand docs/consuming.md.
 */
.signin {
  display: grid;
  place-content: center;
  min-height: 100dvh;
  padding: var(--mgd-space-4);
}

.signin__card {
  max-width: 42ch;
}

/* The sign-in failure message.
 *
 * --mgd-red-on-ink, not --mgd-red: the ground here is ink, and the base red
 * does not carry enough contrast against it. That is the same bug mgd-brand
 * fixed in 1.4.1 for hued tags, and the fix is to use the on-ink pairing
 * rather than to re-tune the colour locally.
 *
 * A left rule and a tinted ground rather than a filled block: this sits
 * directly above the primary action, and a solid red panel next to a solid
 * red button reads as two buttons. */
.signin__error {
  border-left: 3px solid var(--mgd-red-on-ink);
  padding: var(--mgd-space-2) var(--mgd-space-3);
  background: color-mix(in oklab, var(--mgd-red-on-ink) 12%, transparent);
  /* No `color`: the pack sets body text on the card and there is no --mgd-fg
     token to reach for. Tinting the ground and leaving the text alone keeps
     the contrast the pack already guarantees. */
  text-align: left;
  margin: 0;
}

/* ── The project list ───────────────────────────────────────────────────────
 * Cards, not rows.
 *
 * It was rows separated by hairlines, on the reasoning that a grid makes the
 * eye scan across before it scans down. That reasoning holds on a desktop and
 * falls apart on a phone, where a row of four meta fields and a progress
 * readout wraps into an unreadable block — and this has to work on a phone,
 * because that is where it gets opened.
 *
 * auto-fill with a 320px minimum means no breakpoint decides the arrangement:
 * one column on a phone, as many as fit on a monitor, same markup. auto-FILL
 * rather than auto-fit deliberately - auto-fit collapses empty tracks, so two
 * projects on a wide screen would stretch into two half-metre-wide cards.
 */
.cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--mgd-space-4);
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}

/* Border-only, no fill. The pack has no dark surface value, and mgd-brand
   1.4.0's .mgd-on-ink .mgd-card says why: inventing one would be a fork of the
   brand. Border-only also suits a system whose rules are 2px and radius is 0.
   This is Skein's card, not .mgd-card, because .mgd-card's 32px padding is
   sized for a website's content blocks rather than a dense list. */
.card {
  border: var(--mgd-rule) solid var(--hair);
  padding: var(--mgd-space-4);
  display: grid;
  gap: var(--mgd-space-3);
  align-content: start;
}

.card:hover,
.card:focus-within {
  border-color: var(--edge);
}

.card__head {
  display: grid;
  gap: var(--mgd-space-1);
  justify-items: start;
}

.card__name {
  font-size: var(--mgd-size-h3);
  font-weight: 700;
  letter-spacing: -0.01em;
  text-decoration: none;
}

.card__name:hover {
  text-decoration: underline;
  text-decoration-thickness: var(--mgd-rule);
  text-underline-offset: 3px;
}

/* A card with no criteria says so in one line, rather than drawing a bar of
   zeroes. The absence is the state. */
.card__none {
  color: var(--quiet);
  margin: 0;
}

/* ── The readout, spelled out ───────────────────────────────────────────────
 * The card gets the compact one because a card is a glance. The project page
 * has a whole row to itself, so it says the thing in words instead of asking
 * the reader to decode "1 OF 2 USED · 1 STALE" — which required knowing that
 * the stale one is the other one, and that "used" was both the label and the
 * unit.
 */
.readout--full {
  grid-template-columns: 1fr;
  gap: var(--mgd-space-4);
}

.readout__block {
  display: grid;
  gap: var(--mgd-space-1);
  max-width: 68ch;
}

.readout__line {
  display: flex;
  align-items: baseline;
  gap: var(--mgd-space-3);
  flex-wrap: wrap;
}

.readout__count {
  font-variant-numeric: tabular-nums;
}

/* Said once, where there is room to say it. "Stale" is a word this application
   invented for a specific thing, and a reader meeting it in a two-word chip has
   no way to know it does not mean "false". */
.readout__note {
  margin: 0;
  font-size: 14px;
  color: var(--quiet);
}

/* ── Chips ──────────────────────────────────────────────────────────────────
 * Three fields, encoded three different ways, because they are three different
 * kinds of fact.
 *
 * Entity is CATEGORICAL - which of four, no order, no meaning - so it gets a
 * hue from the pack's colour.data ramp as a solid .mgd-tag. The hue-to-entity
 * mapping is in client/src/types/api.ts, because mgd-brand does not know what
 * an entity is and must not be edited to learn.
 *
 * Status is SEMANTIC, so it gets a status role as coloured text: parked is
 * caution, abandoned is dormant, done is ok, and active gets nothing at all -
 * colouring the normal case spends the signal on the thing you never need to
 * notice.
 *
 * Classification is left quiet. It is not a category you scan a list by, and
 * a third coloured thing per card would make the colours mean "chip" rather
 * than anything in particular. It is a label; it reads as one.
 */
.chips {
  display: flex;
  align-items: baseline;
  gap: var(--mgd-space-2) var(--mgd-space-3);
  flex-wrap: wrap;
}

.chip-state {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
}

/* ── The progress readout ───────────────────────────────────────────────────
 * Built and Used side by side on a wide viewport, stacked on a narrow one.
 * auto-fit with a minimum means no media query decides the breakpoint: the
 * content does, at whatever width two 240px columns stop fitting.
 */
.readout {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--mgd-space-2) var(--mgd-space-5);
  align-items: center;
}

.readout__pair {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  gap: var(--mgd-space-3);
}

.readout__figure {
  font-size: var(--mgd-size-h3);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.readout__notes {
  grid-column: 1 / -1;
  display: flex;
  gap: var(--mgd-space-4);
  flex-wrap: wrap;
}

/* Used is a STATE, not a bar. See Progress.tsx for the whole argument; the
   short version is that adoption is not progress toward a fixed scope, and
   drawing it as a proportion meant one stale criterion out of one filled the
   entire track in red — which reads as complete and meant the opposite. */
.used {
  display: flex;
  align-items: baseline;
  gap: var(--mgd-space-3);
  flex-wrap: wrap;
}

.used__state {
  font-weight: 600;
}

.used__count {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
  color: var(--quiet);
  font-variant-numeric: tabular-nums;
}

/* The four status roles, as text. Applied to both the status chip and the Used
   state, because they mean the same four things in both places. */
.tone-good { color: var(--good); }
.tone-warn { color: var(--warn); }
.tone-attn { color: var(--attn); }
.tone-idle { color: var(--idle); }

/* The bar is an SVG with preserveAspectRatio="none", so it stretches to
   whatever width the grid gives it and keeps a fixed height. Geometry is in
   the rect attributes; this only says how big and what colour. */
.bar {
  display: block;
  width: 100%;
  height: 6px;
}

.bar__track {
  fill: var(--hair);
}

.bar__met {
  fill: var(--edge);
}

/* ── The modal ──────────────────────────────────────────────────────────────
 * A native <dialog>, opened with showModal(). Not a div with a high z-index.
 *
 * showModal() gives focus containment, Escape-to-close, inertness of the rest
 * of the page, and the top layer — four things a hand-rolled modal has to
 * implement and usually implements two of. The focus trap in particular is the
 * one people skip, and it is the one that matters: a modal you can Tab out of
 * is a modal a keyboard user is stuck behind.
 *
 * ::backdrop is styleable and is NOT a child, so it needs its own rule and
 * cannot inherit the page's tokens — hence the pack token directly. It is also
 * the reason there is no .scrim element in the markup.
 */
.modal {
  padding: 0;
  border: var(--mgd-rule) solid var(--edge);
  border-radius: var(--mgd-radius);
  background: var(--panel);
  color: inherit;
  width: min(560px, calc(100vw - 2 * var(--mgd-space-4)));
  max-height: calc(100dvh - 2 * var(--mgd-space-5));
  overflow: auto;
}

.modal::backdrop {
  /* colour-mix on a pack token rather than a literal rgba(). The pack forbids
     tinting TYPE with alpha; a backdrop is not type, and the alternative here
     is a hard-coded rgba, which D10 forbids outright. */
  background: color-mix(in srgb, var(--mgd-ink) 82%, transparent);
}

.modal__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--mgd-space-4);
  padding: var(--mgd-space-4);
  border-bottom: var(--mgd-rule) solid var(--edge);
}

/* The actions are INSIDE this, not in a footer band. A submit button outside
   the <form> would need a form= attribute or a click handler, and then Enter
   in a text field does nothing — which is the single most common way a modal
   form feels broken to someone typing. */
.modal__body {
  padding: var(--mgd-space-4);
  display: grid;
  gap: var(--mgd-space-4);
}

.modal__close {
  font: inherit;
  font-size: 20px;
  line-height: 1;
  background: none;
  border: 0;
  color: var(--quiet);
  cursor: pointer;
  padding: 0 var(--mgd-space-1);
}

.modal__close:hover {
  color: var(--mgd-red-on-ink);
}

/* ── Forms ──────────────────────────────────────────────────────────────────
 * No floating labels and no placeholder-as-label. A placeholder disappears the
 * moment you type, which is exactly when you want to check what the field was.
 */
.field {
  display: grid;
  gap: var(--mgd-space-1);
  /* Without this the two selects in a .field-row sit 19px apart.
     Measured, because the cause is not where the symptom is. A .field-row is a
     grid and its items stretch to the tallest, so a field beside one that has a
     help paragraph is taller than its own contents. Its tracks are all `auto`,
     and align-content's initial `normal` behaves as `stretch`, which hands the
     surplus out equally among them — so the LABEL track grew by half the
     difference and pushed the input down. Nothing about either field is wrong
     on its own; only the pair is.
     `start` keeps every track at its content height and lets the surplus fall
     at the bottom, where nothing is looking at it. */
  align-content: start;
}

/* Two fields side by side where they are read together, stacking below the
   same content-driven threshold as the readout. */
.field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--mgd-space-4);
}

.input {
  font: inherit;
  font-size: var(--mgd-size-body);
  color: inherit;
  /* transparent, not a surface colour: the field sits on whatever ground it is
     on, and the border is what says "this is an input". A --mgd-white fill
     would be a light panel punched into a dark form. */
  background: transparent;
  border: var(--mgd-rule) solid var(--hair);
  border-radius: var(--mgd-radius);
  padding: var(--mgd-space-2) var(--mgd-space-3);
  width: 100%;
}

.input:focus {
  border-color: var(--edge);
}

/* Belt and braces with the root colour-scheme above, because which of the two
   works depends on the platform: Chrome on Linux and Windows honours an
   option's own colours, and Chrome on macOS draws a native popup that ignores
   them and obeys only the colour scheme. Setting both covers both. */
.input option {
  background: var(--panel);
  color: inherit;
}

.input:disabled {
  color: var(--quiet);
}

/* A field shown but not offered. The code name is immutable once set - the
   database refuses to change it - so in edit mode it is displayed, not
   editable. Dashed, because a solid border says "type here". */
.input[readonly] {
  color: var(--quiet);
  border-style: dashed;
}

.field__help {
  margin: 0;
  font-size: var(--mgd-size-label);
  color: var(--quiet);
}

.field__help--bad {
  /* Attention, not the raw accent — see .state--error. On ink this resolves to
     #f05941 at 4.91:1; the base red would be 3.95 and fail AA at this size. */
  color: var(--attn);
}

.form__actions {
  display: flex;
  gap: var(--mgd-space-3);
  flex-wrap: wrap;
}

/* ── The code-name suggestions ─────────────────────────────────────────────── */
.suggest {
  display: flex;
  align-items: center;
  gap: var(--mgd-space-2);
  flex-wrap: wrap;
  padding-top: var(--mgd-space-1);
}

.suggest__pick {
  font-size: 13px;
  text-transform: none;
  letter-spacing: 0;
  padding: var(--mgd-space-1) var(--mgd-space-2);
}

/* The chosen suggestion reads as chosen. aria-pressed carries it for a screen
   reader; this is the same fact for everyone else. */
.suggest__pick[aria-pressed='true'] {
  background: var(--edge);
  color: var(--edge-text);
}

/* "More" is a text button, not a bordered one: it is a lesser action than
   picking a name and should not compete with the names for attention. */
.suggest__more {
  font: inherit;
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
  color: var(--quiet);
  background: none;
  border: 0;
  padding: var(--mgd-space-1) 0;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: var(--mgd-rule);
  text-underline-offset: 3px;
}

.suggest__more:hover:not(:disabled) {
  color: var(--mgd-red-on-ink);
}

.suggest__more:disabled {
  cursor: default;
  text-decoration: none;
}

/* ── The definition of done ─────────────────────────────────────────────────
 * The criteria view. Grouped by kind rather than by milestone — see
 * DefinitionOfDone.tsx for why, including the part where the milestone table
 * has no API and every milestoneId is therefore null.
 */
.dod__revision {
  display: flex;
  align-items: baseline;
  gap: var(--mgd-space-2);
  flex-wrap: wrap;
}

/* The next unmet criterion, which C3 requires by name. A left rule rather than
   a fill: it is the one thing on the page being pointed at, and a filled panel
   would be a second surface competing with the criteria list itself. */
.dod__next {
  border-left: var(--mgd-rule) solid var(--mgd-red);
  padding-left: var(--mgd-space-4);
}

.dod__next-statement {
  margin: 0;
  font-size: var(--mgd-size-h3);
  font-weight: 700;
  letter-spacing: -0.01em;
  max-width: 68ch;
}

.crit-group__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--mgd-space-4);
  flex-wrap: wrap;
  border-bottom: var(--mgd-rule) solid var(--hair);
  padding-bottom: var(--mgd-space-2);
}

.crit-group__count {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
  color: var(--quiet);
  font-variant-numeric: tabular-nums;
}

.crits {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
}

/* Rows, not cards. A criterion is one line of prose plus its state, and a
   grid of cards here would make the eye scan across a set of statements that
   are meant to be read down in the order the definition declares them. */
.crit {
  display: grid;
  gap: var(--mgd-space-1);
  padding: var(--mgd-space-3) 0;
  border-bottom: 1px solid var(--hair);
}

.crit__head {
  display: flex;
  align-items: baseline;
  gap: var(--mgd-space-3);
  flex-wrap: wrap;
}

/* The reference is an identifier — C1, C2 — so it is set like one. Fixed width
   so the statements below line up on a common left edge rather than shifting
   between C9 and C10. */
.crit__ref {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  color: var(--quiet);
  min-width: 3ch;
}

.crit__status {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
}

.crit__evidence {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
}

.crit__statement {
  margin: 0;
  max-width: 78ch;
}

.crit__meta {
  display: flex;
  gap: var(--mgd-space-4);
  flex-wrap: wrap;
  font-size: var(--mgd-size-label);
  color: var(--quiet);
}

/* ── "What does this mean?" ─────────────────────────────────────────────────
 * A button, not a tooltip. See Term.tsx.
 */
.term {
  display: inline-flex;
  align-items: baseline;
  gap: var(--mgd-space-1);
}

/* Deliberately not a circle — nothing in this brand is rounded, and
   --mgd-radius is 0 on purpose. A 2px square outline reads as a control at
   this size and stays inside the system. */
.term__ask {
  font: inherit;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
  /* Reset the tracked uppercase it would otherwise inherit from .mgd-label,
     which turned a single "?" into a character with a gap after it. */
  text-transform: none;
  width: 1.35em;
  height: 1.35em;
  display: inline-grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--quiet);
  border-radius: var(--mgd-radius);
  background: transparent;
  color: var(--quiet);
  cursor: pointer;
}

.term__ask:hover,
.term__ask[aria-expanded='true'] {
  border-color: var(--edge);
  color: var(--edge);
}

/* The explanation sits in the flow and pushes the page down. Sentence case and
   body size, not a label: it is prose to be read, and the tracked uppercase of
   the heading it hangs off would make it unreadable at this length. */
.term__what {
  margin: var(--mgd-space-2) 0 0;
  padding-left: var(--mgd-space-4);
  border-left: var(--mgd-rule) solid var(--hair);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--quiet);
  max-width: 72ch;
}

.term__what strong {
  color: var(--edge);
  font-weight: 600;
}

.term__more {
  color: var(--quiet);
}

/* ── The full glossary ─────────────────────────────────────────────────────── */
.glossary {
  border: var(--mgd-rule) solid var(--hair);
  padding: var(--mgd-space-3) var(--mgd-space-4);
}

.glossary[open] {
  padding-bottom: var(--mgd-space-4);
}

.glossary__summary {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
  cursor: pointer;
  color: var(--quiet);
}

.glossary__summary:hover {
  color: var(--edge);
}

.glossary__lede {
  margin: var(--mgd-space-4) 0 0;
}

.glossary__list {
  margin: var(--mgd-space-4) 0 0;
  display: grid;
  gap: var(--mgd-space-3);
}

/* Term above definition rather than beside it. A two-column dl needs a column
   wide enough for "Definition of done" and then wastes that width on "Stale",
   and on a phone it has nowhere to go. */
.glossary__entry {
  display: grid;
  gap: 2px;
  padding-bottom: var(--mgd-space-3);
  border-bottom: 1px solid var(--hair);
}

.glossary__entry:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.glossary__term {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
}

.glossary__def {
  margin: 0;
  max-width: 78ch;
}

.glossary__more {
  color: var(--quiet);
}

/* ── Where the source is, and where the thing is ───────────────────────────
 * A link when the value is one, plain text when it is not — see
 * lib/links.ts. The two states look different ON PURPOSE: a bare hostname
 * styled as an anchor is a control that does nothing when clicked.
 */
.links {
  display: flex;
  gap: var(--mgd-space-2) var(--mgd-space-5);
  flex-wrap: wrap;
}

.links__item {
  display: flex;
  align-items: baseline;
  gap: var(--mgd-space-2);
  min-width: 0;
}

.links__link,
.links__plain {
  font-size: 13px;
  /* Long remotes wrap rather than pushing the page sideways. anywhere, not
     break-all: it breaks at the slashes and dots first, which keeps a URL
     readable, and only splits mid-token when it has no choice. */
  overflow-wrap: anywhere;
}

.links__plain {
  color: var(--quiet);
}

/* ── Writing a definition of done ─────────────────────────────────────────────
   Added with the write UI. Same rule as the rest of this file: no literal hex,
   only the ground-role aliases at the top, so every one of these works on both
   grounds without a second definition. */

/* A quiet text button, for the actions that sit inside a row.
   NOT .mgd-btn--ghost. That variant does not exist in mgd-brand, and giving an
   app-local style an mgd- prefix would make it look like part of the shared
   pack — the next person to read the brand repo looking for it would not find
   it. If this turns out to be wanted everywhere, it can be promoted there and
   this rule deleted. */
.btn-quiet {
  font: inherit;
  font-size: var(--mgd-size-label);
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--quiet);
  background: transparent;
  border: 0;
  border-radius: var(--mgd-radius);
  padding: var(--mgd-space-1) var(--mgd-space-2);
  cursor: pointer;
}
.btn-quiet:hover:not(:disabled) {
  color: var(--edge);
}
/* Not :focus. A mouse click would otherwise leave a ring behind on a control
   whose whole job is to be unobtrusive; :focus-visible is the keyboard case,
   which is the one that needs it. */
.btn-quiet:focus-visible {
  outline: var(--mgd-rule) solid var(--edge);
  outline-offset: 2px;
  color: var(--edge);
}
.btn-quiet:disabled {
  color: var(--idle);
  cursor: default;
}

/* Pushed to the far end of the row, so the actions line up down the list
   instead of sitting at a different place on every line depending on how long
   the status word is. */
.crit__actions {
  display: flex;
  gap: var(--mgd-space-1);
  flex-wrap: wrap;
}
/* Pushed to the far end of the row, so the write actions line up down the list
   instead of sitting at a different place on every line depending on how long
   the status word is. History stays on the left, next to the ref, because it
   is a read and grouping it with Withdraw would invite the wrong click. */
.crit__actions--tail {
  margin-left: auto;
}

.crit--editing {
  gap: var(--mgd-space-3);
  /* A left rule rather than a fill: the row is still part of the list, and a
     panel colour would make it read as a modal that failed to open. */
  border-left: var(--mgd-rule) solid var(--edge);
  padding-left: var(--mgd-space-4);
}

.editor {
  border-top: var(--mgd-rule) solid var(--edge);
  padding-top: var(--mgd-space-4);
}
.editor__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--mgd-space-4);
  flex-wrap: wrap;
}
.editor__note {
  margin: 0;
  font-size: var(--mgd-size-label);
  color: var(--quiet);
}
.editor__add {
  border: var(--mgd-rule) dashed var(--hair);
  border-radius: var(--mgd-radius);
  padding: var(--mgd-space-4);
}
.editor__foot {
  display: grid;
  gap: var(--mgd-space-2);
  border-top: 1px solid var(--hair);
  padding-top: var(--mgd-space-4);
}

.dod__supersede {
  display: grid;
  gap: var(--mgd-space-2);
  border-top: 1px solid var(--hair);
  padding-top: var(--mgd-space-4);
}

/* The claim being answered, at the top of the observation modal. */
.obs__claim {
  display: grid;
  gap: var(--mgd-space-1);
  border-left: var(--mgd-rule) solid var(--edge);
  padding-left: var(--mgd-space-4);
}
.obs__statement {
  margin: 0;
}

.choice {
  display: grid;
  gap: var(--mgd-space-2);
}
.choice__opt {
  display: flex;
  align-items: center;
  gap: var(--mgd-space-3);
  cursor: pointer;
}

/* A fieldset carries the grouping for assistive technology; none of its default
   chrome is wanted, and a legend is not a grid item so it needs unpicking from
   .field's layout. */
fieldset.field {
  border: 0;
  margin: 0;
  padding: 0;
  min-inline-size: 0;
}
fieldset.field > legend {
  padding: 0;
}

/* The INPUT is narrow, not the field. Constraining the field constrained its
   grid column, so the help paragraph under a 14ch input wrapped to four lines
   for one sentence. Measured in a browser, because the input looked right. */
.field--narrow .input {
  max-width: 14ch;
}

/* Permitted, but think about it — distinct from .field__help--bad, which means
   the form will not submit. Caution rather than attention: reusing the error
   colour for a warning teaches you to ignore the error colour. */
.field__help--warn {
  color: var(--warn);
}

/* .input covers <textarea> as a class selector, but two of its defaults are
   wrong there: it resizes in both directions inside a grid that has no room to
   grow sideways, and it starts one line tall. */
textarea.input {
  resize: vertical;
  min-height: 4lh;
  line-height: inherit;
}

/* .state carries its own generous vertical padding for the standalone cases it
   was written for -- "Loading..." on an otherwise empty page, an error where
   nothing else rendered. Inside a .stack that padding is added to the stack's
   own gap, which measured as roughly 70px of dead space between one sentence
   and the button under it. This is the same message in a different role, so it
   says so rather than the padding being unset by a descendant selector that
   would catch the standalone case too. */
.state--inline {
  padding: 0;
}

/* A DISABLED PRIMARY BUTTON, which the brand pack gets wrong at 1.4.1.
   `.mgd-on-ink .mgd-btn:disabled` sets color and border-color and never touches
   `background`, so a disabled .mgd-btn--primary keeps its full red fill and only
   dims its text: a bright, inert call to action. On the light ground it is worse
   -- there is no base `.mgd-btn:disabled` rule at all, so a disabled button
   there looks completely live.
   The same shape as the invisible-chip bug in 1.3.0: an on-ink override written
   for one variant that silently fails for another. Belongs in the pack, raised
   there; overridden here so the editor is not shipping an inert red button in
   the meantime. Delete this block when the pack carries the fix. */
.mgd-btn:disabled {
  background: transparent;
  color: var(--idle);
  border-color: var(--hair);
  cursor: default;
}
.mgd-btn:disabled:hover {
  background: transparent;
  color: var(--idle);
  border-color: var(--hair);
}

/* ── The history of one criterion ─────────────────────────────────────────────
   Expands in the flow under the criterion it belongs to, the same way .term__what
   does, rather than in a modal that would cover the list being worked through. */
.hist {
  border-left: var(--mgd-rule) solid var(--hair);
  padding-left: var(--mgd-space-4);
  margin-top: var(--mgd-space-2);
}
.hist__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--mgd-space-3);
}
.hist__row {
  display: flex;
  align-items: baseline;
  gap: var(--mgd-space-3);
  flex-wrap: wrap;
}
.hist__when {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  color: var(--quiet);
  font-variant-numeric: tabular-nums;
  /* Fixed, so the dates line up down the list and the verdicts beside them do
     too. Without it every row starts at a different place and the column of
     met/not-met -- which is the thing you are scanning for -- zigzags. */
  min-width: 11ch;
}
.hist__verdict {
  font-size: var(--mgd-size-label);
  font-weight: 600;
  letter-spacing: var(--mgd-track-label);
  text-transform: uppercase;
}
.hist__rev,
.hist__proposal {
  font-size: var(--mgd-size-label);
}
.hist__note {
  margin: 0;
  /* Breaks the row so a note reads as prose rather than as another column, and
     lines up under the verdict instead of under the date. */
  flex-basis: 100%;
  /* Under the verdict rather than the date, so a note reads as prose attached
     to the answer above it. Matches .hist__when's fixed width plus the row gap. */
  padding-left: calc(17ch + var(--mgd-space-3));
}
