/* ==========================================================================
   ProjectManagementPro.ClientWASM — collections
   The family of a repeated record: the list that holds the records, the card drawn for
   one of them, the table of counts the project context publishes, and the list of recent
   projects the entry screen draws. It is a family of its own because none of the three
   existing sheets describes it: layout.css frames a screen, forms.css draws a control, and
   feedback.css reacts to a state — none of them is about the same thing drawn n times.

   The classes are the ones these components render:
     * Features/Projects/Components/ProjectList.razor          (.project-list, .project-card)
     * Features/Projects/Components/ProjectArtifacts.razor     (.project-artifacts)
     * Features/Projects/Components/ProjectPhaseActions.razor  (.project-phase)
     * Features/Projects/Components/PhaseGateRejection.razor   (.phase-rejection)
     * Features/Home/HomePage.razor                            (.home__recent*)
     * Features/Background/Components/BackgroundList.razor     (.background-list, .background-card)
     * Features/Background/Components/BackgroundSuggestions.razor (.background-suggestions)

   The measure and the legibility rules are the ones already approved for the product — a
   1px hairline around a white surface, a 12px corner, the muted colour for a label — but
   this sheet is written from the tokens of tokens.css, not carried over from the active
   client's `components.css`: that file states the same card five times over, once per
   screen, and that duplication is what this delivery exists to avoid. Every value below is
   a token; nothing here states a colour, a size or a distance of its own.
   ========================================================================== */

/* ==========================================================================
   The Cards view of any collection — the one definition of its rows

   Every artefact that offers Cards and Table draws its cards inside a container that carries
   this class beside the family's own, and this is the only place a row of cards is measured:
   **four per row** on a laptop, two at tablet width and one on a phone.

   It replaces five different measurements that the families had grown one at a time — a
   `flex` column that stacked the cards, an `auto-fill` grid that gave four columns in one
   screen and three in the next, and two `auto-fit` grids whose column count followed the
   length of the text. The owner asked for the row of four on 2026-09-24, and one rule is what
   makes that true of every artefact instead of true of the ones somebody remembered to edit.

   What each family keeps: the class of its own container as the anchor of its `__item` and
   card rules, the card itself, and anything that is not the row (the `outline: none` of a
   region that takes the caret, the space above a group of cards).
   ========================================================================== */
.collection-cards {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* **Three per row where the Scope Builder takes its 40% of the screen, and four everywhere else.** The owner's order of
     the 2026-09-27 review: the 60/40 split left the cards narrower, so the artefact that draws the scope column shows
     three and the one that does not shows four — and hiding the column gives the room back, so it goes back to four. */
  gap: var(--space-md);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The cards of one row are as tall as the tallest of them, which is the same decision the list
   of projects takes and for the same reason: the actions at the foot of a card line up with
   the actions of its neighbours. A family whose cards are long and uneven — the words of a
   background entry are shown whole — can opt out with `align-items: start` on its own
   container, and that is a measurement of that family and not of the row. */

/* Below a laptop there is no room for four readable cards: two while the window is still a
   tablet, and one when it is a phone. `minmax(0, 1fr)` and not a fixed width, so a long word
   or a badge shrinks the card instead of pushing it out of its column. */
@media (max-width: 1199px) {
  .collection-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 767px) {
  .collection-cards {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ==========================================================================
   The modal that writes one investment row — Components/Investments/InvestmentsPanel.razor

   The rows of its form, and nothing else: the fields are the field family's and the dialog is the dialog family's,
   so what this declares is how they are laid out — the description and the pair of category and nature across the
   width, and the three numbers of the row under them, which is the order the owner fixed on 2026-09-27.
   ========================================================================== */
.investment-form__row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-sm) var(--space-md);
}

.investment-form__row--pair {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* The nature of a purchase is a choice between two, so it is two buttons and not a list: the chosen one is the one
   painted, and pressing it again takes it back. */
.investment-form__nature {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

@media (max-width: 767px) {
  .investment-form__row,
  .investment-form__row--pair {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ==========================================================================
   The content of a table reads like the content of a card

   The two views are two ways of reading one answer (`DEC-035`), so the only thing that changes between them is *how*
   the information is shown and never how loud it is. The owner, on 2026-09-27: «el tipo del campo descripción debe ser
   uniforme en todas las tablas y debe ser igual al que usamos en la descripción de las cards… evitar usar negrita», y
   para todos los artefactos: «esto aplica para todos los artefactos».

   **Every `th` of the application loses the emphasis**, and that is one rule and not one per family: a `th` is bold
   because the browser says so, and both shapes of it carry content — the name of a column and the header of a row (the
   description of a background entry, the name of a stakeholder, the code of a cost center, the title of a risk). What
   tells a header from a value here is its colour and its size, which the family sheets already declare.
   ========================================================================== */
table th {
  font-weight: var(--font-weight-normal);
}

/* The data cells that used to state the emphasis and now state its absence. They are named once here so that the weight
   is declared for every family in one place — and so that a class a table draws keeps being a class some sheet knows. */
:is(.expectation-table__definition,
    .scope-builder__verdict,
    .expert-judgement-table__name,
    .expert-judgement-table__recommendations-label,
    .investment-table__text,
    .investment-table__total,
    .investment-table__foot-value,
    .risk-table__title) {
  font-weight: var(--font-weight-normal);
}

/* ==========================================================================
   The content of a card — the one anatomy of every collection

   The row of four says how wide a card is; this says what is inside it and in which order.
   It exists because the artefacts had grown their card contents one at a time out of one
   contract: the same five slots, each family declaring its own gap, its own title size, its
   own facts — a line of loose text in one artefact and a labelled grid in the next — and its
   own actions: sometimes under a rule and sometimes not, with the destructive action painted
   red in eight artefacts and left plain in the rest. The owner's review of 2026-09-25 named
   the result: «la app se ve como un revoltijo de estilos» (DEC-045).

   A card is one `<article>` carrying this class beside the family's own, and it draws, in
   this order and only when it has something to put there:

     `__head`     the identity of the row: the reference the server published, then the
                  values it published for it, each one a chip.
     `__title`    the line that defines the row. One size and one weight in every artefact.
     `__text`     the free text the artefact stores, drawn as it stores it.
     `__note`     a second and quieter free text (the notes of a known risk, the source of an
                  expectation): the text is the content and this is what annotates it.
     `__facts`    the labelled facts, as a definition grid: a label and a value each.
     `__actions`  what can be done with the row — always the last line, always to the right,
                  always under the same rule, with the destructive action in danger.

   Any card that is not `collection-cards` — the projects list, the schedule tree, the cost
   centers, the catalogues — draws the same anatomy, because it is the anatomy of the card and
   not of the grid: what those screens keep is their own class and whatever is not this
   anatomy (the indent of a sub-deliverable, the drawers of a HAZOP deviation, the total of an
   investment).

   The facts are a grid rather than a line of text so that they line up between neighbours of
   the same row, and they carry a label at all because «Added 12/03/2026» and «12/03/2026»
   under a heading `Added` are one fact drawn twice.
   ========================================================================== */
.collection-card {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--space-xs);
  min-width: 0;
  padding: var(--space-md);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
}

/* The card a reader is working inside: the same emphasis the list of projects gives it. */
.collection-card:focus-within {
  border-color: var(--color-primary-border);
  box-shadow: var(--shadow-md);
}

.collection-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin: 0;
}

/* The reference the server published (`CE-4`, `DV-2`, `R-11`): a code and not a title, so it is the
   mono face the tables of the same artefacts already use. It is never built here out of `Seq` — the
   reference is the server's rule and the string a scope item stores as its origin. */
.collection-card__ref {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* A head that holds a list of values rather than one — the categories of a background, the methods of a
   stakeholder, the kinds of an expectation: the list keeps its semantics and wears the row of the head. */
.collection-card__chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.collection-card__title {
  margin: 0;
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  overflow-wrap: anywhere;
}

.collection-card__text {
  margin: 0;
  color: var(--color-text);
  white-space: pre-line;
  overflow-wrap: anywhere;
}

.collection-card__note {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  white-space: pre-line;
  overflow-wrap: anywhere;
}

.collection-card__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-xs) var(--space-md);
  margin: 0;
}

.collection-card__fact {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  min-width: 0;
}

.collection-card__fact dt {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.collection-card__fact dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* A fact whose value is prose and not a figure — the recommendations of a consultation, the plan of a risk: it
   takes the whole row of the grid instead of one narrow column, and keeps the breaks the text was written with. */
.collection-card__fact--wide {
  grid-column: 1 / -1;
}

.collection-card__fact--wide dd {
  white-space: pre-line;
}

/* The actions close the card: pushed to the foot (`margin-top: auto`) so that they line up across a row of
   cards of different lengths, and separated from the content by the one rule every card wears. */
.collection-card__actions {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-xs);
  margin-top: auto;
  padding-top: var(--space-sm);
  border-top: var(--border-default);
}

/* A chip: one geometry for every value a card shows — the levels of a risk, the categories of a
   background, the methods of a stakeholder, the area of a quality item. A family class beside it is a
   tone and nothing else, which is what keeps a badge from being 2 px narrower in one artefact. */
.collection-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  margin: 0;
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-surface-muted);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  white-space: nowrap;
}

/* A value of the record itself: a category, a method, an area, the level of a deliverable. */
.collection-chip--accent {
  background: var(--color-primary-soft);
  border-color: var(--color-primary-border);
  color: var(--color-primary-strong);
}

/* A reading the server publishes as good: a low risk, a settled definition, a signatory. */
.collection-chip--positive {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-secondary-strong);
}

/* The reading that keeps the phase gate closed: still to define, under assessment, unresolved. */
.collection-chip--warning {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-accent);
}

/* The highest readings of a scale the server publishes: a critical risk, a high impact. */
.collection-chip--danger {
  background: var(--color-error-soft);
  border-color: var(--color-error-border);
  color: var(--color-error-strong);
}

/* ==========================================================================
   The list of projects — Features/Projects/Components/ProjectList.razor
   ========================================================================== */
/* As many cards per row as the width allows. `minmax(min(320px, 100%), 1fr)` is what keeps a
   narrow viewport honest: the 320px floor never becomes a horizontal scrollbar, because below
   it the track shrinks to the column it is in. */
.project-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: var(--space-md);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The item stretches so that every card in a row is as tall as the tallest one, and the
   action at the bottom of a card lines up with the action of its neighbours. */
.project-list__item {
  display: flex;
  min-width: 0;
}

/* ==========================================================================
   One project — the card
   ========================================================================== */
.project-card {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--space-sm);
  min-width: 0;
  padding: var(--space-md);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
  transition: border-color var(--duration-fast) var(--easing-standard),
              box-shadow var(--duration-fast) var(--easing-standard);
}

/* The hover of the family: the surface that holds the row under the pointer lifts, the way the
   active client's table paints its hovered row. `:focus-within` gives the same affordance to a
   keyboard that has reached the card's own link or action, so the highlight is never a mouse
   only hint. Neither state carries meaning on its own, so neither replaces the focus ring of
   base.css — which is drawn on top of both. */
.project-card:hover,
.project-card:focus-within {
  border-color: var(--color-primary-border);
  box-shadow: var(--shadow-md);
}

.project-card__title {
  margin: 0;
  font-size: var(--font-size-lg);
  /* The title step of the scale, declared and not inherited: this title is an `<h3>`, so without this line it would be
     drawn with the browser's own bold (700) while the shared title of a collection card is 600 — two weights for one
     role, which is the same disagreement the owner reported in the tables on 2026-09-27 («evitar usar negrita»). */
  font-weight: var(--font-weight-semibold);
  overflow-wrap: anywhere;
}

/* The name is a link to the project's context and keeps the underline base.css gives every
   anchor: it is the one way into the project, and a title identified by colour alone would be a
   title a colour-blind user has to guess at. A name typed without a space still wraps. */
.project-card__link {
  overflow-wrap: anywhere;
}

/* A description is free text and can be arbitrarily long. Three lines are what a row of cards
   can afford: the card stays the size of its facts, and the link inside it opens the screen
   that draws the description in full. `-webkit-` is the only spelling of the clamp a browser
   implements today. */
.project-card__description {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  overflow-wrap: anywhere;
}

/* The facts the server published with the row. No row is drawn for a value it did not publish,
   so this grid never has to leave a hole: it holds as many label/value columns as fit. */
.project-card__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-xs) var(--space-md);
  margin: 0;
}

.project-card__fact {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  min-width: 0;
}

/* `dd` is indented by the browser's own style sheet (40px): a fact is a label over its value,
   not an indented definition. */
.project-card__fact dt {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.project-card__fact dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* The action of the row, at the bottom of the card whatever the length of the description
   above it, under the same hairline the other action rows of the client use. */
.project-card__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-xs);
  margin-top: auto;
  padding-top: var(--space-sm);
  border-top: var(--border-default);
}

/* The only action a row offers is the destructive one, and the caller can only ask for it as
   the ghost variant (`ProjectList.razor` draws `ButtonVariant.Ghost`). The danger role is
   therefore applied by the surface that knows what the action does — the same role
   `.button--danger` would carry — instead of by a variant the markup cannot choose. The rest
   of the button family is untouched: the focus ring, the disabled state and the target height
   all still come from forms.css. */
/* ==========================================================================
   The artefact counts — Features/Projects/Components/ProjectArtifacts.razor
   ========================================================================== */
.project-artifacts {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  padding: var(--space-lg);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
  /* The table is the widest thing this panel holds and it has no wrapper element of its own to
     scroll in, so the panel scrolls sideways when a narrow viewport cannot fit four columns.
     The alternative — the table widening the page — would move the whole screen, including the
     header the user is reading. */
  overflow-x: auto;
}

.project-artifacts__title,
.project-artifacts__subtitle {
  margin: 0;
}

/* The Initiating figures, drawn only when the server published them. */
.project-artifacts__kpis {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* Why a figure is missing. The screen says it in words instead of drawing a zero that would
   read as progress. */
.project-artifacts__note {
  max-width: 90ch;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.project-artifacts__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-size-sm);
}

/* The caption says what the fourteen rows below it are, so it is read first and left aligned
   with the column it introduces. */
.project-artifacts__caption {
  padding-bottom: var(--space-xs);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  text-align: left;
}

.project-artifacts__table th,
.project-artifacts__table td {
  padding: var(--space-xs) var(--space-sm);
  border-bottom: var(--border-default);
  text-align: left;
  vertical-align: top;
}

/* The four columns are named by the server's own table, and the header row is a band rather
   than three more hairlines. Headers wrap: a line of text that never breaks is what makes a
   table wider than the screen it is read on. */
.project-artifacts__table thead th {
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
}

/* The row header is the label the server published — never its key — and it is the one column
   that is text rather than a number. */
.project-artifacts__table tbody th {
  overflow-wrap: anywhere;
}

/* The three counts are numbers: they align on their right edge, and the tabular figures keep
   the digits of a column over one another. Their headers align with them. */
.project-artifacts__table td,
.project-artifacts__table thead th:not(:first-child) {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.project-artifacts__table tbody tr:last-child th,
.project-artifacts__table tbody tr:last-child td {
  border-bottom: 0;
}

/* The same hover as the cards above: the record under the pointer is painted, so a row of
   counts as wide as four columns is read along the row and not down the page. */
.project-artifacts__row:hover {
  background: var(--color-primary-soft);
}

/* What still blocks the approval of the phase. The three `accent` tokens are the palette's
   warning role, and this is the first screen of the delivery that draws one: the message is
   the server's own sentence and stays in the body colour (the accent ink on the soft accent
   background does not hold the contrast of body text), while the count is emphasised. */
.project-artifacts__blockers {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.project-artifacts__blocker {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-size: var(--font-size-sm);
}

.project-artifacts__blocker-message {
  min-width: 0;
  overflow-wrap: anywhere;
}

.project-artifacts__blocker-count {
  flex: 0 0 auto;
  font-weight: var(--font-weight-semibold);
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   The phase lifecycle — Features/Projects/Components/ProjectPhaseActions.razor
   and the refusal its four paths share,
   Features/Projects/Components/PhaseGateRejection.razor
   ========================================================================== */
/* The panel under the artefact counts. It is the surface of the section above and not a card inside
   it: the two are read together — the blockers say why the approval is not due yet and these two
   rows say what the phase lets the person do — so a second frame between them would separate a
   sentence from the action it is about. */
.project-phase {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-lg);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
}

.project-phase__title {
  margin: 0;
}

.project-phase__lead,
.project-phase__note {
  max-width: 90ch;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* The actions wrap instead of leaving the panel: two of them are offered at once in Planning and in
   Executing, and a narrow viewport has to be able to stack them. */
.project-phase__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

/* The codes of the rules that blocked a transition, as the server sent them. They are drawn as the
   contract's own tokens — monospace, one per chip — and not as sentences: this screen must not turn
   a blocker code into a rule of its own (gate 6), and a code it has never seen is still the reason
   the approval did not happen. */
.phase-rejection {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.phase-rejection__code {
  padding: var(--space-2xs) var(--space-sm);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  overflow-wrap: anywhere;
}

/* ==========================================================================
   The background entries — Features/Background/Components/BackgroundList.razor
   and the suggestions panel of the same feature
   ========================================================================== */
/* The list of entries carries the family's own class and the shared row of four
   (`.collection-cards`, declared at the top of this sheet): four cards on a laptop, two on a
   tablet and one on a phone. Nothing here clamps a description, because the owner's rule for
   this artefact is about its words («debe mostrar todo asi sea que se vea desordenado»). */

.background-list__item {
  display: flex;
  min-width: 0;
}

/* The delete of a table row is the ghost variant the markup chooses, so the danger role is applied by the surface
   that knows what the action does. A card needs no rule: its delete wears `button--danger`, the variant of the
   destructive action, which is what the eight artefacts that painted every ghost button of their card red were
   missing (`DEC-045`). The tables keep this rule until their own delete wears that variant too, and it is why the
   investigations toggle of a collapsed row is still painted with it (`HANDOFF-UI.md` §5.9). */

/* ==========================================================================
   The suggestions of one artefact —
   Features/Background/Components/BackgroundSuggestions.razor
   ========================================================================== */
/* A panel of proposals and of the refusals already filed. It is the collections family: a proposal is a
   record repeated n times, drawn with the text and the one category the server published. */
.background-suggestions {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-lg);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
}

.background-suggestions__title,
.background-suggestions__subtitle {
  margin: 0;
}

.background-suggestions__note {
  max-width: 90ch;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.background-suggestions__actions,
.background-suggestions__recovery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

/* The body of the panel — the proposals and the refusals below them. It is one child of the panel so that the
   collapse can hide it without taking anything out of the document: what is hidden comes back exactly as it was,
   a question left open included.
   `display` is declared here, which is why the hidden state is repeated below: the `[hidden]` rule of the user
   agent's own sheet is the weakest selector there is, and a class that declared a display would win over it and
   leave the body on screen while the attribute said it was closed. */
.background-suggestions__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.background-suggestions__body[hidden] {
  display: none;
}

.background-suggestions__list,
.background-suggestions__dismissed {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The surface of one proposal of this artefact — the muted card. Its **shape** (what goes where, and the decisions
   at the front of the text) is declared once for the ten artefacts of the panel, at the end of this sheet. */
.background-suggestions__item {
  padding: var(--space-sm) var(--space-md);
  background: var(--color-surface-muted);
  border: var(--border-default);
  border-radius: var(--radius-sm);
}

/* A proposal is free text and can be long; it wraps rather than widening the panel. */
.background-suggestions__text {
  margin: 0;
  overflow-wrap: anywhere;
}

/* One refusal: its surface, and the shape the shared block gives every row of the history. */
.background-suggestions__dismissed-item {
  padding: var(--space-xs) var(--space-sm);
  border-bottom: var(--border-default);
}

.background-suggestions__dismissed-item:last-child {
  border-bottom: 0;
}

/* The reason the server stored, in the muted colour of a fact and not as a message: nobody failed. */
.background-suggestions__reason {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* ==========================================================================
   The recent projects of the entry screen — Features/Home/HomePage.razor
   ========================================================================== */
/* These four rules belong to this sheet and not to the home frame: the markup draws the same
   repeated record as the listing does — a name that opens the project and the facts that go
   with it — only denser, one row per project instead of one card per project. */
.home__recent {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
  list-style: none;
}

/* The name and its facts share a row while they fit and stack when they do not. The row is the
   one the list rounds — the first corner, the last corner — so the hover below never paints
   over the corner of the panel it belongs to, and no ancestor has to clip anything: an
   `overflow: hidden` here would be the one thing able to cut the focus ring of the link. */
.home__recent-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2xs) var(--space-md);
  padding: var(--space-sm) var(--space-md);
  border-bottom: var(--border-default);
  min-width: 0;
}

.home__recent-item:first-child {
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.home__recent-item:last-child {
  border-bottom: 0;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

.home__recent-item:hover,
.home__recent-item:focus-within {
  background: var(--color-primary-soft);
}

/* The name keeps the underline and the colours base.css gives every link: it is the one way
   into the project, and a name identified by colour alone would be a name a colour-blind user
   has to guess at. */
.home__recent-link {
  font-weight: var(--font-weight-semibold);
  overflow-wrap: anywhere;
}

.home__recent-facts {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* ==========================================================================
   The constraints of a project —
   Features/Constraints/Components/ConstraintList.razor
   ========================================================================== */
/* The artefact's own list: a record repeated n times, drawn with what the server published for it. The
   frame is the one the background family uses — a card per item, in a column — and nothing here filters,
   sorts or pages: the endpoint answers the whole list and takes no query parameter at all. */

.constraint-list__item {
  display: flex;
  min-width: 0;
}

/* The delete of a table row is the ghost variant the markup chooses, so the danger role is applied by the surface
   that knows what the action does. A card needs no rule: its delete wears `button--danger`, the variant of the
   destructive action, which is what the eight artefacts that painted every ghost button of their card red were
   missing (`DEC-045`). The tables keep this rule until their own delete wears that variant too, and it is why the
   investigations toggle of a collapsed row is still painted with it (`HANDOFF-UI.md` §5.9). */
/* ==========================================================================
   The findings of the constraints artefact —
   Features/Constraints/Components/ConstraintSuggestions.razor
   ========================================================================== */
/* A panel of findings and of the refusals already filed. Same family as the background suggestions: a
   finding is a record repeated n times, with the text and the references the server published. */
.constraint-suggestions {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-lg);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
}

.constraint-suggestions__title,
.constraint-suggestions__subtitle {
  margin: 0;
}

.constraint-suggestions__note {
  max-width: 90ch;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.constraint-suggestions__actions,
.constraint-suggestions__recovery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

/* The body of the panel — the findings and the refusals below them — is drawn inside one element by the shared
   section, so that the artefact that can close it hides it without taking anything out of the document.
   This artefact cannot close it, so the element is transparent to the layout: its children are the flex items of
   the section and keep the gap between them, exactly as they were when the body had no wrapper at all. */
.constraint-suggestions__body {
  display: contents;
}

.constraint-suggestions__list,
.constraint-suggestions__dismissed {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* One finding: its type, its text, the references it cites and the two decisions. */
.constraint-suggestions__item {
  padding: var(--space-sm) var(--space-md);
  background: var(--color-surface-muted);
  border: var(--border-default);
  border-radius: var(--radius-sm);
}

/* The type as the server published it (`contradiction` or `suggestion`). The accent role marks it as the
   classification of the row and not as one of its facts; the client never maps it to a vocabulary of its
   own, because the constants live in Shared and the gate 6 list forbids reading them.
   The element carries the name the shared suggestion section gives the classification of a row — every artefact
   that publishes one draws it there — and the styling is this artefact's own. */
.constraint-suggestions__kind {
  align-self: flex-start;
  margin: 0;
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
  color: var(--color-accent);
  font-size: var(--font-size-sm);
}

/* A finding is free text and can be long; it wraps rather than widening the panel. */
.constraint-suggestions__text {
  margin: 0;
  overflow-wrap: anywhere;
}

/* The references the finding cites. They are tags and not links: turning a `CE-3` into a navigation needs
   a reference-to-identifier resolution the server does not publish (GAP-CRUD-08). */
.constraint-suggestions__refs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.constraint-suggestions__ref {
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-primary-soft);
  border: var(--border-width) solid var(--color-primary-border);
  border-radius: var(--radius-sm);
  color: var(--color-primary-strong);
  font-size: var(--font-size-sm);
}

/* One refusal: what was refused, why, and the way back. */
.constraint-suggestions__dismissed-item {
  padding: var(--space-xs) var(--space-sm);
  border-bottom: var(--border-default);
}

.constraint-suggestions__dismissed-item:last-child {
  border-bottom: 0;
}

/* The reason the server stored, in the muted colour of a fact and not as a message: nobody failed. */
.constraint-suggestions__reason {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* ==========================================================================
   The investigations of one item of an artefact —
   Components/Investigations/InvestigationsPanel.razor
   ========================================================================== */
/* It is drawn inside the editor of an existing item and, expanded, in a row of the list: one row per
   investigation, the form that opens one, and the resolution of each. **It is one block for every artefact that
   carries the mechanism** — the panel was promoted out of `Features/Constraints` when Exclusions became its second
   consumer, so the class carries the mechanism's name and not an artefact's: a feature declares no style of its own
   for it (the rule of the artefact template §0.8). */
.investigations {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-top: var(--space-md);
  padding-top: var(--space-md);
  border-top: var(--border-default);
}

.investigations__title {
  margin: 0;
}

.investigations__note {
  max-width: 90ch;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.investigations__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  padding: var(--space-md);
  background: var(--color-surface-muted);
  border: var(--border-default);
  border-radius: var(--radius-sm);
}

.investigations__actions,
.investigations__recovery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

.investigations__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

.investigations__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-sm) var(--space-md);
  background: var(--color-surface-muted);
  border: var(--border-default);
  border-radius: var(--radius-sm);
}

/* What the row reads first: the finding of a resolved investigation, or the sentence that says it is still open.
   The vestigial question is **not** drawn — it is the literal the panel itself writes, so it said the same word on
   every row (`GAP-105`). */
.investigations__pending {
  margin: 0;
  color: var(--color-text-muted);
  font-style: italic;
}

/* The reading of one row and the two acts that rewrite it, one beside the other. */
.investigations__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-xs) var(--space-md);
}

.investigations__body {
  display: flex;
  flex: 1 1 24rem;
  flex-direction: column;
  gap: var(--space-2xs);
  min-width: 0;
}

.investigations__row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

.investigations__facts {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs) var(--space-md);
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* Whether the server holds this investigation resolved. It is the `resolved` the row carries, drawn as a
   word and never recomputed from the result here. */
.investigations__state {
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-secondary-soft);
  border: var(--border-width) solid var(--color-secondary-border);
  border-radius: var(--radius-sm);
  color: var(--color-secondary-strong);
}

.investigations__fact {
  overflow-wrap: anywhere;
}

.investigations__result {
  margin: 0;
  white-space: pre-line;
  overflow-wrap: anywhere;
}

/* The resolution of one row: the value the server stored, editable, with the two actions that write it. */
.investigations__resolve {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

/* ==========================================================================
   The two views of an artefact —
   Components/Views/ArtifactView.razor and Components/Views/ViewSwitcher.razor
   ========================================================================== */
/* The owner asked for both halves in one breath: «que en cada artefacto podamos visualizar por cards o por tabla
   pero esta seleccion se guarde en las configuraciones del usuario particular». The switch is the collections
   family because what it changes is how a collection is read — the same records, one card per row or one row per
   record — and it is drawn once here so no artefact screen grows a switcher of its own. */
.artifact-view {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

/* The row the switch sits in: it closes the region above the list, aligned with the end of the line. It also carries
   the artefact's create act — the one primary button the screen names through `ArtifactView.CreateLabel` —, and it is
   the last child of the row so that the act is the rightmost thing in it, «arriba y a la derecha» and just above the
   cards or the table, which is where the owner asked for it on 2026-09-27. */
.artifact-view__toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-xs);
}

/* **Los dos grupos de la fila.** El de la izquierda es lo que filtra —lo pone la pantalla, y una pantalla que no
   filtra no lo dibuja— y el de la derecha es el interruptor de vistas con el acto de crear. `margin-left: auto` es lo
   que mantiene el grupo de la derecha pegado al final **tambien cuando hay filtros**, porque sin el los tres trozos de
   la fila se repartirian con `justify-content: space-between` y el interruptor caeria en el centro. */
.artifact-view__filters,
.artifact-view__tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  min-width: 0;
}

.artifact-view__tools {
  margin-left: auto;
}

/* **The create act of this row is drawn 2 px taller, and the two halves of the switch beside it are matched to it.**
   The owner asked for the taller button here and only here: it is the act the row exists for, and a control 2 px shorter
   than the one next to it reads as a different kind of thing in the same line. Both rules are scoped to
   `.artifact-view__tools` —el grupo de la derecha, el del interruptor y el acto— y **no a toda la fila**, porque desde
   el 2026-09-30 la fila tambien lleva a la izquierda el grupo que filtra: si la regla alcanzara a la fila entera, el
   boton *All (N)* del filtro —que es primario— saldria 2 px mas alto que los otros botones primarios de su propio
   grupo. Asi el `.button` y el `.view-switcher` compartidos siguen intactos: el interruptor conserva
   `--control-height` en el resto del producto y cualquier otro boton primario conserva `--button-height`. */
.artifact-view__tools .button--primary {
  min-height: calc(var(--button-height) + 2px);
}

.artifact-view__tools .view-switcher__option {
  min-height: calc(var(--button-height) + 2px);
}

/* The region the two views are read inside. It scrolls (`artifact-scroll`) and it holds a table whose own wrapper
   scrolls sideways, so the body has to be allowed to be narrower than its content: without this the widest table of
   the application pushes the page itself wide instead of scrolling inside its wrapper. */
.artifact-view__body {
  min-width: 0;
}

/* A segmented control: the two ways of reading the list, and the one in force highlighted. The state is carried by
   `aria-pressed`, which is both what a screen reader announces and what paints the chosen half — so the drawing and
   the announcement cannot disagree. */
.view-switcher {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  padding: var(--space-3xs);
  background: var(--color-surface-muted);
  border: var(--border-default);
  border-radius: var(--radius-sm);
}

.view-switcher__option {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  min-height: var(--control-height);
  padding: 0 var(--space-xs);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  font-family: inherit;
  font-size: var(--font-size-sm);
  cursor: pointer;
}

.view-switcher__option:hover {
  color: var(--color-text);
}

.view-switcher__option[aria-pressed="true"] {
  background: var(--color-surface);
  border-color: var(--color-primary-border);
  color: var(--color-primary-strong);
  font-weight: var(--font-weight-semibold);
}

/* ==========================================================================
   The table view of an artefact — Features/Background/Components/BackgroundTable.razor
   and Features/Constraints/Components/ConstraintTable.razor
   ========================================================================== */
/* The same repeated record as the cards, read in rows: the frame is one, so it is declared once for both tables,
   exactly as the page frames of layout.css declare theirs. What each table adds of its own — the badges, the
   reference, the state chip — is declared by its own family below. */
.background-table__wrapper,
.constraint-table__wrapper {
  /* The table has no wrapper of its own inside the screen, so this is what scrolls sideways when a narrow window
     cannot fit six columns. The alternative — the table widening the page — would move the whole screen. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.background-table,
.constraint-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-size-sm);
}

.background-table__caption,
.constraint-table__caption {
  padding-bottom: var(--space-xs);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  text-align: left;
}

.background-table th,
.background-table td,
.constraint-table th,
.constraint-table td {
  padding: var(--space-xs) var(--space-sm);
  border-bottom: var(--border-default);
  text-align: left;
  vertical-align: top;
}

.background-table thead th,
.constraint-table thead th {
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
}

/* The row header is the identity of the row — the text somebody wrote for this entry — and it is the one column
   that is text. An entry has no name of its own any more (`DEC-068`), so the definition is both the row's header
   cell and what the row's two actions are named with. */
.background-table__text {
  overflow-wrap: anywhere;
  white-space: pre-line;
}

/* The definition is free text that is drawn whole: the rule for these artefacts is about their words. */
.constraint-table__text,
.constraint-table__impact {
  overflow-wrap: anywhere;
  white-space: pre-line;
}

.background-table__uncategorised,
.constraint-table__date {
  color: var(--color-text-muted);
}

/* A date is a fact of the row and not a measurement; it never wraps and it keeps the width of its own digits. */
.background-table__date,
.constraint-table__date {
  color: var(--color-text-muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* **The reference of a row, drawn the same way in the ten tables that carry one.** The fact is one — the readable code
   the server publishes (`CE-3`, `QU-7`, `SE-2`…) — and it was drawn three ways: a chip here, plain monospace text in
   four sheets, and a literal `ui-monospace, …` stack in two of them, which is a value that belongs to `tokens.css` and
   was written by hand instead. Since 2026-09-26 it is one rule: the monospace and muted line the **card** of every one
   of these artefacts already draws with `collection-card__ref`, so the two views of one record finally agree.
   The names are written out for the same reason the panel's row shape lists them: a reader sees which families it
   covers, and a new artefact with a reference adds its name here and nothing else. */
:is(.criterion-table__ref,
   .constraint-table__ref,
   .deliverable-table__ref,
   .expectation-table__ref,
   .expert-judgement-table__ref,
   .hazop-table__ref,
   .known-risk-table__ref,
   .quality-table__ref,
   .risk-table__ref,
   .exclusion-table__ref) {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* The state chip is the card's own class: the same value is drawn the same way in both views, and neither view
   restates its styling — the table only gives the cell its place. */
.constraint-table__state {
  white-space: nowrap;
}

/* The actions of a row, aligned to the right of the table under the same hairline the cards use. */
.background-table__actions,
.constraint-table__actions {
  white-space: nowrap;
  text-align: right;
}

.background-table__actions .button + .button,
.constraint-table__actions .button + .button {
  margin-left: var(--space-2xs);
}

/* The row under the pointer is painted, so a table as wide as six columns is read along the row. */
.background-table__row:hover,
.constraint-table__row:hover {
  background: var(--color-primary-soft);
}

.background-table tbody tr:last-child th,
.background-table tbody tr:last-child td,
.constraint-table tbody tr:last-child td {
  border-bottom: 0;
}

/* The badge of a row's category: one name, because an entry is filed under one (`DEC-068`), and never a set. It
   is the card's own badge class, drawn in the cell. */
.background-table__categories {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

.background-table__badge {
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-primary-soft);
  border: var(--border-width) solid var(--color-primary-border);
  border-radius: var(--radius-sm);
  color: var(--color-primary-strong);
  white-space: nowrap;
}

/* -------------------------------------------------------------------------------------------------------------------
   The investment section of the constraint dialog (section 2). The table is the artefact's own class family and not
   the list's: it is drawn inside a dialog, one artefact item's rows at a time, and it carries its own pending mark.
   ------------------------------------------------------------------------------------------------------------------- */

.constraint-investments {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.constraint-investments__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.constraint-investments__title {
  margin: 0;
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text);
}

.constraint-investments__note {
  margin: 0;
  color: var(--color-text-muted);
}

/* The form is a grid of fields with one the row of actions closes: it is inline, so it is laid out and not stacked. */
.constraint-investments__form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-sm);
  padding: var(--space-sm);
  background: var(--color-surface-muted);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

.constraint-investments__form-full {
  grid-column: 1 / -1;
}

.constraint-investments__form-actions {
  display: flex;
  grid-column: 1 / -1;
  gap: var(--space-2xs);
}

.constraint-investments__table-wrapper {
  overflow-x: auto;
}

.constraint-investments__table {
  width: 100%;
  border-collapse: collapse;
}

.constraint-investments__caption {
  padding-bottom: var(--space-2xs);
  color: var(--color-text-muted);
  text-align: left;
}

.constraint-investments__table th,
.constraint-investments__table td {
  padding: var(--space-xs) var(--space-sm);
  border-bottom: var(--border-width) solid var(--color-border);
  text-align: left;
  vertical-align: top;
}

.constraint-investments__table th {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.constraint-investments__row:hover {
  background: var(--color-primary-soft);
}

.constraint-investments__table tbody tr:last-child td {
  border-bottom: 0;
}

.constraint-investments__category,
.constraint-investments__unit {
  white-space: nowrap;
}

.constraint-investments__total {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* A row typed before the artefact exists belongs to no investment list yet, and the mark says so. */
.constraint-investments__pending {
  display: inline-block;
  margin-top: var(--space-3xs);
  padding: var(--space-3xs) var(--space-2xs);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
  color: var(--color-accent);
  font-size: var(--font-size-sm);
}

.constraint-investments__computed {
  color: var(--color-text-muted);
  font-style: italic;
}

.constraint-investments__actions {
  white-space: nowrap;
  text-align: right;
}

.constraint-investments__actions .button + .button {
  margin-left: var(--space-2xs);
}
/* The text of one row, with the pending mark under it when the row has not been written yet. */
.constraint-investments__description {
  min-width: 12rem;
}
/* -------------------------------------------------------------------------------------------------------------------
   Section 3 of the constraints screen: the Scope Builder, drawn in the page's right-hand column because it is about
   the artefact's items and not about the one the dialog has open.
   ------------------------------------------------------------------------------------------------------------------- */

.constraint-page__main {
  min-width: 0;
}

.constraint-page__scope {
  min-width: 0;
}
/* -------------------------------------------------------------------------------------------------------------------
   The summary, the badges and the notices of the constraints list (C06, C07, C15, C16, C17 and C39).
   ------------------------------------------------------------------------------------------------------------------- */

/* The action that adds an item: `DEC-090` point 3 puts it above the list and below the suggestions. */
.constraint-page__list-actions {
  display: flex;
  margin-bottom: var(--space-md);
}

/* The same truth the phase gate refuses the approval with, said where the person can act on it. */
.constraint-page__incomplete {
  margin: 0 0 var(--space-md);
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
}

/* The impact summary: the total and one badge per value the server publishes. */
.constraint-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs);
  margin-bottom: var(--space-md);
}

.constraint-summary__total {
  padding: var(--space-3xs) var(--space-2xs);
  background: var(--color-primary-soft);
  border: var(--border-width) solid var(--color-primary-border);
  border-radius: var(--radius-sm);
  color: var(--color-primary-strong);
  white-space: nowrap;
}

.constraint-summary__note {
  color: var(--color-text-muted);
}

/* The badge of one impact value. Which values exist is the server's; how this system paints one is not. */
.constraint-impact-badge {
  display: inline-block;
  padding: var(--space-3xs) var(--space-2xs);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

.constraint-impact-badge--error {
  background: var(--color-error-soft);
  border-color: var(--color-error-border);
  color: var(--color-error-strong);
}

.constraint-impact-badge--warning {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-accent);
}

.constraint-impact-badge--success {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-secondary-strong);
}

.constraint-impact-badge--neutral {
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
}

/* The chip of the definition state is the shared one (`definitions.css`); what stays here is the badge of the
   state of a decision, in the word the server stored. */
.constraint-decided-badge {
  display: inline-block;
  padding: var(--space-3xs) var(--space-2xs);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

.constraint-decided-badge--discarded {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-accent);
}

.constraint-decided-badge--settled {
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
}

/* The row of investigations a table row opens in place. */
.constraint-table__investigations {
  background: var(--color-surface-muted);
}

/* The three readings of the definition state and the notice that follows each one (C25 and C26). */
.constraint-definition {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs);
}

.constraint-definition__badge {
  display: inline-block;
  padding: var(--space-3xs) var(--space-2xs);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

.constraint-definition__badge--settled {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-secondary-strong);
}

.constraint-definition__badge--warning {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-accent);
}

.constraint-definition__explanation {
  color: var(--color-text-muted);
}

.constraint-definition__notice {
  margin: 0;
  padding: var(--space-xs) var(--space-sm);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

.constraint-definition__notice--open {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-text);
}

.constraint-definition__notice--settled {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-text);
}

/* ==========================================================================
   The exclusions of a project —
   Features/Exclusions/ExclusionPage.razor and Features/Exclusions/Components/*
   ========================================================================== */
/* The artefact whose whole content is a name (DEC-094): a list of records, each one with the state the server
   published for it, and the two dialogs. Its sections 1 and 3 do not exist, so no rule of those families is
   declared here — a screen that drew them would be drawing a section the artefact does not have. */

/* The list actions above the list: the one action of the screen, which is the add. */
.exclusion-page__list-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-bottom: var(--space-md);
}

/* The three figures of the artefact — how many it has, how many are defined and how many still to define — in
   one line, and the same truth the phase gate refuses the approval with, said where a person can act on it. */
.exclusion-page__summary {
  margin: 0 0 var(--space-sm);
  color: var(--color-text-muted);
}

.exclusion-page__incomplete {
  margin: 0 0 var(--space-md);
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
}

.exclusion-page__note {
  margin: 0 0 var(--space-md);
  color: var(--color-text-muted);
}

.exclusion-page__recovery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-top: var(--space-sm);
}

/* The card view: the same card the rest of the artefact families use, with the name as its title. */

.exclusion-list__item {
  display: flex;
  min-width: 0;
}

/* The delete of a table row is the ghost variant the markup chooses, so the danger role is applied by the surface
   that knows what the action does. A card needs no rule: its delete wears `button--danger`, the variant of the
   destructive action, which is what the eight artefacts that painted every ghost button of their card red were
   missing (`DEC-045`). The tables keep this rule until their own delete wears that variant too, and it is why the
   investigations toggle of a collapsed row is still painted with it (`HANDOFF-UI.md` §5.9). */
/* The state the server published, drawn as the chip of the family in the two views and in the dialog's own
   reading of it. It is the word the server sent (`DEC-W62`); the colour is the client's. */
.exclusion-state {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-primary-soft);
  border: var(--border-width) solid var(--color-primary-border);
  border-radius: var(--radius-sm);
  color: var(--color-primary-strong);
  font-size: var(--font-size-sm);
  white-space: nowrap;
}

.exclusion-state--settled {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-secondary-strong);
}

.exclusion-state--warning {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-accent);
}

/* The table view: the three columns the artefact's own screen draws — the name, the definition and the actions. */
.exclusion-table__wrapper {
  overflow-x: auto;
}

.exclusion-table {
  width: 100%;
  border-collapse: collapse;
}

.exclusion-table__caption {
  padding-bottom: var(--space-xs);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  text-align: left;
}

.exclusion-table th,
.exclusion-table td {
  padding: var(--space-sm);
  border-bottom: var(--border-default);
  text-align: left;
  vertical-align: top;
}

.exclusion-table thead th {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* **The text of the row is the elastic column and it is the last one before the actions**, which is the order the owner
   gave on 2026-09-27 for every table. The field is named `Description` since his rename of the same day — «pero llamarlo
   Description» —, so the class says so too. */
.exclusion-table__col-text {
  width: 100%;
}

.exclusion-table__col-ref {
  width: 90px;
}

.exclusion-table__col-state {
  width: 150px;
}

.exclusion-table__col-actions {
  width: 96px;
}

.exclusion-table__text {
  overflow-wrap: anywhere;
}

/* The state chip is the family's own class: the same value is drawn the same way in both views and in the dialog's
   reading of it, and neither view restates its styling — the table only gives the cell its place. */
.exclusion-table__state {
  white-space: nowrap;
}

.exclusion-table__actions {
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-end;
  gap: var(--space-xs);
}

.exclusion-table__row:hover {
  background: var(--color-surface-muted);
}

/* The row of investigations a table row opens in place. */
.exclusion-table__investigations {
  background: var(--color-surface-muted);
}

/* The dialog's own reading of the definition state: the badge and the sentence that explains it, and the one
   notice that follows. It is the same shape the constraints dialog draws, and the promotion of the two is
   reported as a handoff (the destination is outside this task's ownership). */
.exclusion-definition {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs);
}

.exclusion-definition__explanation {
  color: var(--color-text-muted);
}

.exclusion-definition__notice {
  margin: 0;
  padding: var(--space-xs) var(--space-sm);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

.exclusion-definition__notice--open {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-text);
}

.exclusion-definition__notice--settled {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-text);
}

/* The one fact of the item the form does not ask for: the position in the list is the server's (BR-103). */
.exclusion-editor__note {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* ==========================================================================
   The stakeholders of a project —
   Features/Stakeholders/StakeholderPage.razor and Features/Stakeholders/Components/*
   ========================================================================== */
/* The artefact of a **different shape** (DEC-086, CONTRACT-ARTEFACT-CRUD.md §3.9): its content is a person linked to
   the project with a role, an engagement level and the ways they are informed. It has no definition state, no
   investigations, no suggestions, no investment list and no scope section, so no rule of those families is declared
   here — a screen that drew them would be drawing a section the artefact does not have. What is declared is the list,
   the two ways of drawing it, the two dialogs, and the filter the active screen offers. */

/* The list actions above the list: the one action of the screen, which is the add. */
.stakeholder-page__list-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-bottom: var(--space-md);
}

/* The count of the links, and the same answer said once — the active screen draws its counts in the buttons of its
   filter (ProjectStakeholders.razor:104-116) and this line is that answer in one sentence. */
.stakeholder-page__summary {
  margin: 0 0 var(--space-sm);
  color: var(--color-text-muted);
}

/* **La leyenda y el contenido, pegados.** El dueno lo pidio el 2026-09-30 sobre esta pantalla —la tarjeta que abre la
   pantalla, que es la leyenda, y el contenido del artefacto estaban «muy separado»— y el 2026-10-01 lo extendio a
   **todos** los artefactos: «la organizacion y visualizacion de esa leyenda en cada artefacto debe ser igual a como se
   organizo en stakeholders».
   **La regla ya no vive aqui**: los catorce marcos de artefacto se declaran juntos en `layout.css`, que es la hoja que
   posee el marco de pantalla, para que la forma sea una sola y no catorce acuerdos. Lo que esta hoja sigue poseyendo es
   el filtro de esta pantalla, que va en la fila del listado y no en una franja propia. */
.stakeholder-page__filter {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

.stakeholder-page__note {
  margin: 0 0 var(--space-md);
  color: var(--color-text-muted);
}

.stakeholder-page__recovery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-top: var(--space-sm);
}

/* ---- The chip of a value the row carries, and the badge of a classification ----
   The artefact draws two small marks on every row: the engagement level and the ways the person is informed are
   values of the row, and the signatory state is a classification of it. Both are declared once, so the table and the
   cards draw the same value the same way. */

.stakeholder-badge--signatory {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-secondary-strong);
}

/* ---- The table view: the six columns the active screen draws (ProjectStakeholders.razor:217-229) ---- */
.stakeholder-table__wrapper {
  overflow-x: auto;
}

.stakeholder-table {
  width: 100%;
  border-collapse: collapse;
}

.stakeholder-table__caption {
  padding-bottom: var(--space-xs);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  text-align: left;
}

.stakeholder-table th,
.stakeholder-table td {
  padding: var(--space-sm);
  border-bottom: var(--border-default);
  text-align: left;
  vertical-align: top;
}

.stakeholder-table thead th {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.stakeholder-table__row:hover {
  background: var(--color-surface-muted);
}

.stakeholder-table__name {
  overflow-wrap: anywhere;
}

/* The organisation and the telephone are the second fact of their cell: they are drawn in the muted colour the
   table's own header uses, so a cell that holds two facts is read in order. */
.stakeholder-table__organization,
.stakeholder-table__phone,
.stakeholder-table__title {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* The role is text and wraps: a label of the server's map can be two words, and the column is narrow. */
.stakeholder-table__role {
  overflow-wrap: anywhere;
}

/* An em dash, or the sentence that says where a missing address is fixed: never a blank cell. */
.stakeholder-table__none {
  color: var(--color-text-muted);
}

.stakeholder-table__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

.stakeholder-table__actions {
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-end;
  gap: var(--space-xs);
}

/* The delete of a table row is the ghost variant the markup chooses, so the danger role is applied by the surface
   that knows what the action does. A card needs no rule: its delete wears `button--danger`, the variant of the
   destructive action, which is what the eight artefacts that painted every ghost button of their card red were
   missing (`DEC-045`). The tables keep this rule until their own delete wears that variant too, and it is why the
   investigations toggle of a collapsed row is still painted with it (`HANDOFF-UI.md` §5.9). */
/* ---- The card view: the same facts, in the shape the active screen established (:132-212) ---- */

.stakeholder-list__item {
  display: flex;
  min-width: 0;
}

.stakeholder-card__none {
  color: var(--color-text-muted);
}

/* ---- The editor: the person half, the four fields of the profile, and what a missing list says ---- */
.stakeholder-person {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

/* The read-only identity of an edition: name, organisation, address and telephone, one per line, with the label
   over its value — the same facts the active screen draws in read-only fields
   (ProjectStakeholderProfileDialog.razor:99-104). */
.stakeholder-person__facts {
  display: grid;
  gap: var(--space-sm);
  margin: 0;
}

.stakeholder-person__fact {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
}

.stakeholder-person__fact-label {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.stakeholder-person__fact-value {
  margin: 0;
  overflow-wrap: anywhere;
}

/* The line that explains what this half of the dialog does, and the one under a chosen person's facts. */
.stakeholder-person__note {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.stakeholder-person__chosen {
  margin: 0;
  font-weight: var(--font-weight-semibold);
}

.stakeholder-person__facts-line {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-md);
  margin: 0;
  color: var(--color-text-muted);
}

.stakeholder-person__pair {
  display: grid;
  gap: var(--space-sm);
}

.stakeholder-person__actions,
.stakeholder-person__recovery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

.stakeholder-person__reading,
.stakeholder-person__empty {
  margin: 0;
  color: var(--color-text-muted);
}

/* The people the search answered with: one button per person, so the list is reachable with the keyboard alone. */
.stakeholder-person__results {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  max-height: 18rem;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.stakeholder-person__result-item {
  display: flex;
  min-width: 0;
}

.stakeholder-person__result {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--space-3xs);
  min-width: 0;
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-sm);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.stakeholder-person__result:hover:not(:disabled) {
  background: var(--color-surface-muted);
}

.stakeholder-person__result:disabled {
  cursor: not-allowed;
}

.stakeholder-person__result-name {
  font-weight: var(--font-weight-semibold);
  overflow-wrap: anywhere;
}

.stakeholder-person__result-facts,
.stakeholder-person__linked {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* The three blocks that take the whole width of the dialog's two-column grid, and the reason the form reads as a
   column and not as a pile: the person is a search and — with it — four fields, the ways they are informed are a
   control with a list that hangs from it, and the charter is one line of its own. */
.stakeholder-editor__person,
.stakeholder-editor__methods,
.stakeholder-editor__signatory {
  grid-column: 1 / -1;
}

.stakeholder-editor__person {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

/* The ways of being informed are **one control** and no longer a group of switches inside a fieldset, so the box
   around them is gone: the field draws its own. */
.stakeholder-editor__methods {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  margin: 0;
}

/* A value the link holds and the published list no longer declares: it is drawn, it cannot be chosen, and the
   sentence under it says what the save will do with it. */
.stakeholder-editor__undeclared {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
}

/* What a field with no list says: the control is not drawn at all, and this sentence takes its place. */
.stakeholder-editor__unavailable {
  margin: 0;
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-surface-muted);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
}

.stakeholder-editor__note {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}
/* The BR-107 warning of the editor: the person picked from the catalogue has no address and the link would be
   refused, so the sentence says where it is fixed — and the save stays unavailable until it is. It is drawn as this
   screen's own line because the shared alert reports the outcome of an action and has no warning variant, which is
   the same reason the exclusions screen draws its own incomplete notice. */
.stakeholder-editor__warning {
  margin: 0;
  padding: var(--space-xs) var(--space-sm);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
}
/* The cells of the table that hold nothing but do hold the row's own place: the person's name and organisation, the
   level, the ways they are informed and the charter. Each one is a cell of the family and is declared so that the
   value inside it — a chip, a badge or an em dash — is positioned by the cell and not by the mark. */
.stakeholder-table__person,
.stakeholder-table__engagement,
.stakeholder-table__methods,
.stakeholder-table__contact,
.stakeholder-table__charter {
  min-width: 0;
}

/* ==========================================================================
   The quality items of a project — Features/Quality/QualityPage.razor and
   Features/Quality/Components/*
   ========================================================================== */
/* The fifth screen of the «archetype» family (the artefact template), measured against the active screen at
   `NewProjectQuality.razor`: a list of records with the area the server publishes for each one, the state it
   publishes for the item, the two dialogs, section 1 of proposals, section 2 of investments and section 3 of scope.

   **Why these rules are here and not in a sheet of their own.** This artefact's shape is the one the constraints and
   the exclusions families already draw — a list of cards, a table of the same records, the dialog's own reading of the
   state — so the sheet that owns those patterns is this one. `deliverables.css` is a sheet of its own because its list
   is a **tree**, a shape no other family has (its own header says so); the rule of the artefact template §0.9 is that a
   missing style is added to the sheet that already owns the pattern and never in a new one. No rule of the investigations
   family is declared here either: `Components/Investigations` names its block with the mechanism's own name, so its
   styles are the shared ones and this feature adds none (artefact template §0.8).

   Every class below is one the components of this feature render, or one the two shared panels compose from the block
   this feature hands them (`quality-suggestions`, `quality-investments`). */

/* ---- Section 1: the proposals of the artefact (QualitySuggestions.razor) ---- */
/* A panel of proposals and of the refusals already filed. Same family as the constraints and the deliverables ones:
   a proposal is a record repeated n times, with the text and the references the server published. */
.quality-suggestions {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-lg);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
}

.quality-suggestions__title,
.quality-suggestions__subtitle {
  margin: 0;
}

.quality-suggestions__note {
  max-width: 90ch;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.quality-suggestions__actions,
.quality-suggestions__recovery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

/* The body — the proposals and the refusals below them — is drawn inside one element by the shared section, so that
   the artefact that can close it hides it without taking anything out of the document. This artefact cannot close it,
   so the element is transparent to the layout: its children are the flex items of the section and keep the gap between
   them. */
.quality-suggestions__body {
  display: contents;
}

.quality-suggestions__list,
.quality-suggestions__dismissed {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* One proposal: the kind the server classified it as, its text, the references it cites and the two decisions. */
.quality-suggestions__item {
  padding: var(--space-sm) var(--space-md);
  background: var(--color-surface-muted);
  border: var(--border-default);
  border-radius: var(--radius-sm);
}

/* The kind as the server published it. The accent role marks it as the classification of the row and not as one of its
   facts; the client never maps it to a vocabulary of its own, because the constants live in Shared and the gate 6 list
   forbids reading them. */
.quality-suggestions__kind {
  align-self: flex-start;
  margin: 0;
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
  color: var(--color-accent);
  font-size: var(--font-size-sm);
}

/* A proposal is free text and can be long; it wraps rather than widening the panel. */
.quality-suggestions__text {
  margin: 0;
  overflow-wrap: anywhere;
}

/* The references the proposal cites. They are tags and not links: turning one into a navigation needs a
   reference-to-identifier resolution the server does not publish for this artefact (`GAP-CRUD-08`). */
.quality-suggestions__refs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.quality-suggestions__ref {
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-primary-soft);
  border: var(--border-width) solid var(--color-primary-border);
  border-radius: var(--radius-sm);
  color: var(--color-primary-strong);
  font-size: var(--font-size-sm);
}

/* One refusal: what was refused, why, and the way back. */
.quality-suggestions__dismissed-item {
  padding: var(--space-xs) var(--space-sm);
  border-bottom: var(--border-default);
}

.quality-suggestions__dismissed-item:last-child {
  border-bottom: 0;
}

/* The reason the server stored, in the muted colour of a fact and not as a message: nobody failed. */
.quality-suggestions__reason {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* ---- The badge of a decision, which the feature words and classifies (QualityDecisionStates) ---- */
.quality-decided-badge {
  padding: var(--space-3xs) var(--space-xs);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
  white-space: nowrap;
}

.quality-decided-badge--discarded {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-accent);
}

.quality-decided-badge--settled {
  background: var(--color-primary-soft);
  border-color: var(--color-primary-border);
  color: var(--color-primary-strong);
}

/* ---- Section 2: the investment rows of one item (QualityInvestments.razor) ---- */
/* The table is the artefact's own class family and not the list's: it is drawn inside a dialog, one item's rows at a
   time, and it carries its own pending mark. */
.quality-investments {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.quality-investments__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.quality-investments__title {
  margin: 0;
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text);
}

.quality-investments__note {
  margin: 0;
  color: var(--color-text-muted);
}

/* The form is a grid of fields with one the row of actions closes: it is inline, so it is laid out and not stacked. */
.quality-investments__form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-sm);
  padding: var(--space-sm);
  background: var(--color-surface-muted);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

.quality-investments__form-full {
  grid-column: 1 / -1;
}

.quality-investments__form-actions {
  display: flex;
  grid-column: 1 / -1;
  gap: var(--space-2xs);
}

.quality-investments__table-wrapper {
  overflow-x: auto;
}

.quality-investments__table {
  width: 100%;
  border-collapse: collapse;
}

.quality-investments__caption {
  padding-bottom: var(--space-2xs);
  color: var(--color-text-muted);
  text-align: left;
}

.quality-investments__table th,
.quality-investments__table td {
  padding: var(--space-xs) var(--space-sm);
  border-bottom: var(--border-width) solid var(--color-border);
  text-align: left;
  vertical-align: top;
}

.quality-investments__table th {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.quality-investments__row:hover {
  background: var(--color-primary-soft);
}

.quality-investments__table tbody tr:last-child td {
  border-bottom: 0;
}

.quality-investments__category,
.quality-investments__unit {
  white-space: nowrap;
}

.quality-investments__total {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* A row typed before the artefact exists belongs to no investment list yet, and the mark says so. */
.quality-investments__pending {
  display: inline-block;
  margin-top: var(--space-3xs);
  padding: var(--space-3xs) var(--space-2xs);
  background: var(--color-accent-soft);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-sm);
  color: var(--color-accent);
  font-size: var(--font-size-sm);
}

/* The total is the server's (`BR-304`), and the note beside a row that has none yet says where it comes from. */
.quality-investments__computed {
  color: var(--color-text-muted);
  font-style: italic;
}

.quality-investments__actions {
  white-space: nowrap;
  text-align: right;
}

.quality-investments__actions .button + .button {
  margin-left: var(--space-2xs);
}

/* The text of one row, with the pending mark under it when the row has not been written yet. */
.quality-investments__description {
  min-width: 12rem;
}


/* ---- The two views of the list (QualityList.razor and QualityTable.razor) ---- */
/* The card view: the same card the other families of the slice use, with the area the server published as its first
   mark, because the artefact's own DTO publishes no name and no readable reference to head it with. */

.quality-list__item {
  display: flex;
  min-width: 0;
}

/* The delete of a table row is the ghost variant the markup chooses, so the danger role is applied by the surface
   that knows what the action does. A card needs no rule: its delete wears `button--danger`, the variant of the
   destructive action, which is what the eight artefacts that painted every ghost button of their card red were
   missing (`DEC-045`). The tables keep this rule until their own delete wears that variant too, and it is why the
   investigations toggle of a collapsed row is still painted with it (`HANDOFF-UI.md` §5.9). */
/* The table view: the four columns this artefact can draw — the area, the text, the definition and the actions. The
   active screen's own table has five, and the one that is missing is its readable reference, which this DTO does not
   publish (`GAP-CRUD-08`). */
.quality-table__wrapper {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.quality-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-size-sm);
}

.quality-table__caption {
  padding-bottom: var(--space-xs);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  text-align: left;
}

.quality-table th,
.quality-table td {
  padding: var(--space-xs) var(--space-sm);
  border-bottom: var(--border-default);
  text-align: left;
  vertical-align: top;
}

.quality-table thead th {
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
}

/* The area is the value the server publishes for this artefact and is drawn as the chip of the family. */
.quality-table__area {
  white-space: nowrap;
}

/* The definition is free text that is drawn whole: the rule for these artefacts is about their words. */
.quality-table__text {
  overflow-wrap: anywhere;
  white-space: pre-line;
}

/* The state chip is the shared piece of `Components/Definitions`: the same value is drawn the same way in both views
   and in the dialog's own reading of it, and neither view restates its styling — the table only gives the cell its
   place. */
.quality-table__state {
  white-space: nowrap;
}

.quality-table__actions {
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-end;
  gap: var(--space-xs);
}

.quality-table__row:hover {
  background: var(--color-surface-muted);
}

/* The row of investigations a table row opens in place. */
.quality-table__investigations {
  background: var(--color-surface-muted);
}

/* ---- The dialog's own reading of the definition state, and its two own lines ---- */
/* The badge and the sentence that explains it, and the one notice that follows. It is the same shape the constraints
   and the exclusions dialogs draw, and the promotion of the three is reported as a handoff: the destination is a shared
   piece this task does not own (the artefact template §0.1). */
.quality-definition {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs);
}

.quality-definition__badge {
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-primary-soft);
  border: var(--border-width) solid var(--color-primary-border);
  border-radius: var(--radius-sm);
  color: var(--color-primary-strong);
  font-size: var(--font-size-sm);
  white-space: nowrap;
}

.quality-definition__badge--warning {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-accent);
}

.quality-definition__badge--settled {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-secondary-strong);
}

.quality-definition__explanation {
  color: var(--color-text-muted);
}

.quality-definition__notice {
  margin: 0;
  padding: var(--space-xs) var(--space-sm);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

.quality-definition__notice--open {
  background: var(--color-accent-soft);
  border-color: var(--color-accent-border);
  color: var(--color-text);
}

.quality-definition__notice--settled {
  background: var(--color-success-soft);
  border-color: var(--color-success-border);
  color: var(--color-text);
}

/* `.quality-editor__note` stood here, with the legend of the position in the list that the owner took out on
   2026-09-27. The fact itself is the server's (`BR-103`). */

/* The cascade the deletion carries, said in the dialog before the person confirms it: the investigations go with the
   item (`BR-117`) and a person who is not told looks for them. */
.quality-delete__cascade {
  margin: 0;
  color: var(--color-text-muted);
}
.suggestions-heading {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.suggestions-heading .icon {
  color: var(--color-primary);
}

.suggestions-heading__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  min-height: 24px;
  padding-inline: var(--space-2xs);
  background: var(--color-primary-soft);
  border: var(--border-width) solid var(--color-primary-border);
  border-radius: var(--radius-sm);
  color: var(--color-primary-strong);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  line-height: 1;
}

/* Stored AI refusals are secondary history. The shared panel keeps them collapsed until requested,
   while this neutral frame works for every artefact-specific BEM family that renders the rows. */
.suggestions-history__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs);
}

.suggestions-history {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.suggestions-history[hidden] {
  display: none;
}

/* The title of the section and the act that asks the server, **on one row**: the run costs no height of its own, which
   is what the owner asked for on 2026-09-25 — «el boton que crea las sugerencias debe estar a la misma altura que el
   titulo "AI suggestions" esto para que no ocupe espacio en el alto» (`DEC-060`). The container that holds those acts
   is still the family's own `__actions`; what this rule says is where it sits. */
.suggestions-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs);
}

.suggestions-head__acts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  margin-inline-start: auto;
}

/* What was already refused, as a **small strip at the top of the panel** and closed until it is asked for
   (`DEC-060`): one line while it is closed, because a history that competes with the proposals is a history nobody
   reads. Opening it pushes the proposals — and the items of the artefact — down, which is the whole point of the
   frame no longer pinning any area to a share of the viewport (`DEC-061`). */
.suggestions-dismissed {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-xs);
  background: var(--color-surface-muted);
  border: var(--border-default);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-xs);
}

.suggestions-dismissed__heading {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
}

.suggestions-dismissed__toggle {
  min-height: var(--button-height);
  font-size: var(--font-size-xs);
}

/* ==========================================================================
   The row of one proposal — one shape for the ten artefacts of the panel
   ========================================================================== */
/* **This is the shape of a proposal, declared once for every artefact that draws the shared suggestion panel**, and
   each family keeps only the surface of its own row: the muted card of Background, Risks and Quality, the hairline
   row of HAZOP, the accent kind of Constraints, the state of Expert Judgement.

   Why it is one rule and not ten: the panel draws each family's own block name (`SuggestionsPanel.Block`), so the ten
   sheets carried ten copies of the same three declarations — and the owner's request of 2026-09-26, «cada card de cada
   sugerencia ocupa mucho alto… los botones de aceptar/descartar no aparecen al frente, sino más abajo», would have
   cost ten edits and would have drifted the moment one of them was missed. The names are written out instead of a base
   class or an attribute selector on purpose: a reader sees **which** artefacts the shape covers, and a new artefact of
   the panel adds its name here and nothing else.

   In a column — what the ten sheets declared — the decisions were **always** under the text, one row taller per
   proposal whatever the width of the panel. The row is a two-column grid now: everything the proposal says in the
   first column and the decisions in the second one of the first row, which is where the first thing the proposal draws
   is — its text in Background and Deliverables-like families, and the classification the server published in the eight
   that carry one. So the two decisions sit at the top-right of the proposal, in front of it, and never under it. The
   same shape, with the text on its first baseline, carries the rows of the dismissed history. */
:is(.criterion-suggestions__item,
   .background-suggestions__item,
   .constraint-suggestions__item,
   .deliverable-suggestions__item,
   .expectation-suggestions__item,
   .expert-judgement-suggestions__item,
   .hazop-suggestions__item,
   .known-risk-suggestions__item,
   .quality-suggestions__item,
   .risk-suggestions__item) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-xs) var(--space-md);
}

/* Everything that is not a decision lives in the first column… */
:is(.criterion-suggestions__item,
   .background-suggestions__item,
   .constraint-suggestions__item,
   .deliverable-suggestions__item,
   .expectation-suggestions__item,
   .expert-judgement-suggestions__item,
   .hazop-suggestions__item,
   .known-risk-suggestions__item,
   .quality-suggestions__item,
   .risk-suggestions__item) > * {
  grid-column: 1;
}

/* …and the decisions in the second one of the first row: that is what puts them in front of the proposal and what
   stops adding height to the card. */
:is(.criterion-suggestions__item-actions,
   .background-suggestions__item-actions,
   .constraint-suggestions__item-actions,
   .deliverable-suggestions__item-actions,
   .expectation-suggestions__item-actions,
   .expert-judgement-suggestions__item-actions,
   .hazop-suggestions__item-actions,
   .known-risk-suggestions__item-actions,
   .quality-suggestions__item-actions,
   .risk-suggestions__item-actions) {
  display: flex;
  flex-wrap: wrap;
  align-items: start;
  grid-column: 2;
  grid-row: 1;
  gap: var(--space-xs);
}

/* One row of the history of refusals: what was refused first, its reason under it, and the way back beside them. */
:is(.criterion-suggestions__dismissed-item,
   .background-suggestions__dismissed-item,
   .constraint-suggestions__dismissed-item,
   .deliverable-suggestions__dismissed-item,
   .expectation-suggestions__dismissed-item,
   .expert-judgement-suggestions__dismissed-item,
   .hazop-suggestions__dismissed-item,
   .known-risk-suggestions__dismissed-item,
   .quality-suggestions__dismissed-item,
   .risk-suggestions__dismissed-item) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--space-2xs) var(--space-md);
}

:is(.criterion-suggestions__dismissed-item,
   .background-suggestions__dismissed-item,
   .constraint-suggestions__dismissed-item,
   .deliverable-suggestions__dismissed-item,
   .expectation-suggestions__dismissed-item,
   .expert-judgement-suggestions__dismissed-item,
   .hazop-suggestions__dismissed-item,
   .known-risk-suggestions__dismissed-item,
   .quality-suggestions__dismissed-item,
   .risk-suggestions__dismissed-item) > * {
  grid-column: 1;
}

:is(.criterion-suggestions__dismissed-item,
   .background-suggestions__dismissed-item,
   .constraint-suggestions__dismissed-item,
   .deliverable-suggestions__dismissed-item,
   .expectation-suggestions__dismissed-item,
   .expert-judgement-suggestions__dismissed-item,
   .hazop-suggestions__dismissed-item,
   .known-risk-suggestions__dismissed-item,
   .quality-suggestions__dismissed-item,
   .risk-suggestions__dismissed-item) > .button {
  grid-column: 2;
  grid-row: 1;
}
