/* ── StuGar · shared UI kit ──────────────────────────────────────────────────
   Components every module was previously re-implementing: buttons, cards,
   badges, empty states, skeletons, and the shells for ui.js's toast + dialog.
   Everything resolves against /tokens.css, so link that first:

       <link rel="stylesheet" href="/tokens.css">
       <link rel="stylesheet" href="/ui.css">
       <script src="/ui.js" defer></script>

   Class names are prefixed sg- so they can't collide with a page's existing
   .btn / .badge / .modal rules during migration.
   ──────────────────────────────────────────────────────────────────────────── */

/* ── Focus baseline ────────────────────────────────────────────────────────────
   The app had no :focus-visible rule anywhere and 25 `outline:none` declarations
   removing the default ring, leaving keyboard users with a 1.5px border tint.
   This restores a visible ring for keyboard focus only — mouse clicks stay clean
   because :focus-visible doesn't match them. !important is deliberate: this is an
   accessibility floor, and it has to beat the per-page `outline:none` rules that
   load after this file. Pages set nothing on :focus-visible, so nothing conflicts. */
:is(a[href], button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent) !important;
  outline-offset: 2px !important;
  border-radius: inherit;
}

/* ── Buttons ───────────────────────────────────────────────────────────────── */
.sg-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 14px; min-height: 40px;            /* 40px keeps it thumb-sized */
  border: 1.5px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  font-family: var(--font); font-size: var(--fs-sm); font-weight: 700;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background .15s, border-color .15s, color .15s, opacity .15s;
}
.sg-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.sg-btn:disabled { opacity: .5; cursor: default; }
.sg-btn:focus-visible { outline: var(--focus); outline-offset: var(--focus-offset); }

.sg-btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.sg-btn--primary:hover:not(:disabled) { filter: brightness(1.08); color: #fff; }
.sg-btn--danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.sg-btn--danger:hover:not(:disabled) { filter: brightness(1.08); color: #fff; }
.sg-btn--ghost { background: transparent; border-color: transparent; color: var(--muted); }
.sg-btn--ghost:hover:not(:disabled) { background: var(--surface2); color: var(--text); }
.sg-btn--sm { padding: 5px 10px; min-height: 32px; font-size: var(--fs-xs); border-radius: var(--r-sm); }

/* ── Legacy class bridge ───────────────────────────────────────────────────────
   The app grew five incompatible button systems: `.btn.primary` on some pages,
   `.btn-primary` on others, ID-scoped buttons elsewhere. Rewriting every call
   site would churn thousands of lines of generated markup for no behavioural
   gain, so instead the old class names get the kit's geometry here and the
   per-page .btn rules are deleted. Markup is untouched; only the look converges.
   Both naming conventions are covered, so copied markup now works either way. */
.btn, .btn-primary, .btn-outline, .btn-danger, .btn-ghost, .btn-sm, .btn-icon {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 14px; min-height: 40px;
  border: 1.5px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  font-family: var(--font); font-size: var(--fs-sm); font-weight: 700;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background .15s, border-color .15s, color .15s, opacity .15s;
}
.btn:hover:not(:disabled), .btn-outline:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.btn:disabled, .btn-primary:disabled, .btn-danger:disabled { opacity: .5; cursor: default; }

.btn.primary, .btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.primary:hover:not(:disabled), .btn-primary:hover:not(:disabled) { filter: brightness(1.08); color: #fff; }

.btn.danger, .btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn.danger:hover:not(:disabled), .btn-danger:hover:not(:disabled) { filter: brightness(1.08); color: #fff; }

.btn.ghost, .btn-ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn.ghost:hover:not(:disabled), .btn-ghost:hover:not(:disabled) { background: var(--surface2); color: var(--text); }

.btn.sm, .btn-sm { padding: 5px 10px; min-height: 32px; font-size: var(--fs-xs); border-radius: var(--r-sm); }

/* Icon-only buttons. A single ✕ inside a full 40px pill (and, for .danger, a
   solid red block) reads as a heavy control for a light action — these are
   square, quiet, and tint only on hover. */
.btn.icon, .btn-icon {
  width: 32px; min-width: 32px; height: 32px; min-height: 32px;
  padding: 0; border-radius: var(--r-sm); line-height: 1; font-size: .95rem;
  background: transparent; border-color: transparent; color: var(--muted);
}
.btn.icon:hover:not(:disabled), .btn-icon:hover:not(:disabled) {
  background: var(--surface2); color: var(--text); border-color: transparent;
}
.btn.icon.danger, .btn.icon.btn-danger, .btn-icon.danger {
  background: transparent; border-color: transparent; color: var(--danger);
}
.btn.icon.danger:hover:not(:disabled), .btn-icon.danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger);
}
.btn.icon.primary, .btn.icon.btn-primary { background: transparent; color: var(--accent); border-color: transparent; }

/* ── Card ──────────────────────────────────────────────────────────────────── */
.sg-card {
  background: var(--surface); border: 1.5px solid var(--border);
  border-radius: var(--r-lg); padding: var(--sp-4);
}

/* ── Badge geometry bridge ─────────────────────────────────────────────────────
   Ten badge families had grown across the app, from .56rem/1px 5px/radius 5px to
   .68rem/2px 8px/radius 999px, so the same "status chip" idea looked different in
   every module. Size, shape and weight are set once here; each page keeps its own
   semantic COLOURS and its own `display` (a few are flex rows with a gap). */
.badge, .item-badge, .pill, .tag-pill, .type-badge, .trade-badge, .mod-tag,
.ownership-pill, .vac-type-badge, .liab-badge {
  padding: 2px 7px; border-radius: var(--r-sm);
  font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .02em; line-height: 1.45;
}

/* ── Badges ────────────────────────────────────────────────────────────────── */
.sg-badge {
  display: inline-block; padding: 2px 7px; border-radius: var(--r-sm);
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .02em;
  background: var(--surface2); color: var(--muted);
}
.sg-badge--ok     { background: color-mix(in srgb, var(--success) 16%, transparent); color: var(--success); }
.sg-badge--warn   { background: color-mix(in srgb, var(--warn) 18%, transparent);    color: var(--warn); }
.sg-badge--danger { background: color-mix(in srgb, var(--danger) 16%, transparent);  color: var(--danger); }
.sg-badge--info   { background: color-mix(in srgb, var(--info) 16%, transparent);    color: var(--info); }

/* ── Empty state ───────────────────────────────────────────────────────────── */
.sg-empty { text-align: center; padding: 36px 16px; color: var(--muted); font-size: var(--fs-sm); }
.sg-empty__icon { font-size: 2.4rem; line-height: 1; margin-bottom: 8px; }

/* A failed load is not an empty list. Six pages used the empty style for errors,
   so "Could not load tasks" looked exactly like "you have no tasks". */
.sg-empty--error { color: var(--danger); font-weight: 600; }
.sg-empty--error .sg-empty__icon { opacity: .85; }
.sg-empty--loading { color: var(--muted); opacity: .8; }

/* ── Skeleton ──────────────────────────────────────────────────────────────── */
.sg-skeleton {
  height: 14px; border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--surface2), var(--border), var(--surface2));
  background-size: 200% 100%; animation: sg-sh 1.2s infinite;
}
@keyframes sg-sh { 0% { background-position: 200% 0 } 100% { background-position: -200% 0 } }
/* Placeholder rows for the first paint, so a loading list isn't a blank panel. */
.sg-skel-rows { display: flex; flex-direction: column; gap: 12px; padding: 16px 0; }
.sg-skel-rows .sg-skeleton:nth-child(1) { width: 72%; }
.sg-skel-rows .sg-skeleton:nth-child(2) { width: 90%; }
.sg-skel-rows .sg-skeleton:nth-child(3) { width: 64%; }
.sg-skel-rows .sg-skeleton:nth-child(4) { width: 80%; }

/* ── Toast (driven by ui.js) ───────────────────────────────────────────────── */
.sg-toasts {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(20px + env(safe-area-inset-bottom));
  z-index: 900; display: flex; flex-direction: column; gap: 8px;
  align-items: center; pointer-events: none; width: max-content; max-width: 92vw;
}
.sg-toast {
  background: #0f172a; color: #fff; padding: 10px 18px;
  border-radius: var(--r-md); font-size: var(--fs-sm); font-weight: 600;
  box-shadow: var(--shadow-2); opacity: 0; transition: opacity .2s, transform .2s;
  transform: translateY(6px); text-align: center;
}
.sg-toast.is-in { opacity: 1; transform: none; }
.sg-toast--error { background: var(--danger); }
.sg-toast--success { background: var(--success); color: #05261d; }

/* ── Dialog (driven by ui.js) ──────────────────────────────────────────────── */
.sg-dialog-bg {
  position: fixed; inset: 0; z-index: 950;
  background: rgba(15, 23, 42, .55);
  display: flex; align-items: center; justify-content: center;
  padding: calc(18px + env(safe-area-inset-top)) 18px calc(18px + env(safe-area-inset-bottom));
  opacity: 0; transition: opacity .15s;
  overscroll-behavior: contain;
}
.sg-dialog-bg.is-in { opacity: 1; }
.sg-dialog {
  background: var(--surface); color: var(--text);
  border: 1.5px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-3); padding: 20px;
  width: 100%; max-width: 380px;
  max-height: calc(100vh - 36px); overflow-y: auto;
  font-family: var(--font); font-size: var(--fs-body);
  transform: translateY(8px) scale(.98); transition: transform .15s;
}
.sg-dialog-bg.is-in .sg-dialog { transform: none; }
.sg-dialog__title { font-size: var(--fs-title); font-weight: 700; margin: 0 0 8px; }
.sg-dialog__body  { color: var(--muted); font-size: var(--fs-sm); line-height: 1.5; white-space: pre-wrap; }
.sg-dialog__input {
  width: 100%; box-sizing: border-box; margin-top: 12px;
  padding: 9px 10px; border: 1.5px solid var(--border); border-radius: var(--r-md);
  background: var(--bg); color: var(--text); font-family: var(--font); font-size: 1rem;
}
.sg-dialog__input:focus-visible { outline: var(--focus); outline-offset: 1px; border-color: var(--accent); }
.sg-dialog__actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 18px; flex-wrap: wrap; }
.sg-dialog__actions .sg-btn { flex: 1 1 auto; }

@media (prefers-reduced-motion: reduce) {
  .sg-toast, .sg-dialog-bg, .sg-dialog { transition: none; }
  .sg-skeleton { animation: none; }
}
