/*
 * elfrique.components.data.css — Data / form primitives
 * Mandate: M02 · C2 Component Kit
 *
 * Scope: DataTable, StatusPill, EntityCell, FilterBar, FormField,
 *        Sparkline, SegmentedControl, Kbd.
 * Siblings: elfrique.components.layout.css · elfrique.components.overlay.css
 *           elfrique.components.admin.css (admin-surface primitives; saved-views, etc.)
 *
 * All styles in this file MUST consume tokens from elfrique.css via var(--token).
 * No raw hex. No raw ms. No Bootstrap class names.
 *
 * Populated in Mandate 02 Phases 2, 3, 6. Admin surfaces (M04 · W3.v2.1+)
 * live in elfrique.components.admin.css — see F-9a-05. M10 Phase 2 (W6.2)
 * extended the cards-mode block with declarative [data-slot] layout.
 */

/* ==========================================================================
   DATA TABLE
   Column-config-driven table with sortable headers, optional sticky first
   column, row hover, row-click → kit:drawer-request, empty state, footer
   slot. Cards-mode switch at <640px is CSS-only.
   Source: Views/Shared/Kit/_DataTable.cshtml · Model: DataTableModel.
   Script: wwwroot/js/kit/data-table.js (solhigson.kit.dataTable).
   ========================================================================== */

.data-table-wrapper {
  display:      block;
  width:        100%;
  font-family:  var(--font-sans);
  color:        var(--brand-ink);
  border:       1px solid var(--n-200);
  border-radius: var(--r-3);
  background-color: var(--n-0);
  overflow:     hidden;
  box-shadow:   var(--shadow-1);
}

.data-table-scroll {
  width:      100%;
  overflow-x: auto;
}

.data-table {
  width:           100%;
  border-collapse: collapse;
  font-size:       var(--fs-2);
  color:           var(--brand-ink);
  background-color: var(--n-0);
}

.data-table__caption {
  /* Accessible caption is visually hidden but read aloud. */
  position:    absolute;
  width:       1px;
  height:      1px;
  padding:     0;
  margin:      -1px;
  overflow:    hidden;
  clip:        rect(0 0 0 0);
  white-space: nowrap;
  border:      0;
}

.data-table__thead {
  background-color: var(--n-50);
  position:         sticky;
  top:              0;
  z-index:          var(--z-sticky);
}

.data-table__tbody {
  background-color: var(--n-0);
}

.data-table__row {
  border-bottom: 1px solid var(--n-100);
  transition:    background-color var(--d-1) var(--ease-out-swift);
}

.data-table__row:last-child {
  border-bottom: none;
}

.data-table__row--head {
  border-bottom: 1px solid var(--n-200);
}

.data-table__row--clickable {
  cursor: pointer;
}

.data-table__row--clickable:hover {
  background-color: var(--n-50);
}

.data-table__row--clickable:focus-visible {
  outline:        3px solid var(--state-info);
  outline-offset: -3px;
  background-color: var(--n-50);
}

.data-table__cell {
  padding:        var(--sp-3) var(--sp-4);
  text-align:     start;
  vertical-align: middle;
  min-height:     44px;
}

.data-table__cell--start  { text-align: start; }
.data-table__cell--center { text-align: center; }
.data-table__cell--end    { text-align: end; }

.data-table__cell--numeric {
  font-variant-numeric: tabular-nums;
  font-family:          var(--font-mono);
  font-size:            var(--fs-2);
}

.data-table__cell--date {
  font-family: var(--font-mono);
  font-size:   var(--fs-1);
  color:       var(--n-600);
  white-space: nowrap;
}

.data-table__cell--head {
  font-family:    var(--font-mono);
  font-size:      var(--fs-1);
  font-weight:    500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color:          var(--n-600);
  padding:        var(--sp-3) var(--sp-4);
  background-color: var(--n-50);
  white-space:    nowrap;
}

.data-table__cell--actions {
  width:      1%;
  white-space: nowrap;
  text-align: end;
}

.data-table__cell--sticky {
  position:         sticky;
  left:             0;
  background-color: inherit;
  /* Sticky column needs an opaque surface so rows beneath don't bleed through. */
  z-index: 1;
}

.data-table__row--head .data-table__cell--sticky {
  background-color: var(--n-50);
  z-index: 2;
}

.data-table__row--clickable:hover .data-table__cell--sticky {
  background-color: var(--n-50);
}

.data-table__sort {
  display:          inline-flex;
  align-items:      center;
  gap:              var(--sp-1);
  padding:          var(--sp-1) var(--sp-2);
  margin:           0;
  background-color: transparent;
  border:           0;
  border-radius:    var(--r-1);
  color:            inherit;
  font:             inherit;
  text-transform:   inherit;
  letter-spacing:   inherit;
  cursor:           pointer;
  min-height:       44px;
  transition:       background-color var(--d-1) var(--ease-out-swift);
}

.data-table__sort:hover {
  background-color: var(--n-100);
  color:            var(--brand-ink);
}

.data-table__sort:focus-visible {
  outline:        3px solid var(--state-info);
  outline-offset: 2px;
}

.data-table__sort-label {
  font:           inherit;
  letter-spacing: inherit;
}

.data-table__sort-indicator {
  font-size:   var(--fs-2);
  line-height: 1;
  color:       var(--n-500);
}

.data-table__tbody--empty .data-table__cell--empty {
  padding:    var(--sp-6) var(--sp-4);
  text-align: center;
}

.data-table__empty-cell {
  text-align:  center;
  padding:     var(--sp-5) var(--sp-4);
  color:       var(--n-500);
  font-style:  italic;
}

.data-table__empty {
  display:        flex;
  flex-direction: column;
  align-items:    center;
  gap:            var(--sp-2);
  padding:        var(--sp-5) var(--sp-4);
  color:          var(--n-600);
}

.data-table__empty-headline {
  margin:      0;
  font-size:   var(--fs-3);
  font-weight: 600;
  color:       var(--brand-ink);
}

.data-table__empty-hint {
  margin:    0;
  font-size: var(--fs-2);
  color:     var(--n-500);
}

.data-table__footer {
  display:         flex;
  align-items:     center;
  justify-content: space-between;
  gap:             var(--sp-3);
  padding:         var(--sp-3) var(--sp-4);
  background-color: var(--n-50);
  border-top:      1px solid var(--n-200);
  font-size:       var(--fs-1);
  color:           var(--n-600);
}

/* DataTable · cards-mode (<640px) — M10 Phase 2 W6.2.
   Single markup tree; row→card via CSS only. [data-slot] from _DataTable.cshtml:
   primary (col 0), secondary (col 1), meta (col >=2 + Status), actions. */

@media (max-width: 640px) {
  .data-table-wrapper { border-radius: var(--r-3); box-shadow: var(--shadow-1); }

  .data-table,
  .data-table__thead,
  .data-table__tbody,
  .data-table__row,
  .data-table__cell { display: block; width: 100%; }

  .data-table__thead {
    position: absolute; width: 1px; height: 1px; padding: 0;
    margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  }

  .data-table__row {
    display:          flex;
    flex-direction:   column;
    gap:              var(--sp-2);
    padding:          var(--sp-4);
    border-bottom:    1px solid var(--n-200);
    background-color: var(--n-0);
  }

  .data-table__cell { padding: 0; border-bottom: none; text-align: start; }

  .data-table__cell[data-slot="primary"] {
    font-size:   var(--fs-3);
    font-weight: 600;
    color:       var(--brand-ink);
    line-height: 1.25;
  }

  .data-table__cell[data-slot="secondary"] {
    font-size:   var(--fs-2);
    color:       var(--n-700);
    line-height: 1.4;
  }

  .data-table__cell[data-slot="meta"] {
    display:      inline-flex;
    align-items:  baseline;
    gap:          var(--sp-2);
    font-size:    var(--fs-1);
    color:        var(--n-700);
    margin-right: var(--sp-3);
  }

  .data-table__cell[data-slot="meta"]::before {
    content:        attr(data-label);
    flex:           0 0 auto;
    font-family:    var(--font-mono);
    font-size:      var(--fs-1);
    font-weight:    500;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color:          var(--n-500);
  }

  .data-table__cell[data-slot="actions"] {
    display:         flex;
    justify-content: flex-end;
    align-items:     center;
    gap:             var(--sp-2);
    margin-top:      var(--sp-2);
    padding-top:     var(--sp-2);
    border-top:      1px solid var(--n-100);
  }

  .data-table__cell--sticky        { position: static; background-color: transparent; }
  .data-table__cell[data-slot="meta"]:empty { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .data-table__row,
  .data-table__sort {
    transition: none;
  }
}

/* ==========================================================================
   STATUS PILL
   Outline + tinted-background pill. Variants map 1:1 to state / neutral
   tokens. --state-success is TEAL (hard rule #1) — no green.
   Source: Views/Shared/Kit/_StatusPill.cshtml · Model: StatusPillModel.
   ========================================================================== */

.status-pill {
  display:        inline-flex;
  align-items:    center;
  gap:            var(--sp-1);
  padding:        var(--sp-1) var(--sp-3);
  border:         1px solid transparent;
  border-radius:  var(--r-5);
  font-family:    var(--font-mono);
  font-size:      var(--fs-1);
  font-weight:    500;
  line-height:    1.2;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space:    nowrap;
  min-height:     24px;
  background-color: var(--n-50);
  color:          var(--n-700);
  /* Cap the pill at the parent's content width so a long label (e.g.
     "Override differs from IP geo" inside a stat-cell on Order Detail)
     can shrink + wrap instead of overflowing the card. The wrap-friendly
     variant below relaxes white-space when the pill is allowed to grow
     vertically. */
  max-width:      100%;
}

/* Wrap-friendly pill — used inside narrow containers like .stat-cell__body
   where a long label would otherwise spill out behind the next section.
   max-width:100% above caps the box; this rule lets text break across
   lines and the border-radius squeezes the wrapped block instead. */
.stat-cell__body .status-pill,
.status-pill--wrap {
  white-space:    normal;
  overflow-wrap:  anywhere;
  text-align:     start;
  border-radius:  var(--r-3);
}

.status-pill__dot {
  display:          inline-block;
  width:            0.5rem;
  height:           0.5rem;
  border-radius:    50%;
  background-color: currentColor;
  flex:             0 0 auto;
}

.status-pill__label {
  font: inherit;
}

.status-pill--active {
  color:            var(--state-success);
  border-color:     color-mix(in srgb, var(--state-success) 40%, transparent);
  background-color: color-mix(in srgb, var(--state-success) 10%, var(--n-0));
}

.status-pill--paid {
  color:            var(--state-success);
  border-color:     color-mix(in srgb, var(--state-success) 40%, transparent);
  background-color: color-mix(in srgb, var(--state-success) 10%, var(--n-0));
}

.status-pill--pending {
  color:            var(--state-warn);
  border-color:     color-mix(in srgb, var(--state-warn) 40%, transparent);
  background-color: color-mix(in srgb, var(--state-warn) 10%, var(--n-0));
}

.status-pill--failed {
  color:            var(--state-danger);
  border-color:     color-mix(in srgb, var(--state-danger) 40%, transparent);
  background-color: color-mix(in srgb, var(--state-danger) 10%, var(--n-0));
}

.status-pill--draft {
  color:            var(--n-600);
  border-color:     var(--n-400);
  background-color: var(--n-50);
}

.status-pill--archived {
  /* M11 P1 W8.2: lift n-500 -> n-600 on n-100 background (4.39 -> 6.87 AA). */
  color:            var(--n-600);
  border-color:     var(--n-300);
  background-color: var(--n-100);
}

.status-pill--closed {
  /* Mandate 2026-05-18 admin-impersonation-parity Phase 5: heavier neutral
     variant for terminated/closed entity states (e.g. closed user accounts,
     closed disputes). Differentiated from --archived by darker foreground
     (n-700 vs n-600), stronger border (n-500 vs n-300), and heavier
     background fill (n-200 vs n-100) so the visual weight reads as
     "terminated, final" rather than "moved to archive".
     Contrast: --n-700 (#374151) on --n-200 (#E5E7EB) = 8.10:1 — PASS AAA. */
  color:            var(--n-700);
  border-color:     var(--n-500);
  background-color: var(--n-200);
}

/* ==========================================================================
   ENTITY CELL
   Avatar (image or deterministic initials) + primary name + meta line.
   Designed to drop into a DataTable cell or any primary-column slot.
   Source: Views/Shared/Kit/_EntityCell.cshtml · Model: EntityCellModel.
   ========================================================================== */

.entity-cell {
  display:     inline-flex;
  align-items: center;
  gap:         var(--sp-3);
  min-height:  44px;
  color:       var(--brand-ink);
  text-decoration: none;
  font-family: var(--font-sans);
}

/* Link variant uses default cursor and inherits color so rows that wrap
   the cell in a link still look like an editorial list, not a blue link. */
a.entity-cell {
  color:           var(--brand-ink);
  text-decoration: none;
  transition:      color var(--d-1) var(--ease-out-swift);
}

a.entity-cell:hover .entity-cell__name {
  text-decoration: underline;
  text-underline-offset: 3px;
}

a.entity-cell:focus-visible {
  outline:        3px solid var(--state-info);
  outline-offset: 2px;
  border-radius:  var(--r-2);
}

.entity-cell__avatar {
  display:          inline-flex;
  align-items:      center;
  justify-content:  center;
  width:            2.25rem;
  height:           2.25rem;
  border-radius:    50%;
  overflow:         hidden;
  flex:             0 0 auto;
  background-color: var(--n-100);
  border:           1px solid var(--n-200);
}

.entity-cell__avatar--image {
  padding: 0;
}

.entity-cell__avatar-img {
  display:    block;
  width:      100%;
  height:     100%;
  object-fit: cover;
}

.entity-cell__avatar--initials {
  background-color: var(--n-100);
  color:            var(--brand-ink);
}

.entity-cell__initials {
  font-family:    var(--font-mono);
  font-size:      var(--fs-1);
  font-weight:    600;
  letter-spacing: 0.04em;
  line-height:    1;
  text-transform: uppercase;
  color:          var(--brand-ink);
}

.entity-cell__body {
  display:        flex;
  flex-direction: column;
  gap:            2px;
  min-width:      0;
}

.entity-cell__name {
  font-family:  var(--font-sans);
  font-size:    var(--fs-2);
  font-weight:  600;
  line-height:  1.25;
  color:        var(--brand-ink);
  overflow:     hidden;
  text-overflow: ellipsis;
  white-space:  nowrap;
  max-width:    22rem;
}

.entity-cell__meta {
  font-family:  var(--font-mono);
  font-size:    var(--fs-1);
  line-height:  1.25;
  color:        var(--n-500);
  overflow:     hidden;
  text-overflow: ellipsis;
  white-space:  nowrap;
  max-width:    22rem;
}

@media (prefers-reduced-motion: reduce) {
  a.entity-cell {
    transition: none;
  }
}

/* ==========================================================================
   FILTER BAR
   Optional search + active filter chips + "Add filter" disclosure + saved-
   views disclosure. Chip remove is a data-action button (hard rule #7 — no
   positional onclick). Every actionable element has a ≥44×44 touch target.
   Source: Views/Shared/Kit/_FilterBar.cshtml · Model: FilterBarModel.
   Script: wwwroot/js/kit/filter-bar.js (solhigson.kit.filterBar).
   ========================================================================== */

.filter-bar {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  background-color: var(--n-0); border: 1px solid var(--n-200);
  border-radius: var(--r-3); font-family: var(--font-sans); color: var(--brand-ink);
}

.filter-bar__search {
  display: flex; flex: 1 1 14rem; align-items: center;
  min-width: 12rem; position: relative;
}

.filter-bar__search-label,
.form-field__sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.filter-bar__search-input {
  width: 100%; min-height: 44px; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--n-300); border-radius: var(--r-2);
  background-color: var(--n-0); color: var(--brand-ink);
  font-family: var(--font-sans); font-size: var(--fs-2); line-height: 1.3;
  transition: border-color var(--d-1) var(--ease-out-swift),
              box-shadow var(--d-1) var(--ease-out-swift);
}

.filter-bar__search-input::placeholder { color: var(--n-500); }

.filter-bar__search-input:focus-visible {
  outline: 2px solid var(--brand-spark); outline-offset: 2px;
  border-color: var(--state-info);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--state-info) 25%, transparent);
}

/* Form input focus parity — every `.form-control` (the class TextBoxHelper
   emits for TextBox/Number/etc.) gets the same orange outline + info-tinted
   focus shadow as the filter-bar search input above. Overrides the legacy
   `site.css` raw-hex blue ring on `.form-control:focus` (HR2 violation in
   the legacy file, kept out of scope here). Both `:focus` and
   `:focus-visible` covered so keyboard + pointer focus surface the same
   accent — `site.css` only paints `:focus`. */
.form-control:focus,
.form-control:focus-visible {
  outline: 2px solid var(--brand-spark);
  outline-offset: 2px;
  border-color: var(--state-info);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--state-info) 25%, transparent);
}

.filter-bar__chips {
  display: inline-flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-2); flex: 1 1 auto; min-width: 0; margin: 0; padding: 0;
}

.filter-bar__chips-empty {
  margin: 0; font-family: var(--font-mono); font-size: var(--fs-1);
  color: var(--n-500); font-style: italic;
}

.filter-bar__chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-1) var(--sp-1) var(--sp-3);
  background-color: var(--n-100); border: 1px solid var(--n-200);
  border-radius: var(--r-5); color: var(--brand-ink);
  font-family: var(--font-sans); font-size: var(--fs-1); font-weight: 500;
  line-height: 1.2; max-width: 100%;
}

.filter-bar__chip-label {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 14rem;
}

.filter-bar__chip-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  padding: 0; margin: calc(-1 * var(--sp-1)) 0;
  border: 0; background-color: transparent; color: var(--n-600);
  cursor: pointer; border-radius: 50%;
  transition: background-color var(--d-1) var(--ease-out-swift),
              color var(--d-1) var(--ease-out-swift);
}

.filter-bar__chip-remove:hover { background-color: var(--brand-ink); color: var(--n-0); }

.filter-bar__chip-remove:focus-visible {
  outline: 3px solid var(--state-info); outline-offset: 2px;
}

.filter-bar__chip-remove-glyph {
  font-family: var(--font-mono); font-size: var(--fs-3); line-height: 1; font-weight: 600;
}

.filter-bar__disclosures {
  display: inline-flex; align-items: center; gap: var(--sp-2); flex: 0 0 auto;
}

/* Content-sized so panel's right:0 anchors to the trigger's right edge, not a
   full-width container. Inside .filter-bar__disclosures (flex parent) the
   inline-block is overridden by flex-item layout, so safe in both contexts. */
.filter-bar__disclosure { position: relative; display: inline-block; }

.filter-bar__disclosure-trigger {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 44px; padding: var(--sp-2) var(--sp-3);
  background-color: var(--n-0); border: 1px solid var(--n-300);
  border-radius: var(--r-2); color: var(--brand-ink);
  font-family: var(--font-sans); font-size: var(--fs-2); font-weight: 500;
  cursor: pointer;
  transition: background-color var(--d-1) var(--ease-out-swift),
              border-color var(--d-1) var(--ease-out-swift),
              color var(--d-1) var(--ease-out-swift);
}

.filter-bar__disclosure-trigger:hover {
  background-color: var(--n-50); border-color: var(--brand-ink);
}

.filter-bar__disclosure-trigger:focus-visible {
  outline: 3px solid var(--state-info); outline-offset: 2px;
}

.filter-bar__disclosure-trigger[aria-expanded="true"] {
  background-color: var(--brand-ink); border-color: var(--brand-ink); color: var(--n-0);
}

/* Native <details> open-state parity — see M32 phase 7 FC1 F-FC1-post-1 */
details.filter-bar__disclosure[open] > .filter-bar__disclosure-trigger {
  background-color: var(--brand-ink);
  border-color: var(--brand-ink);
  color: var(--n-0);
}

.filter-bar__disclosure-glyph {
  font-family: var(--font-mono); font-size: var(--fs-2); line-height: 1; font-weight: 600;
}

.filter-bar__disclosure-panel {
  position: absolute; top: calc(100% + var(--sp-2)); right: 0;
  min-width: 16rem; max-width: 22rem; padding: var(--sp-2);
  background-color: var(--n-0); border: 1px solid var(--n-200);
  border-radius: var(--r-3); box-shadow: var(--shadow-3);
  /* M31 P5 F-5-1 (N8): raise above sticky table head (--z-sticky = 20).
     Uplifted from --z-fixed (30) to --z-popover (60) to clear admin sticky
     chrome that sits above --z-fixed (date-range panel was rendering behind
     it on AuditLog/ApplicationLog/SalesAnalysis). */
  z-index: var(--z-popover);
  display: flex; flex-direction: column; gap: var(--sp-1);
}

.filter-bar__disclosure-panel[hidden] { display: none; }

.filter-bar__disclosure-empty {
  margin: 0; padding: var(--sp-3); font-family: var(--font-sans);
  font-size: var(--fs-1); color: var(--n-500); font-style: italic; text-align: center;
}

.filter-bar__disclosure-option,
.filter-bar__saved-view {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 2px; width: 100%; min-height: 44px; padding: var(--sp-2) var(--sp-3);
  background-color: transparent; border: 0; border-radius: var(--r-2);
  text-align: start; color: var(--brand-ink);
  font-family: var(--font-sans); font-size: var(--fs-2); cursor: pointer;
  transition: background-color var(--d-1) var(--ease-out-swift);
}

.filter-bar__disclosure-option { font-weight: 500; }

.filter-bar__disclosure-option:hover,
.filter-bar__disclosure-option:focus-visible,
.filter-bar__saved-view:hover,
.filter-bar__saved-view:focus-visible {
  background-color: var(--n-50);
}

.filter-bar__disclosure-option:focus-visible,
.filter-bar__saved-view:focus-visible {
  outline: 3px solid var(--state-info); outline-offset: -3px;
}

.filter-bar__disclosure-option-description,
.filter-bar__saved-view-preview {
  font-family: var(--font-mono); font-size: var(--fs-1); color: var(--n-500);
}

.filter-bar__disclosure-option-description { font-weight: 400; }

.filter-bar__saved-views-empty {
  display: flex; flex-direction: column; gap: var(--sp-1);
  padding: var(--sp-4); text-align: center;
}

.filter-bar__saved-views-empty-headline {
  margin: 0; font-family: var(--font-sans); font-size: var(--fs-2);
  font-weight: 600; color: var(--brand-ink);
}

.filter-bar__saved-views-empty-hint {
  margin: 0; font-family: var(--font-mono); font-size: var(--fs-1); color: var(--n-500);
}

.filter-bar__saved-view-name {
  display: inline-flex; align-items: center; gap: var(--sp-2); font-weight: 600;
}

.filter-bar__saved-view-default {
  font-family: var(--font-mono); font-size: var(--fs-1); font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.06em;
  padding: 2px var(--sp-2); background-color: var(--n-100);
  border-radius: var(--r-1); color: var(--n-700);
}

@media (prefers-reduced-motion: reduce) {
  .filter-bar__search-input,
  .filter-bar__chip-remove,
  .filter-bar__disclosure-trigger,
  .filter-bar__disclosure-option,
  .filter-bar__saved-view { transition: none; }
}

/* ==========================================================================
   FORM FIELD
   Single partial handles all ten kinds (text / email / number / select /
   textarea / date / file / checkbox / radio / toggle) via FormFieldKind.
   Label + input + hint + inline error; aria-describedby links both hint and
   error when present. No Bootstrap form-* classes.
   Source: Views/Shared/Kit/_FormField.cshtml · Model: FormFieldModel.
   ========================================================================== */

.form-field {
  display: flex; flex-direction: column; gap: var(--sp-1);
  font-family: var(--font-sans); color: var(--brand-ink);
}

.form-field--disabled { opacity: 0.6; pointer-events: none; }

.form-field__label {
  display: inline-flex; align-items: baseline; gap: var(--sp-1);
  font-family: var(--font-sans); font-size: var(--fs-2); font-weight: 600;
  line-height: 1.3; color: var(--brand-ink);
}

.form-field__label-text { font: inherit; }

.form-field__label--group { margin-bottom: var(--sp-1); }

.form-field__required-marker {
  color: var(--state-danger); font-weight: 700; line-height: 1;
}

.form-field__control { display: block; }

.form-field__input,
.form-field__textarea,
.form-field__select {
  width: 100%; min-height: 44px; padding: var(--sp-2) var(--sp-3);
  background-color: var(--n-0); border: 1px solid var(--n-300);
  border-radius: var(--r-2); color: var(--brand-ink);
  font-family: var(--font-sans); font-size: var(--fs-2); line-height: 1.4;
  transition: border-color var(--d-1) var(--ease-out-swift),
              box-shadow var(--d-1) var(--ease-out-swift);
}

.form-field__input::placeholder,
.form-field__textarea::placeholder { color: var(--n-500); }

.form-field__input:focus-visible,
.form-field__textarea:focus-visible,
.form-field__select:focus-visible {
  outline: 2px solid var(--brand-spark); outline-offset: 2px;
  border-color: var(--state-info);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--state-info) 25%, transparent);
}

.form-field__input:disabled,
.form-field__textarea:disabled,
.form-field__select:disabled {
  background-color: var(--n-100); color: var(--n-500); cursor: not-allowed;
}

.form-field--has-error .form-field__input,
.form-field--has-error .form-field__textarea,
.form-field--has-error .form-field__select { border-color: var(--state-danger); }

.form-field--has-error .form-field__input:focus-visible,
.form-field--has-error .form-field__textarea:focus-visible,
.form-field--has-error .form-field__select:focus-visible {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--state-danger) 25%, transparent);
}

.form-field__textarea { min-height: 6.5rem; resize: vertical; }

.form-field__select-wrap { position: relative; }

.form-field__select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-inline-end: var(--sp-6); cursor: pointer;
}

.form-field__select-glyph {
  position: absolute; top: 50%; right: var(--sp-3);
  transform: translateY(-50%); pointer-events: none;
  color: var(--n-600); font-size: var(--fs-3); line-height: 1;
}

.form-field__input--file {
  padding: var(--sp-2); cursor: pointer; background-color: var(--n-50);
}

.form-field__inline-label,
.form-field__radio,
.form-field__toggle {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 44px; cursor: pointer;
  font-family: var(--font-sans); font-size: var(--fs-2); color: var(--brand-ink);
}

.form-field__toggle { position: relative; }

.form-field__inline-label-text { font: inherit; line-height: 1.3; }

.form-field__checkbox,
.form-field__radio-input {
  width: 20px; height: 20px; margin: 0; flex: 0 0 auto;
  cursor: pointer; accent-color: var(--brand-ink);
}

.form-field__checkbox:focus-visible,
.form-field__radio-input:focus-visible {
  outline: 3px solid var(--state-info); outline-offset: 2px;
}

.form-field__checkbox:focus-visible { border-radius: var(--r-1); }
.form-field__radio-input:focus-visible { border-radius: 50%; }

.form-field__radio-group {
  display: flex; flex-direction: column; gap: var(--sp-2);
}

.form-field__radio-label { line-height: 1.3; }

.form-field__toggle-input {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.form-field__toggle-track {
  position: relative; display: inline-block;
  width: 2.5rem; height: 1.5rem;
  background-color: var(--n-300); border-radius: var(--r-5); flex: 0 0 auto;
  transition: background-color var(--d-2) var(--ease-out-swift);
}

.form-field__toggle-thumb {
  position: absolute; top: 2px; left: 2px;
  width: calc(1.5rem - 4px); height: calc(1.5rem - 4px);
  background-color: var(--n-0); border-radius: 50%;
  box-shadow: var(--shadow-1);
  transition: transform var(--d-2) var(--ease-out-swift);
}

.form-field__toggle-input:checked + .form-field__toggle-track {
  background-color: var(--brand-ink);
}

.form-field__toggle-input:checked + .form-field__toggle-track .form-field__toggle-thumb {
  transform: translateX(1rem);
}

.form-field__toggle-input:focus-visible + .form-field__toggle-track {
  outline: 3px solid var(--state-info); outline-offset: 2px;
}

.form-field__hint {
  margin: 0; font-family: var(--font-mono); font-size: var(--fs-1);
  color: var(--n-500); line-height: 1.4;
}

.form-field__error {
  display: inline-flex; align-items: center; gap: var(--sp-1); margin: 0;
  font-family: var(--font-sans); font-size: var(--fs-1); font-weight: 500;
  color: var(--state-danger); line-height: 1.4;
}

.form-field__error-glyph {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1rem; height: 1rem; border-radius: 50%;
  background-color: var(--state-danger); color: var(--n-0);
  font-family: var(--font-mono); font-size: var(--fs-1); font-weight: 700;
  line-height: 1; flex: 0 0 auto;
}

@media (prefers-reduced-motion: reduce) {
  .form-field__input,
  .form-field__textarea,
  .form-field__select,
  .form-field__toggle-track,
  .form-field__toggle-thumb { transition: none; }
}

/* ==========================================================================
   RICH TEXT EDITOR  (M49 Phase 3)
   Wrapper styles for the Quill-backed Rich-Text-Editor kit primitive.
   Vendor styles live in wwwroot/lib/quill/quill.snow.css (BSD-3); the
   kit wrapper provides the same outer shape as FormField so consumers
   can swap a textarea for an RTE without disturbing surrounding layout.

   Toolbar buttons inherit Quill's snow theme; the editor surface is
   themed via the .ql-container + .ql-editor selectors below to align
   border / radius / typography with the rest of the kit.
   Source: Views/Shared/Kit/_RichTextEditor.cshtml · Model: RichTextEditorModel.
   ========================================================================== */

.kit-rte {
  display: flex; flex-direction: column; gap: var(--sp-1);
  font-family: var(--font-sans); color: var(--brand-ink);
}

.kit-rte__label {
  display: inline-flex; align-items: baseline; gap: var(--sp-1);
  font-family: var(--font-sans); font-size: var(--fs-2); font-weight: 600;
  line-height: 1.3; color: var(--brand-ink);
}

.kit-rte__label-text { font: inherit; }

.kit-rte__required-marker {
  color: var(--state-danger); font-weight: 700; line-height: 1;
}

.kit-rte__sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.kit-rte__control { display: block; }

/* Quill mount surface — sized to feel like a textarea by default.
   Touch target: 44px+ via the Quill toolbar buttons (Snow theme uses
   28px buttons inside a 42px-tall toolbar; we bump to ≥44px below). */
.kit-rte__editor {
  min-height: 12rem;
  border-radius: var(--r-2);
}

/* Override Quill's snow theme to align with kit tokens. The vendor CSS
   uses #ccc / #06c hex literals — these wrapper selectors come after
   quill.snow.css in load order and override via specificity. */
.kit-rte .ql-toolbar.ql-snow {
  border: 1px solid var(--n-300);
  border-bottom: none;
  border-top-left-radius: var(--r-2);
  border-top-right-radius: var(--r-2);
  background-color: var(--n-50);
  padding: var(--sp-2);
  /* Hard-rule #8: every interactive button reaches ≥44px via the
     min-height claim below. Snow's defaults are 28px which fails
     the touch-target floor. */
}

.kit-rte .ql-toolbar.ql-snow button,
.kit-rte .ql-toolbar.ql-snow .ql-picker-label {
  min-width: 44px; min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
}

.kit-rte .ql-container.ql-snow {
  border: 1px solid var(--n-300);
  border-bottom-left-radius: var(--r-2);
  border-bottom-right-radius: var(--r-2);
  font-family: var(--font-sans);
  font-size: var(--fs-2);
  background-color: var(--n-0);
  color: var(--brand-ink);
}

.kit-rte .ql-editor {
  min-height: 10rem;
  padding: var(--sp-3);
  line-height: 1.5;
  color: var(--brand-ink);
}

.kit-rte .ql-editor.ql-blank::before {
  color: var(--n-500);
  font-style: normal;
  font-family: var(--font-sans);
}

/* Focus ring — match FormField's brand-spark + state-info pattern. */
.kit-rte:focus-within .ql-container.ql-snow {
  border-color: var(--state-info);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--state-info) 25%, transparent);
  outline: 2px solid var(--brand-spark);
  outline-offset: 2px;
}

.kit-rte__initial { display: none; }

.kit-rte__help {
  margin: 0; font-family: var(--font-mono); font-size: var(--fs-1);
  color: var(--n-500); line-height: 1.4;
}

@media (prefers-reduced-motion: reduce) {
  .kit-rte .ql-container.ql-snow,
  .kit-rte .ql-toolbar.ql-snow button,
  .kit-rte .ql-toolbar.ql-snow .ql-picker-label { transition: none; }
}

/* ==========================================================================
   SPARKLINE  (Phase 6 · W2.v2.2)
   Inline-SVG trend line. Line colour cascades via currentColor; the root
   span sets color based on the data-sparkline-color attribute whose value
   is the token name (without leading --). Finite set of supported tokens
   is enumerated below to avoid dynamic style attributes.
   Source: Views/Shared/Kit/_Sparkline.cshtml · Model: SparklineModel.
   ========================================================================== */

.sparkline {
  display: inline-flex; align-items: center;
  width: 100%; max-width: 160px; height: auto;
  color: var(--brand-ink);
}

.sparkline[data-sparkline-color="brand-spark"]   { color: var(--brand-spark); }
.sparkline[data-sparkline-color="state-success"] { color: var(--state-success); }
.sparkline[data-sparkline-color="state-warn"]    { color: var(--state-warn); }
.sparkline[data-sparkline-color="state-danger"]  { color: var(--state-danger); }
.sparkline[data-sparkline-color="state-info"]    { color: var(--state-info); }
.sparkline[data-sparkline-color="n-500"]         { color: var(--n-500); }
.sparkline__svg { display: block; width: 100%; height: auto; overflow: visible; }

/* ==========================================================================
   SEGMENTED CONTROL  (Phase 6 · W2.v2.3)
   Minimum 2 mutually exclusive options (no upper bound) backed by a native
   radio group. The <input> is visually hidden but keeps focus semantics +
   arrow-key cycling. The <label> is the visible button face. Medium size
   meets the 44x44 touch-target rule; Small is density-capped.
   2026-05-20-uat-round-2-fixes Phase 10 — flex-wrap: wrap added so wide
   controls (e.g. Home Trending Now filter strip with up to 7 pills) break
   onto a second row on narrow viewports instead of overflowing.
   Source: Views/Shared/Kit/_SegmentedControl.cshtml · Model: SegmentedControlModel.
   ========================================================================== */

.segmented-control {
  display: inline-flex; flex-wrap: wrap; padding: var(--sp-1);
  border: 1px solid var(--n-200); border-radius: var(--r-3);
  background-color: var(--n-50); margin: 0;
  font-family: var(--font-sans);
}

.segmented-control__input {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

.segmented-control__option {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2); padding: 0 var(--sp-4);
  min-width: 44px; min-height: 44px;
  border-radius: var(--r-2); color: var(--n-700);
  font-size: var(--fs-2); font-weight: 500; line-height: 1;
  cursor: pointer; user-select: none;
  transition:
    background-color var(--d-1) var(--ease-out-swift),
    color var(--d-1) var(--ease-out-swift),
    box-shadow var(--d-1) var(--ease-out-swift);
}

.segmented-control--sm .segmented-control__option {
  min-width: 32px; min-height: 32px;
  padding: 0 var(--sp-3); font-size: var(--fs-1);
}

.segmented-control__option:hover {
  background-color: color-mix(in srgb, var(--brand-ink) 6%, transparent);
  color: var(--brand-ink);
}

.segmented-control__input:checked + .segmented-control__option {
  background-color: var(--brand-ink); color: var(--n-0);
  box-shadow: var(--shadow-1);
}

.segmented-control__input:focus-visible + .segmented-control__option {
  outline: 3px solid var(--state-info); outline-offset: 2px;
}

.segmented-control__input:disabled + .segmented-control__option {
  opacity: 0.5; cursor: not-allowed;
}

.segmented-control__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1rem; height: 1rem;
}

@media (prefers-reduced-motion: reduce) {
  .segmented-control__option { transition: none; }
}

/* ==========================================================================
   KBD  (Phase 6 · W2.v2.4)
   Single keyboard-key glyph. Multi-key combos render adjacent <kbd>
   elements. Ambient variant is subtler for CmdK footer hints.
   Source: Views/Shared/Kit/_Kbd.cshtml · Model: KbdModel.
   ========================================================================== */

.kit-kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; height: 1.5rem; padding: 0 var(--sp-2);
  border: 1px solid var(--n-300);
  border-radius: var(--r-1); background-color: var(--n-0);
  color: var(--brand-ink);
  font-family: var(--font-mono); font-size: var(--fs-1); font-weight: 500;
  line-height: 1; box-shadow: inset 0 -1px 0 var(--n-200);
}

.kit-kbd--ambient {
  border-color: var(--n-200); background-color: var(--n-50);
  color: var(--n-600); box-shadow: none;
}

/* ==========================================================================
   PERSONALIZATION SUMMARY  (M16 Phase 4 · W15.6)
   Account · Preferences "what's on file" surface + Clear All form.
   Token-only. No raw hex. No raw ms. No <style> in the consuming view.
   Source: Views/Shared/Kit/_PersonalizationSummary.cshtml ·
           Model: Application.Personalization.UserSignalSummary
   ========================================================================== */

.account-preferences__section--summary {
  margin-block-start: var(--sp-6);
  padding-block-start: var(--sp-5);
  border-block-start: 1px solid var(--n-200);
}

.account-preferences__summary-empty {
  margin: var(--sp-3) 0 var(--sp-4);
  color: var(--n-600);
  font-size: var(--fs-2);
}

.account-preferences__summary-list {
  list-style: none;
  margin: var(--sp-3) 0 var(--sp-5);
  padding: 0;
  display: grid; gap: var(--sp-2);
}

.account-preferences__summary-list li {
  display: grid;
  grid-template-columns: minmax(8rem, 12rem) 1fr;
  gap: var(--sp-3);
  align-items: baseline;
  padding-block: var(--sp-2);
  border-block-end: 1px solid var(--n-100);
}

.account-preferences__summary-list li:last-child {
  border-block-end: 0;
}

.account-preferences__summary-label {
  font-family: var(--font-mono);
  font-size: var(--fs-1);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--n-600);
}

.account-preferences__summary-value {
  font-size: var(--fs-2);
  color: var(--brand-ink);
}

.account-preferences__summary-help {
  margin: var(--sp-2) 0 var(--sp-3);
  color: var(--n-600);
  font-size: var(--fs-1);
  line-height: 1.5;
}

.account-preferences__form--clear {
  margin-block-start: var(--sp-4);
  padding-block-start: var(--sp-4);
  border-block-start: 1px dashed var(--n-200);
}

@media (max-width: 480px) {
  .account-preferences__summary-list li {
    grid-template-columns: 1fr;
    gap: var(--sp-1);
  }
}

/* ==========================================================================
   M19 PHASE 2 — CUSTOM.CSS RULE MIGRATIONS (data target)
   Source: wwwroot/custom/custom.css (deleted at Phase 2 close)
   All legacy token refs replaced with canonical equivalents per M19 mapping.
   No new tokens introduced. Token map:
     --primary-color → --brand-ink
     --white         → --n-0
     --neutral-*     → --n-*
     --secondary-color (#4CAF50 green) → colour-mix(in srgb, var(--brand-ink) 85%, var(--n-0))
                        (accepted visual delta: legacy green focus→ desaturated brand-ink)
     #eee            → --n-200
     #e0e0e0         → --n-300
     #e5e5e5         → --n-200
     #d5e2ea         → --n-200 (accepted neutral approximation)
     #8ac0e6         → --n-300 (accepted neutral approximation)
     #2E7D32 green (bg-success) → --state-success (TEAL — CLAUDE.md HR1 corrective)
   HC-mode: --state-success flips to #115E59 (deeper teal) under prefers-contrast:more
   and .theme-high-contrast. Background remains teal-family (non-green). Verified.
   ========================================================================== */

/* ── .card-header (M19 P2 migration)
   Live consumers: ApplicationLogDetailInfo.cshtml, UserDetail.cshtml, and others.
   Classification (III) — no canonical equivalent.
   --primary-color → --brand-ink for background.
   Second .card-header rule (padding-bottom: 0px) merged as override property.
   ──────────────────────────────────────────────────────────────────────────────── */
.card-header {
  font-size: 17px;
  color: var(--n-0) !important;
  border-bottom: 1px solid var(--n-200);
  padding-bottom: 0px !important;
  background-color: var(--brand-ink);
  text-transform: uppercase !important;
}

/* ── .hide-data + animation (M19 P2 migration)
   Live consumer: ApplicationLog.cshtml (JS: $("#resultsTable").addClass("hide-data")).
   Classification (III) — no canonical equivalent.
   Raw hex #d5e2ea → --n-100 (close light-blue-gray approximation; accepted delta).
   Raw hex #8ac0e6 → --n-200 (accepted neutral approximation for shimmer mid-tone).
   Motion: animation-duration 2s retained as raw value — deliberate loading-shimmer
   pace not mapped to a motion token (looping keyframe, not a transition).
   ESCALATION: 2s raw value pending orchestrator decision on shimmer motion tokens.
   Prefers-reduced-motion fallback added per HR#10.
   ──────────────────────────────────────────────────────────────────────────────── */
.hide-data {
  background: var(--n-100) !important;
  position: relative;
  overflow: hidden;
}

.hide-data::before {
  content: "";
  position: absolute;
  left: 0%;
  top: 0;
  height: 100%;
  width: 50px;
  background: linear-gradient(to right, var(--n-100) 25%, var(--n-200) 50%, var(--n-100) 100%);
  animation-name: hide-data-shimmer;
  animation-duration: 2s; /* deliberate shimmer pace — see note above */
  animation-iteration-count: infinite;
  filter: blur(5px);
}

@keyframes hide-data-shimmer {
  from { left: 0%; }
  to   { left: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .hide-data::before {
    animation: none;
  }
}

/* ── .readonly-select (M19 P2 migration)
   Live consumer: Users.cshtml (JS: roleElem.addClass("readonly-select")).
   Classification (III) — no canonical equivalent.
   #eee → --n-200 (accepted visual delta: slightly lighter than #eeeeee).
   ──────────────────────────────────────────────────────────────────────────────── */
.readonly-select {
  pointer-events: none;
  background-color: var(--n-200);
}

/* ── .divider (M19 P2 migration)
   Live consumer: Permissions.cshtml:117.
   Classification (III) — no canonical equivalent (sidebar-divider is a different component).
   #e0e0e0 → --n-300 (D1D5DB — accepted visual delta).
   ──────────────────────────────────────────────────────────────────────────────── */
.divider {
  overflow: hidden !important;
  height: 1px !important;
  background-color: var(--n-300) !important;
}

/* ── .bg-success override (M19 P2 migration — CLAUDE.md HR1 corrective)
   Live consumers: UserDetail.cshtml, AdminDsar/Index.cshtml, CreatorForm/ManageForm.cshtml,
   Registrations.cshtml, CreatorTour/Bookings.cshtml, ManageTour.cshtml, _ManageContest.cshtml.
   Classification (III) — no canonical override exists; custom.css hard-coded #2E7D32 GREEN.
   This is an HR1 violation. Migration replaces with --state-success (teal #0D9488).
   HC-mode: --state-success → #115E59 (deeper teal) — remains teal-family. Verified.
   ──────────────────────────────────────────────────────────────────────────────── */
.bg-success {
  background-color: var(--state-success) !important;
}

/* ── .bg-warning / .badge.bg-warning (M19 P2 migration)
   Live consumers: AdminOrder/OrderDetail.cshtml, CreatorForm/ManageForm.cshtml,
   Registrations.cshtml, CreatorTour/Bookings.cshtml, ManageTour.cshtml, etc.
   Classification (III) — no canonical override for the dark-text WCAG fix.
   WK-351: bg-warning badge needs dark text for WCAG AA contrast.
   Bootstrap's bg-warning is yellow (#FFC107); dark text is required.
   --bs-badge-color is a Bootstrap 5 custom property for badge text colour.
   ──────────────────────────────────────────────────────────────────────────────── */
.bg-warning,
.badge.bg-warning {
  --bs-badge-color: var(--n-900);
  color: var(--n-900) !important;
}

/* ==========================================================================
   PAYMENT-METHOD SELECTOR
   M23 Phase 6 · C7 · F-6-C7b + F-6-C7c
   Source: Views/Shared/_PaymentMethodSelector.cshtml
   Fixes styling regression: zero CSS existed for this partial prior to M23 P6.
   Replaces inline style with raw hex on .pm-logo i (icon glyph now uses var(--n-600)).
   Token discipline: zero raw hex, zero raw ms.
   ========================================================================== */

.payment-methods {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0 0 1.25rem;
}

.payment-method {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  border: 1px solid var(--n-200);
  border-radius: var(--r-2);
  min-height: 2.75rem; /* 44px touch target — HR8 */
  cursor: pointer;
  position: relative;
  transition: border-color var(--d-2) var(--ease-out-swift),
              background-color var(--d-2) var(--ease-out-swift);
}

.payment-method:hover,
.payment-method:focus-within {
  border-color: var(--brand-ink);
  background: var(--n-50);
}

.payment-method.selected {
  border-color: var(--brand-ink);
  background: var(--n-50);
  box-shadow: 0 0 0 1px var(--brand-ink);
}

.payment-method input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.pm-radio {
  width: 1.125rem;
  height: 1.125rem;
  border: 2px solid var(--n-300);
  border-radius: 50%;
  flex: 0 0 auto;
  position: relative;
  transition: border-color var(--d-2) var(--ease-out-swift);
}

.payment-method.selected .pm-radio {
  border-color: var(--brand-ink);
}

.payment-method.selected .pm-radio::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--brand-ink);
}

.pm-logo {
  width: 2.5rem;
  height: 2.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-1);
  background: var(--n-100);
  flex: 0 0 auto;
}

.pm-logo i {
  font-size: var(--fs-4);
  color: var(--n-600);
}

.pm-info {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.pm-name {
  font-size: var(--fs-3);
  font-weight: 600;
  color: var(--n-900);
  line-height: 1.3;
}

.pm-desc {
  font-size: var(--fs-1);
  color: var(--n-500);
  line-height: 1.4;
}

@media (prefers-reduced-motion: reduce) {
  .payment-method,
  .pm-radio {
    transition: none;
  }
}

/* ----------------------------------------------------------------------- */
/* M31 Phase 5 — Cluster F (List-page polish)                               */
/* ----------------------------------------------------------------------- */

/*
 * F-5-5 (N14) — Admin application-logs message/details column overflow.
 *
 * Long row content in the AppLog Message and Details columns pushes the
 * row's action button off the right edge of the table. The _DataTable
 * partial emits each <td> with data-label="@col.Label", so we can scope
 * truncation to the AppLog-specific column labels without forking the
 * primitive or re-classing every consumer cell.
 *
 * Per-column max-width (40ch) + ellipsis lets the View action stay
 * visible on the row's right edge; full content remains readable in the
 * drawer (rendered via the View Details delegated handler) and is
 * exposed to assistive tech via the cell's existing markup.
 *
 * Defense-in-depth: Phase 6 N15 first-column-actions also addresses the
 * "View button hidden" symptom; per user pick at Phase 6 dispatch this
 * rule stays as belt-and-braces — log messages still need ellipsis to
 * keep the table compact regardless of action-column position.
 */
.data-table__cell[data-label="Message"],
.data-table__cell[data-label="Details"] {
  max-width:     40ch;
  overflow:      hidden;
  text-overflow: ellipsis;
  white-space:   nowrap;
}

/*
 * F-5-6 (N16) — Admin date-range filter inputs visible.
 *
 * The FromToDate helper emits <input class="form-control datetime-picker">
 * and <input class="form-control datepicker"> (both type="text"; flatpickr
 * binds the picker JS by class). In the admin shell the inputs render with
 * a transparent background and no border, blending with the surface — give
 * them a token-aligned card-style treatment with focus-visible ring.
 *
 * Scoped to [data-shell="admin"] so public surfaces (which currently do
 * not use FromToDate inside FilterBar contexts) are unaffected; admin
 * consumers: Views/Admin/{ApplicationLog,AuditLog}.cshtml + AdminLedger
 * + AdminPayout sales analyses + CreatorLedger + CreatorPayout.
 */
[data-shell="admin"] input.datepicker,
[data-shell="admin"] input.datetime-picker {
  background-color: var(--n-0);
  border:           1px solid var(--n-200);
  border-radius:    var(--r-2);
  padding:          var(--sp-2) var(--sp-3);
  color:            var(--n-900);
  font:             inherit;
  min-height:       44px;
}

[data-shell="admin"] input.datepicker:focus-visible,
[data-shell="admin"] input.datetime-picker:focus-visible {
  outline:        2px solid var(--brand-ink);
  outline-offset: 2px;
}

/* ==========================================================================
   M31 Phase 11 F-11-3 — Short-link copy button (N30 parity)
   ==========================================================================
   `.shortlink-copy` is rendered by the shared `_ShortLinkDisplay.cshtml`
   partial; both the contest detail page (VotingContest.cshtml) and the
   candidate detail page (ContestantDetail.cshtml) compose it. Pre-Phase-11
   the rule lived inside the inline <style asp-add-nonce> block in
   VotingContest.cshtml, which scoped the visual treatment to the contest
   page only — the candidate detail page rendered the button bare (no
   background, no radius, no padding), so the two pages drifted visually
   despite sharing the partial. Promoting the rule here lets both pages
   inherit the same treatment. Padding `6px 14px` re-tokenised to
   `var(--sp-2) var(--sp-4)` (HR3 binding); font-size `13px` mapped to
   `--fs-1` (12-14px clamp). HR8 touch-target via min-height:44px.
   ========================================================================== */
.shortlink-copy {
  background:    var(--brand-spark);
  color:         var(--n-0);
  border:        none;
  border-radius: var(--r-2);
  padding:       var(--sp-2) var(--sp-4);
  font-size:     var(--fs-1);
  font-weight:   600;
  cursor:        pointer;
  flex-shrink:   0;
  min-height:    44px;
  transition:    filter var(--d-1) var(--ease-out-swift),
                 background-color var(--d-1) var(--ease-out-swift),
                 box-shadow var(--d-1) var(--ease-out-swift);
}
.shortlink-copy:hover {
  filter: brightness(1.05);
}
.shortlink-copy:focus-visible {
  outline:        2px solid var(--brand-ink);
  outline-offset: 2px;
}

/* ==========================================================================
   M52 Phase 3 fold-in (F-2-01) — visible "copied" feedback for any button
   carrying [data-action="copy-link"]. The unified click handler in
   wwwroot/js/public.js sets data-copy-state="copied" + flashes aria-label
   for ~2000ms when navigator.clipboard succeeds. Pre-fold-in only the
   aria-label flipped (assistive-tech path) — sighted users got no visual
   cue on icon-only buttons (e.g. EventDetail share). This block adds the
   visual layer: brief teal flash via --state-success + soft ring, keeping
   the brand-spark default underneath. Honour HR10: drop the transition
   when prefers-reduced-motion is set so the swap is instantaneous.
   ========================================================================== */
[data-action="copy-link"][data-copy-state="copied"] {
  background-color: var(--state-success);
  color:            var(--n-0);
  box-shadow:       0 0 0 3px color-mix(in oklab, var(--state-success) 25%, transparent);
}
[data-action="copy-link"][data-copy-state="copied"]:hover {
  /* Suppress the default hover brightness flash while in "copied" state so
     the success cue stays visually stable for the full 2s window. */
  filter: none;
}

@media (prefers-reduced-motion: reduce) {
  .shortlink-copy { transition: none; }
  [data-action="copy-link"][data-copy-state="copied"] {
    /* No motion — the colour swap still happens, but instantaneously. */
    transition: none;
  }
}

/* ==========================================================================
   USER PROFILE PAGE (Phase 3 of 2026-05-07-admin-fix-batch)
   Layout primitives for the unified user-profile page partial
   (Views/Shared/_UserProfilePage.cshtml). Drives BOTH the admin "view another
   user" surface and the self-service "my profile" surface.

   Hard rules engaged:
     #2  no raw hex — token-only via --n-* / --brand-ink / --state-* tokens
     #3  no raw ms — motion via --d-* tokens (none required at present;
         reuses kit primitives for animations)
     #8  touch targets ≥ 44×44 — handled by the consumed kit btn-- helpers
   ========================================================================== */

/* Profile summary header — avatar + identity block above the detail list. */
.profile-summary {
  display:        flex;
  align-items:    center;
  gap:            var(--sp-3);
  margin-bottom:  var(--sp-4);
}

.profile-summary__id {
  display:        flex;
  flex-direction: column;
  gap:            var(--sp-1);
}

/* Definition list for read-only profile attributes (Email / Phone / Role /
   Organisation / Identity Verified). Replaces the bespoke "stat-strip__list"
   markup absorbed from the M32 carry-forward — semantics here are KV pairs,
   not metrics, so the kit StatStrip partial (which enforces 3-5 metric cells)
   is intentionally NOT consumed. CLAUDE.md "raise it" path: the partial does
   not fit the semantic shape, so a profile-specific class lives here. */
.profile-detail-list {
  display:               grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap:                   var(--sp-3);
  margin:                0;
}

.profile-detail-list__item {
  padding:          var(--sp-3);
  border-radius:    var(--r-2);
  border:           1px solid var(--n-100);
  background-color: var(--n-50);
  display:          flex;
  flex-direction:   column;
  gap:              var(--sp-1);
}

.profile-detail-list__label {
  font-family:    var(--font-mono);
  font-size:      var(--fs-1);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color:          var(--n-700);
  margin:         0;
}

.profile-detail-list__value {
  display:     flex;
  flex-wrap:   wrap;
  align-items: center;
  gap:         var(--sp-2);
  margin:      0;
  color:       var(--n-900);
}

/* Editable form (name + phone + picture). Two-column grid that collapses to
   single column under 640px. */
.profile-edit-form__grid {
  display:               grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap:                   var(--sp-4);
}

.profile-edit-form__field--full {
  grid-column: 1 / -1;
}

.profile-edit-form__actions {
  margin-top:      var(--sp-4);
  display:         flex;
  justify-content: flex-end;
  gap:             var(--sp-2);
}

@media (max-width: 640px) {
  .profile-edit-form__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* CTA row — stacks "Create Event/Contest on Behalf" links above tables on
   admin-context renders. Replaces a Bootstrap d-flex gap-2 mb-4 stack. */
.profile-cta-row {
  display:       flex;
  flex-wrap:     wrap;
  gap:           var(--sp-2);
  margin-bottom: var(--sp-4);
}

/* Load-more anchor centring (events / contests pagination). */
.profile-load-more {
  display:         flex;
  justify-content: center;
  margin-top:      var(--sp-3);
}

/* ==========================================================================
   KIT · LOAD MORE (Mandate 2026-05-08 · Phase 5)
   Single "Load more" button rendered by Views/Shared/Kit/_LoadMore.cshtml.
   Companion JS: wwwroot/js/kit/load-more.js — appends fetched rows to a
   target <tbody> and marks them with data-load-more-just-added="true" so
   the fade-in transition plays on insertion.

   Hard rules:
     #2  no raw hex (uses --brand-* / --n-* tokens via .btn--primary)
     #3  no raw ms (uses --d-2 motion token)
     #8  ≥ 44×44 touch target (inherited from .btn--md min-height)
    #10  prefers-reduced-motion: reduce → fade-in becomes instant
   ========================================================================== */

.kit-load-more {
  display:         flex;
  justify-content: center;
  margin-top:      var(--sp-3);
  margin-bottom:   var(--sp-3);
}

.kit-load-more__button[data-loading="true"] .kit-load-more__label {
  opacity: 0.55;
}

.kit-load-more__spinner {
  display:        none;
  width:          var(--sp-3);
  height:         var(--sp-3);
  margin-left:    var(--sp-2);
  border:         2px solid currentColor;
  border-right-color: transparent;
  border-radius:  50%;
  animation:      kit-load-more-spin var(--d-4) linear infinite;
}

.kit-load-more__button[data-loading="true"] .kit-load-more__spinner {
  display: inline-block;
}

@keyframes kit-load-more-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Newly-inserted rows fade in over --d-2. The marker attribute is set
   by load-more.js on append and cleared on the next animation frame —
   the from→to transition runs once per insertion. */
[data-load-more-just-added="true"] {
  animation: kit-load-more-row-fade-in var(--d-2) var(--ease-out-swift, ease-out) both;
}

@keyframes kit-load-more-row-fade-in {
  from {
    opacity:   0;
    transform: translateY(4px);
  }
  to {
    opacity:   1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .kit-load-more__spinner {
    animation: none;
    /* Static dot — still gives a visual loading affordance without spin. */
    border-right-color: currentColor;
  }
  [data-load-more-just-added="true"] {
    animation: none;
  }
}

/* ── DateRangePicker ────────────────────────────────────────────────────────
   Phase 16 / D-16-11 rewrite — Kit/_DateRangePicker.cshtml.
   Replaces native <input type="date"> with <button> triggers + dropdown panel.
   Data-primitive owner: this file (elfrique.components.data.css).
   Hard Rules #2 (no raw hex — token-only), #3 (no raw ms — motion tokens),
   #4/#5 (no inline style in partial — CSS here), #6 (D-16-06 touch targets),
   #8 (≥ 44×44px day cells), #10 (prefers-reduced-motion fallback D-16-08).
   ─────────────────────────────────────────────────────────────────────────── */

/* Fieldset root — inline with FilterBar (D-16-05: picker lives inside .filter-bar) */
/* Phase 2 (2026-05-13-website-feedback): align-items: center to vertically
   center the fields cluster with the actions cluster on the cross axis,
   matching .filter-bar's align-items: center (line 545). Previously flex-end
   caused actions to drop to the bottom of the taller label+trigger column,
   creating the misalignment shown in docs/work/screenshots/orders.jpg. */
.date-range-picker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border: none;
  background: transparent;
  margin: 0;
  position: relative;
}

.date-range-picker__fields {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  flex: 1 1 auto;
}

.date-range-picker__field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  position: relative;
}

.date-range-picker__label {
  font-size: var(--fs-1);
  font-weight: 500;
  color: var(--n-600);
  line-height: 1.25;
}

/* Trigger button — replaces <input type="date"> */
.date-range-picker__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 9rem;
  min-height: 2.75rem;          /* Hard Rule #8 — 44×44px touch target (D-16-06) */
  padding-block: var(--sp-2);
  padding-inline: var(--sp-3);
  border: 1px solid var(--n-300);
  border-radius: var(--r-2);
  background: var(--n-0);
  color: var(--brand-ink);
  font-size: var(--fs-2);
  cursor: pointer;
  transition: border-color var(--d-1) var(--ease-out-swift),
              box-shadow var(--d-1) var(--ease-out-swift);
  text-align: start;
}

.date-range-picker__trigger:hover {
  border-color: var(--brand-spark);
}

.date-range-picker__trigger:focus-visible {
  outline: 2px solid var(--brand-spark);
  outline-offset: 2px;
  border-color: var(--brand-spark);
}

.date-range-picker__trigger-icon {
  font-style: normal;
  flex-shrink: 0;
}

.date-range-picker__trigger-label {
  flex: 1 1 auto;
}

/* Dropdown calendar panel */
.date-range-picker__panel {
  position: absolute;
  top: 100%;
  inset-inline-start: 0;
  z-index: 200;
  background: var(--n-0);
  border: 1px solid var(--n-200);
  border-radius: var(--radius-md);
  box-shadow: 0 var(--sp-2) var(--sp-5) color-mix(in srgb, var(--brand-ink) 12%, transparent);
  min-width: 18rem;
  padding: var(--sp-3);
  margin-block-start: var(--sp-1);
  transition: opacity var(--d-1) var(--ease-out-swift);
}

.date-range-picker__panel[hidden] {
  display: none;
}

.date-range-picker__panel-inner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* Month navigation row */
.date-range-picker__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}

.date-range-picker__nav-btn {
  min-width: 2.75rem;
  min-height: 2.75rem;           /* Hard Rule #8 — 44×44px touch target (D-16-06) */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--n-200);
  border-radius: var(--r-2);
  background: var(--n-0);
  color: var(--brand-ink);
  font-size: var(--fs-3);
  cursor: pointer;
  transition: background-color var(--d-1) var(--ease-out-swift);
}

.date-range-picker__nav-btn:hover {
  background: var(--n-100);
}

.date-range-picker__nav-btn:focus-visible {
  outline: 2px solid var(--brand-spark);
  outline-offset: 2px;
}

.date-range-picker__month-label {
  font-size: var(--fs-2);
  font-weight: 600;
  color: var(--brand-ink);
  flex: 1 1 auto;
  text-align: center;
}

/* Weekday header row */
.date-range-picker__weekdays {
  display: grid;
  grid-template-columns: repeat(7, 2.75rem);
  gap: 0;
  text-align: center;
  font-size: var(--fs-1);
  font-weight: 600;
  color: var(--n-500);
  padding-block-end: var(--sp-1);
}

/* Calendar grid — day cells */
.date-range-picker__calendar {
  display: grid;
  grid-template-columns: repeat(7, 2.75rem);
  gap: 2px;
}

/* Day cell button (AC-16-09 / D-16-06 — ≥ 44×44px) */
.date-range-picker__day {
  min-width: 2.75rem;
  min-height: 2.75rem;           /* Hard Rule #8 — AC-16-09 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--r-2);
  background: transparent;
  color: var(--brand-ink);
  font-size: var(--fs-2);
  cursor: pointer;
  transition: background-color var(--d-1) var(--ease-out-swift),
              color var(--d-1) var(--ease-out-swift);
}

.date-range-picker__day:hover {
  background: var(--n-100);
}

.date-range-picker__day:focus-visible {
  outline: 2px solid var(--brand-spark);
  outline-offset: -2px;
  z-index: 1;
}

.date-range-picker__day--selected {
  background: var(--brand-spark);
  color: var(--n-0);
  font-weight: 600;
}

.date-range-picker__day--selected:hover {
  background: var(--brand-spark);
}

.date-range-picker__day--blank {
  cursor: default;
  pointer-events: none;
}

/* Panel close/action row */
.date-range-picker__panel-actions {
  display: flex;
  justify-content: flex-end;
  padding-block-start: var(--sp-2);
  border-top: 1px solid var(--n-100);
}

/* Apply/Reset row (outside the panel, inside the fieldset) */
.date-range-picker__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-shrink: 0;
}

/* Hard Rule #10 / D-16-08 — prefers-reduced-motion fallback (AC-16-10) */
@media (prefers-reduced-motion: reduce) {
  .date-range-picker__panel,
  .date-range-picker__day {
    transition: none;
  }
}

/* ──────────────────────────────────────────────────────────────────────
   Portfolio multi-image widget (M50 Phase 6)
   ───────────────────────────────────────────────────────────────────────
   Multi-file upload widget used by vendor portfolio add drawer. Companion
   JS lives in custom-script.js (.portfolio-multi-image-container handler).
   First uploaded URL populates the primary hidden #ImageUrl input; later
   uploads append as AdditionalImageUrls[i] hidden inputs into the form.
   HR #8 — remove buttons sized via min-height/min-width to meet 44×44.
   HR #10 — opacity transitions guarded by prefers-reduced-motion below.
*/
.portfolio-multi-image-container {
  display:        flex;
  flex-direction: column;
  gap:            var(--sp-2);
}
.portfolio-multi-image-list {
  list-style: none;
  margin:     0;
  padding:    0;
  display:    grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap:        var(--sp-2);
}
.portfolio-multi-image-list:empty {
  display: none;
}
.portfolio-multi-image-item {
  position:       relative;
  border:         1px solid var(--n-200);
  border-radius:  var(--r-2);
  overflow:       hidden;
  aspect-ratio:   1 / 1;
  background:     var(--n-50);
  transition:     opacity var(--d-2) var(--ease-out-swift);
}
.portfolio-multi-image-item--pending {
  opacity: 0.6;
}
.portfolio-multi-image-item--error {
  border-color: var(--state-danger);
}
.portfolio-multi-image-item__img {
  width:      100%;
  height:     100%;
  object-fit: cover;
  display:    block;
}
.portfolio-multi-image-item__remove {
  position:       absolute;
  top:            var(--sp-1);
  right:          var(--sp-1);
  min-width:      44px;
  min-height:     44px;
  display:        inline-flex;
  align-items:    center;
  justify-content:center;
  background:     var(--n-900);
  color:          var(--n-0);
  border:         0;
  border-radius:  var(--r-pill);
  cursor:         pointer;
  opacity:        0.85;
  transition:     opacity var(--d-1) var(--ease-out-swift);
}
.portfolio-multi-image-item__remove:hover,
.portfolio-multi-image-item__remove:focus-visible {
  opacity: 1;
}
.portfolio-multi-image-item__badge {
  position:       absolute;
  bottom:         var(--sp-1);
  left:           var(--sp-1);
  background:     var(--brand-ink);
  color:          var(--n-0);
  padding:        2px 8px;
  border-radius:  var(--r-pill);
  font-size:      var(--fs-1);
  font-family:    var(--font-mono);
}
.portfolio-multi-image-status {
  color:     var(--n-600);
  font-size: var(--fs-2);
}
.portfolio-multi-image-status--error {
  color: var(--state-danger);
}
.portfolio-multi-image-status--success {
  color: var(--state-success);
}

@media (prefers-reduced-motion: reduce) {
  .portfolio-multi-image-item,
  .portfolio-multi-image-item__remove {
    transition: none;
  }
}

/* ───────────────────────────────────────────────────────────────────────
   Bid Post Reference Photo Upload (M50 Phase 7)
   ───────────────────────────────────────────────────────────────────────
   Multi-file upload widget on the Creator quote-request form. Companion
   JS lives in wwwroot/js/pages/creator-bidpost-form.js. Mirrors the
   .portfolio-multi-image-container shape above but without the cover
   badge — all reference photos are equal-weight inspiration imagery.
   HR #2 (tokens only), #8 (≥44×44 remove), #10 (reduced-motion respect).
*/
.bidpost-reference-photo-container {
  display:        flex;
  flex-direction: column;
  gap:            var(--sp-2);
}
.bidpost-reference-photo-list {
  list-style: none;
  margin:     0;
  padding:    0;
  display:    grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap:        var(--sp-2);
}
.bidpost-reference-photo-list:empty {
  display: none;
}
.bidpost-reference-photo-item {
  position:       relative;
  border:         1px solid var(--n-200);
  border-radius:  var(--r-2);
  overflow:       hidden;
  aspect-ratio:   1 / 1;
  background:     var(--n-50);
  transition:     opacity var(--d-2) var(--ease-out-swift);
}
.bidpost-reference-photo-item__img {
  width:      100%;
  height:     100%;
  object-fit: cover;
  display:    block;
}
.bidpost-reference-photo-item__remove {
  position:       absolute;
  top:            var(--sp-1);
  right:          var(--sp-1);
  min-width:      44px;
  min-height:     44px;
  display:        inline-flex;
  align-items:    center;
  justify-content:center;
  background:     var(--n-900);
  color:          var(--n-0);
  border:         0;
  border-radius:  var(--r-pill);
  cursor:         pointer;
  opacity:        0.85;
  transition:     opacity var(--d-1) var(--ease-out-swift);
}
.bidpost-reference-photo-item__remove:hover,
.bidpost-reference-photo-item__remove:focus-visible {
  opacity: 1;
}
.bidpost-reference-photo-status {
  color:     var(--n-600);
  font-size: var(--fs-2);
}
.bidpost-reference-photo-status--error {
  color: var(--state-danger);
}
.bidpost-reference-photo-status--success {
  color: var(--state-success);
}

@media (prefers-reduced-motion: reduce) {
  .bidpost-reference-photo-item,
  .bidpost-reference-photo-item__remove {
    transition: none;
  }
}

/*
 * 2026-05-16 transaction-visibility-and-fulfillment Phase 6b — FilterAutocomplete
 * kit primitive. Custom ARIA combobox (WAI-ARIA 1.2) backed by a server endpoint
 * with prefix-match suggestion lookup. Replaces the Phase 5 admin-filter-typeahead
 * block (HTML5 <datalist>-backed) which did not paginate and was broken at scale.
 *
 * Hard rules in force:
 *   #1  Picked-state border is --state-info (teal), NOT green.
 *   #2  Tokens only — no raw hex.
 *   #3  Motion via tokens — no raw ms; --d-2 + --ease-out-swift.
 *   #4  Component renders via _FilterAutocomplete.cshtml; no inline style=.
 *   #8  Clear button + option rows ≥ 44×44px.
 *   #10 prefers-reduced-motion: reduce fallback on the mobile-modal transition.
 *
 * 11-state machine (per plan §Autocomplete State Machine):
 *   idle-empty / idle-prefilled / idle-prefilled-unresolved / focused-empty /
 *   typing-below-min / typing-loading / suggestion-open-with-results /
 *   suggestion-open-no-results / suggestion-open-error / picked /
 *   picked-then-edited / disabled.
 *
 * Companion JS: wwwroot/js/kit/filter-autocomplete.js.
 */
.filter-autocomplete {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 14rem;
  flex: 1 1 14rem;
}
.filter-autocomplete__label {
  font-family: var(--font-mono);
  font-size: var(--fs-1);
  color: var(--n-700);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.filter-autocomplete__field {
  position: relative;
  display: flex;
  align-items: stretch;
}
.filter-autocomplete__input {
  min-height: 44px;
  width: 100%;
  padding: 0 var(--sp-6) 0 var(--sp-2);  /* right padding reserves space for the clear glyph */
  font-family: var(--font-sans);
  font-size: var(--fs-2);
  color: var(--n-900);
  background: var(--n-0);
  border: 1px solid var(--n-200);
  border-radius: var(--r-2);
  transition: border-color var(--d-2) var(--ease-out-swift);
}
/* 2026-05-18 orders-list-and-guid-cleanup Phase 1 — native <select> control
   used by /admin/orders for Order Type + Payment Status. Mirrors the input
   visual treatment so the row reads as one cohesive control set; right
   padding is reduced (no clear glyph needed — the OS-supplied caret takes
   the right-edge slot). min-height enforces hard rule #8 touch target. */
.filter-autocomplete__select {
  min-height: 44px;
  width: 100%;
  padding: 0 var(--sp-2);
  font-family: var(--font-sans);
  font-size: var(--fs-2);
  color: var(--n-900);
  background: var(--n-0);
  border: 1px solid var(--n-200);
  border-radius: var(--r-2);
  transition: border-color var(--d-2) var(--ease-out-swift);
}
.filter-autocomplete__select:focus-visible {
  outline-offset: 0;
}
@media (prefers-reduced-motion: reduce) {
  .filter-autocomplete__select {
    transition: none;
  }
}
.filter-autocomplete__input::placeholder {
  color: var(--n-500);
}
.filter-autocomplete__input:focus-visible {
  /* Global :focus-visible ring on --brand-spark already applies. Override
     outline-offset to 0 so the ring hugs the rounded border. */
  outline-offset: 0;
}
/* Picked state — entity bound to hidden id field. Teal border (NEVER green;
   hard rule #1). State token --state-info matches the InfoPill / focus ring
   used elsewhere in the kit. */
.filter-autocomplete--picked .filter-autocomplete__input {
  border: 2px solid var(--state-info);
}
.filter-autocomplete--idle-prefilled .filter-autocomplete__input {
  border: 2px solid var(--state-info);
}
.filter-autocomplete--idle-prefilled-unresolved .filter-autocomplete__input {
  color: var(--n-500);
}
/* Disabled state — non-interactive while form submit is in flight. */
.filter-autocomplete--disabled .filter-autocomplete__input {
  background: var(--n-50);
  color: var(--n-500);
  pointer-events: none;
}

/* Search icon — decorative magnifying-glass affordance signalling "type to
   search" before the user discovers the typeahead. 2026-05-16 Phase 6c. The
   icon is display-only (aria-hidden on the partial; pointer-events: none here)
   so clicks pass through to the input. Sized 16×16 inside a 44×44 box that
   right-aligns within the input's reserved right padding (`var(--sp-6)` on
   .filter-autocomplete__input). Token-driven color: --n-500 default,
   transitions to --n-700 when the field gains focus. Hidden when the root
   carries any of the picked / idle-prefilled / idle-prefilled-unresolved
   modifiers — the × clear button takes the right-edge slot in those states. */
.filter-autocomplete__search-icon {
  position: absolute;
  right: 0;
  top: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  color: var(--n-500);
  pointer-events: none;
  transition: color var(--d-2) var(--ease-out-swift);
}
.filter-autocomplete__field:focus-within .filter-autocomplete__search-icon {
  color: var(--n-700);
}
.filter-autocomplete--picked .filter-autocomplete__search-icon,
.filter-autocomplete--idle-prefilled .filter-autocomplete__search-icon,
.filter-autocomplete--idle-prefilled-unresolved .filter-autocomplete__search-icon {
  display: none;
}

/* Clear button — only rendered while a hidden id is bound. Sized to the 44×44
   touch target. Positioned at the right edge inside the field via absolute. */
.filter-autocomplete__clear {
  position: absolute;
  right: 0;
  top: 0;
  display: none;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--n-700);
  cursor: pointer;
  font-size: var(--fs-3);
  line-height: 1;
}
.filter-autocomplete--picked .filter-autocomplete__clear,
.filter-autocomplete--idle-prefilled .filter-autocomplete__clear,
.filter-autocomplete--idle-prefilled-unresolved .filter-autocomplete__clear {
  display: inline-flex;
}
.filter-autocomplete__clear:focus-visible {
  outline-offset: -2px;
}
.filter-autocomplete__clear:hover {
  color: var(--n-900);
}

/* Listbox — suggestion panel. Hidden by default; the JS toggles aria-hidden
   + the --open modifier on the parent. */
.filter-autocomplete__listbox {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 50;
  margin: var(--sp-1) 0 0 0;
  padding: 0;
  list-style: none;
  background: var(--n-0);
  border: 1px solid var(--n-200);
  border-radius: var(--r-2);
  box-shadow: var(--shadow-2, 0 4px 16px rgba(0,0,0,0.08));
  max-height: 20rem;
  overflow-y: auto;
  opacity: 0;
  transform: translateY(-2px);
  pointer-events: none;
  transition: opacity var(--d-2) var(--ease-out-swift),
              transform var(--d-2) var(--ease-out-swift);
}
.filter-autocomplete--open .filter-autocomplete__listbox {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.filter-autocomplete__option {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: var(--sp-2);
  min-height: 44px;
  cursor: pointer;
  border-bottom: 1px solid var(--n-100);
}
.filter-autocomplete__option:last-child {
  border-bottom: 0;
}
.filter-autocomplete__option-name {
  font-size: var(--fs-2);
  color: var(--n-900);
}
.filter-autocomplete__option-secondary {
  font-size: var(--fs-1);
  color: var(--n-500);
}
.filter-autocomplete__option:hover {
  background: var(--n-50);
}
/* Active (keyboard-highlighted) row — distinct from hover. */
.filter-autocomplete__option--active,
.filter-autocomplete__option[aria-selected="true"] {
  background: var(--n-100);
}
/* Refine-row — non-clickable hint when hasMore=true. */
.filter-autocomplete__option--more {
  cursor: default;
  color: var(--n-500);
  font-size: var(--fs-1);
  background: var(--n-50);
}
.filter-autocomplete__option--more:hover {
  background: var(--n-50);
}
/* No-results / loading / error rows — single non-clickable row inside the
   listbox shell. Color tokens distinguish error from neutral states. */
.filter-autocomplete__status {
  padding: var(--sp-2);
  font-size: var(--fs-1);
  color: var(--n-500);
}
.filter-autocomplete__status--error {
  color: var(--state-danger);
}

/* Done button — hidden by default (desktop + mobile inline). Only the mobile
   fullscreen modal state surfaces the button (rule block below). 2026-05-16
   Phase 6b fix-cycle 1 (F-6b-R-02). */
.filter-autocomplete__mobile-done {
  display: none;
}

/* Mobile fullscreen modal — at <= 640px the autocomplete expands to fullscreen.
   Mirrors the _CmdK precedent's overlay structure. Reduced-motion snaps. */
@media (max-width: 640px) {
  .filter-autocomplete--mobile-modal {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: var(--n-0);
    padding: var(--sp-3);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
  }
  .filter-autocomplete--mobile-modal .filter-autocomplete__listbox {
    position: static;
    flex: 1 1 auto;
    margin-top: var(--sp-2);
    box-shadow: none;
    opacity: 1;
    transform: none;
    pointer-events: auto;
    max-height: none;
  }
  /* Visible only when the root has the modal class (toggled by JS on focus). */
  .filter-autocomplete--mobile-modal .filter-autocomplete__mobile-done {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    align-self: flex-end;
    min-width: 44px;
    min-height: 44px;
    padding: 0 var(--sp-3);
    background: var(--brand-ink);
    color: var(--n-0);
    border: 0;
    border-radius: var(--r-2);
    cursor: pointer;
  }
}

@media (prefers-reduced-motion: reduce) {
  .filter-autocomplete__listbox,
  .filter-autocomplete__input {
    transition: none;
  }
}

/* Row wrapper used by /admin/orders to lay out the 3 filter controls + Apply/Clear
   buttons below the FilterBar. Page-specific composition; CSS lives with the kit
   primitive so the spacing tokens stay consistent. */
.admin-filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  align-items: flex-end;
  margin-top: var(--sp-3);
  padding: var(--sp-3);
  background: var(--n-50);
  border: 1px solid var(--n-200);
  border-radius: var(--r-2);
}
.admin-filter-row__actions {
  display: flex;
  gap: var(--sp-2);
  flex: 0 0 auto;
  align-items: center;
  min-height: 44px;
}

/* ── Order Totals Block (admin Orders pre-table summary) ──────────────
   2026-05-18 orders-list-and-guid-cleanup Phase 2. Per-currency summary
   cards rendered above the _DataTable via the new ResourceListViewModel
   .PreTableContent slot. Tokens only — no raw hex, no raw ms.
   Reconciliation states use --state-success (teal) / --state-warn per
   hard rule #1. Radii reference the canonical --r-2 / --r-3 tokens from
   elfrique.css. No motion / no animations here — read-only summary block. */

.resource-list__pre-table {
  margin-top: var(--sp-3);
  margin-bottom: var(--sp-3);
}

.order-totals-block {
  display: block;
}
.order-totals-block__empty {
  padding: var(--sp-4);
  background: var(--n-50);
  border: 1px solid var(--n-200);
  border-radius: var(--r-2);
  text-align: center;
}
.order-totals-block__empty-text {
  margin: 0;
  color: var(--n-700);
  font-size: var(--fs-2);
}
.order-totals-block__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--sp-3);
}

.order-totals-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  background: var(--n-0);
  border: 1px solid var(--n-200);
  border-radius: var(--r-2);
}
.order-totals-card--ok {
  border-left: 4px solid var(--state-success);
}
.order-totals-card--mismatch {
  border-left: 4px solid var(--state-warn);
}

.order-totals-card__header {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.order-totals-card__currency {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-3);
  letter-spacing: 0.04em;
  color: var(--n-900);
}
.order-totals-card__gross {
  margin: 0;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-2);
}
.order-totals-card__gross-label {
  font-size: var(--fs-1);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--n-600);
}
.order-totals-card__gross-amount {
  font-size: var(--fs-4);
  font-weight: 600;
  color: var(--n-900);
  font-variant-numeric: tabular-nums;
}

.order-totals-card__buckets,
.order-totals-card__types {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.order-totals-card__bucket,
.order-totals-card__type-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-3);
  font-size: var(--fs-2);
}
.order-totals-card__bucket-label,
.order-totals-card__type-label {
  margin: 0;
  color: var(--n-700);
}
.order-totals-card__bucket-value,
.order-totals-card__type-value {
  margin: 0;
  color: var(--n-900);
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.order-totals-card__types {
  padding-top: var(--sp-2);
  border-top: 1px dashed var(--n-200);
}

.order-totals-card__footer {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--n-200);
}
.order-totals-card__scan {
  margin: 0;
  font-size: var(--fs-1);
  color: var(--n-600);
}
.order-totals-card__recon {
  margin: 0;
  font-size: var(--fs-1);
  font-variant-numeric: tabular-nums;
}
.order-totals-card__recon--ok {
  color: var(--state-success);
}
.order-totals-card__recon--mismatch {
  color: var(--state-warn);
}
