/* ==========================================================================
   Phantom — components
   ==========================================================================
   Shapes and shadows follow r5systems.co.za: white cards on an off-white
   page, 24px corners, full-pill controls, and R5's two-part shadows.
   ========================================================================== */

/* ── Buttons ─────────────────────────────────────────────────────────── */

.btn {
  --btn-bg: var(--surface-1);
  --btn-fg: var(--text-1);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: 34px;
  padding: 0 16px;
  /* Every control on the R5 site is a full pill. Nothing else carries the
     look as strongly — with square corners the palette alone doesn't read
     as the same brand. */
  border-radius: var(--r-full);
  background: var(--btn-bg);
  color: var(--btn-fg);
  box-shadow: var(--ring);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: -0.004em;
  white-space: nowrap;
  transition:
    background var(--dur-fast) var(--ease),
    box-shadow  var(--dur-fast) var(--ease),
    transform   var(--dur-instant) var(--ease),
    opacity     var(--dur-fast) var(--ease);
}
.btn:hover:not(:disabled) { background: var(--surface-2); }
/* A 1px settle on press — enough to feel mechanical, too small to notice. */
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn--primary {
  --btn-bg: var(--accent);
  --btn-fg: var(--accent-ink);
  /* The coloured lift is R5's, retinted. A neutral drop shadow under a
     saturated pill reads as dirt; one tinted with the fill reads as light. */
  box-shadow: var(--lift-accent);
  font-weight: 650;
}
.btn--primary:hover:not(:disabled) { background: var(--accent-hover); }
.btn--primary:active:not(:disabled) { background: var(--accent-press); }

.btn--ghost { --btn-bg: transparent; --btn-fg: var(--text-2); box-shadow: none; }
.btn--ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--text-1); }

.btn--danger { --btn-fg: var(--danger); }
.btn--danger:hover:not(:disabled) { background: var(--danger-soft); }

.btn--sm { height: 28px; padding: 0 12px; font-size: var(--t-xs); }
.btn--lg { height: 44px; padding: 0 24px; font-size: var(--t-base); }
.btn--block { width: 100%; }
.btn--icon { width: 34px; padding: 0; }
.btn--sm.btn--icon { width: 28px; }

.btn__spinner {
  width: 13px; height: 13px; flex-shrink: 0;
  border: 1.5px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--r-full);
  animation: spin 640ms linear infinite;
}

/* ── Inputs ──────────────────────────────────────────────────────────── */

.field { display: flex; flex-direction: column; gap: 6px; }
.field__label { font-size: var(--t-sm); font-weight: 520; color: var(--text-1); }
.field__hint  { font-size: var(--t-xs); color: var(--text-3); line-height: 1.5; max-width: 62ch; }
.field__error { font-size: var(--t-xs); color: var(--danger); }

.input, .select, .textarea {
  width: 100%;
  min-width: 0;
  padding: 9px 13px;
  border-radius: var(--r-sm);
  /* White on the off-white page. Inputs tinted to the canvas disappear on a
     light ground — the reverse of the dark-theme convention. */
  background: var(--surface-1);
  color: var(--text-1);
  box-shadow: var(--ring);
  font-size: var(--t-sm);
  transition: box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.input:hover, .select:hover, .textarea:hover { box-shadow: 0 0 0 1px var(--line-strong); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  box-shadow: 0 0 0 1px var(--accent), 0 0 0 4px var(--accent-soft);
}
.input::placeholder, .textarea::placeholder { color: var(--text-4); }
.input:disabled, .select:disabled, .textarea:disabled { opacity: 0.55; cursor: not-allowed; }

.textarea { resize: vertical; min-height: 84px; line-height: 1.55; field-sizing: content; }

.select {
  appearance: none;
  padding-right: 30px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 15px) 55%, calc(100% - 10px) 55%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
}

/* Choice rows — radio/checkbox as a full selectable card. */
.choice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  box-shadow: var(--ring);
  cursor: pointer;
  transition: box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.choice:hover { background: var(--surface-2); }
.choice:has(:checked) {
  background: var(--accent-soft);
  box-shadow: 0 0 0 1px var(--accent-line);
}
.choice input { accent-color: var(--accent); margin-top: 2px; flex-shrink: 0; }
/* Both are spans inside a span, so without this they render on one line and
   the description runs straight into the title. */
.choice__title { display: block; font-size: var(--t-sm); font-weight: 550; color: var(--text-1); }
.choice__sub   { display: block; margin-top: 2px; font-size: var(--t-xs); color: var(--text-3); line-height: 1.5; }

/* ── Card / panel ────────────────────────────────────────────────────── */

.card {
  --r: var(--r-lg);
  border-radius: var(--r);
  background: var(--surface-1);
  box-shadow: var(--elev-2);
  corner-shape: squircle;   /* free enhancement; degrades to a normal arc */
  overflow: hidden;
}
.card__head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: 14px var(--sp-5);
  border-bottom: 1px solid var(--line);
}
.card__title { font-size: var(--t-sm); font-weight: 550; color: var(--text-1); }
.card__body { padding: var(--sp-5); }
.card__body--flush { padding: 0; }

/* Rows inside a flush card. */
.rows > * + * { border-top: 1px solid var(--line); }
.rowlink {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 12px var(--sp-5);
  transition: background var(--dur-fast) var(--ease);
}
.rowlink:hover { background: var(--surface-2); }

/* ── Badges ──────────────────────────────────────────────────────────── */

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  height: 22px; padding: 0 9px;
  border-radius: var(--r-full);
  background: var(--tone-soft, var(--neutral-soft));
  color: var(--tone, var(--neutral));
  font-size: var(--t-2xs);
  font-weight: 540;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.badge__dot { width: 5px; height: 5px; border-radius: var(--r-full); background: currentColor; flex-shrink: 0; }
.badge__dot--live { animation: pulse-soft 2s var(--ease) infinite; }

.tone-neutral { --tone: var(--neutral); --tone-soft: var(--neutral-soft); }
.tone-info    { --tone: var(--info);    --tone-soft: var(--info-soft); }
.tone-accent  { --tone: var(--accent);  --tone-soft: var(--accent-soft); }
.tone-warning { --tone: var(--warning); --tone-soft: var(--warning-soft); }
.tone-success { --tone: var(--success); --tone-soft: var(--success-soft); }
.tone-danger  { --tone: var(--danger);  --tone-soft: var(--danger-soft); }

/* ── Banners ─────────────────────────────────────────────────────────── */

.banner {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 14px;
  border-radius: var(--r-md);
  background: var(--tone-soft);
  color: var(--tone);
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--tone) 26%, transparent);
  font-size: var(--t-sm);
}
.banner__body { color: var(--text-2); }
.banner__body strong { color: var(--text-1); font-weight: 550; }

/* ── Glass ───────────────────────────────────────────────────────────────
   Floating chrome ONLY — top bar, command palette, modal chrome. Never a
   layout surface, never behind body copy, never over user content.

   Three things separate this from cheap glass: the tint is a gradient (not
   flat alpha) so it implies a light source; saturate() undoes the grey wash
   that blur alone causes; and the top edge is brighter than the rest. */

.glass {
  background: linear-gradient(
    160deg,
    rgb(255 255 255 / 0.82) 0%,
    rgb(255 255 255 / 0.62) 100%
  );
  -webkit-backdrop-filter: blur(16px) saturate(150%);
          backdrop-filter: blur(16px) saturate(150%);
  border-bottom: 1px solid var(--line);
}

/* Glass is a progressive enhancement — a solid fallback must always exist. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass { background: var(--surface-1); }
}
@media (prefers-reduced-transparency: reduce) {
  .glass {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: var(--surface-1);
  }
}

/* ── Skeletons ───────────────────────────────────────────────────────── */

.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--surface-3);
  border-radius: var(--r-xs);
}
.skeleton::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgb(20 23 26 / 0.05), transparent);
  animation: skeleton-sweep 1.4s var(--ease) infinite;
}
@keyframes skeleton-sweep { from { transform: translateX(-100%) } to { transform: translateX(100%) } }

/* ── Empty state ─────────────────────────────────────────────────────── */

.empty {
  padding: var(--sp-10) var(--sp-6);
  text-align: center;
  color: var(--text-3);
  font-size: var(--t-sm);
}

/* ── Toast ───────────────────────────────────────────────────────────── */

#toasts {
  position: fixed; bottom: var(--sp-5); right: var(--sp-5);
  z-index: 60;
  display: flex; flex-direction: column; gap: var(--sp-2);
  pointer-events: none;
}
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  min-width: 260px; max-width: 380px;
  padding: 14px 18px;
  /* A dark slab, the way r5systems.co.za renders its own dialog: near-black,
     generous radius, white copy. On a light UI that also reads as "the system
     is speaking", which is exactly what a toast is. */
  border-radius: var(--r-lg);
  background: var(--slab);
  color: var(--slab-ink);
  box-shadow: var(--shadow-dark);
  font-size: var(--t-sm);
  pointer-events: auto;
  animation: rise var(--dur-slow) var(--ease-out) both;
}
.toast--leaving { animation: fade-in var(--dur-exit) var(--ease-in) reverse both; }
.toast__mark { width: 6px; height: 6px; margin-top: 7px; border-radius: var(--r-full); background: var(--tone, var(--accent)); flex-shrink: 0; }

/* The status hues are tuned for dark-on-light and disappear against the slab,
   so the dot — the only coloured thing on a toast — gets a brightened set. */
.toast.tone-accent  { --tone: #B563FF; }
.toast.tone-success { --tone: #34D399; }
.toast.tone-warning { --tone: #FBBF24; }
.toast.tone-danger  { --tone: #FF6B6B; }
.toast.tone-info    { --tone: #7DB0FF; }
.toast.tone-neutral { --tone: var(--slab-soft); }

/* ── Progress bar (navigation) ───────────────────────────────────────── */

#nav-progress {
  position: fixed; inset: 0 0 auto; height: 2px; z-index: 100;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
}
#nav-progress.on { opacity: 1; }
#nav-progress > i {
  display: block; height: 100%; width: 100%;
  background: var(--accent);
  transform-origin: left;
  transform: scaleX(0);
  transition: transform var(--dur-slow) var(--ease-out);
}
