/* shell.css — the app-shell kit: buttons, fields, pills, notes, cards, tabs, tables,
   sheets, toasts, drawers, menus and empty states.
   ==========================================================================================

   WHAT THIS IS FOR. The signed-in pages — org, admin, welcome, join, signin — each grew
   their own buttons. org.html has .og-btn, admin.html has .ad-btn, join.html has .jn-btn,
   welcome.html has .wc-btn, and every one of them is a slightly different height, radius and
   hover. They were written months apart and each looked fine on its own page; together they
   read as five products. This file is the one answer, so a button means the same thing
   wherever it is.

   WHAT IT IS NOT. site.css keeps `.btn` for the marketing pages and is not loaded beside
   this one. Marketing CTAs stay pill-shaped with the gradient; inside the app the primary is
   a flat accent, so the gradient keeps meaning exactly one thing — Premium — instead of
   meaning "button".

   The editor (app.css) is not migrated here. Its tokens have the same names where they
   overlap, so it can adopt this later without a rename.

   ── THE HIERARCHY RULES ─────────────────────────────────────────────────────────────────
   Written here rather than in a document because this is the file someone has open when
   they are about to break one.

   1. ONE `.primary` per card, sheet or table toolbar. Two primaries side by side is a design
      bug: it means nobody decided what the view is for.
   2. Secondary sits to the LEFT of primary: [Cancel] [Send 3 invitations]. The primary is
      rightmost, because that is where the eye and the thumb both end up.
   3. DANGER NEVER SITS BESIDE PRIMARY. It belongs in a ⋯ menu, or at the bottom of a
      settings card with its own line explaining what it destroys.
   4. Table-row actions: at most two, `.b.sm`, secondary. The rest go in a ⋯ menu.
   5. Labels are a verb and its object — "Send invitations", "Give a seat", "Activate with 5
      seats". Never "OK", "Submit", "Yes". A button that only says Yes makes the person
      re-read the question to find out what they are agreeing to.
   6. A BUTTON THE DATABASE WOULD REFUSE IS NOT RENDERED. Not disabled — not rendered — with
      the reason given once in the card's hint line. A disabled control is a promise that it
      might work later; if the policy will never allow it, that promise is a lie. This
      codebase has fixed the same bug three times under the name "a UI offering what the
      server denies".
   ───────────────────────────────────────────────────────────────────────────────────────── */

:root {
  --accent: #7C5CFF;
  --accent-ink: #4B2FBF;          /* the mark's deep violet — hover and pressed */
  --accent-soft: #EFEBFF;
  --pink: #FF6B9D;
  --grad: linear-gradient(135deg, #7C5CFF, #FF6B9D);

  --ink: #1c1c28;
  --ink-soft: #56566a;
  --ink-faint: #8d8da0;

  --panel: #fff;
  --panel-2: #f6f6fb;
  --panel-3: #eeeef5;
  --border: #e9e8f0;
  --border-strong: #dcdbe6;

  --ok: #0d6b43;    --ok-bg: #eafaf2;    --ok-line: #c4ecd9;
  --warn: #7a4b00;  --warn-bg: #fff6e8;  --warn-line: #f3dcb8;
  --bad: #9d2020;   --bad-bg: #fdecec;   --bad-line: #f7cfcf;
  --info: #2a2a3c;  --info-bg: #f1f0f7;  --info-line: #e3e1ef;

  --r-sm: 8px; --r-md: 10px; --r-lg: 14px; --r-xl: 18px;

  /* Two rings, not one: the white inner ring keeps the focus visible when the control sits
     on a tinted row or a coloured button. */
  --focus: 0 0 0 2px #fff, 0 0 0 5px rgba(124, 92, 255, .45);
  --shadow-1: 0 1px 2px rgba(28, 28, 40, .08);
  --shadow-2: 0 8px 26px rgba(20, 14, 50, .10);
  --shadow-3: 0 24px 70px rgba(20, 18, 34, .30);
}

/* ===========================================================================  BUTTONS  === */
/* Minimum hit target is 32px tall at every size, including .sm — below that a touch misses
   often enough to be noticed, and a mouse has to be aimed. */
.b {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 38px; padding: 0 16px; border-radius: var(--r-md);
  background: var(--panel); color: var(--ink);
  border: 1.5px solid var(--border-strong);
  font: 700 14px/1 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: background .12s ease, border-color .12s ease, color .12s ease, transform .06s ease;
  -webkit-tap-highlight-color: transparent;
}
.b:hover { border-color: var(--accent); color: var(--accent); }
.b:active { background: var(--panel-2); transform: translateY(1px); }

.b.primary { background: var(--accent); color: #fff; border-color: var(--accent); box-shadow: var(--shadow-1); }
.b.primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); color: #fff; }
.b.primary:active { background: var(--accent-ink); }

.b.ghost { background: transparent; border-color: transparent; color: var(--ink-soft); }
.b.ghost:hover { background: var(--panel-2); color: var(--ink); border-color: transparent; }
.b.ghost:active { background: var(--panel-3); }

.b.danger { color: var(--bad); border-color: var(--border-strong); }
.b.danger:hover { background: var(--bad-bg); border-color: var(--bad-line); color: var(--bad); }

/* Inline, inside a sentence. No padding and no height, so it sits on the text baseline. */
.b.link {
  height: auto; padding: 0; border: 0; background: none; color: var(--accent);
  font-weight: 700; border-radius: 3px;
}
.b.link:hover { text-decoration: underline; background: none; color: var(--accent-ink); }
.b.link:active { transform: none; background: none; }

/* Marketing only — the hero CTA and the nav Sign up. Inside the app, use .primary. */
.b.pill { border-radius: 999px; background: var(--grad); color: #fff; border-color: transparent; }
.b.pill:hover { color: #fff; transform: translateY(-1px); box-shadow: var(--shadow-2); }

/* THE FOCUS RING, LAST IN THIS BLOCK ON PURPOSE, AND NAMING THE VARIANTS EXPLICITLY.
   `.b:focus-visible` and `.b.primary` have the SAME specificity (0,2,0), so whichever is
   written later wins. With the ring declared first — the obvious place, right after :hover
   and :active — `.b.primary`'s resting `box-shadow: var(--shadow-1)` overrode it and the one
   button people reach for most had no visible focus at all. It still matched :focus-visible,
   so it looked correct in the DOM; only the computed box-shadow gave it away.
   qa/kit.test.js checks this specific trap now. */
.b:focus-visible,
.b.primary:focus-visible,
.b.pill:focus-visible,
.b.ghost:focus-visible,
.b.danger:focus-visible,
.b.link:focus-visible { outline: none; box-shadow: var(--focus); }

/* ---- sizes ---- */
.b.sm { height: 32px; padding: 0 12px; font-size: 13px; border-radius: var(--r-sm); }
.b.lg { height: 46px; padding: 0 22px; font-size: 15px; border-radius: var(--r-lg); }
.b.icon { padding: 0; width: 38px; }
.b.sm.icon { width: 32px; }
.b.lg.icon { width: 46px; }
.b.icon svg { width: 18px; height: 18px; }
.b.block { display: flex; width: 100%; }

/* ---- disabled ---- */
/* aria-disabled as well as the attribute: a link styled as a button cannot carry [disabled]. */
.b[disabled], .b[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
.b[disabled]:hover, .b[aria-disabled="true"]:hover {
  border-color: var(--border-strong); color: inherit; background: var(--panel);
}
.b.primary[disabled]:hover { background: var(--accent); }
.b.ghost[disabled]:hover { background: transparent; }
.b[disabled]:active, .b[aria-disabled="true"]:active { transform: none; }

/* ---- busy ---- */
/* THE BUTTON KEEPS ITS WIDTH. shell.js pins min-width from offsetWidth before swapping the
   label, because a row of buttons that reflows the moment one is pressed makes the person
   wonder whether they hit the right one. Replaces five hand-rolled
   `btn.disabled = true; btn.textContent = 'Creating…'` sequences. */
.b.busy { pointer-events: none; }
.b.busy > .b-spin {
  width: 16px; height: 16px; flex: none; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: b-spin .7s linear infinite;
}
@keyframes b-spin { to { transform: rotate(360deg); } }

/* ===========================================================================  FIELDS   === */
.field { margin: 0 0 14px; }
.field label, .field > .f-label {
  display: block; font-size: 11.5px; font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-faint); margin: 0 0 6px;
}
.field input, .field textarea, .field select {
  width: 100%; box-sizing: border-box; background: var(--panel); color: var(--ink);
  border: 1.5px solid var(--border); border-radius: 11px; padding: 10px 12px;
  font: 600 14px/1.35 'Plus Jakarta Sans', system-ui, sans-serif;
}
.field textarea { min-height: 84px; resize: vertical; }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(124, 92, 255, .14);
}
.field .hint { margin: 6px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--ink-faint); }
.field.bad input, .field.bad textarea, .field.bad select { border-color: var(--bad-line); }
.field.bad .hint { color: var(--bad); }

/* ===========================================================================  PILLS    === */
/* NOTE THE :not(.b). The spec gave the badge and the marketing button-shape the same name —
   `.pill` for a status badge, `.b.pill` for the rounded gradient CTA — and both rules match an
   element with class="b pill". The badge is defined later, so its 10.5px uppercase font won
   and the hero CTA rendered as a tiny shouting chip. Scoping the badge away from buttons keeps
   both names from the spec working; renaming either would mean touching every page that has
   already been written against it. */
.pill:not(.b) {
  display: inline-block; border-radius: 999px; padding: 3px 9px; white-space: nowrap;
  font: 800 10.5px/1.6 'Plus Jakarta Sans', system-ui, sans-serif;
  letter-spacing: .04em; text-transform: uppercase;
  background: var(--panel-3); color: var(--ink-soft);
}
.pill:not(.b).ok    { background: var(--ok-bg);   color: var(--ok); }
.pill:not(.b).warn  { background: var(--warn-bg); color: var(--warn); }
.pill:not(.b).bad   { background: var(--bad-bg);  color: var(--bad); }
.pill:not(.b).info  { background: var(--info-bg); color: var(--info); }
.pill:not(.b).owner { background: var(--ink); color: #fff; }
.pill:not(.b).admin { background: var(--accent-soft); color: var(--accent-ink); }
.pill:not(.b).seat  { background: var(--grad); color: #fff; }

/* ===========================================================================  NOTES    === */
/* A note explains a state. It is not an alert — four tones, and the page decides which. */
.note {
  border-radius: 13px; padding: 14px 16px; margin: 0 0 16px;
  font-size: 13.5px; line-height: 1.6;
  background: var(--info-bg); border: 1px solid var(--info-line); color: var(--info);
}
.note.ok   { background: var(--ok-bg);   border-color: var(--ok-line);   color: var(--ok); }
.note.warn { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn); }
.note.bad  { background: var(--bad-bg);  border-color: var(--bad-line);  color: var(--bad); }
.note b { font-weight: 800; }

/* ===========================================================================  CARDS    === */
.card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-xl);
  padding: 20px; margin: 0 0 18px;
}
.card > h2, .card > .c-head h2 {
  font: 800 16px/1.3 'Poppins', 'Plus Jakarta Sans', sans-serif; margin: 0 0 4px; color: var(--ink);
}
.card > p.hint, .card .c-hint {
  color: var(--ink-soft); font-size: 13px; line-height: 1.55; margin: 0 0 14px;
}
.c-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 4px; }
.c-head .c-space { flex: 1 1 auto; }

/* ===========================================================================  TABS     === */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); margin: 0 0 20px; overflow-x: auto; }
.tabs button {
  appearance: none; background: none; border: 0; cursor: pointer; white-space: nowrap;
  padding: 11px 14px; margin-bottom: -1px; border-bottom: 2px solid transparent;
  font: 700 13.5px/1 'Plus Jakarta Sans', system-ui, sans-serif; color: var(--ink-faint);
}
.tabs button:hover { color: var(--ink); }
.tabs button[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }
.tabs button:focus-visible { outline: none; box-shadow: var(--focus); border-radius: var(--r-sm); }
.tabs .t-count { display: inline-block; margin-left: 6px; font-size: 11px; color: var(--ink-faint); }

/* ===========================================================================  TABLE    === */
.table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.table th {
  text-align: left; padding: 10px 12px; white-space: nowrap;
  font: 800 11px/1.4 'Plus Jakarta Sans', system-ui, sans-serif;
  letter-spacing: .05em; text-transform: uppercase; color: var(--ink-faint);
  background: var(--panel-2); border-bottom: 1px solid var(--border);
}
.table td { padding: 12px; border-bottom: 1px solid var(--border); vertical-align: middle; color: var(--ink); }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--panel-2); }
.table .t-who b { display: block; font-weight: 700; }
.table .t-who i { font-style: normal; display: block; font-size: 12px; color: var(--ink-faint); }
.table .t-acts { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }

/* ===========================================================================  SHEET    === */
/* The confirm dialog. shell.js's sheet() returns a promise, so a destructive action reads as
   one statement at the call site instead of a callback the reader has to chase. */
.sheet-wrap {
  position: fixed; inset: 0; z-index: 90; display: flex; align-items: center; justify-content: center;
  padding: 20px; background: rgba(20, 18, 34, .44);
}
.sheet {
  background: var(--panel); border-radius: var(--r-xl); width: min(480px, 100%);
  max-height: 88vh; overflow: auto; box-shadow: var(--shadow-3);
  padding: 22px; box-sizing: border-box;
}
.sheet h3 { font: 800 18px/1.3 'Poppins', 'Plus Jakarta Sans', sans-serif; margin: 0 0 8px; color: var(--ink); }
.sheet p { margin: 0 0 14px; font-size: 14px; line-height: 1.6; color: var(--ink-soft); }
.sheet .s-acts { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }

/* ===========================================================================  TOAST    === */
/* Bottom-left, one at a time. Bottom-RIGHT is where the editor puts its own toasts and where
   most chat widgets sit; left keeps them apart. */
.toast {
  position: fixed; left: 20px; bottom: 20px; z-index: 95; max-width: min(420px, calc(100vw - 40px));
  background: var(--ink); color: #fff; border-radius: var(--r-lg); padding: 12px 16px;
  font: 600 13.5px/1.5 'Plus Jakarta Sans', system-ui, sans-serif;
  box-shadow: var(--shadow-2); animation: toast-in .18s ease;
}
.toast.ok  { background: #0f5c3c; }
.toast.bad { background: #8d1f1f; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } }

/* ===========================================================================  DRAWER   === */
.drawer-wrap { position: fixed; inset: 0; z-index: 85; background: rgba(20, 18, 34, .38); }
.drawer {
  position: absolute; top: 0; right: 0; bottom: 0; width: min(520px, 100%);
  background: var(--panel); box-shadow: var(--shadow-3); overflow: auto; padding: 24px;
  box-sizing: border-box; animation: drawer-in .2s ease;
}
@keyframes drawer-in { from { transform: translateX(16px); opacity: .6; } }

/* ===========================================================================  EMPTY    === */
.empty { text-align: center; padding: 38px 20px; color: var(--ink-faint); }
.empty svg { width: 32px; height: 32px; opacity: .55; margin-bottom: 10px; }
.empty p { margin: 0 0 14px; font-size: 13.5px; line-height: 1.6; }

/* ===========================================================================  MENU     === */
.menu {
  position: fixed; z-index: 92; min-width: 190px; padding: 6px;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
}
.menu button {
  display: flex; align-items: center; gap: 9px; width: 100%; height: 34px; padding: 0 10px;
  background: none; border: 0; border-radius: var(--r-sm); cursor: pointer; text-align: left;
  font: 600 13.5px/1 'Plus Jakarta Sans', system-ui, sans-serif; color: var(--ink);
}
.menu button:hover { background: var(--panel-2); }
.menu button:focus-visible { outline: none; box-shadow: var(--focus); }
.menu button.danger { color: var(--bad); }
.menu button.danger:hover { background: var(--bad-bg); }
.menu .m-div { height: 1px; margin: 5px 6px; background: var(--border); }

/* ========================================================================  MOTION      === */
/* Someone who has asked their system for less movement has usually asked for a reason. */
@media (prefers-reduced-motion: reduce) {
  .b, .toast, .drawer { transition: none; animation: none; }
  .b.busy > .b-spin { animation-duration: 2.4s; }
}
