/* =========================================================================
   components.css — Shared component vocabulary
   iDev Digital Library Portal — Wireframe Pack v2 ("refined institutional")

   Implements every class in contract §4.2 (surfaces), §4.3 (controls),
   §4.4 (data display) and §4.5 (feedback). 56 screens are written
   against exactly this vocabulary — nothing here may be renamed.

   v2 craft rules:
   - Controls sit on the --ctl-h-* height rhythm and the --r-sm radius;
     cards and wraps use --r-md/--r-lg. Nothing is generically round.
   - Every interactive element has considered rest / hover / active /
     focus-visible / disabled states. Focus rings come from --focus-ring
     and are never removed without an equivalent indicator.
   - Numerals are tabular wherever values are compared (tables, stats,
     counts, pagination, kv values, steps).
   - Elevation is near-subliminal: --shadow-xs on controls and wraps,
     --shadow-sm on cards, --shadow-md on menus, --shadow-lg on overlays.

   RTL policy: logical properties only. Direction-encoding icons carry
   .icon--dirflip; charts/progress/timelines fill from the inline start
   and therefore mirror by construction.

   Percentage-driven visuals use unitless custom properties set inline:
     .bar        style="--v:64"   (0–100, column height)
     .progress   style="--p:64"   (0–100, fill)
     .meter      style="--p:64"   (0–100, fill; colour via --meter-c)
     .donut      style="--p:64"   (0–100, ring sweep; colour via --donut-c)

   Structure:
     1.  Icons
     2.  Surfaces        card / panel / section / toolbar / well
     3.  Buttons         btn (+8 modifiers), btn-group
     4.  Forms           field, input/select/textarea, checkbox/radio,
                         switch, searchbar
     5.  Navigation      tabs, chips, pagination, dropdown/menu,
                         breadcrumbs
     6.  Tables & lists  table, list, kv
     7.  Indicators      badge, stat, avatar, progress, meter
     8.  Charts          chart-bars, chart-line, donut, sparkline
     9.  Structure viz   tree, stepper, timeline, facet
     10. Feedback        alert, empty, skeleton, note
     11. Overlays        modal, drawer, toast
     12. Density (v2)    disclosure, rail, seg/viewmode
     13. Hints (v2)      hint, hint-pop
     14. Typeahead (v2)  ac, ac-group, ac-item
   ========================================================================= */

/* ------------------------------------------------------------------ */
/* 1. Icons                                                           */
/*    icons.js swaps <i class="icon" data-icon="…"> for an inline     */
/*    <svg class="icon">. Both forms get identical sizing. Icons are  */
/*    1em squares drawn in currentColor.                              */
/* ------------------------------------------------------------------ */

.icon {
  display: inline-block;
  inline-size: 1em;
  block-size: 1em;
  vertical-align: -0.125em;
  flex: none;
  fill: currentColor;
}

.icon > svg {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  fill: currentColor;
}

/* Direction-encoding icons (chevrons, back/next arrows) mirror under
   RTL. This is the one sanctioned [dir] hook in the pack (§5.3). */
[dir="rtl"] .icon--dirflip {
  transform: scaleX(-1);
}

/* ------------------------------------------------------------------ */
/* 2. Surfaces                                                        */
/*    The layer system: page ground (--bg) → raised surface (.card,   */
/*    .panel, .toolbar on --surface + hairline + --shadow-sm/xs) →    */
/*    sunken well (.well on --bg-sunken). Separation comes from 1px   */
/*    hairlines and luminance, never from loud shadows.               */
/* ------------------------------------------------------------------ */

/* -- Card ---------------------------------------------------------- */

.card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}

/* Internal rhythm: the head is a compact strip, the body carries the
   reading padding, the foot is a quiet recessed bar. */
.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-3);
  padding-block: var(--sp-3);
  padding-inline: var(--sp-4);
  border-block-end: var(--border-w) solid var(--border);
  min-block-size: var(--ctl-h-lg);
}

.card-title {
  /* v3: was --fs-md, i.e. exactly body size, so a card's title carried no
     more weight than the sentence under it and every region on a page
     read as equally important. One clear step up is the cheapest
     hierarchy available and it costs no vertical space worth having. */
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-heading);
  letter-spacing: var(--tracking-tight-2);
  color: var(--text);
}

.card-sub {
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

.card-body {
  flex: 1 1 auto;
  padding-block: var(--sp-4);
  padding-inline: var(--sp-4);
}

.card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-block: var(--sp-2);
  padding-inline: var(--sp-4);
  border-block-start: var(--border-w) solid var(--border);
  background: var(--surface-2);
  border-end-start-radius: inherit;
  border-end-end-radius: inherit;
  min-block-size: var(--ctl-h-lg);
}

/* Flat: hairline only, for nesting inside other surfaces. */
.card--flat {
  box-shadow: none;
}

/* Accent: brand keyline along the block-start edge. */
/* The signature of the v3 language: a ruled margin.
   A tenant-coloured keyline on the card's INLINE-START edge — the ruled
   margin of a manuscript page, the coloured tab of a catalogue divider.
   It earns its place three times over: it marks which surface on a screen
   is the primary one (v2 gave every card identical weight); it is the one
   place the tenant's own colour appears on every screen, so the
   white-label mechanism is visible rather than merely claimed; and being
   logical rather than physical, it mirrors to the right-hand edge in
   Arabic with no conditional rule anywhere.

   Reserved for the PRIMARY surface on a screen. Applied to everything it
   stops meaning anything. */
.card--accent {
  border-inline-start: 3px solid var(--primary);
  box-shadow: var(--shadow-md);
}

/* -- Panel — lightweight bordered box, no head/body anatomy. -------- */

.panel {
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-md);
  padding-block: var(--sp-4);
  padding-inline: var(--sp-4);
  box-shadow: var(--shadow-xs);
}

/* -- Section — a titled page region. ------------------------------- */

/* Vertical rhythm. v2 separated everything by the same ~24px, which is a
   large part of why the pack read as flat: when every gap is equal no
   grouping is visible and the eye has nothing to hold on to. The rhythm
   now STEPS — a section is separated from its neighbour by far more than
   its own parts are separated from each other, so grouping is legible
   before a single word is read.

   Applied as padding rather than margin because sections sit inside flex
   .stack containers whose gap would compound with a margin and produce a
   different rhythm on every screen. */
.section {
  padding-block: var(--sp-8);
}

/* Consecutive sections take the full step. The first in a column does not
   need a lead-in it already has from the page header. */
.section + .section {
  padding-block-start: var(--sp-12);
}

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-block-end: var(--sp-6);
}

.section-title {
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-tight-2);
  line-height: var(--lh-heading);
  color: var(--text);
}

.section-sub {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* -- Toolbar — filter/action strip above tables and lists. --------- */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  padding-block: var(--sp-2);
  padding-inline: var(--sp-2);
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-xs);
}

/* -- Well — recessed area for secondary/inline content. ------------ */

.well {
  background: var(--bg-sunken);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-md);
  padding-block: var(--sp-4);
  padding-inline: var(--sp-4);
}

/* ------------------------------------------------------------------ */
/* 3. Buttons                                                         */
/*    Height rhythm: sm 24 / md 32 / lg 40 (--ctl-h-*). Radius --r-sm.*/
/*    Icon + label alignment relies on flex gap (never margins), so   */
/*    it is correct in RTL with no overrides.                         */
/* ------------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding-block: 0;
  padding-inline: var(--sp-3);
  min-block-size: var(--ctl-h-md);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  line-height: 1.2;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  box-shadow: var(--shadow-xs);
  transition: background var(--t-fast), border-color var(--t-fast),
              color var(--t-fast), box-shadow var(--t-fast);
}

.btn:hover {
  background: var(--surface-hover);
  border-color: var(--text-faint);
  text-decoration: none;
}

/* Pressed: the surface darkens and the control loses its lift — depth
   change, not position change (no translate: it blurs the label). */
.btn:active {
  background: var(--surface-2);
  box-shadow: none;
}

.btn:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 2px;
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  box-shadow: none;
  pointer-events: none;
}

.btn .icon {
  font-size: 1.05em;
  color: var(--text-muted);
}

/* Modifier 1/8 — primary action. Navy fill with a hairline inner
   highlight so it reads machined rather than flat-painted. */
.btn--primary {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--primary-fg);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10), var(--shadow-xs);
}

.btn--primary:hover {
  background: var(--primary-hover);
  border-color: var(--primary-hover);
}

.btn--primary:active {
  background: var(--primary-hover);
  box-shadow: none;
}

.btn--primary .icon {
  color: inherit;
}

/* Modifier 2/8 — ghost: borderless, quiet. */
.btn--ghost {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  color: var(--text-muted);
}

.btn--ghost:hover {
  background: var(--surface-2);
  border-color: transparent;
  color: var(--text);
}

.btn--ghost:active {
  background: var(--bg-sunken);
}

/* Modifier 3/8 — destructive. Text colour uses --surface so it stays
   readable on the solid status fill in both themes. */
.btn--danger {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--surface);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10), var(--shadow-xs);
}

.btn--danger:hover {
  background: var(--danger-hover);
  border-color: var(--danger-hover);
}

.btn--danger:active {
  background: var(--danger-hover);
  box-shadow: none;
}

.btn--danger .icon {
  color: inherit;
}

/* Modifier 4/8 — subtle: brand-tinted secondary. Ink role, so it uses
   --primary-ink (tokens.css §3) and stays AA in dark tenants. */
.btn--subtle {
  background: var(--primary-soft);
  border-color: transparent;
  box-shadow: none;
  color: var(--primary-ink);
}

.btn--subtle:hover {
  background: var(--primary-soft);
  border-color: var(--primary-ink);
}

.btn--subtle:active {
  border-color: var(--primary-ink);
  box-shadow: inset 0 1px 2px rgba(20, 28, 43, 0.08);
}

.btn--subtle .icon {
  color: inherit;
}

/* Modifier 5/8 — small. */
.btn--sm {
  min-block-size: var(--ctl-h-sm);
  padding-inline: var(--sp-2);
  font-size: var(--fs-xs);
}

/* Modifier 6/8 — large. */
.btn--lg {
  min-block-size: var(--ctl-h-lg);
  padding-inline: var(--sp-5);
  font-size: var(--fs-md);
  border-radius: var(--r-md);
}

/* Modifier 7/8 — icon-only square. Pair with aria-label. */
.btn--icon {
  inline-size: var(--ctl-h-md);
  padding-inline: 0;
}

.btn--icon.btn--sm {
  inline-size: var(--ctl-h-sm);
}

.btn--icon.btn--lg {
  inline-size: var(--ctl-h-lg);
}

/* Modifier 8/8 — full-width. */
.btn--block {
  display: flex;
  inline-size: 100%;
}

/* -- Button group — fused segments, logical corner radii. ---------- */

.btn-group {
  display: inline-flex;
}

.btn-group .btn {
  border-radius: 0;
}

.btn-group .btn:first-child {
  border-start-start-radius: var(--r-sm);
  border-end-start-radius: var(--r-sm);
}

.btn-group .btn:last-child {
  border-start-end-radius: var(--r-sm);
  border-end-end-radius: var(--r-sm);
}

.btn-group .btn + .btn {
  margin-inline-start: calc(var(--border-w) * -1);
}

.btn-group .btn:hover,
.btn-group .btn:focus-visible {
  position: relative;
  z-index: 1;
}

/* ------------------------------------------------------------------ */
/* 4. Forms                                                           */
/* ------------------------------------------------------------------ */

/* -- Field wrapper: label / control / hint / error. ---------------- */

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

.field-label {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text);
}

.field-hint {
  font-size: var(--fs-xs);
  color: var(--text-faint);
}

.field-error {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--danger);
}

/* Inline variant — label sits beside the control (settings rows). */
.field--inline {
  flex-direction: row;
  align-items: center;
  gap: var(--sp-3);
}

.field--inline .field-label {
  flex: none;
}

/* -- Text controls ------------------------------------------------- */

.input,
.select,
.textarea {
  inline-size: 100%;
  padding-block: var(--sp-1);
  padding-inline: var(--sp-3);
  background: var(--surface);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: var(--fs-sm);
  line-height: 1.4;
  box-shadow: var(--shadow-xs);
  transition: border-color var(--t-fast), box-shadow var(--t-fast),
              background var(--t-fast);
}

.input,
.select {
  min-block-size: var(--ctl-h-md);
}

.textarea {
  min-block-size: 88px;
  padding-block: var(--sp-2);
  resize: vertical;
}

.input:hover,
.select:hover,
.textarea:hover {
  border-color: var(--text-faint);
}

/* Focus. Never remove the ring without an equivalent replacement
   (base.css §3). A --primary-tinted halo is NOT an equivalent: it is
   decoration, not an indicator — --primary-soft measures ~1.2:1 against
   --surface and even the --primary border swap is only ~2.45:1 in qasr
   dark, both well under the 3:1 that WCAG 1.4.11 requires of a focus
   indicator. So the ring is drawn from --focus-ring (tokens.css §3/§4:
   the navy ink in light, the pale brand ink in dark — high-contrast in
   every theme and tenant). Surfaces that invert their ink (.toast, §11)
   re-point --focus-ring rather than inheriting a ring tuned for
   --surface. The brand cue survives as the border colour plus a 2px
   halo that exactly fills the outline offset; neither is load-bearing. */
.input:focus,
.select:focus,
.textarea:focus {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 2px;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--primary-soft);
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  background: var(--bg-sunken);
  color: var(--text-faint);
  box-shadow: none;
  cursor: not-allowed;
}

/* Invalid — via aria-invalid (preferred) or .is-invalid on the field. */
.input[aria-invalid="true"],
.select[aria-invalid="true"],
.textarea[aria-invalid="true"],
.field.is-invalid .input,
.field.is-invalid .select,
.field.is-invalid .textarea {
  border-color: var(--danger);
}

/* Invalid + focused: the halo turns danger-tinted, but the ring itself
   stays --focus-ring — the halo carries meaning, the ring carries
   visibility, and swapping the ring to --danger would put us back under
   3:1. (.select variants added so this matches the border rule above,
   which already covered them.) */
.input[aria-invalid="true"]:focus,
.select[aria-invalid="true"]:focus,
.textarea[aria-invalid="true"]:focus,
.field.is-invalid .input:focus,
.field.is-invalid .select:focus,
.field.is-invalid .textarea:focus {
  outline-color: var(--focus-ring, var(--text));
  box-shadow: 0 0 0 2px var(--danger-soft);
}

/* Native select keeps its built-in indicator (it mirrors in RTL for
   free); we only normalise the box. */
.select {
  cursor: pointer;
}

/* -- Checkbox / radio — label wrappers around native inputs, tinted
      via accent-color so states and RTL come from the platform. ----- */

.checkbox,
.radio {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--text);
  cursor: pointer;
}

.checkbox input,
.radio input {
  inline-size: 16px;
  block-size: 16px;
  margin-block-start: 0.2em;
  accent-color: var(--primary);
  flex: none;
  cursor: pointer;
}

.checkbox input:focus-visible,
.radio input:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 2px;
}

.checkbox input:disabled,
.radio input:disabled {
  cursor: not-allowed;
}

.checkbox:has(input:disabled),
.radio:has(input:disabled) {
  color: var(--text-faint);
  cursor: not-allowed;
}

/* -- Switch -------------------------------------------------------- */
/* Markup: <label class="switch"><input type="checkbox"></label>
   (optionally followed by a text label outside the .switch).
   Track and knob are pseudo-elements; knob travel uses
   inset-inline-start so it mirrors in RTL with no overrides.

   WCAG 1.4.11: off/on is carried entirely by the track fill and the knob
   position — no text, no icon — so both the track and the knob have to be
   perceivable in every state. Two things buy that:
     Fill  — the OFF track is --border-strong, which carries a 3:1 floor
             against every surface role AND against the white knob
             (3.54:1 light / 4.66:1 dark). It is the same token .btn and
             .input use for exactly the same reason.
     Ring  — the track also outlines itself, so its boundary never depends
             on the fill. This is what the ON state needs: --primary is a
             fill role and is only required to clear 4.5:1 against
             --primary-fg, so on a dark page it drops to 2.18–2.83:1
             against the surface behind it (worst case dark qasr on
             --surface-2). The ring holds that edge at >= 3.05:1 for every
             theme x tenant x surface combination.
   The ring is deliberately the same colour as the OFF fill, so it is
   invisible until the track is filled with --primary. */

.switch {
  --sw-w: 36px;
  --sw-h: 20px;
  position: relative;
  display: inline-block;
  inline-size: var(--sw-w);
  block-size: var(--sw-h);
  flex: none;
  cursor: pointer;
}

.switch input {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.switch::before {
  /* Track — recessed, with a hairline so it reads as a slot. The hairline
     is also the accessible boundary of the control (see contract above). */
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--r-full);
  background: var(--border-strong);
  box-shadow:
    inset 0 1px 2px rgba(20, 28, 43, 0.10),
    inset 0 0 0 var(--border-w) var(--border-strong);
  transition: background var(--t-fast);
}

.switch::after {
  /* Knob — travels along the inline axis. */
  content: "";
  position: absolute;
  inset-block-start: 2px;
  inset-inline-start: 2px;
  inline-size: calc(var(--sw-h) - 4px);
  block-size: calc(var(--sw-h) - 4px);
  border-radius: 50%;
  background: var(--primary-fg);
  box-shadow: var(--shadow-sm);
  transition: inset-inline-start var(--t-fast);
}

/* Hover darkens the OFF fill in light and lifts it in dark; both keep the
   knob above 3:1 (5.19:1 / 3.15:1), so the state survives the hover. */
.switch:hover::before {
  background: var(--text-faint);
}

.switch:has(input:checked)::before {
  background: var(--primary);
}

.switch:has(input:checked):hover::before {
  background: var(--primary-hover);
}

.switch:has(input:checked)::after {
  inset-inline-start: calc(var(--sw-w) - var(--sw-h) + 2px);
}

/* The real <input> is transparent, so the track stands in for it and
   must draw the ring itself — same --focus-ring contract as .input. */
.switch:has(input:focus-visible)::before {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 2px;
}

.switch:has(input:disabled) {
  opacity: 0.5;
  cursor: not-allowed;
}

/* -- Searchbar — icon + bare input (+ button) in one control. ------ */

.searchbar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-block-size: var(--ctl-h-lg);
  padding-inline: var(--sp-3);
  background: var(--surface);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-xs);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}

.searchbar:hover {
  border-color: var(--text-faint);
}

.searchbar > .icon {
  color: var(--text-faint);
}

.searchbar input,
.searchbar .input {
  flex: 1 1 auto;
  min-inline-size: 0;
  min-block-size: auto;
  padding-inline: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
  font-size: var(--fs-md);
  color: var(--text);
}

/* The bare input delegates its focus indicator to the container
   below — legitimate only because the container draws a real ring. */
.searchbar input:focus,
.searchbar .input:focus {
  outline: none;
  box-shadow: none;
}

/* Same ring contract as .input:focus above. */
.searchbar:focus-within {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 2px;
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--primary-soft);
}

.searchbar .btn {
  flex: none;
}

/* ------------------------------------------------------------------ */
/* 5. Navigation                                                      */
/* ------------------------------------------------------------------ */

/* -- Tabs ---------------------------------------------------------- */

.tabs {
  display: flex;
  align-items: stretch;
  gap: var(--sp-1);
  border-block-end: var(--border-w) solid var(--border);

  /* Scrollable, but with no visible scrollbar. Overflow has to stay on:
     several screens carry more tabs than fit, and letting them wrap would
     break the active tab's underline away from the strip's bottom border.
     What we do not want is the scrollbar gutter itself — a grey track under
     a five-item tab row reads as a rendering artefact, not a control.
     Keyboard, trackpad and touch scrolling all still work. */
  overflow-x: auto;
  scrollbar-width: none;          /* Firefox */
  -ms-overflow-style: none;       /* legacy Edge */
}

.tabs::-webkit-scrollbar { display: none; }   /* WebKit / Blink */

.tab {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding-block: var(--sp-2);
  padding-inline: var(--sp-3);
  margin-block-end: calc(var(--border-w) * -1);
  border: 0;
  border-block-end: 2px solid transparent;
  background: none;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast);
}

.tab:hover {
  color: var(--text);
  border-block-end-color: var(--border-strong);
  text-decoration: none;
}

/* Inset ring: .tabs is a scroll container, so an offset ring would be
   clipped at the edges. */
.tab:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: -2px;
  border-radius: var(--r-sm);
}

.tab--active {
  color: var(--primary-ink);
  font-weight: var(--fw-semibold);
  border-block-end-color: var(--primary);
}

/* -- Chips — filter/tag tokens. ------------------------------------ */

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-block-size: var(--ctl-h-sm);
  padding-block: 0;
  padding-inline: var(--sp-3);
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-full);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast),
              border-color var(--t-fast);
}

.chip:hover {
  background: var(--surface-hover);
  color: var(--text);
  border-color: var(--border-strong);
  text-decoration: none;
}

.chip:active {
  background: var(--surface-2);
}

.chip:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 2px;
}

.chip--active {
  background: var(--primary-soft);
  border-color: var(--primary-ink);
  color: var(--primary-ink);
  font-weight: var(--fw-semibold);
}

/* Removable — a built-in ✕ affordance on the inline-end side. */
.chip--removable::after {
  content: "✕";
  font-size: 0.85em;
  opacity: 0.55;
  margin-inline-start: 2px;
}

.chip--removable:hover::after {
  opacity: 1;
}

/* -- Pagination ---------------------------------------------------- */
/* Markup: <nav class="pagination"> of <a>/<button>/<span> children.
   Current page: aria-current="page" (preferred) or .is-current. */

.pagination {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}

.pagination > * {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: var(--ctl-h-md);
  block-size: var(--ctl-h-md);
  padding-inline: var(--sp-2);
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}

.pagination > a:hover,
.pagination > button:hover {
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
}

.pagination > a:focus-visible,
.pagination > button:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 2px;
}

.pagination > [aria-current="page"],
.pagination > .is-current {
  background: var(--primary);
  color: var(--primary-fg);
  font-weight: var(--fw-semibold);
  cursor: default;
}

.pagination > [disabled],
.pagination > .is-disabled {
  opacity: 0.45;
  pointer-events: none;
}

/* -- Dropdown / menu ----------------------------------------------- */
/* .menu works standalone (statically shown in wireframes) or
   absolutely positioned when nested directly in a .dropdown. */

.dropdown {
  position: relative;
  display: inline-block;
}

.menu {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-inline-size: 200px;
  padding: var(--sp-1);
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
}

/* z-index: the one layering scale, tokens.css §2. */
.dropdown > .menu {
  position: absolute;
  inset-block-start: calc(100% + var(--sp-1));
  inset-inline-start: 0;
  z-index: var(--z-dropdown, 300);
}

.menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  inline-size: 100%;
  min-block-size: var(--ctl-h-md);
  padding-block: var(--sp-1);
  padding-inline: var(--sp-3);
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text);
  font-size: var(--fs-sm);
  text-align: start;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t-fast);
}

.menu-item:hover {
  background: var(--surface-2);
  text-decoration: none;
}

.menu-item:active {
  background: var(--bg-sunken);
}

.menu-item:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: -2px;
}

.menu-item.is-active {
  background: var(--primary-soft);
  color: var(--primary-ink);
  font-weight: var(--fw-semibold);
}

.menu-item .icon {
  color: var(--text-muted);
}

.menu-item.is-active .icon {
  color: inherit;
}

/* -- Breadcrumbs --------------------------------------------------- */

.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  padding: 0;
  list-style: none;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

.breadcrumbs a {
  color: inherit;
}

.breadcrumbs a:hover {
  color: var(--primary-ink);
}

/* "/" separator is direction-neutral; drawn before every item but
   the first. */
.breadcrumbs > * + *::before {
  content: "/";
  display: inline-block;
  opacity: 0.45;
  margin-inline-end: var(--sp-2);
}

.breadcrumbs [aria-current="page"],
.breadcrumbs .is-current {
  color: var(--text);
  font-weight: var(--fw-medium);
}

/* ------------------------------------------------------------------ */
/* 6. Tables & lists                                                  */
/* ------------------------------------------------------------------ */

/* -- Table --------------------------------------------------------- */
/* .table-wrap provides the border, radius and scrolling; give it a
   max-block-size inline (style="max-block-size:360px") to activate
   vertical scrolling with the sticky header. */

.table-wrap {
  overflow: auto;
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-xs);
}

.table {
  inline-size: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-sm);
  /* Numerals line up down a column everywhere in a table. */
  font-variant-numeric: tabular-nums;
}

.table th {
  position: sticky;
  inset-block-start: 0;
  z-index: 1;
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  text-align: start;
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  padding-block: var(--sp-2);
  padding-inline: var(--sp-3);
  border-block-end: var(--border-w) solid var(--border-strong);
  white-space: nowrap;
}

.table td {
  padding-block: var(--sp-3);
  padding-inline: var(--sp-3);
  border-block-end: var(--border-w) solid var(--border);
  color: var(--text);
  vertical-align: top;
  transition: background var(--t-fast);
}

.table tbody tr:last-child td {
  border-block-end: 0;
}

.table tbody tr:hover td {
  background: var(--surface-hover);
}

/* Zebra striping — a half-step quieter than the hover, so hovering a
   striped row still reads. */
.table--zebra tbody tr:nth-child(even) td {
  background: var(--surface-hover);
}

.table--zebra tbody tr:hover td {
  background: var(--surface-2);
}

/* Compact density for the admin console. */
.table--compact th {
  padding-block: var(--sp-1);
  padding-inline: var(--sp-2);
}

.table--compact td {
  padding-block: var(--sp-2);
  padding-inline: var(--sp-2);
  font-size: var(--fs-xs);
}

/* -- List — media-object rows. ------------------------------------- */

.list {
  display: flex;
  flex-direction: column;
  padding: 0;
  list-style: none;
}

.list-item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding-block: var(--sp-3);
  border-block-end: var(--border-w) solid var(--border);
  transition: background var(--t-fast);
}

.list-item:last-child {
  border-block-end: 0;
}

/* Link/button rows get a hover surface; static rows are unaffected. */
a.list-item:hover,
button.list-item:hover {
  background: var(--surface-hover);
  text-decoration: none;
}

a.list-item:focus-visible,
button.list-item:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: -2px;
  border-radius: var(--r-sm);
}

.list-item-main {
  flex: 1 1 auto;
  min-inline-size: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.list-item-meta {
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

.list-item-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-inline-start: auto;
  flex: none;
}

/* -- Key/value — definition grid. ---------------------------------- */
/* Markup: <dl class="kv"> alternating .kv-key / .kv-val children. */

.kv {
  display: grid;
  grid-template-columns: minmax(140px, max-content) minmax(0, 1fr);
  column-gap: var(--sp-6);
  row-gap: var(--sp-2);
  font-size: var(--fs-sm);
}

.kv-key {
  color: var(--text-muted);
}

.kv-val {
  color: var(--text);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

@media (max-width: 480px) {
  .kv {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 2px;
  }

  .kv-val {
    margin-block-end: var(--sp-2);
  }
}

/* ------------------------------------------------------------------ */
/* 7. Indicators                                                      */
/* ------------------------------------------------------------------ */

/* -- Badge — status pill: soft tint + status ink + a hairline ring
      drawn from the ink itself, so every variant is one family. The
      color-mix ring degrades by dropping (no ring) where unsupported. */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding-block: 2px;
  padding-inline: var(--sp-2);
  border-radius: var(--r-full);
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  line-height: 1.5;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 22%, transparent);
}

.badge--ok     { background: var(--ok-soft);      color: var(--ok); }
.badge--warn   { background: var(--warn-soft);    color: var(--warn); }
.badge--danger { background: var(--danger-soft);  color: var(--danger); }
.badge--info   { background: var(--info-soft);    color: var(--info); }
.badge--accent { background: var(--accent-soft);  color: var(--accent); }
.badge--muted  { background: var(--surface-2);    color: var(--text-muted); }

/* -- Stat — KPI block (compose inside .card / .panel). ------------- */

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

.stat-value {
  font-size: var(--fs-2xl);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.stat-label {
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
}

.stat-delta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}

.stat-delta--up   { color: var(--ok); }
.stat-delta--down { color: var(--danger); }

/* Direction-neutral trend glyphs. */
.stat-delta--up::before   { content: "▴"; }
.stat-delta--down::before { content: "▾"; }

/* -- Avatar — initials disc; size via --size. ---------------------- */

.avatar {
  display: inline-grid;
  place-items: center;
  inline-size: var(--size, 32px);
  block-size: var(--size, 32px);
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary-ink);
  font-size: calc(var(--size, 32px) * 0.38);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 20%, transparent);
  overflow: hidden;
  flex: none;
  user-select: none;
}

/* -- Progress — determinate fill, 0–100 via --p. ------------------- */
/* Fills from the inline start, so it mirrors under RTL. */

.progress {
  block-size: 6px;
  border-radius: var(--r-full);
  background: var(--bg-sunken);
  box-shadow: inset 0 0 0 1px var(--border);
  overflow: hidden;
}

.progress::before {
  content: "";
  display: block;
  block-size: 100%;
  inline-size: calc(var(--p, 0) * 1%);
  border-radius: inherit;
  background: var(--progress-c, var(--primary));
  transition: inline-size var(--t-med);
}

/* -- Meter — thresholded quantity (quota, capacity).
      Colour via --meter-c: var(--ok) | var(--warn) | var(--danger). -- */

.meter {
  block-size: 4px;
  border-radius: var(--r-full);
  background: var(--bg-sunken);
  box-shadow: inset 0 0 0 1px var(--border);
  overflow: hidden;
}

.meter::before {
  content: "";
  display: block;
  block-size: 100%;
  inline-size: calc(var(--p, 0) * 1%);
  border-radius: inherit;
  background: var(--meter-c, var(--ok));
  transition: inline-size var(--t-med);
}

/* ------------------------------------------------------------------ */
/* 8. Charts — pure CSS/SVG, no libraries                             */
/*    Column order and fills run from the inline start, so charts     */
/*    mirror under RTL. Western digits on axes do not mirror.         */
/* ------------------------------------------------------------------ */

.chart {
  inline-size: 100%;
}

/* -- Column chart: flex columns, height via --v (0–100). ----------- */

.chart-bars {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  block-size: var(--chart-h, 160px);
  padding-block-start: var(--sp-2);
  border-block-end: var(--border-w) solid var(--border-strong);
}

/* A flat fill reads as a spreadsheet; a column with light falling down it
   reads as a chart someone designed. The gradient is a single hue at two
   strengths — no second colour, because --bar-c is the tenant's and must
   stay recognisably theirs. */
.bar {
  flex: 1 1 0;
  min-inline-size: 8px;
  max-inline-size: 64px;
  block-size: calc(var(--v, 20) * 1%);
  background: linear-gradient(to bottom,
    var(--bar-c, var(--primary)),
    color-mix(in srgb, var(--bar-c, var(--primary)) 72%, transparent));
  border-start-start-radius: 3px;
  border-start-end-radius: 3px;
  transition: block-size var(--t-med);
}

/* -- Line chart: container draws the grid; the author supplies an
      inline <svg> sized to the box.

      AUTHORING SHAPE (this is what the RTL mirror below expects):

        <div class="chart-line">
          <svg viewBox="0 0 300 160" preserveAspectRatio="none">
            <g class="plot"><polyline points="…"/></g>   <!-- mirrors -->
            <text x="8"  y="152">Jan</text>               <!-- does not -->
            <text x="272" y="152">2026</text>
          </svg>
        </div>

      Data geometry goes in <g class="plot">; axis ticks, value labels
      and any other <text> stay outside it. Only the plot group is
      mirrored under RTL, so Western digits and axis labels keep their
      reading direction (contract §5.4). A bare <polyline>/<path> written
      as a direct child of the <svg> is treated as plot geometry too, for
      label-free trend lines. A <text> that genuinely belongs to the
      geometry (a point callout) may live inside .plot — it is
      counter-flipped back to upright automatically. -------------------- */

.chart-line {
  position: relative;
  block-size: var(--chart-h, 160px);
  inline-size: 100%;
  border-block-end: var(--border-w) solid var(--border-strong);
  /* Gridlines sit UNDER a faint wash rising from the baseline, so the plot
     area reads as a field the data sits in rather than as ruled paper the
     line happens to cross. */
  background-image:
    repeating-linear-gradient(
      to top,
      var(--border) 0,
      var(--border) 1px,
      transparent 1px,
      transparent 25%
    ),
    linear-gradient(to top,
      color-mix(in srgb, var(--primary) 4%, transparent),
      transparent 70%);
}

.chart-line svg {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
}

.chart-line svg polyline,
.chart-line svg path {
  fill: none;
  stroke: var(--line-c, var(--primary));
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Labels default to the ink colour and to LTR flow. SVG <text> inherits
   `direction` from the document, and under RTL that moves the anchor to
   the other side of its x coordinate — so the same markup would place a
   tick inside the plot in English and off the canvas in Arabic. Pinning
   direction here makes an x coordinate mean one thing in both languages
   (contract §5.4); `isolate` still lets an Arabic label shape RTL inside
   its own box. Authors override with text-anchor when they want otherwise. */
.chart-line svg text,
.sparkline svg text {
  direction: ltr;
  unicode-bidi: isolate;
  fill: var(--text-muted);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

/* RTL: mirror the plotted geometry, never the whole <svg>. Flipping the
   <svg> element would mirror every <text> inside it too, so axis ticks
   and value labels would render backwards — contract §5.4 says numeric
   axes and Western digits do not mirror, and §4.4 gives labels nowhere
   to live except inside this same <svg>. Same split the .donut uses
   below: flip the drawing, leave the label alone. */
[dir="rtl"] .chart-line svg > g.plot,
[dir="rtl"] .chart-line svg > polyline,
[dir="rtl"] .chart-line svg > path {
  transform: scaleX(-1);
  transform-box: view-box;
  transform-origin: center;
}

/* Escape hatch: text that must sit inside the flipped plot group is
   flipped back about its own box, so it reads normally. */
[dir="rtl"] .chart-line svg > g.plot text {
  transform: scaleX(-1);
  transform-box: fill-box;
  transform-origin: center;
}

/* -- Donut: conic ring on ::before (via --p), centred label as
      normal children. Ring sweep mirrors; the label does not. ------ */

.donut {
  --size: 96px;
  --thickness: 12px;
  position: relative;
  display: grid;
  place-items: center;
  inline-size: var(--size);
  block-size: var(--size);
  text-align: center;
  flex: none;
}

.donut::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(
    var(--donut-c, var(--primary)) calc(var(--p, 40) * 1%),
    var(--surface-2) 0
  );
  -webkit-mask: radial-gradient(
    farthest-side,
    transparent calc(100% - var(--thickness)),
    #000 calc(100% - var(--thickness) + 1px)
  );
  mask: radial-gradient(
    farthest-side,
    transparent calc(100% - var(--thickness)),
    #000 calc(100% - var(--thickness) + 1px)
  );
}

[dir="rtl"] .donut::before {
  transform: scaleX(-1);
}

/* -- Sparkline: tiny inline trend; author supplies the <svg>. Same
      authoring shape as .chart-line — geometry in <g class="plot">, any
      end-value label as a plain <text> sibling. ---------------------- */

.sparkline {
  display: inline-block;
  inline-size: var(--spark-w, 96px);
  block-size: var(--spark-h, 28px);
  vertical-align: middle;
  flex: none;
}

.sparkline svg {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.sparkline svg polyline,
.sparkline svg path {
  fill: none;
  stroke: var(--line-c, var(--primary));
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* RTL: geometry only — see the note on .chart-line above. */
[dir="rtl"] .sparkline svg > g.plot,
[dir="rtl"] .sparkline svg > polyline,
[dir="rtl"] .sparkline svg > path {
  transform: scaleX(-1);
  transform-box: view-box;
  transform-origin: center;
}

[dir="rtl"] .sparkline svg > g.plot text {
  transform: scaleX(-1);
  transform-box: fill-box;
  transform-origin: center;
}

/* ------------------------------------------------------------------ */
/* 9. Structure visualisation                                         */
/* ------------------------------------------------------------------ */

/* -- Tree — nested <ul class="tree"> of .tree-node rows. ----------- */

.tree {
  padding: 0;
  list-style: none;
  font-size: var(--fs-sm);
}

/* Nested levels indent along the inline axis with a guide rule. */
.tree ul {
  list-style: none;
  margin-inline-start: var(--sp-4);
  padding-inline-start: var(--sp-3);
  border-inline-start: var(--border-w) solid var(--border);
}

.tree-node {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-block-size: 28px;
  padding-block: var(--sp-1);
  padding-inline: var(--sp-2);
  border-radius: var(--r-sm);
  color: var(--text);
  transition: background var(--t-fast);
}

.tree-node:hover {
  background: var(--surface-hover);
}

.tree-node:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: -2px;
}

.tree-node.is-active {
  background: var(--primary-soft);
  color: var(--primary-ink);
  font-weight: var(--fw-semibold);
}

.tree-toggle {
  display: inline-grid;
  place-items: center;
  inline-size: 18px;
  block-size: 18px;
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text-faint);
  cursor: pointer;
  flex: none;
  transition: background var(--t-fast), color var(--t-fast);
}

.tree-toggle:hover {
  background: var(--bg-sunken);
  color: var(--text);
}

.tree-toggle:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 1px;
}

/* -- Stepper — numbered horizontal progress (wizards). ------------- */

.stepper {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  counter-reset: wf-step;
}

.step {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: 1 1 0;
  min-inline-size: 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  white-space: nowrap;
}

.step:last-child {
  flex: 0 0 auto;
}

/* Number disc. */
.step::before {
  counter-increment: wf-step;
  content: counter(wf-step);
  display: grid;
  place-items: center;
  inline-size: var(--ctl-h-sm);
  block-size: var(--ctl-h-sm);
  border-radius: 50%;
  background: var(--surface);
  border: var(--border-w) solid var(--border-strong);
  color: var(--text-muted);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  flex: none;
}

/* Connector to the next step. */
.step:not(:last-child)::after {
  content: "";
  flex: 1 1 auto;
  min-inline-size: var(--sp-4);
  block-size: 2px;
  border-radius: 1px;
  background: var(--border);
}

.step--current {
  color: var(--text);
  font-weight: var(--fw-semibold);
}

.step--current::before {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--primary-fg);
}

.step--done::before {
  content: "✓";
  background: var(--ok);
  border-color: var(--ok);
  color: var(--surface);
}

.step--done:not(:last-child)::after {
  background: var(--ok);
}

/* -- Timeline — vertical event trail, rail on the inline start. ---- */

.timeline {
  display: flex;
  flex-direction: column;
  padding: 0;
  list-style: none;
  margin-inline-start: var(--sp-2);
}

.timeline-item {
  position: relative;
  padding-inline-start: var(--sp-6);
  padding-block-end: var(--sp-5);
  border-inline-start: 2px solid var(--border);
}

.timeline-item:last-child {
  border-inline-start-color: transparent;
  padding-block-end: 0;
}

/* Event dot; colour via --dot-c (e.g. var(--ok), var(--danger)). */
.timeline-item::before {
  content: "";
  position: absolute;
  inset-inline-start: -6px;
  inset-block-start: 0.35em;
  inline-size: 10px;
  block-size: 10px;
  border-radius: 50%;
  background: var(--dot-c, var(--primary));
  border: 2px solid var(--surface);
}

/* -- Facet — discovery filter group (search rail). ----------------- */

.facet {
  padding-block: var(--sp-3);
  border-block-end: var(--border-w) solid var(--border);
}

.facet:last-child {
  border-block-end: 0;
}

.facet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-block-end: var(--sp-2);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
}

.facet-list {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 0;
  list-style: none;
}

.facet-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-block-size: var(--ctl-h-sm);
  padding-block: 2px;
  padding-inline: var(--sp-2);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}

.facet-item:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.facet-item:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: -2px;
}

.facet-item.is-active {
  background: var(--primary-soft);
  color: var(--primary-ink);
  font-weight: var(--fw-semibold);
}

.facet-count {
  margin-inline-start: auto;
  padding-inline: var(--sp-2);
  border-radius: var(--r-full);
  background: var(--surface-2);
  color: var(--text-faint);
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
  line-height: 1.7;
  flex: none;
}

.facet-item.is-active .facet-count {
  background: var(--surface);
  color: var(--text-muted);
}

/* ------------------------------------------------------------------ */
/* 10. Feedback                                                       */
/* ------------------------------------------------------------------ */

/* -- Alert — soft tint + status keyline on the inline start. ------- */

.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding-block: var(--sp-3);
  padding-inline: var(--sp-4);
  border: var(--border-w) solid var(--border);
  border-inline-start-width: 3px;
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  color: var(--text);
}

.alert > .icon {
  margin-block-start: 0.2em;
}

.alert--info {
  background: var(--info-soft);
  border-inline-start-color: var(--info);
}
.alert--info > .icon { color: var(--info); }

.alert--warn {
  background: var(--warn-soft);
  border-inline-start-color: var(--warn);
}
.alert--warn > .icon { color: var(--warn); }

.alert--danger {
  background: var(--danger-soft);
  border-inline-start-color: var(--danger);
}
.alert--danger > .icon { color: var(--danger); }

.alert--success {
  background: var(--ok-soft);
  border-inline-start-color: var(--ok);
}
.alert--success > .icon { color: var(--ok); }

/* -- Empty state — deliberate, quiet, centred. --------------------- */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding-block: var(--sp-10);
  padding-inline: var(--sp-6);
  text-align: center;
}

.empty-icon {
  display: grid;
  place-items: center;
  inline-size: 48px;
  block-size: 48px;
  border-radius: var(--r-lg);
  background: var(--surface-2);
  box-shadow: inset 0 0 0 1px var(--border);
  color: var(--text-faint);
  font-size: 22px;
  margin-block-end: var(--sp-2);
}

.empty-title {
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  color: var(--text);
}

.empty-body {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  max-inline-size: 44ch;
}

/* -- Skeleton — loading shimmer. ----------------------------------- */
/* Size via --sk-w / --sk-h; the sweep only animates when the user
   allows motion (static two-tone block otherwise). */

.skeleton {
  display: block;
  inline-size: var(--sk-w, 100%);
  block-size: var(--sk-h, 12px);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}

@media (prefers-reduced-motion: no-preference) {
  .skeleton {
    background: linear-gradient(
      90deg,
      var(--surface-2) 25%,
      var(--bg-sunken) 40%,
      var(--surface-2) 60%
    );
    background-size: 300% 100%;
    animation: wf-shimmer 1.4s ease infinite;
  }

  @keyframes wf-shimmer {
    from { background-position: 100% 0; }
    to   { background-position: 0% 0; }
  }
}

/* -- Note — wireframe annotation callout. Deliberately styled like a
      sticky note so it never reads as product UI. ------------------- */

.note {
  padding-block: var(--sp-3);
  padding-inline: var(--sp-4);
  background: var(--warn-soft);
  border: var(--border-w) dashed var(--warn);
  border-radius: var(--r-md);
  color: var(--text-muted);
  font-size: var(--fs-xs);
}

.note::before {
  content: "✎";
  color: var(--warn);
  font-size: var(--fs-sm);
  margin-inline-end: var(--sp-2);
}

/* ------------------------------------------------------------------ */
/* 11. Overlays                                                       */
/*     Wireframes render these open; they are real overlays so a      */
/*     screen can show them above its normal content.                 */
/*                                                                    */
/*     LAYERING. Every stacking decision in the pack comes from the   */
/*     one ordered scale in tokens.css §2 (--z-sticky 100 →           */
/*     --z-toast 700; guide.css owns 800+). The fallbacks below keep  */
/*     this file correct on its own.                                  */
/* ------------------------------------------------------------------ */

/* -- Modal --------------------------------------------------------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal, 600);
  display: grid;
  place-items: center;
  padding: var(--sp-4);
  background: var(--scrim, rgba(16, 24, 40, 0.55));
}

.modal-card {
  inline-size: min(560px, 100%);
  max-block-size: 85vh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-block: var(--sp-4);
  padding-inline: var(--sp-5);
  border-block-end: var(--border-w) solid var(--border);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-tight-2);
  color: var(--text);
}

.modal-body {
  flex: 1 1 auto;
  overflow: auto;
  padding-block: var(--sp-5);
  padding-inline: var(--sp-5);
}

.modal-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding-block: var(--sp-3);
  padding-inline: var(--sp-5);
  border-block-start: var(--border-w) solid var(--border);
  background: var(--surface-2);
}

/* -- Drawer — side panel docked to the inline-end edge (mirrors). -- */

.drawer {
  position: fixed;
  inset-block: 0;
  inset-inline-end: 0;
  z-index: var(--z-drawer, 500);
  inline-size: min(420px, 92vw);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-block: var(--sp-5);
  padding-inline: var(--sp-5);
  overflow: auto;
  background: var(--surface);
  border-inline-start: var(--border-w) solid var(--border);
  box-shadow: var(--shadow-lg);
}

/* -- Toast — transient confirmation, inverted surface. -------------
      Because the surface is inverted, the tokens tuned for --surface
      (status inks, the brand focus ring) are the wrong lightness inside
      it. Re-point them locally rather than letting children inherit
      values that were never measured against this background. */

.toast {
  /* Focus ring for anything focusable in here (undo link, dismiss
     button): the toast's own background colour, so it is guaranteed to
     contrast with the toast ink. --primary measures 1.6–2.6:1 here. */
  --focus-ring: var(--bg);

  position: fixed;
  inset-block-end: var(--sp-6);
  inset-inline-end: var(--sp-6);
  z-index: var(--z-toast, 700);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  max-inline-size: min(360px, calc(100vw - var(--sp-12)));
  padding-block: var(--sp-3);
  padding-inline: var(--sp-4);
  border-radius: var(--r-md);
  background: var(--text);
  color: var(--bg);
  font-size: var(--fs-sm);
  box-shadow: var(--shadow-lg);
}

/* Status glyph. Hue via --toast-icon-c (default: success). The raw
   status token is a surface-tuned ink and lands at ~3:1 (light) /
   ~2:1 (dark) on this background, so it is mixed toward the toast's
   own ink until it lifts off it while keeping the hue. Where color-mix
   is unsupported the declaration drops and the glyph falls back to the
   toast ink — still legible. */
.toast .icon {
  color: color-mix(in srgb, var(--toast-icon-c, var(--ok)) 55%, var(--bg));
}

/* base.css draws :focus-visible in --primary, a colour tuned against
   --surface; on the inverted toast it measures 1.6–2.6:1. */
.toast :focus-visible {
  outline-color: var(--focus-ring, var(--bg));
}

/* ------------------------------------------------------------------ */
/* 12. Density (v2) — contract §10                                    */
/* ------------------------------------------------------------------ */

/* -- Disclosure — collapsed-by-default secondary detail. -----------
   Built on native <details>/<summary> so it works with zero JS, keeps
   keyboard and screen-reader semantics for free, and cannot fall out
   of sync with its own open state. The marker is drawn by us because
   the native triangle is a different glyph on every platform and does
   not mirror in RTL. */

.disclosure {
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
}

.disclosure + .disclosure {
  margin-block-start: var(--sp-2);
}

.disclosure-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-block-size: var(--ctl-h-lg);
  padding-block: var(--sp-2);
  padding-inline: var(--sp-4);
  border-radius: var(--r-md);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  list-style: none;                 /* Firefox */
  transition: background var(--t-fast);
}

.disclosure-head::-webkit-details-marker { display: none; }   /* WebKit */

.disclosure-head:hover {
  background: var(--surface-hover);
}

.disclosure-head:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: -2px;
}

/* Chevron drawn as a rotating box corner: one glyph, no icon dependency,
   and it mirrors by construction because the rotation origin is central.
   Points to the inline end when closed, down when open. */
.disclosure-head::after {
  content: "";
  flex: none;
  inline-size: 7px;
  block-size: 7px;
  margin-inline-start: auto;
  border-block-end: 2px solid var(--text-faint);
  border-inline-end: 2px solid var(--text-faint);
  transform: rotate(-45deg);
  transition: transform var(--t-fast);
}

:where([dir="rtl"]) .disclosure-head::after {
  transform: rotate(135deg);
}

.disclosure[open] > .disclosure-head::after,
:where([dir="rtl"]) .disclosure[open] > .disclosure-head::after {
  transform: rotate(45deg);
}

.disclosure[open] > .disclosure-head {
  border-end-start-radius: 0;
  border-end-end-radius: 0;
  border-block-end: var(--border-w) solid var(--border);
}

.disclosure-body {
  padding-block: var(--sp-4);
  padding-inline: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* Count of what is hidden — the reason a reviewer trusts a collapsed
   section rather than assuming the content was cut (contract §10: we
   relocate, we do not delete). */
.disclosure-head .badge {
  margin-inline-start: var(--sp-1);
}

/* -- Rail — the secondary column. -----------------------------------
   Pairs with .grid--sidebar for the layout itself; .rail only styles
   what lands in the narrow column: quieter surface, tighter type, so
   the eye reads it as support rather than as a second primary column. */

.rail {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  font-size: var(--fs-sm);
}

.rail > .card {
  box-shadow: none;
  background: var(--bg-sunken);
}

.rail .card-title {
  font-size: var(--fs-sm);
}

.rail .stat-value {
  font-size: var(--fs-xl);
}

/* -- Segmented switch — the web sibling of mobile's .app-segment. ---
   Two to four mutually exclusive views of the same content. Not a tab
   strip: tabs change what you are looking at, a segment changes how. */

.seg {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  background: var(--bg-sunken);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-sm);
}

.seg-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-block-size: var(--ctl-h-sm);
  padding-inline: var(--sp-3);
  border: 0;
  border-radius: calc(var(--r-sm) - 1px);
  background: none;
  color: var(--text-muted);
  font-family: inherit;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}

.seg-btn:hover {
  color: var(--text);
}

.seg-btn:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: -2px;
}

.seg-btn.is-on {
  background: var(--surface);
  color: var(--text);
  font-weight: var(--fw-semibold);
  box-shadow: var(--shadow-xs);
}

/* -- Viewmode — the Basic/Advanced switch (§10.4). ------------------
   A .seg with a fixed contract, so the shell can find it without the
   author wiring anything. Advanced-only content carries [data-adv] and
   is hidden until the container is marked .is-advanced. */

.viewmode {
  margin-inline-start: auto;
}

[data-adv] {
  display: none;
}

.is-advanced [data-adv] {
  display: revert;
}

/* ------------------------------------------------------------------ */
/* 13. Hints (v2) — contract §11                                      */
/* ------------------------------------------------------------------ */

/* A quiet question mark that explains a label in one or two plain
   sentences. Deliberately low-contrast at rest: on an admin dashboard
   every stat carries one, and a page of high-contrast markers would
   itself become the clutter this exists to prevent. */

.hint {
  display: inline-grid;
  place-items: center;
  inline-size: 14px;
  block-size: 14px;
  margin-inline-start: var(--sp-1);
  padding: 0;
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--r-full);
  background: none;
  color: var(--text-faint);
  font-family: inherit;
  font-size: 9px;
  font-weight: var(--fw-bold);
  line-height: 1;
  vertical-align: middle;
  cursor: help;
  transition: color var(--t-fast), border-color var(--t-fast);
}

.hint::before { content: "?"; }

.hint:hover,
.hint[aria-expanded="true"] {
  color: var(--primary-ink);
  border-color: var(--primary);
}

.hint:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: 2px;
}

/* The popover. Authored as a sibling of its marker and hidden; shell.js
   positions and unhides it. Rendered statically (no [hidden]) in the one
   screen per pack that demonstrates the pattern open. */
.hint-pop {
  position: absolute;
  z-index: var(--z-dropdown, 300);
  max-inline-size: 260px;
  padding-block: var(--sp-2);
  padding-inline: var(--sp-3);
  background: var(--surface);
  border: var(--border-w) solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
  color: var(--text);
  font-size: var(--fs-xs);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  letter-spacing: normal;
  text-transform: none;             /* .stat-label is uppercase; this is not */
  text-align: start;
  white-space: normal;
}

.hint-pop[hidden] { display: none; }

/* ------------------------------------------------------------------ */
/* 14. Typeahead (v2) — contract §12                                  */
/* ------------------------------------------------------------------ */

/* Suggestions under a .searchbar, grouped by kind. Absolutely
   positioned against a .searchbar-wrap so the panel overlays the page
   instead of pushing it down — a search box that reflows the layout as
   you type is the classic way this pattern feels cheap. */

.searchbar-wrap {
  position: relative;
}

.ac {
  position: absolute;
  inset-block-start: calc(100% + var(--sp-1));
  inset-inline: 0;
  z-index: var(--z-dropdown, 300);
  padding: var(--sp-1);
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
  max-block-size: 380px;
  overflow-y: auto;
}

.ac[hidden] { display: none; }

.ac-group + .ac-group {
  margin-block-start: var(--sp-1);
  padding-block-start: var(--sp-1);
  border-block-start: var(--border-w) solid var(--border);
}

.ac-group-label {
  display: block;
  padding-block: var(--sp-1);
  padding-inline: var(--sp-3);
  color: var(--text-faint);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
}

.ac-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  inline-size: 100%;
  min-block-size: var(--ctl-h-md);
  padding-block: var(--sp-1);
  padding-inline: var(--sp-3);
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: var(--fs-sm);
  text-align: start;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t-fast);
}

.ac-item:hover,
.ac-item.is-active {
  background: var(--surface-2);
  text-decoration: none;
}

.ac-item:focus-visible {
  outline: 2px solid var(--focus-ring, var(--text));
  outline-offset: -2px;
}

.ac-item .icon {
  flex: none;
  color: var(--text-faint);
}

/* The matched substring, emphasised inside the suggestion. */
.ac-item mark {
  background: none;
  color: inherit;
  font-weight: var(--fw-semibold);
}

/* Trailing kind label — "Journal", "Subject" — so a suggestion is
   never ambiguous about what pressing Enter will do. */
.ac-item-kind {
  margin-inline-start: auto;
  flex: none;
  color: var(--text-faint);
  font-size: var(--fs-2xs);
  white-space: nowrap;
}

/* Always the last row: escape hatch to the full results page. */
.ac-item--all {
  margin-block-start: var(--sp-1);
  border-block-start: var(--border-w) solid var(--border);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  color: var(--primary-ink);
  font-weight: var(--fw-semibold);
}
