/* ============================================================
   Unoyah Component Library — components.css
   ------------------------------------------------------------
   Class-based components consuming ONLY tokens from
   colors_and_type.css (load that first). Every colour resolves
   through the semantic tier, so light + dark both work with no
   extra rules in this file — theme flips via the OS preference
   or an explicit data-theme="dark" / data-theme="light".

   Zero dependencies. Works offline from file://. RTL-safe: all
   flow-relative spacing uses CSS logical properties
   (padding-inline, margin-block, inset-inline, …).

   Behavioural pieces (<uno-modal>, <uno-tabs>, <uno-command>, …)
   live in unoyah-components.js and are styled by the sections at
   the bottom of this file. They are light-DOM elements, so these
   classes reach them directly.

   Load order:
     <link rel="stylesheet" href="../Colors%20and%20Type/colors_and_type.css">
     <link rel="stylesheet" href="../Components/components.css">
     <script src="../Components/unoyah-components.js" defer></script>
   ============================================================ */

/* ============================================================
   Focus — shared recipe from the token layer:
   1px solid --focus-ring-edge (carries WCAG 1.4.11 3:1) plus a
   4px soft --focus-ring glow (decorative). Transparent outline
   keeps a visible ring in Windows forced-colors mode.
   ============================================================ */
.u-btn:focus-visible,
.u-input:focus-visible,
.u-tab:focus-visible,
.u-sort-btn:focus-visible,
.u-cmd-item:focus-visible,
.u-toast-close:focus-visible,
.u-tooltip:focus-visible,
.u-sortable-list > *:focus-visible {
  outline: 2px solid transparent;
  outline-offset: 2px;
  box-shadow: 0 0 0 1px var(--focus-ring-edge), 0 0 0 4px var(--focus-ring);
}

.u-sort-btn {
  display: inline-flex;
  align-items: center;
  min-block-size: 48px;
}

/* ============================================================
   Buttons — .u-btn
   Variants: --primary --secondary --ghost --gold
   Sizes:    --sm (default md) --lg
   States:   :disabled / [aria-disabled] · .is-loading
   ============================================================ */
.u-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 48px;
  gap: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--btn-fs);
  font-weight: var(--btn-weight);
  line-height: var(--lh-snug);
  padding-block: var(--btn-pad-y);
  padding-inline: var(--btn-pad-x);
  border-radius: var(--btn-radius);
  border: 1px solid transparent;
  background: none;
  color: inherit;
  cursor: pointer;
  text-decoration: none;
  position: relative; /* anchors the .is-loading pixel-pulse */
  transition:
    background-color var(--dur-base) var(--ease-out),
    color            var(--dur-base) var(--ease-out),
    border-color     var(--dur-base) var(--ease-out),
    box-shadow       var(--dur-base) var(--ease-out),
    transform        var(--dur-fast) var(--ease-out);
}

.u-btn:not(:disabled):not([aria-disabled="true"]):active { transform: translateY(1px); }

/* Primary — petrol fill, white label. Brand fills stay constant in
   dark mode and keep --fg-on-brand (see colors_and_type.css). */
.u-btn--primary { background: var(--petrol); color: var(--fg-on-brand); box-shadow: var(--shadow-brand); }
.u-btn--primary:hover { background: var(--sapphire); }

/* Secondary — outlined on the current surface; headings colour.
   --field-border, NOT --line-2: this variant's fill IS --surface, i.e. exactly
   the card it sits on, so the 1px edge is the only thing that identifies the
   control and WCAG 1.4.11 puts it at 3:1. --line-2 is 1.53:1 and the token
   layer already labels it a decorative hairline. Same reasoning, and the same
   token, as --input-border on .u-input below. */
.u-btn--secondary { background: var(--surface); color: var(--brand-deep); border-color: var(--field-border); }
.u-btn--secondary:hover { border-color: var(--link); color: var(--link); }

/* Ghost — text-only; quiet tint on hover (info-bg = blue-50 light,
   deep navy tint dark, so the hover reads in both themes). */
.u-btn--ghost { background: transparent; color: var(--link); }
.u-btn--ghost:hover { background: var(--info-bg); }

/* Gold — special/rare. --gold-ink is REQUIRED on gold fills:
   white in light mode, dark ink in dark mode (AA both ways). */
.u-btn--gold { background: var(--gold); color: var(--gold-ink); font-weight: 700; }

/* Sizes */
.u-btn--sm { padding-block: 6px; padding-inline: 14px; font-size: var(--fs-xs); }
.u-btn--lg { padding-block: 14px; padding-inline: 28px; font-size: var(--fs-base); }

/* Disabled. NOTE :disabled and [aria-disabled] are NOT interchangeable —
   an aria-disabled control stays keyboard focusable, so the focus ring
   must survive this rule (which would otherwise win on source order). */
.u-btn:disabled,
.u-btn[aria-disabled="true"] {
  opacity: var(--opacity-disabled);
  cursor: not-allowed;
  box-shadow: none;
}
.u-btn[aria-disabled="true"]:focus-visible {
  box-shadow: 0 0 0 1px var(--focus-ring-edge), 0 0 0 4px var(--focus-ring);
}

/* Loading — the pixel-pulse spinner (logo motif: three rounded
   squares, see preview/24-states.html). The label goes transparent
   (layout is preserved, no width jump); the squares are drawn by the
   two pseudo-elements: ::before carries the OUTER PAIR via box-shadow
   (they pulse in unison), ::after the middle square, half a cycle out
   of phase. Two phases, not three — a box-shadow pair cannot carry
   independent delays. Static under reduced motion.

   ::after is shared with .u-tooltip, which owns it: a button that is
   both keeps its tip and draws all three squares from ::before. */
.u-btn.is-loading {
  color: transparent;
  pointer-events: none;
  cursor: progress;
}
.u-btn.is-loading::before,
.u-btn.is-loading:not(.u-tooltip)::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;               /* direction-neutral centering */
  inline-size: 8px;
  block-size: 8px;
  border-radius: 2px;         /* motif proportion: 1/4 of the square */
  animation: u-pixel-pulse 1.2s var(--ease-in-out) infinite;
}
.u-btn.is-loading::before {
  background: transparent;    /* squares live in the box-shadows */
  box-shadow: -14px 0 0 var(--brand), 14px 0 0 var(--brand-deep);
}
.u-btn.is-loading:not(.u-tooltip)::after { background: var(--link-hover); animation-delay: -0.6s; }
/* Filled variants: monochrome squares in the fill's ink colour. */
.u-btn--primary.is-loading::before { box-shadow: -14px 0 0 var(--fg-on-brand), 14px 0 0 var(--fg-on-brand); }
.u-btn--primary.is-loading:not(.u-tooltip)::after  { background: var(--fg-on-brand); }
.u-btn--gold.is-loading::before { box-shadow: -14px 0 0 var(--gold-ink), 14px 0 0 var(--gold-ink); }
.u-btn--gold.is-loading:not(.u-tooltip)::after  { background: var(--gold-ink); }
/* Tooltip + loading: three squares from ::before alone. */
.u-btn.u-tooltip.is-loading::before {
  box-shadow: -14px 0 0 var(--brand), 0 0 0 var(--link-hover), 14px 0 0 var(--brand-deep);
}
.u-btn--primary.u-tooltip.is-loading::before {
  box-shadow: -14px 0 0 var(--fg-on-brand), 0 0 0 var(--fg-on-brand), 14px 0 0 var(--fg-on-brand);
}
.u-btn--gold.u-tooltip.is-loading::before {
  box-shadow: -14px 0 0 var(--gold-ink), 0 0 0 var(--gold-ink), 14px 0 0 var(--gold-ink);
}

@keyframes u-pixel-pulse {
  0%, 100% { opacity: 0.25; }
  50%      { opacity: 1; }
}

/* ============================================================
   Spinner — .u-spinner (standalone pixel-pulse, 12px squares).
   Give it role="status" + aria-label="Loading" in markup.
   ============================================================ */
.u-spinner {
  display: inline-block;
  inline-size: 44px;  /* 3 × 12px squares + 2 × 4px gaps */
  block-size: 12px;
  position: relative;
}
.u-spinner::before,
.u-spinner::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  inline-size: 12px;
  block-size: 12px;
  border-radius: var(--radius-xs);
  animation: u-pixel-pulse 1.2s var(--ease-in-out) infinite;
}
.u-spinner::before {
  background: transparent;
  box-shadow: -16px 0 0 var(--brand), 16px 0 0 var(--brand-deep);
}
.u-spinner::after { background: var(--link-hover); animation-delay: -0.6s; }

/* ============================================================
   Forms — .u-label / .u-input / .u-help / .u-error
   Works on input, select and textarea (class the control).
   Invalid state binds to aria-invalid="true", so the visual and
   the announced state can never diverge.
   ============================================================ */
.u-label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--fg-muted);
  margin-block-end: var(--space-1);
}
.u-input {
  display: block;
  inline-size: 100%;
  min-block-size: 48px;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--ink);
  background: var(--surface);
  border: var(--input-border);       /* --field-border: 3:1 control boundary */
  border-radius: var(--input-radius);
  padding-block: var(--input-pad-y);
  padding-inline: var(--input-pad-x);
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.u-input::placeholder { color: var(--fg-soft); }
.u-input:focus-visible { border-color: var(--focus-ring-edge); }
.u-input:disabled { opacity: var(--opacity-disabled); cursor: not-allowed; }
textarea.u-input { min-block-size: 80px; resize: vertical; }
.u-input[aria-invalid="true"] { border-color: var(--danger); }
.u-input[aria-invalid="true"]:focus-visible {
  border-color: var(--danger);
  box-shadow: 0 0 0 1px var(--danger), 0 0 0 4px var(--danger-bg);
}

/* iOS zooms the viewport when a focused field is below 16px. The desktop
   density remains compact; touch-sized screens get a stable, readable field. */
@media (max-width: 768px) {
  .u-input { font-size: var(--fs-base); }
}
.u-help {
  font-size: var(--fs-xs);
  color: var(--fg-soft);
  margin-block-start: var(--space-1);
}
.u-error {
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--danger);
  margin-block-start: var(--space-1);
}

/* ============================================================
   Card — .u-card (+ -header / -body / -footer)
   ============================================================ */
.u-card {
  background: var(--surface);
  border: var(--card-border);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
}
.u-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-4);
  padding-inline: var(--space-5);
  border-block-end: 1px solid var(--line);
}
.u-card-body {
  padding-block: var(--space-5);
  padding-inline: var(--space-5);
}
.u-card-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding-block: var(--space-4);
  padding-inline: var(--space-5);
  border-block-start: 1px solid var(--line);
  background: var(--bg-soft);
  border-end-start-radius: calc(var(--card-radius) - 1px);
  border-end-end-radius: calc(var(--card-radius) - 1px);
}

/* ============================================================
   Badge — .u-badge (semantic variants)
   GEOMETRY matches the badge spec card, preview/16-badges.html:
   4px/10px padding on a --radius-pill silhouette. The pill (not
   the 6px --chip-radius) is what three of the four badge surfaces
   in this system draw — 16-badges, the card pill in 15-cards and
   the marketing .dash-pill. --chip-radius stays the SQUARE chip
   token (.u-step-dot, .dash-tabs); reshaping it would have
   flattened those too.
   VARIANTS: success/warning/danger/info/neutral come from the
   semantic tier (16-badges reaches for the primitives --surface-3
   /--ink-2 for neutral; the resolved colour is the same, but the
   semantic pair is the one that survives a theme flip). --brand is
   16-badges' navy "Foundational" badge; --gold is library-only.
   ============================================================ */
.u-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: var(--lh-snug);
  padding-block: var(--space-1);
  padding-inline: 10px;
  border-radius: var(--radius-pill);
}
.u-badge--success { background: var(--success-bg); color: var(--success); }
.u-badge--warning { background: var(--warning-bg); color: var(--warning); }
.u-badge--danger  { background: var(--danger-bg);  color: var(--danger); }
.u-badge--info    { background: var(--info-bg);    color: var(--info); }
.u-badge--neutral { background: var(--bg-quiet);   color: var(--fg-muted); }
/* Brand badge: navy fill keeps --fg-on-brand in BOTH themes. */
/* --brand-fg, NOT --fg-on-brand. --fg-on-brand is a constant white, correct on
   fills that never change (--navy, --petrol). --brand-deep is not one of those:
   it flips to #C8E4EB in dark, and white on it is 1.33:1. --brand-fg is the
   theme-aware ink for brand fills -- white in light, #0F1526 in dark (13.63:1),
   which is what the token's own comment says it exists for. */
.u-badge--brand   { background: var(--brand-deep); color: var(--brand-fg); }
/* Gold badge: --gold-ink required (white light / dark ink dark). */
.u-badge--gold    { background: var(--gold);       color: var(--gold-ink); }

/* ============================================================
   Table — .u-table
   Every <th> MUST carry scope="col" (or scope="row" for row
   headers) — screen readers need it to associate cells.
   Sticky header is opt-in: wrap in .u-table-scroll and add
   .u-table--sticky to the table.
   ============================================================ */
.u-table {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.u-table caption {
  text-align: start;
  font-size: var(--fs-xs);
  color: var(--fg-soft);
  padding-block-end: var(--space-2);
}
.u-table th {
  text-align: start;
  font-weight: 600;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-soft);
  background: var(--bg-soft);
  padding-block: 10px;
  padding-inline: var(--space-3);
  border-block-end: 1.5px solid var(--brand-deep);
}
.u-table td {
  padding-block: 10px;
  padding-inline: var(--space-3);
  border-block-end: 1px solid var(--line); /* decorative hairline; swap for
    var(--line-accessible) when the rules must be perceivable (dense data) */
  color: var(--ink);
}
.u-table tbody tr:last-child td { border-block-end: none; }
.u-table .is-num { font-family: var(--font-mono); color: var(--fg-muted); text-align: end; }
.u-table-scroll {
  max-block-size: 320px;
  overflow: auto;
  border: var(--card-border);
  border-radius: var(--radius-md);
}
.u-table--sticky thead th {
  position: sticky;
  inset-block-start: 0;
  z-index: 1; /* th background is opaque (--bg-soft), rows scroll under */
}

/* ============================================================
   Alert — .u-alert (4 semantics)
   ROLE GUIDANCE (set in markup, not here):
     info / success  → role="status"  (polite; does not interrupt)
     warning / danger → role="alert"  (assertive; interrupts — use
                        only for things the user must act on now)
   Static alerts that are present at page load need no role.
   ============================================================ */
.u-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding-block: var(--space-3);
  padding-inline: var(--space-4);
  border-radius: var(--radius-md);
  border-inline-start: 4px solid;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--ink);
}
.u-alert--info    { background: var(--info-bg);    border-color: var(--info); }
.u-alert--success { background: var(--success-bg); border-color: var(--success); }
.u-alert--warning { background: var(--warning-bg); border-color: var(--warning); }
.u-alert--danger  { background: var(--danger-bg);  border-color: var(--danger); }
.u-alert-title { font-weight: 600; }
.u-alert--info    .u-alert-title { color: var(--info); }
.u-alert--success .u-alert-title { color: var(--success); }
.u-alert--warning .u-alert-title { color: var(--warning); }
.u-alert--danger  .u-alert-title { color: var(--danger); }

/* ============================================================
   Tooltip — .u-tooltip (CSS-only)
   Put the class ON the focusable trigger (button/a) and the text
   in data-tip. Shows on :hover and :focus-visible — never on
   plain :focus, so mouse clicks don't strand a tooltip open.
   A11Y: attr() content is not reliably exposed to AT — the tip
   must be supplementary. If it carries real information, mirror
   it via aria-label or an aria-describedby target.
   Inverted bubble: --ink on --bg flips with the theme.
   ============================================================ */
.u-tooltip { position: relative; }
.u-tooltip::after {
  content: attr(data-tip);
  position: absolute;
  inset-block-end: calc(100% + var(--space-2));
  left: 50%;                       /* physical centering is direction-neutral */
  transform: translateX(-50%);
  background: var(--ink);
  color: var(--bg);
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: var(--lh-snug);
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  padding-block: var(--space-1);
  padding-inline: var(--space-2);
  border-radius: var(--radius-xs);
  box-shadow: var(--shadow-md);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-out), visibility var(--dur-fast) var(--ease-out);
  z-index: 30;
}
.u-tooltip:hover::after,
.u-tooltip:focus-visible::after,
.u-tooltip:has(:focus-visible)::after {
  opacity: 1;
  visibility: visible;
}

/* ============================================================
   Empty state — .u-empty
   Pattern from preview/24-states.html: eyebrow + one line +
   action, no icon.
   ============================================================ */
.u-empty {
  background: var(--bg-soft);
  border: var(--card-border);
  border-radius: var(--card-radius);
  padding-block: var(--space-6);
  padding-inline: var(--space-5);
  text-align: center;
}
.u-empty-text {
  margin-block: var(--space-2) var(--space-3);
  font-size: var(--fs-sm);
  color: var(--fg-muted);
  line-height: var(--lh-normal);
}

/* ============================================================
   Skeleton — .u-skeleton (reduced-motion safe)
   Defaults to one text line; size it with inline-size/block-size.
   Mark the loading REGION aria-busy="true" and hide skeletons
   from AT (aria-hidden="true") — they are purely visual.
   ============================================================ */
.u-skeleton {
  display: block;
  block-size: 1em;
  border-radius: var(--radius-xs);
  background: linear-gradient(90deg, var(--bg-quiet) 25%, var(--bg-soft) 50%, var(--bg-quiet) 75%);
  background-size: 200% 100%;
  animation: u-shimmer 1.4s linear infinite;
}
.u-skeleton--circle {
  border-radius: var(--radius-pill);
  aspect-ratio: 1;
  block-size: auto;
}
@keyframes u-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

/* ============================================================
   Brand-fill ink — correction for .u-brand-gradient
   ------------------------------------------------------------
   --brand-gradient is CONSTANT across themes (petrol → navy), so
   its label must be too. colors_and_type.css pairs it with
   --brand-fg, and --brand-fg flips to dark ink in dark mode:
   3.12:1 at the petrol stop and 1.60:1 at the navy stop — the
   right half of the panel is unreadable. --fg-on-brand is the
   token for "ink that sits on a brand fill in both themes"
   (white → 5.83:1 petrol / 11.39:1 navy).
   ============================================================ */
.u-brand-gradient { color: var(--fg-on-brand); }

/* ============================================================
   Visually hidden — .u-visually-hidden
   For screen-reader-only text (live regions, instructions).
   ============================================================ */
.u-visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   ============================================================
   Styles for the unoyah-components.js custom elements
   (light-DOM, so plain classes reach them)
   ============================================================
   ============================================================ */

/* ----- <uno-toast-host> + UnoToast.show() ------------------- */
uno-toast-host {
  position: fixed;
  inset-block-end: var(--space-6);
  inset-inline-end: var(--space-6);
  display: grid;
  gap: var(--space-3);
  justify-items: end;
  z-index: 120;
}
.u-toast {
  align-items: center;
  box-shadow: var(--shadow-lg);
  max-inline-size: 340px;
  animation: u-toast-in var(--dur-slow) var(--ease-out);
}
.u-toast-msg { flex: 1; }
.u-toast-close {
  appearance: none;
  background: none;
  border: none;
  color: inherit;
  font-size: var(--fs-base);
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: var(--radius-xs);
  margin-inline-start: var(--space-2);
}
@keyframes u-toast-in {
  from { opacity: 0; translate: 0 8px; }
}

/* ----- <uno-modal> ------------------------------------------ */
uno-modal { display: none; }
uno-modal[open] {
  display: grid;
  place-items: center;
  position: fixed;
  inset: 0;
  z-index: 100;
  padding: var(--space-6);
  /* Fallback FIRST: without color-mix() support the declaration is dropped
     and the scrim would be transparent — no dim layer, no signal of
     modality. The two values are the same navy at 55%. */
  background: rgba(1, 55, 125, 0.55);
  background: color-mix(in srgb, var(--navy) 55%, transparent);
  -webkit-backdrop-filter: blur(var(--blur-sm));
  backdrop-filter: blur(var(--blur-sm));
}
.u-modal-panel {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-6);
  inline-size: 100%;
  max-inline-size: 440px;
  max-block-size: 100%;
  overflow: auto;
  animation: u-modal-in var(--dur-base) var(--ease-out);
}

@keyframes u-modal-in {
  from { opacity: 0; scale: 0.96; }
}

/* ----- <uno-tabs> ------------------------------------------- */
uno-tabs { display: block; }
.u-tabs-list {
  display: flex;
  gap: var(--space-1);
  border-block-end: 1px solid var(--line);
}
.u-tab {
  appearance: none;
  background: none;
  border: none;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--fg-muted);
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
  cursor: pointer;
  border-start-start-radius: var(--radius-xs);
  border-start-end-radius: var(--radius-xs);
  transition: color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.u-tab:hover { color: var(--link); }
.u-tab[aria-selected="true"] {
  color: var(--link);
  border-block-end-color: var(--brand);
  font-weight: 600;
}
uno-tabs [role="tabpanel"] { padding-block: var(--space-4); }

/* ----- <uno-stepper> ---------------------------------------- */
uno-stepper { display: block; }
.u-steps {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  list-style: none;
  margin-block: 0 var(--space-4);
  margin-inline: 0;
  padding: 0;
}
.u-step {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-xs);
  color: var(--fg-soft);
}
.u-step-dot {
  display: inline-grid;
  place-items: center;
  inline-size: 24px;
  block-size: 24px;
  border-radius: var(--radius-sm); /* pixel-square motif */
  background: var(--bg-quiet);
  color: var(--fg-muted);
  font-weight: 600;
}
.u-step.is-current { color: var(--fg); font-weight: 600; }
.u-step.is-current .u-step-dot { background: var(--brand); color: var(--brand-fg); }
.u-step.is-done .u-step-dot { background: var(--success-bg); color: var(--success); }
/* The JS toggles [hidden]; !important so an author's display rule on
   steps/panels can never resurrect an inactive one. */
uno-stepper > [data-step][hidden],
uno-tabs [role="tabpanel"][hidden],
.u-cmd-item[hidden] { display: none !important; }

/* ----- <uno-command> ---------------------------------------- */
uno-command {
  display: block;
  background: var(--surface);
  border: var(--card-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: var(--space-2);
}
.u-cmd-input { margin-block-end: var(--space-2); }
.u-cmd-list {
  display: grid;
  gap: 2px;
  max-block-size: 220px;
  overflow: auto;
}
.u-cmd-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  appearance: none;
  background: none;
  border: none;
  text-align: start;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--fg);
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.u-cmd-item:hover { background: var(--bg-soft); }
/* NOTE no `.u-cmd-item[hidden] { display: none }` here — the grouped
   !important rule in the <uno-stepper> section above already owns it, and a
   second declaration would be dead code that invites a phantom "fix". */
.u-cmd-kbd {
  margin-inline-start: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-soft);
  background: var(--bg-soft);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  padding-block: 1px;
  padding-inline: var(--space-1);
}
.u-cmd-empty {
  font-size: var(--fs-sm);
  color: var(--fg-soft);
  padding: var(--space-3);
  text-align: center;
}

/* ----- <uno-sort-table> ------------------------------------- */
uno-sort-table { display: block; }
.u-sort-btn {
  appearance: none;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  border-radius: var(--radius-xs);
}
th[aria-sort] .u-sort-btn::after { content: "\2195"; opacity: 0.45; }
th[aria-sort="ascending"] .u-sort-btn::after { content: "\2191"; opacity: 1; }
th[aria-sort="descending"] .u-sort-btn::after { content: "\2193"; opacity: 1; }

/* ----- <uno-datepicker> ------------------------------------- */
/* Deliberately a thin wrapper: the inner control is the NATIVE
   input[type=date], styled with .u-input. See the JS for why. */
uno-datepicker { display: block; }

/* ----- <uno-sortable> --------------------------------------- */
uno-sortable { display: block; }
.u-sortable-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-2);
}
.u-sortable-list > * {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--surface);
  border: var(--card-border);
  border-radius: var(--radius-sm);
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  font-size: var(--fs-sm);
  cursor: grab;
}
.u-sortable-list > *::before { content: "\2261"; color: var(--fg-soft); } /* ≡ grip, decorative */
/* Without a <ul>/<ol> the host IS the list, so the JS-injected screen-reader
   instructions land among the items. They are not an item: no grip glyph, or
   the ≡ is read out at the head of every item's description. */
.u-sortable-list > .u-sortable-help::before { content: none; }
.u-sortable-list > .is-dragging { opacity: var(--opacity-muted); border-style: dashed; }
/* Grabbed is ADDITIVE — the item is grabbed and :focus-visible for the whole
   keyboard reorder, so this must not replace the focus ring. */
.u-sortable-list > .is-grabbed { border-color: var(--brand); box-shadow: var(--shadow-md); }
.u-sortable-list > .is-grabbed:focus-visible {
  box-shadow: 0 0 0 1px var(--focus-ring-edge), 0 0 0 4px var(--focus-ring), var(--shadow-md);
}

/* ============================================================
   Reduced motion — every animated piece in this file degrades
   to a static, fully-legible state.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .u-btn.is-loading::before,
  .u-btn.is-loading:not(.u-tooltip)::after,
  .u-spinner::before,
  .u-spinner::after {
    animation: none;
    opacity: 1;
  }
  .u-skeleton { animation: none; background: var(--bg-quiet); }
  .u-toast, .u-modal-panel { animation: none; }
  .u-btn, .u-input, .u-tab, .u-tooltip::after { transition: none; }
}
