/* ==========================================================================
   ProjectManagementPro.ClientWASM — forms
   The form family: the field wrapper (label, required marker, hint, error), the text and
   password inputs, the checkbox and the button with its variants. Every rule consumes
   tokens.css only; nothing here states a colour, a size or a distance of its own.

   The classes are the ones the components under Components/Forms render.
   ========================================================================== */

/* ==========================================================================
   Button — Components/Forms/Button.razor
   ========================================================================== */
/* **No button is filled, and none of them shouts.** The owner, on 2026-09-25: «los botones en muchas partes está
   usando colores fuertes (muy fuertes) eso desdibuja el estilo en general de toda la app, entonces vamos a bajarle esa
   intensidad a esos colores al mínimo… cuando uno pase por el botón que cambie un poco el tono indicando que está
   sobre él, no usar el botón relleno de color, el color del botón bastante débil» (`DEC-056`).

   What that means, one variant at a time:

     * the **main action** of a region keeps its role but is drawn in the role's *soft* tone — the same treatment as
       the tinted control of a screen, one step quieter;
     * a **supporting action** — the Edit of a row among them — is transparent, with the role's tone in its text and
       its border: «prefiero que se vea transparentoso verde para edit»;
     * a **ghost** is transparent with the body's ink, and it is what every action that only reads wears;
     * the **destructive action** is grey at rest — «transparentoso gris para delete» — and keeps the warning for its
       hover and for the confirmation that always follows it;
     * every one of them starts from the same faint hairline the tabs wear and moves its tone on hover. The transition
       is colour only: no rule here changes a button's size, so a control never moves when the pointer crosses it. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  min-height: var(--button-height);
  padding: 0 var(--space-sm);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  line-height: 1;
  cursor: pointer;
  user-select: none;
  /* The family is drawn on a link when the action is navigation rather than an operation:
     `HomePage` reaches the portfolio with `<a class="button button--secondary">`. An anchor
     inherits the underline of base.css, and a button never has one. */
  text-decoration: none;
  transition: background var(--duration-fast) var(--easing-standard),
              border-color var(--duration-fast) var(--easing-standard),
              color var(--duration-fast) var(--easing-standard);
}

/* Disabled and busy are the same visual state, and the component also sets
   `aria-disabled`/`aria-busy` so the state is not carried by opacity alone. */
.button:disabled,
.button[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* The main action of a region: the one tinted control of a screen, in the soft tone of its role. */
.button--primary {
  background: var(--color-primary-soft);
  border-color: var(--color-primary-border);
  color: var(--color-primary-strong);
}

.button--primary:hover:not(:disabled) {
  background: var(--color-primary-border);
}

/* A supporting action, and the Edit of a row: transparent, with the role's tone in its text and its border. */
.button--secondary {
  background: transparent;
  border-color: var(--color-secondary-border);
  color: var(--color-secondary-strong);
}

.button--secondary:hover:not(:disabled) {
  background: var(--color-secondary-soft);
}

/* An action that only reads, or a dismissal: the body's ink on nothing at all. */
.button--ghost {
  background: transparent;
  color: var(--color-text);
}

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

/* The action that destroys the thing it sits beside — the delete of a row. It is a variant of its own and not a ghost
   painted by the surface that holds it: eight artefacts used to colour *every* ghost button of their card red, which is
   how the «Investigations» button of a constraint ended up meaning danger, and the remaining artefacts left their
   delete the same grey as the actions that only read (`DEC-045`). Since `DEC-056` it rests **grey** — the owner asked
   for the bin of a row to be «transparentoso gris» — and the warning role is kept for the hover and for the
   confirmation dialog, which is where a destructive decision belongs. */
.button--danger {
  background: transparent;
  color: var(--color-text-muted);
}

.button--danger:hover:not(:disabled) {
  background: var(--color-error-soft);
  border-color: var(--color-error-border);
  color: var(--color-error-strong);
}

/* The destruction a **dialog confirms with**. The same danger role as the row's bin, one step stronger, because a
   confirmation has exactly one affirmative action and it has to be the one the eye finds first: the nineteen
   confirmations of the client drew a soft blue button — the same as a Save — and the quiet grey of `.button--danger`
   next to a ghost Cancel left the destructive action the palest thing in its own dialog. It is the primary treatment
   (`DEC-056`: no strong fill anywhere) in the error role: soft fill, error border, error text, and a hover that moves
   the tone instead of filling it. The owner chose it on 2026-09-25 (`DEC-064`). */
.button--danger-confirm {
  background: var(--color-error-soft);
  border-color: var(--color-error-border);
  color: var(--color-error-strong);
}

.button--danger-confirm:hover:not(:disabled) {
  background: var(--color-error-border);
}

.button--block {
  width: 100%;
}

/* An icon-only action — the Edit/Delete pair of a listing row (`Components/Forms/RowActions`, which `DEC-035` fixes
   for every listing). Its accessible name is the `aria-label` the component sets and its tooltip is the `title`, so the
   box holds a drawing and no text at all: the horizontal padding of a text button would make it twice as wide as
   the icon inside it, and the square keeps the two actions of a row the same size whatever their names say. */
.button--icon {
  width: var(--button-height);
  min-width: var(--button-height);
  padding: 0;
}

/* The slot the caller fills with a drawing; the icon never changes the button's box. */
.button__icon {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
}

/* On a touch layout the button grows back to the minimum a finger needs, which is the one thing `DEC-056` does not
   take away: the compact height is for a pointer. */
@media (max-width: 767px) {
  .button {
    min-height: 44px;
  }

  .button--icon {
    width: 44px;
    min-width: 44px;
  }
}

/* ==========================================================================
   Field — Components/Forms/TextField.razor (and the password field built on it)
   ========================================================================== */
.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.field__label {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text);
}

/* The marker is decorative: the input carries `aria-required`, and the text
   "(required)" that follows this asterisk is read by a screen reader. */
.field__required {
  margin-left: var(--space-3xs);
  color: var(--color-error);
  font-weight: var(--font-weight-semibold);
}

.field__input {
  width: 100%;
  min-height: var(--control-height);
  padding: var(--space-xs) var(--space-sm);
  border: var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--font-size-base);
  line-height: var(--line-height-snug);
  transition: border-color var(--duration-fast) var(--easing-standard),
              background var(--duration-fast) var(--easing-standard);
}

.field__input:hover:not(:disabled) {
  border-color: var(--color-primary-border);
}

/* A field tints its border while it holds the caret, on top of the one focus ring every
   focusable element gets from base.css. An invalid field tints that same ring red. */
.field__input:focus {
  border-color: var(--color-primary);
}

.field__input[aria-invalid="true"] {
  border-color: var(--color-error);
}

.field__input[aria-invalid="true"]:focus {
  outline-color: var(--color-error);
}

.field__input:disabled {
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
  cursor: not-allowed;
}

.field__input[readonly] {
  background: var(--color-surface-muted);
}

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

/* The message is rendered with `role="alert"`, so it is announced when it appears. */
.field__error {
  font-size: var(--font-size-sm);
  color: var(--color-error);
}

/* The row a field draws under its own input, for a control that belongs to that field
   without being a second field: the show-password toggle of the password field. */
.field__extra {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  margin-top: var(--space-2xs);
}

/* ==========================================================================
   Definition field — Components/Definitions/DefinitionField.razor
   ========================================================================== */
/* The field of a definition and the inline translation DEC-030 asks for. It is a form control of this
   family — a label, its input, a hint and an error — so the textarea, the hint and the error carry the
   `.field__*` classes unchanged and nothing here re-draws an input. What this adds is the multi-line
   geometry and the one muted line the proposal is drawn on. */
.definition-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

/* A definition is written in sentences, not in a line: the field is as tall as the rows it was given, and
   the person can make it taller. It never shrinks below those rows, which would hide what is being read. */
.definition-field__input {
  min-height: calc(var(--control-height) * 2);
  resize: vertical;
}

/* The proposal: under the field, in the secondary colour, with the action that applies it at its end. It exists
   only while there is something to propose, so an empty proposal takes no space and the form does not move while
   somebody writes. */
.definition-field__proposal {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2xs) var(--space-xs);
}

/* **The whole proposal is read, wrapped over as many lines as it needs.** It was cut to one line with an ellipsis
   so that a long paragraph could not grow the row, and the owner reported what that costs on 2026-09-27: «me sale
   la traducción ok pero no me sale todo antes de presionar Use this» — a proposal nobody can read is a proposal
   nobody can decide on, and the person has to choose between keeping their text and accepting something they have
   not seen. The row grows while a proposal is on screen and shrinks again when it leaves. */
.definition-field__text {
  flex: 1 1 20rem;
  min-width: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  overflow-wrap: anywhere;
  white-space: pre-line;
}

/* ==========================================================================
   Catalogue combo — Components/Forms/CatalogueField.razor
   ========================================================================== */
/* The one field that chooses from a catalogue: a box that shows what is chosen as chips, the list it opens, and the
   question it asks when the list can grow. It is a control of this family — a label, a box, a hint — so `.field` and
   `.field__label` are used unchanged and what is declared here is the box, its chips and the list it opens. */
.catalogue-combo {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.catalogue-combo__box {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3xs) var(--space-2xs);
  min-width: 0;
  min-height: var(--control-height);
  padding: var(--space-3xs) var(--space-xs);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-sm);
  cursor: text;
}

/* **The edit act of the value in force, pushed to the far end of the box** — the owner asked for it on 2026-09-27:
   «con eso se muestra en la parte derecha del combo un botón edit». It is the little button of a row action, so it
   takes no room of its own beyond the caret of the field, and `margin-left: auto` is what sends it right whatever the
   chips before it measure. The wrapper is the element that stops the press from reaching the box, so it is also the one
   that carries the alignment. */
.catalogue-combo__edit {
  display: inline-flex;
  margin-left: auto;
}

/* The box says it owns the list while the list is open — and it says it **with the border**, as every field of this
   family does (`:focus` tints the border and nothing else), because the chips inside it are already painted with
   `--color-primary-soft` and a box filled with the same colour leaves them with nothing to stand out against. The
   owner saw exactly that on 2026-09-27: «cuando se seleccionan chips el color de fondo del control es igual al de los
   chips y no contrasta». The caret tints it one step further, which is the family's own rule for a field with the
   caret in it. */
.catalogue-combo__box.is-open {
  border-color: var(--color-primary-border);
}

.catalogue-combo__box:focus-within {
  border-color: var(--color-primary);
}

/* The input is the box's own text: no border, no background, no ring — the box is what a person sees. */
.catalogue-combo__input {
  flex: 1 1 6rem;
  min-width: 6rem;
  padding: 0;
  background: transparent;
  border: 0;
  color: inherit;
  font: inherit;
  outline: none;
}

/* What is chosen: one chip per value, in both shapes of the field. It is taller than a text chip of the collections
   — the owner asked for it on 2026-09-27, «me gustaría mejorar es que los chips fueran un poco más altos» — because it
   sits inside a control that is `--control-height` tall and a chip that reads as a line of text makes the control look
   half empty. */
.catalogue-combo__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) 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);
  font-weight: var(--font-weight-semibold);
  line-height: 1.5;
}

/* The way a chip is taken away grows with the chip: an ✕ of ten pixels in a control that is forty tall is a target a
   person has to aim at. */
.catalogue-combo__chip-remove {
  padding: 0 var(--space-3xs);
  background: none;
  border: 0;
  color: inherit;
  font-size: var(--font-size-sm);
  line-height: 1;
  cursor: pointer;
}

.catalogue-combo__chip-remove:hover {
  color: var(--color-error);
}

/* **The list hangs from the bottom of the box and moves nothing.** It is absolutely positioned so that opening it
   cannot push the field's own hint, or the action row of the dialog, down the screen while somebody types: the row
   under the pointer is what the eye is following. It is drawn with the surface and the shadow of a floating layer,
   which is what tells it apart from the form behind it.

   **`top: 100 %` is the whole point of this rule.** The box is what it is positioned against — the chips, the input
   and the chevron are its only children — so the list starts where the box ends and stretches to the width of the
   field. A list positioned against the **field** instead (the label, the box, the question and the hint inside it) is
   placed by the flex rules of that container, which puts it at the start of the column: on top of the input, hiding it
   and eating the clicks, which is the defect the owner reported on 2026-09-26 («cuando sale el listado sale encima del
   cajón y no me deja meterme al cajón para escribir»). */
.catalogue-combo__list {
  position: absolute;
  top: calc(100% + var(--space-3xs));
  right: 0;
  left: 0;
  z-index: var(--z-index-dropdown);
  display: flex;
  flex-direction: column;
  min-width: 12rem;
  max-height: 16rem;
  margin: 0;
  padding: var(--space-3xs);
  overflow-y: auto;
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  list-style: none;
}

.catalogue-combo__group {
  padding: var(--space-2xs) var(--space-xs) 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
}

.catalogue-combo__option {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2xs) var(--space-xs);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

/* The row under the pointer or under the keyboard is painted, so the two ways of choosing see the same thing. */
.catalogue-combo__option:hover,
.catalogue-combo__option[aria-selected='true'] {
  background: var(--color-primary-soft);
}

/* The name of a row: it is what is read and what the search matched on. A person's name and an organisation can be
   long, and a row is one line of a floating list, so it wraps instead of pushing the list wide. */
.catalogue-combo__option-label {
  overflow-wrap: anywhere;
}

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

/* What the artefact does about a name the list does not hold, when creating it needs fields of its own. It is a row of
   the form and not a floating layer: the offer is part of what the dialog is doing. */
.catalogue-combo__offer {
  padding-top: var(--space-2xs);
}

/* The question the flow ends in — «it is not in the list, do you create it?» — and the way out of a question that
   could not be answered: the sentence is the field's hint above, and this is the row of the answer it asks for. It
   moves the action row of the dialog down with it, which is what makes it impossible to miss. */
.catalogue-combo__question {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
}

/* ==========================================================================
   Checkbox — Components/Forms/Checkbox.razor
   ========================================================================== */
.checkbox {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--space-xs);
  font-size: var(--font-size-base);
  cursor: pointer;
}

.checkbox__input {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin: var(--space-3xs) 0 0;
  accent-color: var(--color-primary);
  cursor: pointer;
}

.checkbox__label {
  line-height: var(--line-height-snug);
}

.checkbox--disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.checkbox--disabled .checkbox__input,
.checkbox--disabled .checkbox__label {
  cursor: not-allowed;
}

/* ==========================================================================
   Filters — Features/Projects/Components/ProjectFilters.razor
   ========================================================================== */
/* The filter bar of the listing. It is a form-shaped piece and it lives here for that
   reason: a row of labelled controls that submits once, built on the same `.field` and
   `.button` rules above — the selects and the text field of this bar carry the classes of
   the form family unchanged, so nothing below re-draws an input. */
.project-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-md);
  padding: var(--space-md);
  background: var(--color-surface);
  border: var(--border-default);
  border-radius: var(--radius-lg);
}

/* Search and the button that submits it are one unit: the field grows, the button does not,
   and both sit on the same edge. One round trip follows one deliberate submission, which is
   why the bar carries a submit button at all. */
.project-filters__search {
  display: flex;
  flex: 1 1 320px;
  align-items: flex-end;
  gap: var(--space-xs);
  min-width: 0;
}

.project-filters__search .field {
  flex: 1 1 auto;
  min-width: 0;
}

/* A label and its control drawn without the `Components/Forms` wrapper — the markup of this
   bar pairs them directly — so the stack is the one `.field` already declares. */
.project-filters__field {
  display: flex;
  flex: 0 1 180px;
  flex-direction: column;
  gap: var(--space-2xs);
  min-width: 0;
}

/* The organization scope, with the sentence that says what the server does with it. The note
   belongs to the scope control it explains, so both share one column of the bar. */
.project-filters__scope {
  display: flex;
  flex: 1 1 100%;
  flex-direction: column;
  gap: var(--space-2xs);
}

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

/* The way out of a filtered listing, at the end of the row of controls it undoes. */
.project-filters__clear {
  margin-left: auto;
}

/* ==========================================================================
   Filter of the background list — Features/Background/BackgroundPage.razor
   ========================================================================== */
/* The filter of one artefact's list. It is the shared row of chips — `.filter-chips`, drawn by
   `Components/Filters/FilterChips` — beside the count of what is on screen.
   **Ya no es una franja con tarjeta propia**: desde el 2026-10-01 se dibuja dentro de la fila del listado —el grupo
   de la izquierda del hueco `Filters` de `ArtifactView`—, asi que la superficie, el borde, el relleno y el radio se
   fueron con la franja, y el hueco con el interruptor de vistas y el acto de crear lo pone esa fila y la lista sube.
   Es la misma correccion que el dueno pidio para los interesados el 2026-09-30, con sus palabras de esta pantalla:
   «en el contenido del artefacto hay unos botones de filtracion y unos botones de cards/table agregar background todo
   eso debe quedar en la misma fila pero los botones de filtrado a la izquierda y los botones de cards/table agregar a
   la derecha». */
.background-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  min-width: 0;
}

/* How much of the list is on screen, said in words: the count is a status of the region below it, and the
   only thing that tells a filtered list apart from an artefact with nothing in it. Va **dentro de la fila**, a la
   derecha de los chips, asi que no lleva margen: el que tenia —`0 0 var(--space-xs) auto`— era para empujarlo al
   final de su propia franja. */
.background-filter__count {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}
