/**
 * FormState - the uniform form save-state design guide, as tokens and classes.
 *
 * Every color lives in a --fs-* custom property (Bootstrap 5 palette defaults, per the Design
 * Guide's "reference things by variable name" rule) so a template can customize the whole design
 * by re-declaring the tokens - the seeded "Form State" Savants in CSS Definitions carry exactly
 * these properties, and the generated Templar stylesheet loads after this file, so an edited
 * savant wins the cascade. Nothing below the token block names a raw color.
 */
:root {
  --fs-focused:    #ffc107; /* focused / dirty - the impermanence yellow */
  --fs-saving:     #212529; /* request in flight */
  --fs-saved:      #198754; /* server confirmed */
  --fs-error:      #dc3545; /* validation / save failure */
  --fs-muted:      #6c757d; /* pristine / fetching text */
  --fs-error-soft: rgba(220, 53, 69, 0.08);
  --fs-icon-width: 1.75rem; /* the FIXED width every state icon occupies */
  --fs-label-bg:   #ffffff; /* behind a raised floating label */
}

@media (prefers-color-scheme: dark) {
  :root {
    --fs-saving:   #f8f9fa;
    --fs-label-bg: #212529;
  }
}

/* ---------------------------------------------------------------- the status line */

/* The status line occupies IDENTICAL space in every state: block-level flex (an inline box
   carries baseline slack that varies with its content) and a FIXED height, so swapping the
   message text or trading the empty icon placeholder for a real glyph never shifts the form
   around it by even a pixel. */
.fs-status {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  height: 1.5rem;
  overflow: hidden;
  color: var(--fs-muted);
}

.fs-status .fs-status-icon {
  width: var(--fs-icon-width);
  text-align: center;
  flex: 0 0 var(--fs-icon-width);
  line-height: 1;
}

.fs-status .fs-status-msg { white-space: nowrap; }

.fs-status--right { justify-content: flex-end; }

.fs-status--focused { color: var(--fs-focused); }
.fs-status--saving  { color: var(--fs-saving); }
.fs-status--saved   { color: var(--fs-saved); }
.fs-status--error   { color: var(--fs-error); }

/* ---------------------------------------------------------------- per-field state */

/* The wrapper (wrap-id-{name}) carries the state class; the control and the icon read it. */
.fs-field { position: relative; }

.fs-field .fs-field-icon {
  position: absolute;
  top: 0.55rem;
  right: 0.25rem;
  width: var(--fs-icon-width);
  text-align: center;
  pointer-events: none;
  /* Pristine's neutral dot: the muted resting color until a state class recolors the slot. */
  color: var(--fs-muted);
}

.fs-field--dirty   .fs-field-icon { color: var(--fs-focused); }
.fs-field--saving  .fs-field-icon { color: var(--fs-saving); }
.fs-field--saved   .fs-field-icon { color: var(--fs-saved); }
.fs-field--invalid .fs-field-icon { color: var(--fs-error); }

/* A select's icon steps left of the native chevron instead of sitting on top of it. */
.fs-field--select .fs-field-icon { right: 1.5rem; }

.fs-field--dirty input, .fs-field--dirty select, .fs-field--dirty textarea {
  border-color: var(--fs-focused);
}
.fs-field--saving input, .fs-field--saving select, .fs-field--saving textarea {
  border-color: var(--fs-saving);
}
.fs-field--saved input, .fs-field--saved select, .fs-field--saved textarea {
  border-color: var(--fs-saved);
}
.fs-field--invalid input, .fs-field--invalid select, .fs-field--invalid textarea {
  border-color: var(--fs-error);
  background-color: var(--fs-error-soft);
}

/* The message right next to the input - colors over words, but with the words too. */
.fs-field-msg {
  display: none;
  font-size: 0.875rem;
  color: var(--fs-error);
  margin-top: 0.125rem;
}
.fs-field--invalid .fs-field-msg { display: block; }

/* Room for the icon so text never runs under it. */
.fs-field input, .fs-field select, .fs-field textarea {
  padding-right: calc(var(--fs-icon-width) + 0.5rem);
}
.fs-field--select select {
  padding-right: calc(var(--fs-icon-width) + 1.75rem);
}

/* data-fs-icon="off": no icon slot exists, so the input keeps its normal padding. */
.fs-field--no-icon input, .fs-field--no-icon select, .fs-field--no-icon textarea {
  padding-right: 0.75rem;
}

/* ---------------------------------------------------------------- floating labels */

/* The label starts INSIDE the element footprint (placeholder position) and raises to sit on the
   input's top border once the field is focused or holds a value - the inline-label pattern. */
.fs-float { position: relative; }

.fs-float > label {
  position: absolute;
  left: 0.75rem;
  top: 0.45rem;
  margin: 0;
  padding: 0 0.25rem;
  color: var(--fs-muted);
  pointer-events: none;
  transition: 0.3s all ease-in-out;
  background: transparent;
}

.fs-float.fs-raised > label {
  top: -0.7rem;
  font-size: 0.75rem;
  background: var(--fs-label-bg);
}

/* ---------------------------------------------------------------- the spinner */

/* CapsuleIcons' `spinner` key has always carried this class; this is its first actual rule. */
@keyframes fs-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

.spinner {
  display: inline-block;
  animation: fs-spin 0.9s linear infinite;
}

/* ---------------------------------------------------------------- check-type fields */

/* Checkboxes, radios and switches (fs-field--check) keep their plain caption label - the
   floating-label trick is a text-box idea - and the icon slot rides INLINE after the label
   instead of hanging at the wrapper's right edge; the box itself never grows icon padding. */
.fs-field--check .fs-field-icon {
  position: static;
  display: inline-block;
  vertical-align: middle;
}
.fs-field--check input[type="checkbox"], .fs-field--check input[type="radio"] {
  padding-right: 0;
}
