/* ==========================================================================
   IX · INPUTS — focus character for every .rb-field (email captures in
   teaser50 + teaser100, nav search).

   Variants (body[data-rbs-inputs]):
     calm   (default) — the shipped ring, retimed. Works with zero JS: these
                        base rules never depend on a body attribute.
     trace  — a hairline draws the field's outline once per focus.
     lift   — 1px rise + soft shadow; the placeholder steps back.
     rule   — no box at all: the field stands on a baseline, and a thicker
              brand rule slides in from the left on focus.
     inset  — the field is a well in the surface at rest and comes up flush
              against a brand hairline on focus.
     label  — the placeholder climbs into a small mono label (float label).

   Knobs: --rbs-input-ring (color) · --rbs-input-dur (160–500ms)
        · --rbs-input-rule-w (rule) · --rbs-input-depth (inset)
        · --rbs-input-rise (label — one lever: travel AND row height).
   All of this is FEEDBACK — it runs at every motion level. Only the pieces
   that are pure travel (the trace draw, the rule's slide) are gated to
   `authored`; elsewhere they land quickly, never dead.
   ========================================================================== */

/* --------------------------------------------------------------------------
   CALM — base refinement. Cascade note: this file loads after 05-components
   and the section styles, so equal specificity wins here.
   Exit runs at 0.7× the enter duration (exits faster than enters).
   -------------------------------------------------------------------------- */
.rb-field .rb-field__row {
  position: relative; /* hosts the trace overlay and the float label */
  /* background-color is here for the inset variant only — the other four
     never move it, so listing it costs them nothing. */
  transition:
    border-color     calc(var(--rbs-input-dur, 220ms) * 0.7) var(--rb-sys-ease-swift),
    box-shadow       calc(var(--rbs-input-dur, 220ms) * 0.7) var(--rb-sys-ease-swift),
    background-color calc(var(--rbs-input-dur, 220ms) * 0.7) var(--rb-sys-ease-swift),
    transform        calc(var(--rbs-input-dur, 220ms) * 0.7) var(--rb-sys-ease-swift);
}

.rb-field .rb-field__row:focus-within,
.rb-field .rb-field__row.rbs-demo-focus {
  transition-duration: var(--rbs-input-dur, 220ms);
  border-color: var(--rbs-input-ring, var(--rb-sys-border-brand));
  box-shadow: 0 0 0 3px
    color-mix(in srgb, var(--rbs-input-ring, var(--rb-sys-border-brand)) 12%, transparent);
}

/* On-dark fields shipped with NO visible focus state (the transparent border
   won the cascade). Fixed quietly: border stays transparent — the white pill
   needs no outline — and the halo carries the feedback at higher strength so
   it reads against ink. */
.rb-field--on-dark .rb-field__row:focus-within,
.rb-field--on-dark .rb-field__row.rbs-demo-focus {
  border-color: transparent;
  box-shadow: 0 0 0 3px
    color-mix(in srgb, var(--rbs-input-ring, var(--rb-sys-border-brand)) 45%, transparent);
}

/* --------------------------------------------------------------------------
   TRACE — an SVG rect overlay (built once by js/areas/inputs.js) whose
   stroke draws via dashoffset. pathLength="1" normalises every field to the
   same draw regardless of size. The hairline replaces the halo entirely;
   the border itself stays at rest so the draw is the only event.
   -------------------------------------------------------------------------- */
.rbs-input-trace {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

body[data-rbs-inputs="trace"] .rbs-input-trace { display: block; }

.rbs-input-trace rect {
  fill: none;
  stroke: var(--rbs-input-ring, var(--rb-sys-border-brand));
  stroke-width: 1.25;
  rx: 10px;                       /* matches --rb-ref-radius-lg rows */
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  /* Retreat (blur) is instant by default; authored gets the timed retreat. */
  transition: stroke-dashoffset 0ms var(--rb-sys-ease-swift);
}
/* Pill rows: oversized rx clamps to half the height — a perfect pill. */
.rb-field--pill .rbs-input-trace rect { rx: 999px; }

body[data-rbs-inputs="trace"] .rb-field__row:focus-within .rbs-input-trace rect,
body[data-rbs-inputs="trace"] .rb-field__row.rbs-demo-focus .rbs-input-trace rect {
  stroke-dashoffset: 0;
}

/* The draw itself only under authored motion; reduced/essential/static get
   the hairline instantly — feedback survives, choreography doesn't. */
body[data-rbs-inputs="trace"][data-rbs-motion-level="authored"] .rbs-input-trace rect {
  transition-duration: calc(var(--rbs-input-dur, 220ms) * 1.2); /* retreat */
}
body[data-rbs-inputs="trace"][data-rbs-motion-level="authored"] .rb-field__row:focus-within .rbs-input-trace rect,
body[data-rbs-inputs="trace"][data-rbs-motion-level="authored"] .rb-field__row.rbs-demo-focus .rbs-input-trace rect {
  transition-duration: calc(var(--rbs-input-dur, 220ms) * 2.2); /* ≈480ms draw */
}

/* Under trace, focus leaves border and shadow at rest. */
body[data-rbs-inputs="trace"] .rb-field__row:focus-within,
body[data-rbs-inputs="trace"] .rb-field__row.rbs-demo-focus {
  border-color: var(--rb-sys-border-subtle);
  box-shadow: none;
}
body[data-rbs-inputs="trace"] .rb-field--on-dark .rb-field__row:focus-within,
body[data-rbs-inputs="trace"] .rb-field--on-dark .rb-field__row.rbs-demo-focus {
  border-color: transparent;
}

/* --------------------------------------------------------------------------
   LIFT — the quietest option. 1px rise, a soft shadow, border darkens,
   placeholder eases 20% dimmer. No halo, no color statement (the ring knob
   hides for this variant).
   -------------------------------------------------------------------------- */
body[data-rbs-inputs="lift"] .rb-field__row:focus-within,
body[data-rbs-inputs="lift"] .rb-field__row.rbs-demo-focus {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--rb-sys-fg-primary) 45%, var(--rb-sys-border-subtle));
  box-shadow: 0 3px 10px color-mix(in srgb, var(--rb-sys-fg-primary) 12%, transparent);
}
body[data-rbs-inputs="lift"] .rb-field--on-dark .rb-field__row:focus-within,
body[data-rbs-inputs="lift"] .rb-field--on-dark .rb-field__row.rbs-demo-focus {
  border-color: transparent;
  box-shadow: 0 3px 10px color-mix(in srgb, var(--rb-ref-black) 35%, transparent);
}

body[data-rbs-inputs="lift"] .rb-field__input::placeholder {
  transition: opacity var(--rbs-input-dur, 220ms) ease;
}
body[data-rbs-inputs="lift"] .rb-field__row:focus-within .rb-field__input::placeholder,
body[data-rbs-inputs="lift"] .rb-field__row.rbs-demo-focus .rb-field__input::placeholder {
  opacity: 0.8;
}

@media (prefers-reduced-motion: reduce) {
  body[data-rbs-inputs="lift"] .rb-field__row:focus-within,
  body[data-rbs-inputs="lift"] .rb-field__row.rbs-demo-focus {
    transform: none; /* keep shadow + border; drop the position change */
  }
}

/* --------------------------------------------------------------------------
   RULE — the box goes away. What is left is a baseline the field sits on,
   plus a thicker brand rule that slides in from the left on focus.

   The row keeps its flex geometry untouched, so the inline submit button
   still rides at the right-hand end of the line; only the ground, the
   radius and the inline padding change. Every variant rule carries
   `.rb-field` so it outranks the `--on-dark` pair further up this file.
   -------------------------------------------------------------------------- */
body[data-rbs-inputs="rule"] .rb-field .rb-field__row {
  /* Both colours are held in custom properties so the on-dark block below
     can restate them once, instead of re-winning every state's cascade. */
  --rbs-rule-rest: var(--rb-sys-border-default);
  --rbs-rule-accent: var(--rbs-input-ring, var(--rb-sys-border-brand));

  background: transparent;
  border-radius: var(--rb-ref-radius-none);
  border-color: transparent transparent var(--rbs-rule-rest);
  padding-inline: 0;
  padding-block: var(--rb-ref-space-2);
  box-shadow: none;
}
/* Focus is the rule's job alone — border and halo stay exactly at rest. */
body[data-rbs-inputs="rule"] .rb-field .rb-field__row:focus-within,
body[data-rbs-inputs="rule"] .rb-field .rb-field__row.rbs-demo-focus {
  border-color: transparent transparent var(--rbs-rule-rest);
  box-shadow: none;
  transform: none;
}

/* The active rule. `bottom: -1px` lands it exactly on the resting hairline,
   so weight reads as the line thickening rather than a second line. */
body[data-rbs-inputs="rule"] .rb-field__row::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  bottom: calc(-1 * var(--rb-ref-border-hairline));
  height: var(--rbs-input-rule-w, 2px);
  background: var(--rbs-rule-accent, var(--rbs-input-ring, var(--rb-sys-border-brand)));
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
  /* Retract is quick and swift; the authored draw below is the slow half. */
  transition: transform calc(var(--rbs-input-dur, 220ms) * 0.7) var(--rb-sys-ease-swift);
}
body[data-rbs-inputs="rule"] .rb-field__row:focus-within::after,
body[data-rbs-inputs="rule"] .rb-field__row.rbs-demo-focus::after {
  transform: scaleX(1);
}
/* The travel itself is choreography, so it is gated: at essential/static the
   rule still arrives, just on the short swift curve. */
body[data-rbs-inputs="rule"][data-rbs-motion-level="authored"] .rb-field__row:focus-within::after,
body[data-rbs-inputs="rule"][data-rbs-motion-level="authored"] .rb-field__row.rbs-demo-focus::after {
  transition: transform calc(var(--rbs-input-dur, 220ms) * 1.6) var(--rb-sys-ease-expo);
}

/* On the two dark captures the pill's ground goes with the box, so the type
   has to carry itself against ink — and the deep-teal accent would vanish
   there. The rule mixes the knob colour into the bright accent: still
   knob-driven, never darker than the surface it sits on. */
body[data-rbs-inputs="rule"] .rb-field--on-dark .rb-field__row {
  --rbs-rule-rest: color-mix(in srgb, var(--rb-sys-fg-on-dark) 30%, transparent);
  --rbs-rule-accent: color-mix(in srgb,
    var(--rbs-input-ring, var(--rb-sys-border-brand)) 35%, var(--rb-sys-fg-accent));
}
body[data-rbs-inputs="rule"] .rb-field--on-dark .rb-field__input {
  color: var(--rb-sys-fg-on-dark);
}
body[data-rbs-inputs="rule"] .rb-field--on-dark .rb-field__input::placeholder {
  color: color-mix(in srgb, var(--rb-sys-fg-on-dark) 60%, transparent);
}
/* Token remap rather than a hard override, so the submit pill keeps its own
   hover behaviour from the buttons area — it only changes which two colours
   that behaviour runs between. Teal-on-ink would be unreadable. */
body[data-rbs-inputs="rule"] .rb-field--on-dark .rb-field__row .rb-btn {
  --rb-sys-cta-primary-bg: var(--rb-ref-white);
  --rb-sys-cta-primary-fg: var(--rb-ref-ink);
  --rb-sys-cta-primary-bg-hover: var(--rb-ref-teal-050);
}
/* Both captures lift their white pill off the art with a pill-shaped drop
   shadow. With no pill there is nothing to lift. */
body[data-rbs-inputs="rule"] .rb-teaser50__form,
body[data-rbs-inputs="rule"] .rb-teaser100__form {
  box-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
  /* Drop the travel, keep the event: the rule is already full width and
     simply fades up to weight. */
  body[data-rbs-inputs="rule"] .rb-field__row::after {
    transform: scaleX(1);
    opacity: 0;
    transition: opacity calc(var(--rbs-input-dur, 220ms) * 0.7) linear;
  }
  body[data-rbs-inputs="rule"] .rb-field__row:focus-within::after,
  body[data-rbs-inputs="rule"] .rb-field__row.rbs-demo-focus::after {
    opacity: 1;
    transition-duration: var(--rbs-input-dur, 220ms);
  }
}

/* --------------------------------------------------------------------------
   INSET — the only variant that changes the field's RESTING state: it sits
   in the surface rather than on it. Focus collapses the well to nothing and
   the field arrives flush, held by a 1px brand rule.

   Both shadow lists keep the same three layers in the same inset/outset
   order (well · edge · lift) so the two states interpolate instead of
   snapping — the depth genuinely travels.
   -------------------------------------------------------------------------- */
body[data-rbs-inputs="inset"] .rb-field .rb-field__row {
  background: color-mix(in srgb, var(--rb-sys-fg-primary) 4%, var(--rb-sys-bg-canvas));
  border-color: transparent;
  box-shadow:
    inset 0 var(--rbs-input-depth, 4px)
          calc(var(--rbs-input-depth, 4px) * 1.5)
          calc(var(--rbs-input-depth, 4px) * -0.5)
          color-mix(in srgb, var(--rb-sys-fg-primary) 20%, transparent),
    inset 0 0 0 var(--rb-ref-border-hairline)
          color-mix(in srgb, var(--rb-sys-fg-primary) 8%, transparent),
    0 0 0 0 transparent;
}
body[data-rbs-inputs="inset"] .rb-field .rb-field__row:focus-within,
body[data-rbs-inputs="inset"] .rb-field .rb-field__row.rbs-demo-focus {
  background: var(--rb-sys-bg-canvas);
  border-color: transparent;
  box-shadow:
    inset 0 0 0 0 transparent,
    inset 0 0 0 var(--rb-ref-border-hairline)
          var(--rbs-input-ring, var(--rb-sys-border-brand)),
    0 1px 2px color-mix(in srgb, var(--rb-sys-fg-primary) 10%, transparent);
}
/* The placeholder is part of the depth read: dimmer down in the well,
   full strength once the field is flush. */
body[data-rbs-inputs="inset"] .rb-field__input::placeholder {
  opacity: 0.7;
  transition: opacity var(--rbs-input-dur, 220ms) ease;
}
body[data-rbs-inputs="inset"] .rb-field__row:focus-within .rb-field__input::placeholder,
body[data-rbs-inputs="inset"] .rb-field__row.rbs-demo-focus .rb-field__input::placeholder {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   LABEL — float label. The row grows, the input's text is pushed to the
   lower half, and the field's own name rides above it.

   One knob governs the whole geometry: --rbs-input-rise is the travel, the
   input's top padding (rise − 6) and the row height (rise × 2 + 16) are
   both derived from it, so the label always lands in the gap it opened.

   A11y: the visually-hidden <label> is untouched and still the accessible
   name; the placeholder attribute stays in the DOM and is only hidden
   visually. This wrapper is aria-hidden decoration, built by
   js/areas/inputs.js. `:has(.rbs-float)` gates every rule on that span
   actually existing — if the module never ran, the field stays a normal
   field with a visible placeholder rather than an empty box.
   -------------------------------------------------------------------------- */
.rbs-float {
  display: none;
  position: absolute;
  left: var(--rbs-float-x, var(--rb-ref-space-4));
  top: var(--rbs-float-pad, 0px);
  bottom: 0;
  pointer-events: none;
  /* Base = the drop back down: quicker than the climb. */
  transition: transform calc(var(--rbs-input-dur, 220ms) * 0.7) var(--rb-sys-ease-swift);
}
body[data-rbs-inputs="label"] .rbs-float { display: block; }

.rbs-float__rest,
.rbs-float__name {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  transition: opacity calc(var(--rbs-input-dur, 220ms) * 0.6) linear;
}
/* The resting layer is the placeholder, pixel for pixel. */
.rbs-float__rest {
  color: var(--rb-sys-fg-placeholder);
  font-size: 16px;
  line-height: var(--rb-sys-text-p1-leading);
  letter-spacing: var(--rb-sys-text-p1-tracking);
}
@media (min-width: 768px) {
  .rbs-float__rest { font-size: var(--rb-sys-text-p1-size); }
}
/* The name layer is what it becomes. Cross-fading the two is what lets the
   family change from sans to mono without animating a font. */
.rbs-float__name {
  opacity: 0;
  color: var(--rbs-input-ring, var(--rb-sys-border-brand));
  font-family: var(--rb-sys-font-label);
  font-size: var(--rb-sys-text-l1-size);
  font-weight: var(--rb-sys-text-l1-weight);
  line-height: 1;
  letter-spacing: var(--rb-sys-text-l1-tracking);
  text-transform: uppercase;
}

body[data-rbs-inputs="label"] .rb-field .rb-field__row:has(.rbs-float) {
  --rbs-float-pad: calc(var(--rbs-input-rise, 22px) - 6px);
  --rbs-float-x: var(--rb-ref-space-4);
  min-height: calc(var(--rbs-input-rise, 22px) * 2 + 16px);
}
/* A pill this tall curves further in — the copy needs to clear it. */
body[data-rbs-inputs="label"] .rb-field--pill .rb-field__row:has(.rbs-float) {
  padding-left: var(--rb-ref-space-6);
  --rbs-float-x: var(--rb-ref-space-6);
}
body[data-rbs-inputs="label"] .rb-field__row:has(.rbs-float) .rb-field__input {
  padding-top: var(--rbs-float-pad);
}
/* Only ever hidden while the layer that replaces it is in the DOM. */
body[data-rbs-inputs="label"] .rb-field__row:has(.rbs-float) .rb-field__input::placeholder {
  opacity: 0;
}

/* Focused OR filled OR demoed — the classic float-label contract. The
   `~` combinators are why the wrapper is appended last in the row. */
body[data-rbs-inputs="label"] .rb-field__input:focus ~ .rbs-float,
body[data-rbs-inputs="label"] .rb-field__input:not(:placeholder-shown) ~ .rbs-float,
body[data-rbs-inputs="label"] .rb-field__row.rbs-demo-focus .rbs-float {
  transform: translateY(calc(-1 * var(--rbs-input-rise, 22px)));
  transition-duration: calc(var(--rbs-input-dur, 220ms) * 1.5);
  transition-timing-function: var(--rb-sys-ease-expo);
}
body[data-rbs-inputs="label"] .rb-field__input:focus ~ .rbs-float .rbs-float__rest,
body[data-rbs-inputs="label"] .rb-field__input:not(:placeholder-shown) ~ .rbs-float .rbs-float__rest,
body[data-rbs-inputs="label"] .rb-field__row.rbs-demo-focus .rbs-float .rbs-float__rest {
  opacity: 0;
}
body[data-rbs-inputs="label"] .rb-field__input:focus ~ .rbs-float .rbs-float__name,
body[data-rbs-inputs="label"] .rb-field__input:not(:placeholder-shown) ~ .rbs-float .rbs-float__name,
body[data-rbs-inputs="label"] .rb-field__row.rbs-demo-focus .rbs-float .rbs-float__name {
  opacity: 1;
  transition-delay: calc(var(--rbs-input-dur, 220ms) * 0.25);
}

/* With the label carrying the whole event, the ring would be a second
   announcement — the border tightens to the accent and stops there. */
body[data-rbs-inputs="label"] .rb-field .rb-field__row:focus-within,
body[data-rbs-inputs="label"] .rb-field .rb-field__row.rbs-demo-focus {
  border-color: var(--rbs-input-ring, var(--rb-sys-border-brand));
  box-shadow: none;
}
body[data-rbs-inputs="label"] .rb-field--on-dark .rb-field__row:focus-within,
body[data-rbs-inputs="label"] .rb-field--on-dark .rb-field__row.rbs-demo-focus {
  border-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
  /* The climb is functional — a label that stayed put would sit on the
     typing. Keep it, halve it, and let the two layers hard-cut. */
  body[data-rbs-inputs="label"] .rb-field__input:focus ~ .rbs-float,
  body[data-rbs-inputs="label"] .rb-field__input:not(:placeholder-shown) ~ .rbs-float,
  body[data-rbs-inputs="label"] .rb-field__row.rbs-demo-focus .rbs-float {
    transition-duration: calc(var(--rbs-input-dur, 220ms) * 0.5);
    transition-timing-function: var(--rb-sys-ease-swift);
  }
  body[data-rbs-inputs="label"] .rb-field__input:focus ~ .rbs-float .rbs-float__name,
  body[data-rbs-inputs="label"] .rb-field__input:not(:placeholder-shown) ~ .rbs-float .rbs-float__name,
  body[data-rbs-inputs="label"] .rb-field__row.rbs-demo-focus .rbs-float .rbs-float__name {
    transition-delay: 0ms;
  }
}

/* --------------------------------------------------------------------------
   SUBMIT SEQUENCE — label → three-dot pulse → checkmark + "You're in".
   Content is swapped by JS; these classes own the look. The pill's width
   morphs between measured px values (authored only; elsewhere it steps).
   -------------------------------------------------------------------------- */
.rb-btn.rbs-seq {
  transition:
    background-color var(--rb-sys-duration-2) ease,
    border-color     var(--rb-sys-duration-2) ease,
    color            var(--rb-sys-duration-2) ease;
}
body[data-rbs-motion-level="authored"] .rb-btn.rbs-seq {
  transition:
    background-color var(--rb-sys-duration-2) ease,
    border-color     var(--rb-sys-duration-2) ease,
    color            var(--rb-sys-duration-2) ease,
    width            var(--rb-sys-duration-3) var(--rb-sys-ease-morph);
}
/* The disabled dimming reads as "broken" mid-sequence — the states ARE the
   feedback, so the button holds full strength while it works. */
.rb-btn.rbs-seq:disabled {
  opacity: 1;
  cursor: default;
}

/* Each swapped-in state enters from 0.96 + fade — never from zero. */
.rbs-dots,
.rbs-check {
  animation: rbs-swap-in var(--rb-sys-duration-2) var(--rb-sys-ease-swift) backwards;
}
@keyframes rbs-swap-in {
  from { opacity: 0; transform: translateY(2px) scale(0.96); }
}

.rbs-dots {
  display: inline-flex;
  align-items: center;
  gap: var(--rb-ref-space-1);
}
.rbs-dots i {
  width: var(--rb-ref-space-1);
  height: var(--rb-ref-space-1);
  border-radius: var(--rb-ref-radius-full);
  background: currentColor;
  /* Opacity-only pulse: legible progress under reduced motion too. */
  animation: rbs-dot-pulse 900ms linear infinite;
}
.rbs-dots i:nth-child(2) { animation-delay: 150ms; }
.rbs-dots i:nth-child(3) { animation-delay: 300ms; }
@keyframes rbs-dot-pulse {
  0%, 100% { opacity: 0.25; }
  30%      { opacity: 1; }
  60%      { opacity: 0.25; }
}

.rbs-check {
  display: inline-flex;
  align-items: center;
  gap: var(--rb-ref-space-2);
}
.rbs-check svg { display: block; width: 12px; height: 12px; }
.rbs-check svg path {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The tick draws itself only when motion is authored; otherwise it simply is. */
body[data-rbs-motion-level="authored"] .rbs-check svg path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: rbs-check-draw var(--rb-sys-duration-3) var(--rb-sys-ease-swift) 60ms both;
}
@keyframes rbs-check-draw {
  to { stroke-dashoffset: 0; }
}

@keyframes rbs-swap-fade {
  from { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .rbs-dots,
  .rbs-check { animation-name: rbs-swap-fade; } /* fade only — no travel */
}

/* --------------------------------------------------------------------------
   INVALID — danger border + halo, and (motionOK-gated, applied from JS) a
   1px settle shake: two oscillations, 300ms, decaying amplitude. Placed
   last and written wide so it outranks every variant's focus rule.
   -------------------------------------------------------------------------- */
@keyframes rbs-input-shake {
  0%, 100% { translate: 0 0; }
  15%      { translate: -1px 0; }
  40%      { translate: 1px 0; }
  65%      { translate: -0.5px 0; }
  85%      { translate: 0.25px 0; }
}
.rb-field__row.rbs-shake {
  animation: rbs-input-shake 300ms linear;
}

body .rb-field .rb-field__row.rbs-invalid,
body .rb-field .rb-field__row.rbs-invalid:focus-within,
body[data-rbs-inputs] .rb-field .rb-field__row.rbs-invalid,
body[data-rbs-inputs] .rb-field .rb-field__row.rbs-invalid:focus-within,
body[data-rbs-inputs] .rb-field--on-dark .rb-field__row.rbs-invalid:focus-within {
  border-color: var(--rb-sys-fg-danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--rb-sys-fg-danger) 15%, transparent);
}
/* The trace hairline goes danger too, instead of arguing with the border. */
body[data-rbs-inputs="trace"] .rb-field__row.rbs-invalid .rbs-input-trace rect {
  stroke: var(--rb-sys-fg-danger);
}

/* Variants that own the border or the shadow outright restate invalid in
   their own language rather than letting a box reappear around them.
   Written to outrank the four-selector block above, and placed after it. */
body[data-rbs-inputs="rule"] .rb-field .rb-field__row.rbs-invalid,
body[data-rbs-inputs="rule"] .rb-field .rb-field__row.rbs-invalid:focus-within {
  border-color: transparent transparent var(--rb-sys-fg-danger);
  box-shadow: none;
}
body[data-rbs-inputs="rule"] .rb-field__row.rbs-invalid::after {
  background: var(--rb-sys-fg-danger);
}

body[data-rbs-inputs="inset"] .rb-field .rb-field__row.rbs-invalid,
body[data-rbs-inputs="inset"] .rb-field .rb-field__row.rbs-invalid:focus-within {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 0 transparent,
    inset 0 0 0 var(--rb-ref-border-medium) var(--rb-sys-fg-danger),
    0 0 0 3px color-mix(in srgb, var(--rb-sys-fg-danger) 12%, transparent);
}

/* The float label answers for the error too — it is the field's name. */
body[data-rbs-inputs="label"] .rb-field__row.rbs-invalid .rbs-float__name {
  color: var(--rb-sys-fg-danger);
}
