/* Spirezen foundation — design tokens + base interaction states.
   Part of the Spirezen UI/UX Standard (.claude/skills/spirezen-uiux, adopted
   2026-10-19 from "A Real UI/UX Sh*t"). Loaded by every portal page.

   Phase 1 is deliberately non-visual for mouse users: tokens, keyboard focus,
   pressed/disabled/loading states, phone tap targets and reduced motion.
   Rules use :where() (zero specificity) so a page's own styles still win,
   except the focus ring, which must beat the old `outline:none` rules. */

:root {
  /* Spacing — 4/8 scale (rule S1) */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;

  /* Type — named scale, nothing under 12px (rules T1, T2). Pixel values on
     purpose: some pages set their own root size (Comms uses 14px), which
     would shrink rem tokens below the 12px floor. Browser zoom still scales. */
  --fs-caption: 12px;
  --fs-label: 13px;
  --fs-body: 14px;
  --fs-body-lg: 16px;
  --fs-h4: 18px;
  --fs-h3: 20px;
  --fs-h2: 24px;
  --fs-h1: 28px;
  --fs-display: 36px;
  --lh-body: 1.5; --lh-heading: 1.25;
  --fw-body: 400; --fw-label: 500; --fw-button: 600; --fw-heading: 700;

  /* Radius (rule K7 — one small set) */
  --r-sm: 6px; --r-md: 10px; --r-lg: 16px; --r-pill: 999px;

  /* Motion (rule M1) */
  --dur-1: 120ms; --dur-2: 200ms; --dur-3: 300ms;
  --ease-out: cubic-bezier(.2, .8, .2, 1);

  /* Functional colours (rule C2) — dark theme values, AA on #0d0f14…#1e2128 */
  --ok: #9caa6b;      --ok-bg: rgba(156, 170, 107, .14);  --ok-text: #b5c486;
  --warn: #e0b341;    --warn-bg: rgba(224, 179, 65, .14); --warn-text: #ecc766;
  --danger: #e07a64;  --danger-bg: rgba(224, 122, 100, .14); --danger-text: #ef9a87;
  --info: #7fa6bd;    --info-bg: rgba(127, 166, 189, .14); --info-text: #a3c2d4;
  --gold-text: #e8a854;

  /* Focus + touch (rules K1, K4) */
  --focus-ring: #f2c06a;
  --focus-ring-soft: rgba(242, 192, 106, .55);
  --tap: 44px;
}
:root.light {
  --ok-text: #4f6420; --warn-text: #7a5a00; --danger-text: #a6391f; --info-text: #2c5d78;
  --gold-text: #8a5a12;
  --focus-ring: #8a5a12;
  --focus-ring-soft: rgba(138, 90, 18, .45);
}

/* ── K1 Keyboard focus: visible on every interactive element ───────────── */
:where(a[href], button, summary, [role="button"], [role="tab"], [role="menuitem"], [role="link"],
       [tabindex]:not([tabindex="-1"]), .btn, .icon-btn, .nav-item):focus-visible {
  outline: 2px solid var(--focus-ring) !important;
  outline-offset: 2px !important;
}
/* Text fields already show a caret; a softer ring keeps them calm (still ≥3:1). */
:where(input:not([type="checkbox"]):not([type="radio"]), select, textarea):focus-visible {
  outline: 2px solid var(--focus-ring-soft) !important;
  outline-offset: 1px !important;
}
:where(input[type="checkbox"], input[type="radio"]):focus-visible {
  outline: 2px solid var(--focus-ring) !important;
  outline-offset: 2px !important;
}

/* Skip link (rule A3) — appears on first Tab */
.spz-skip {
  position: fixed; left: var(--sp-4); top: -60px; z-index: 100000;
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-md);
  background: #0d0d0d; color: #f2c06a; font: 600 var(--fs-label)/1.4 'Poppins', sans-serif;
  text-decoration: none; transition: top var(--dur-2) var(--ease-out);
}
.spz-skip:focus { top: var(--sp-4); }
:root.light .spz-skip { background: #fff; color: #8a5a12; box-shadow: 0 4px 16px rgba(0, 0, 0, .18); }

/* Screen-reader-only helper */
.spz-sr { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ── K2 Buttons: pressed, disabled, loading ───────────────────────────── */
:where(.btn, .icon-btn, button) { touch-action: manipulation; }
:where(.btn, .icon-btn):active:not(:disabled):not([aria-disabled="true"]) {
  transform: translateY(1px);
  filter: brightness(.94);
  transition-duration: var(--dur-1);
}
:where(button, .btn, .icon-btn, input, select, textarea):disabled,
:where(.btn, .icon-btn)[aria-disabled="true"] { cursor: not-allowed; }
:where(.btn, .icon-btn):disabled, :where(.btn, .icon-btn)[aria-disabled="true"] { opacity: .55; }

/* Loading — set by spzBusy(); text stays for screen readers, spinner shows */
:where(.btn, button)[aria-busy="true"] {
  position: relative; pointer-events: none; color: transparent !important;
}
:where(.btn, button)[aria-busy="true"] > * { visibility: hidden; }
:where(.btn, button)[aria-busy="true"]::after {
  content: ""; position: absolute; inset: 0; margin: auto; width: 16px; height: 16px;
  border-radius: 50%; border: 2px solid currentColor; border-color: rgba(0, 0, 0, .55) rgba(0, 0, 0, .55) transparent transparent;
  animation: spz-spin .7s linear infinite;
}
.btn.outline[aria-busy="true"]::after, .icon-btn[aria-busy="true"]::after {
  border-color: var(--focus-ring) var(--focus-ring) transparent transparent;
}
@keyframes spz-spin { to { transform: rotate(360deg); } }

/* ── K4 Phones: 44×44 tap targets ─────────────────────────────────────── */
@media (pointer: coarse) {
  :where(.btn) { min-height: var(--tap); }
  /* Icon buttons keep their look; the hit area grows invisibly to 44px. */
  :where(.icon-btn) { position: relative; }
  :where(.icon-btn)::after { content: ""; position: absolute; inset: -7px; }

  /* Phase 4 (2026-10-19): older phone rules pinned buttons at 30–40px; these
     win over them (html body …) so every common control reaches 44px. */
  html body :is(.btn, a.btn, button.btn, .nav-item, .v3-tabbar button, .kb-sb, .kb-hd-btn, .v3-ibtn, .v3-link) { min-height: var(--tap); }
  html body :is(.msg-act-btn, .ch-btn, .msg-star, .c-ico, .c-attach, .sb-sec-plus, .hbtn, .icon-btn) { min-width: var(--tap); min-height: var(--tap); }
  /* Form fields: 44px tall and 16px text — under 16px iPhones zoom the whole
     page on focus, which then fights scrolling (rule K4 / FO5). */
  html body :is(select, textarea, input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden])) {
    min-height: var(--tap); font-size: max(16px, 1em);
  }
  html body textarea { min-height: 88px; }
}

/* ── FO3 Inline validation (spz-foundation.js marks fields on blur) ───── */
.spz-invalid, [aria-invalid="true"].spz-invalid { border-color: var(--danger) !important; box-shadow: 0 0 0 1px var(--danger) inset; }
.spz-field-error {
  display: flex; align-items: flex-start; gap: 6px; margin-top: 6px;
  font: 500 var(--fs-caption)/1.4 'Poppins', sans-serif; color: var(--danger-text);
}
.spz-field-error::before { content: "⚠"; font-size: 12px; line-height: 1.4; }

/* ── M3 Reduced motion: keep the state change, drop the movement ──────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  :where(.btn, button)[aria-busy="true"]::after { animation: spz-spin 1.6s linear infinite !important; animation-iteration-count: infinite !important; }
}

/* ── Designed confirm dialog (spzConfirm) — rule F2 ───────────────────── */
.spz-dialog-backdrop {
  position: fixed; inset: 0; z-index: 99990; display: flex; align-items: center; justify-content: center;
  padding: var(--sp-4); background: rgba(0, 0, 0, .55);
  animation: spz-fade var(--dur-2) var(--ease-out);
}
.spz-dialog {
  width: min(440px, 100%); background: var(--surface, #1e2128); color: var(--text, #e2e5f0);
  border: 1px solid var(--border, #2e3340); border-radius: var(--r-lg); padding: var(--sp-5);
  box-shadow: 0 24px 64px rgba(0, 0, 0, .45); font-family: 'Poppins', sans-serif;
  animation: spz-rise var(--dur-3) var(--ease-out);
}
.spz-dialog h2 { margin: 0 0 var(--sp-2); font-size: var(--fs-h4); line-height: var(--lh-heading); font-weight: var(--fw-button); }
.spz-dialog p { margin: 0 0 var(--sp-5); font-size: var(--fs-body); line-height: var(--lh-body); color: var(--muted, #a4abbd); }
.spz-dialog .spz-dialog-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); flex-wrap: wrap; }
.spz-dialog .spz-dialog-actions button {
  min-height: 40px; padding: 0 var(--sp-4); border-radius: var(--r-md); font: var(--fw-button) var(--fs-label)/1 'Poppins', sans-serif; cursor: pointer;
  border: 1px solid var(--border, #2e3340); background: transparent; color: var(--text, #e2e5f0);
}
.spz-dialog .spz-dialog-actions .spz-primary { background: linear-gradient(90deg, #dbaa5e, #ebd693, #e8a854, #d8a254); color: #0d0d0d; border-color: transparent; }
.spz-dialog .spz-dialog-actions .spz-danger { background: var(--danger); color: #1a0a06; border-color: transparent; }
@media (pointer: coarse) { .spz-dialog .spz-dialog-actions button { min-height: var(--tap); } }
@keyframes spz-fade { from { opacity: 0; } }
@keyframes spz-rise { from { opacity: 0; transform: translateY(8px); } }
:root.light .spz-dialog { background: #fff; color: #1a1a2e; border-color: rgba(0, 0, 0, .12); }
:root.light .spz-dialog p { color: #4b5563; }

/* ── C3 Contrast: status colours hard-coded inline on light tints ──────── */
:root.light :is(.badge, .pill, .tag, span)[style*="color:#d2705a" i] { color: #9e5444 !important; }
:root.light :is(.badge, .pill, .tag, span)[style*="color:#ffd166" i] { color: #a65b05 !important; }
:root.light :is(.badge, .pill, .tag, span)[style*="color:#9caa6b" i] { color: #647336 !important; }

/* ── No sideways scrolling (2026-10-19) ────────────────────────────────
   Pages set overflow-x:hidden on <body> only. Browsers then report the page
   as screen-wide, but iPhones still let a finger pan to anything that sticks
   out. clip on both <html> and <body> stops the pan without turning <body>
   into its own scroller (hidden would, and break window scrolling). */
@supports (overflow: clip) {
  html, body { overflow-x: clip; }
}

/* Pop-ups on phones: side-by-side field rows used plain 1fr columns, which
   can't shrink below their fields — a two-column date row was 598px wide in a
   314px dialog and scrolled sideways. They now flow into as many columns as
   fit (two on most phones); date-time pickers get a full row. */
@media (max-width: 600px) {
  .modal input, .modal select, .modal textarea { min-width: 0; max-width: 100%; }
  .modal input[type="file"] { width: 100%; }
  .modal [style*="grid-template-columns:1fr 1fr"], .modal [style*="grid-template-columns: 1fr 1fr"],
  .modal [style*="grid-template-columns:repeat(2,1fr)"], .modal [style*="grid-template-columns:repeat(3,1fr)"],
  .modal [style*="grid-template-columns:2fr 1fr"] {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)) !important;
  }
  .modal [style*="grid-template-columns"]:has(input[type="datetime-local"]) { grid-template-columns: minmax(0, 1fr) !important; }
  .modal [style*="grid-template-columns"] > * { min-width: 0; }
  .modal [style*="display:flex"]:has(> input, > select, > button, > .btn) { flex-wrap: wrap; }
  /* invoice line items: description on its own row, the five small fields under it */
  .modal [style*="90px 60px 100px 92px 28px"] { grid-template-columns: repeat(4, minmax(0, 1fr)) 36px !important; }
  .modal [style*="90px 60px 100px 92px 28px"] > :first-child { grid-column: 1 / -1; }
}
