/* css/organizations.css — Keduka School OS (the `organizations` app).
 *
 * WHY THIS FILE EXISTS
 * --------------------
 * Every template under templates/organizations/ was originally styled purely
 * in Tailwind utility classes. staticfiles/css/tailwind-main.css is a
 * VENDORED, PRE-BUILT file with no build pipeline (there is no
 * tailwind.config.js and no package.json outside frontend_fixseat/), so it
 * carries only a narrow subset of utilities. The classes those pages leaned
 * on hardest — max-w-4xl, max-w-3xl, max-w-2xl, grid-cols-2, sm:grid-cols-4,
 * py-12, mt-8, gap-4, list-decimal — are ALL absent from it. `mx-auto` IS
 * present, which is what made the failure so quiet: the container centred
 * itself against a max-width that never existed, so every page rendered as
 * full-bleed unstyled text. Adding more Tailwind classes cannot fix this.
 *
 * SCOPE DISCIPLINE
 * ----------------
 * Every selector hangs off the `.orgs` root class. dashboard.css installs a
 * global `* { margin: 0; padding: 0 }` reset and an `html, body` background;
 * importing that pattern here would restyle base.html's navbar and footer on
 * /teams/, which is a PUBLIC, indexable marketing page. This is the same rule
 * resources/static/resources/css/list.css documents at its own head, learned
 * the same way. Pinned by test_every_selector_is_scoped_under_the_root_class.
 *
 * PALETTE
 * -------
 * The token VALUES are the canonical KAIS dashboard/home palette, re-declared
 * inside the `.orgs` scope rather than inherited from a `:root` block we do
 * not load. Two inherited values are deliberately NOT reused, because they
 * measurably fail WCAG 2.2 AA against THIS surface (the composited
 * glassmorphic card top #202745, not the flat page background — which is
 * exactly why they read as safe):
 *
 *   --text-muted  #7a83a0  measures 3.88:1  -> replaced by #9aa2bb (5.75:1)
 *   --brand-2     #9b6dff  measures 4.19:1  -> replaced by #b494ff (6.00:1)
 *
 * Likewise the primary CTA uses DARK ink on the brand gradient: white on that
 * gradient measures 2.43:1 at the blue end and 3.49:1 at the purple end and
 * fails outright, while #0b1020 measures 7.81:1 and 5.43:1. home.css records
 * the same finding and solves it with a darker solid; on this dark surface a
 * bright gradient with dark ink reads better and measures better.
 *
 * All of the above is COMPUTED from these token values by
 * tests/test_organizations/test_org_templates_styling.py::TestMeasuredContrast,
 * so an edit that breaks contrast turns the suite red rather than shipping.
 *
 * RTL: logical properties only (margin-inline, padding-inline,
 * border-inline-start, inset-inline). KAIS ships 35+ locales.
 */

/* ------------------------------------------------------------------
 * 1. Token scope
 * ------------------------------------------------------------------ */

.orgs {
  /* Surfaces (canonical KAIS navy) */
  --org-bg-page: #0b1020;
  --org-bg-alt: #0e1429;
  --org-surface-card: #121939;
  /* The composited top edge of the glass gradient below. Declared as a flat
     value so contrast can be COMPUTED rather than eyeballed. */
  --org-surface-glass-top: #202745;
  --org-surface-inset: #0d1430;

  /* Brand */
  --org-brand: #6aa8ff;
  --org-brand-2: #9b6dff;

  /* Text — every one of these is contrast-tested against the glass top */
  --org-text-heading: #e7e9f3;
  --org-text-body: #b9bfd3;
  --org-text-muted: #9aa2bb;
  --org-text-accent: #b494ff;
  --org-text-link: #6aa8ff;
  --org-text-ok: #2fd37a;
  --org-text-warn: #ffc800;
  --org-text-danger: #ff8080;

  /* Interaction */
  --org-btn-primary-ink: #0b1020;
  --org-focus-ring: #8ec2ff;

  /* Lines and depth */
  --org-border-card: rgba(255, 255, 255, 0.08);
  --org-border-strong: rgba(255, 255, 255, 0.16);
  /* The edge of a DRAWN form control, which WCAG 2.2 SC 1.4.11 holds to 3:1
     against what is adjacent — a stricter bar than a decorative card edge.
     --org-border-strong cannot serve here: it MEASURES 1.61:1 on
     --org-surface-inset (the .orgs-choices row) and 1.66:1 on the consent
     panel. This one measures 3.79:1 and 3.57:1 on those same two surfaces.
     Contrast is COMPUTED from this value by test_checkbox_control.py, so a
     tweak is re-measured rather than assumed. */
  --org-control-border: rgba(255, 255, 255, 0.4);
  --org-glass: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.06),
    rgba(255, 255, 255, 0.02)
  );
  --org-gradient-cta: linear-gradient(90deg, var(--org-brand), var(--org-brand-2));
  --org-gradient-hero:
    radial-gradient(1200px 600px at 80% -10%, rgba(155, 109, 255, 0.25), transparent),
    radial-gradient(900px 500px at -10% 10%, rgba(106, 168, 255, 0.25), transparent),
    var(--org-bg-page);
  --org-shadow-card: 0 10px 30px rgba(0, 0, 0, 0.35);
  --org-shadow-card-hover: 0 25px 60px rgba(31, 45, 92, 0.45);

  /* Geometry */
  --org-radius-card: 20px;
  --org-radius-sm: 12px;
  --org-radius-pill: 999px;
  --org-tap: 44px;

  --org-font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  font-family: var(--org-font);
  color: var(--org-text-body);
}

/* Scoped box-sizing only. NOT a global reset — see the header note. */
.orgs *,
.orgs *::before,
.orgs *::after {
  box-sizing: border-box;
}

/* ------------------------------------------------------------------
 * 2. Page frame
 * ------------------------------------------------------------------ */

.orgs .orgs-page {
  background: var(--org-gradient-hero);
  color: var(--org-text-body);
  min-block-size: 100vh;
  /* Belt and braces: nothing inside may push the document into horizontal
     scroll. Wide content gets its own .orgs-table-wrap instead.
     `hidden` rather than `clip`: clip is unsupported on iOS Safari < 16,
     where it degrades to `visible` and containment is silently lost. This
     also matches dashboard.css's own .dashboard-page rule. */
  overflow-x: hidden;
}

.orgs .orgs-shell {
  inline-size: 100%;
  max-inline-size: 1120px;
  margin-inline: auto;
  padding-inline: clamp(1rem, 4vw, 2.5rem);
  padding-block: clamp(2rem, 6vw, 4rem);
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 4vw, 2.5rem);
}

.orgs .orgs-shell--narrow {
  max-inline-size: 720px;
}

/* The middle measure, for a page that is a FORM PLUS CARDS.
   --narrow's 720px is right for a bare form and wrong the moment the page also
   carries the two-up .orgs-addons pair: at 720px those cards measured 204px
   each. The 1120px default is wrong in the other direction — it would stretch
   a two-letter country-code input across most of a desktop viewport. 960px
   holds a readable card pair and a two-column field grid whose tracks land
   near 420px. */
.orgs .orgs-shell--form {
  max-inline-size: 960px;
}

.orgs .orgs-shell--wide {
  max-inline-size: 1280px;
}

.orgs .orgs-visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------------
 * 3. Page header
 * ------------------------------------------------------------------ */

.orgs .orgs-header {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.orgs .orgs-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  align-self: flex-start;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--org-text-accent);
  margin: 0;
}

.orgs .orgs-eyebrow::before {
  content: "";
  inline-size: 1.75rem;
  block-size: 3px;
  border-radius: var(--org-radius-pill);
  background: var(--org-gradient-cta);
}

/* MODIFIER, and deliberately not a change to `.orgs-eyebrow` itself: that
   class appears on all eleven organizations templates, ten of which are
   signed-in console pages where a filled marketing badge would be noise.
   Only the public acquisition hero wears this.

   Ink is DARK on the brand gradient, never white. That is the same rule the
   primary CTA follows and it is measured, not preferred: white on this
   gradient reads 2.43:1 at the blue stop and 3.49:1 at the purple one and
   fails outright. --org-btn-primary-ink (#0b1020) measures 7.81:1 against
   #6aa8ff and 5.43:1 against #9b6dff, so the badge clears AA 4.5:1 across
   the whole sweep rather than only at its lighter end — which matters
   because the text sits over the full width of the gradient, not one stop.

   The dash `::before` is dropped: it reads as a rule leading INTO a label,
   and a label inside a filled pill has no line to lead into. */
.orgs .orgs-eyebrow--badge {
  gap: 0;
  padding-block: 0.4rem;
  padding-inline: 0.8rem;
  border-radius: var(--org-radius-pill);
  background: var(--org-gradient-cta);
  color: var(--org-btn-primary-ink);
  letter-spacing: 0.1em;
}

.orgs .orgs-eyebrow--badge::before {
  content: none;
}

.orgs .orgs-title {
  font-size: clamp(1.6rem, 1.1rem + 2.4vw, 2.5rem);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--org-text-heading);
  margin: 0;
  /* A long organization name must wrap, never widen the page. */
  overflow-wrap: anywhere;
}

.orgs .orgs-lede {
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.15rem);
  line-height: 1.65;
  color: var(--org-text-body);
  max-inline-size: 62ch;
  margin: 0;
}

.orgs .orgs-fineprint {
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--org-text-muted);
  max-inline-size: 68ch;
  margin: 0;
}

/* ------------------------------------------------------------------
 * 4. Section + card
 * ------------------------------------------------------------------ */

.orgs .orgs-section {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.orgs .orgs-section__title {
  font-size: clamp(1.15rem, 1rem + 0.6vw, 1.5rem);
  font-weight: 700;
  line-height: 1.3;
  color: var(--org-text-heading);
  margin: 0;
}

.orgs .orgs-section__intro {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--org-text-muted);
  max-inline-size: 68ch;
  margin: 0;
}

.orgs .orgs-card {
  position: relative;
  background-color: var(--org-surface-card);
  background-image: var(--org-glass);
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-card);
  padding: clamp(1.15rem, 3vw, 1.75rem);
  box-shadow: var(--org-shadow-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

/* The house top-accent stripe, matched to the resources dashboard. It scales
   in on hover; under reduced motion it is simply present. */
.orgs .orgs-card::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 3px;
  background: var(--org-gradient-cta);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.35s ease;
}

.orgs .orgs-card:hover::before,
.orgs .orgs-card:focus-within::before {
  transform: scaleX(1);
}

.orgs .orgs-card--flush {
  padding: 0;
  gap: 0;
}

.orgs .orgs-card__title {
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--org-text-heading);
  margin: 0;
  overflow-wrap: anywhere;
}

.orgs .orgs-card__meta {
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--org-text-muted);
  margin: 0;
  overflow-wrap: anywhere;
}

@supports not (backdrop-filter: blur(2px)) {
  .orgs .orgs-card {
    background-image: none;
    background-color: var(--org-surface-card);
  }
}

/* ------------------------------------------------------------------
 * 5. Stat grid
 * ------------------------------------------------------------------ */

.orgs .orgs-stats {
  display: grid;
  /* Single column on a 320px phone; fills up naturally with room. */
  grid-template-columns: 1fr;
  gap: 0.85rem;
  margin: 0;
}

@media (min-width: 30rem) {
  .orgs .orgs-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 60rem) {
  .orgs .orgs-stats {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.orgs .orgs-stat {
  background-color: var(--org-surface-card);
  background-image: var(--org-glass);
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-sm);
  padding: 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-inline-size: 0;
}

.orgs .orgs-stat__label {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--org-text-muted);
  margin: 0;
}

.orgs .orgs-stat__value {
  font-size: clamp(1.6rem, 1.3rem + 1.2vw, 2.1rem);
  font-weight: 800;
  line-height: 1.1;
  color: var(--org-text-heading);
  font-variant-numeric: tabular-nums;
  margin: 0;
}

.orgs .orgs-stat__hint {
  font-size: 0.8rem;
  color: var(--org-text-muted);
  margin: 0;
}

/* ------------------------------------------------------------------
 * 6. Buttons and links
 * ------------------------------------------------------------------ */

.orgs .orgs-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-block-size: var(--org-tap);
  padding-inline: 1.5rem;
  padding-block: 0.7rem;
  border: 1px solid transparent;
  border-radius: var(--org-radius-pill);
  font-family: inherit;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.orgs .orgs-btn:hover {
  transform: translateY(-1px);
}

/* Dark ink on the bright gradient. White measures 2.43:1 here and fails. */
.orgs .orgs-btn--primary {
  background: var(--org-gradient-cta);
  color: var(--org-btn-primary-ink);
  box-shadow: 0 4px 15px rgba(106, 168, 255, 0.3);
}

.orgs .orgs-btn--primary:hover {
  box-shadow: 0 8px 24px rgba(106, 168, 255, 0.42);
}

.orgs .orgs-btn--ghost {
  background: transparent;
  color: var(--org-text-link);
  border-color: var(--org-border-strong);
}

.orgs .orgs-btn--ghost:hover {
  background: rgba(106, 168, 255, 0.12);
}

.orgs .orgs-btn--approve {
  background: rgba(47, 211, 122, 0.14);
  color: var(--org-text-ok);
  border-color: rgba(47, 211, 122, 0.45);
}

.orgs .orgs-btn--approve:hover {
  background: rgba(47, 211, 122, 0.22);
}

.orgs .orgs-btn--reject {
  background: rgba(255, 128, 128, 0.14);
  color: var(--org-text-danger);
  border-color: rgba(255, 128, 128, 0.45);
}

.orgs .orgs-btn--reject:hover {
  background: rgba(255, 128, 128, 0.22);
}

.orgs .orgs-btn--warn {
  background: rgba(255, 200, 0, 0.12);
  color: var(--org-text-warn);
  border-color: rgba(255, 200, 0, 0.45);
}

.orgs .orgs-btn--warn:hover {
  background: rgba(255, 200, 0, 0.2);
}

.orgs .orgs-btn--neutral {
  background: rgba(255, 255, 255, 0.06);
  color: var(--org-text-body);
  border-color: var(--org-border-strong);
}

.orgs .orgs-btn--neutral:hover {
  background: rgba(255, 255, 255, 0.12);
}

.orgs .orgs-btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: 0;
}

.orgs .orgs-link {
  color: var(--org-text-link);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  border-radius: 4px;
}

.orgs .orgs-link:hover {
  color: var(--org-text-heading);
}

.orgs .orgs-back {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-block-size: var(--org-tap);
  color: var(--org-text-link);
  font-weight: 600;
  text-decoration: none;
  border-radius: var(--org-radius-sm);
}

.orgs .orgs-back:hover {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* One focus treatment for everything focusable. #8ec2ff measures 7.87:1 on
   the card, 10.20:1 on the page — comfortably past the 3:1 that WCAG 2.2
   requires of a non-text indicator. The offset is POSITIVE so the ring paints
   outside the element rather than over its own content. */
.orgs a:focus-visible,
.orgs button:focus-visible,
.orgs input:focus-visible,
.orgs select:focus-visible,
.orgs textarea:focus-visible,
.orgs [tabindex]:focus-visible {
  outline: 3px solid var(--org-focus-ring);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ------------------------------------------------------------------
 * 7. Console navigation
 * ------------------------------------------------------------------ */

.orgs .orgs-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.orgs .orgs-nav__link {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  min-block-size: var(--org-tap);
  padding-inline: 1.1rem;
  padding-block: 0.6rem;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-pill);
  background-color: var(--org-surface-card);
  color: var(--org-text-body);
  font-weight: 600;
  text-decoration: none;
  transition: border-color 0.2s ease, color 0.2s ease, background-color 0.2s ease;
}

.orgs .orgs-nav__link:hover {
  border-color: var(--org-border-strong);
  background-color: var(--org-bg-alt);
  color: var(--org-text-heading);
}

.orgs .orgs-icon {
  flex: 0 0 auto;
  color: var(--org-brand);
}

/* ------------------------------------------------------------------
 * 8. Tables
 * ------------------------------------------------------------------ */

/* Wide tabular data scrolls INSIDE this box. Without it a three-column
   roster pushes the whole document into horizontal scroll at 320px. */
.orgs .orgs-table-wrap {
  inline-size: 100%;
  overflow-x: auto;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-card);
  background-color: var(--org-surface-card);
  background-image: var(--org-glass);
}

.orgs .orgs-table {
  inline-size: 100%;
  min-inline-size: 32rem;
  border-collapse: collapse;
  font-size: 0.95rem;
  text-align: start;
}

.orgs .orgs-table caption {
  text-align: start;
  padding: 0.9rem 1.1rem 0;
  color: var(--org-text-muted);
  font-size: 0.85rem;
}

.orgs .orgs-table th,
.orgs .orgs-table td {
  padding: 0.85rem 1.1rem;
  text-align: start;
  vertical-align: top;
  border-block-end: 1px solid var(--org-border-card);
  overflow-wrap: anywhere;
}

.orgs .orgs-table thead th {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--org-text-muted);
  white-space: nowrap;
  background-color: rgba(255, 255, 255, 0.03);
}

.orgs .orgs-table tbody th {
  font-weight: 600;
  color: var(--org-text-heading);
}

.orgs .orgs-table tbody td {
  color: var(--org-text-body);
}

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

.orgs .orgs-table tbody tr:hover {
  background-color: rgba(255, 255, 255, 0.03);
}

.orgs .orgs-table__empty {
  color: var(--org-text-muted);
  font-style: italic;
}

/* ------------------------------------------------------------------
 * 9. Definition lists (stat pairs)
 * ------------------------------------------------------------------ */

.orgs .orgs-dl {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem 1.5rem;
  margin: 0;
}

@media (min-width: 34rem) {
  .orgs .orgs-dl {
    grid-template-columns: minmax(10rem, auto) 1fr;
    align-items: baseline;
  }
}

.orgs .orgs-dl__term {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--org-text-muted);
  margin: 0;
}

.orgs .orgs-dl__desc {
  color: var(--org-text-heading);
  font-weight: 600;
  margin: 0;
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------------
 * 10. Lists
 * ------------------------------------------------------------------ */

.orgs .orgs-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.orgs .orgs-list__item {
  margin: 0;
}

.orgs .orgs-list__link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.75rem;
  min-block-size: var(--org-tap);
  padding: 0.7rem 1rem;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-sm);
  background-color: var(--org-surface-card);
  color: var(--org-text-heading);
  font-weight: 600;
  text-decoration: none;
  transition: border-color 0.2s ease, background-color 0.2s ease;
  overflow-wrap: anywhere;
}

.orgs .orgs-list__link:hover {
  border-color: var(--org-border-strong);
  background-color: var(--org-bg-alt);
}

.orgs .orgs-list__meta {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--org-text-muted);
}

/* Numbered getting-started steps. `list-decimal` does not exist in the
   vendored Tailwind build, so the counter is drawn here. */
.orgs .orgs-steps {
  list-style: none;
  counter-reset: orgs-step;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.orgs .orgs-steps__item {
  counter-increment: orgs-step;
  position: relative;
  padding-inline-start: 2.75rem;
  line-height: 1.6;
  color: var(--org-text-body);
  min-block-size: var(--org-tap);
  display: flex;
  align-items: center;
}

.orgs .orgs-steps__item::before {
  content: counter(orgs-step);
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0;
  inline-size: 1.85rem;
  block-size: 1.85rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--org-gradient-cta);
  color: var(--org-btn-primary-ink);
  font-size: 0.85rem;
  font-weight: 800;
}

/* ------------------------------------------------------------------
 * 11. Notes, messages, badges
 * ------------------------------------------------------------------ */

.orgs .orgs-note {
  border: 1px solid var(--org-border-card);
  border-inline-start: 3px solid var(--org-brand);
  border-radius: var(--org-radius-sm);
  background-color: rgba(106, 168, 255, 0.08);
  padding: 0.95rem 1.1rem;
  color: var(--org-text-body);
  line-height: 1.6;
  margin: 0;
}

.orgs .orgs-note--info {
  border-inline-start-color: var(--org-brand-2);
  background-color: rgba(155, 109, 255, 0.1);
}

/* A note that names something OUTSTANDING — work the reader still has to do,
 * not information. Its one user is the console's terms-confirmation prompt,
 * which is the only route a newly approved admin has to the page that
 * unblocks their first roster if the approval email is lost or filtered.
 *
 * A MODIFIER rather than a new note class, and NO new colour: --org-text-warn
 * is already in the token set TestMeasuredContrast computes against, so this
 * cannot introduce an unmeasured pair. The body text deliberately keeps
 * --org-text-body — the warn token carries the STRIPE and the title, because
 * a whole paragraph in #ffc800 reads as an error rather than as a next step,
 * and this is neither an error nor a failure.
 */
.orgs .orgs-note--warn {
  border-inline-start-color: var(--org-text-warn);
  background-color: rgba(255, 200, 0, 0.08);
}

.orgs .orgs-note--warn .orgs-note__title {
  color: var(--org-text-warn);
}

.orgs .orgs-note__title {
  display: block;
  font-weight: 700;
  color: var(--org-text-heading);
  margin-block-end: 0.35rem;
}

.orgs .orgs-messages {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

/* Driven by a data- attribute rather than an interpolated class name, so the
   class-set parity test stays exact. See
   test_no_template_builds_a_class_name_from_context. */
.orgs .orgs-message {
  border: 1px solid var(--org-border-card);
  border-inline-start: 3px solid var(--org-border-strong);
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 255, 255, 0.04);
  padding: 0.85rem 1.1rem;
  color: var(--org-text-body);
  line-height: 1.6;
}

.orgs .orgs-message[data-tag~="success"] {
  border-inline-start-color: var(--org-text-ok);
  background-color: rgba(47, 211, 122, 0.1);
}

.orgs .orgs-message[data-tag~="warning"] {
  border-inline-start-color: var(--org-text-warn);
  background-color: rgba(255, 200, 0, 0.1);
}

.orgs .orgs-message[data-tag~="error"] {
  border-inline-start-color: var(--org-text-danger);
  background-color: rgba(255, 128, 128, 0.1);
}

.orgs .orgs-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding-inline: 0.65rem;
  padding-block: 0.25rem;
  border-radius: var(--org-radius-pill);
  border: 1px solid var(--org-border-strong);
  background-color: rgba(255, 255, 255, 0.06);
  color: var(--org-text-body);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.orgs .orgs-badge--ok {
  color: var(--org-text-ok);
  border-color: rgba(47, 211, 122, 0.45);
  background-color: rgba(47, 211, 122, 0.12);
}

.orgs .orgs-badge--warn {
  color: var(--org-text-warn);
  border-color: rgba(255, 200, 0, 0.45);
  background-color: rgba(255, 200, 0, 0.12);
}

.orgs .orgs-badge--danger {
  color: var(--org-text-danger);
  border-color: rgba(255, 128, 128, 0.45);
  background-color: rgba(255, 128, 128, 0.12);
}

.orgs .orgs-badge--info {
  color: var(--org-text-link);
  border-color: rgba(106, 168, 255, 0.45);
  background-color: rgba(106, 168, 255, 0.12);
}

.orgs .orgs-badge--muted {
  color: var(--org-text-muted);
}

/* ------------------------------------------------------------------
 * 12. Forms
 * ------------------------------------------------------------------
 * `{{ form.as_p }}` emits <p><label>…</label> <input></p> plus Django's own
 * .helptext / .errorlist. Those class names come from Django rather than from
 * a template, so they are styled here without appearing in the parity check.
 */

.orgs .orgs-form {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  margin: 0;
}

.orgs .orgs-form p {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
}

.orgs .orgs-form label {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--org-text-heading);
  line-height: 1.5;
}

.orgs .orgs-form input[type="text"],
.orgs .orgs-form input[type="email"],
.orgs .orgs-form input[type="number"],
.orgs .orgs-form input[type="url"],
.orgs .orgs-form input[type="tel"],
.orgs .orgs-form select,
.orgs .orgs-form textarea,
.orgs .orgs-textarea {
  inline-size: 100%;
  min-block-size: var(--org-tap);
  padding-inline: 0.9rem;
  padding-block: 0.65rem;
  border: 1px solid var(--org-border-strong);
  border-radius: var(--org-radius-sm);
  background-color: var(--org-surface-inset);
  color: var(--org-text-heading);
  font-family: inherit;
  /* 16px minimum: anything smaller makes iOS Safari zoom on focus. */
  font-size: 1rem;
  line-height: 1.5;
  transition: border-color 0.2s ease;
}

.orgs .orgs-form textarea,
.orgs .orgs-textarea {
  resize: vertical;
  min-block-size: 88px;
}

/* Clearance for the sticky site header, on the CONTROL.
 *
 * The reported bug was "Submit application just gets stuck". MEASURED in
 * headless Chromium at 1280x800 and again at 390x844: with a required field
 * unanswered, Chromium refuses the submit, scrolls the offending control to
 * `top: -0.4` with its label at `-28`, and `document.elementFromPoint()` at
 * the control returns `nav.navbar` — `position: sticky; top: 0; z-index: 1000`,
 * occupying y = 0..59. So the browser DID refuse and DID say which question,
 * underneath the header, where nobody can read it. Nothing visibly happened.
 *
 * Three things this rule is, each of them measured rather than chosen:
 *
 *   1. ON THE CONTROL, not on the .orgs-field wrapper. The browser scrolls the
 *      input, not its container: with the offset on .orgs-field the measurement
 *      was unchanged at control top -0 / label -28, i.e. the wrapper version
 *      declares an offset that never binds.
 *   2. EXACTLY ONE lever. `scroll-padding-top` on `html` fixes the same bug on
 *      its own (96 / 68), but the two STACK — declaring both measured 192, a
 *      quarter of a 800px viewport spent on empty space above the question.
 *      This one also stays inside the `.orgs` scope; a global `html` rule from
 *      a page-scoped stylesheet would re-anchor every `#`-jump on the site,
 *      which is the blast radius this file's scoping discipline exists to
 *      prevent.
 *   3. 96px is DERIVED. The bar ends at 59 and the label sits 28px above the
 *      control, so anything under 87 still scrolls the question off screen and
 *      leaves the applicant reading a refusal about a field they cannot see.
 *      96 measured control top 96 / label top 68 — clear by 9px. Do not tidy
 *      it down to the navbar height.
 *
 * The same offset also lands the error-summary anchors (`#id_<field>`) in
 * view, since anchor navigation honours scroll-margin too. The DECLARATION is
 * pinned by test_apply_refusal_is_visible.py; whether it BINDS is measured by
 * tests/visual/org_apply_submit_check.py, which is the evidence. */
.orgs .orgs-form input,
.orgs .orgs-form select,
.orgs .orgs-form textarea {
  scroll-margin-block-start: 96px;
}

.orgs .orgs-form input:hover,
.orgs .orgs-form select:hover,
.orgs .orgs-form textarea:hover,
.orgs .orgs-textarea:hover {
  border-color: var(--org-brand);
}

.orgs .orgs-form input::placeholder,
.orgs .orgs-form textarea::placeholder,
.orgs .orgs-textarea::placeholder {
  color: var(--org-text-muted);
}

/* A DRAWN checkbox, not the platform's.
 *
 * `accent-color` only tints the CHECKED fill. An unchecked native checkbox is
 * still painted by the OS as a light grey square, which on this navy surface
 * reads as leftover unstyled markup rather than as part of the form.
 *
 * Taking the rendering over means re-establishing, deliberately, four things
 * the platform was providing for free — each pinned by
 * tests/test_organizations/test_checkbox_control.py:
 *
 *   1. NON-TEXT CONTRAST. The UA's own border goes away with `appearance`, so
 *      the unchecked boundary becomes ours. `--org-border-strong` MEASURES
 *      1.61:1 on --org-surface-inset and 1.66:1 on the consent panel — both
 *      well under the 3:1 WCAG 2.2 SC 1.4.11 wants for a control edge. It was
 *      never a visible bug only because the platform was drawing the box.
 *      --org-control-border measures 3.79:1 / 3.57:1 on those same two.
 *   2. FOCUS. The platform ring leaves with the platform rendering.
 *   3. FORCED COLORS. See the forced-colors block near the end of this file:
 *      a custom-painted control opts OUT of the user's High Contrast palette,
 *      so it hands rendering back rather than guessing at their colours.
 *   4. RTL. The tick is drawn with `clip-path`, NOT the usual two-borders-on-
 *      a-rotated-box. That trick mirrors into a backwards tick under
 *      dir="rtl" when written logically, and trips this suite's RTL rule when
 *      written physically. A tick is an icon; it must not flip.
 *
 * One rule reaches every checkbox on these forms — the .orgs-choices add-on
 * options, the .orgs-consent attestation, and provision.html's as_p form —
 * because all of them are inside .orgs-form.
 */
.orgs .orgs-form input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  inline-size: 1.35rem;
  block-size: 1.35rem;
  flex: 0 0 auto;
  cursor: pointer;
  /* Centres the tick without giving the box a baseline to sit off. */
  display: inline-grid;
  place-content: center;
  border: 1.5px solid var(--org-control-border);
  border-radius: 0.4rem;
  background-color: var(--org-surface-inset);
  transition: background-color 0.18s ease, border-color 0.18s ease;
}

/* The tick itself: a shape, scaled from 0 so the box never reflows. */
.orgs .orgs-form input[type="checkbox"]::before {
  content: "";
  inline-size: 0.8rem;
  block-size: 0.8rem;
  background-color: var(--org-btn-primary-ink);
  clip-path: polygon(14% 47%, 0 61%, 39% 100%, 100% 22%, 86% 8%, 39% 72%);
  transform: scale(0);
  transition: transform 0.15s ease;
}

/* Dark ink on the brand gradient, exactly as .orgs-btn--primary does: white
   measures 2.43:1 at the blue end and fails, while --org-btn-primary-ink
   measures 7.81:1 there and 5.43:1 at the purple end. */
.orgs .orgs-form input[type="checkbox"]:checked {
  background-image: var(--org-gradient-cta);
  border-color: transparent;
}

.orgs .orgs-form input[type="checkbox"]:checked::before {
  transform: scale(1);
}

.orgs .orgs-form input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--org-focus-ring);
  outline-offset: 2px;
}

/* A checkbox row reads as "[x] statement", never as a label stranded above a
   lone box. Browsers without :has() simply keep the stacked default. */
.orgs .orgs-form p:has(input[type="checkbox"]) {
  flex-direction: row;
  align-items: flex-start;
  gap: 0.7rem;
  min-block-size: var(--org-tap);
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 255, 255, 0.03);
}

.orgs .orgs-form p:has(input[type="checkbox"]) input[type="checkbox"] {
  order: -1;
  margin-block-start: 0.15rem;
}

/* `display` is declared, and declared `!important`, on purpose.
 *
 * tailwind-main.css carries a site-wide `.helptext, ul.helptext,
 * .password-helptext { display: none !important }` — written to hide Django's
 * password-validator help text, and base.html loads that sheet on every page.
 * It therefore hid EVERY field's help text on these forms too. MEASURED in
 * Chromium on /kais/teams/apply/: all five .helptext nodes computed to
 * `display: none` with a 0x0 box, including "For example: your-school.edu" and
 * "Selects the data-protection package that applies to you" — the only place
 * either of those fields is explained at all.
 *
 * The rule was invisible in review because the markup was correct and the
 * class name is Django's, not ours: nothing in this stylesheet or these
 * templates mentions it. Overriding here rather than editing the vendored
 * sheet keeps the password help text hidden everywhere else, and the
 * `.orgs`-scoped selector (0,3,0) beats the vendored `.helptext` (0,1,0) so
 * the win does not depend on source order.
 */
.orgs .orgs-form .helptext {
  display: block !important;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--org-text-muted);
  margin: 0;
}

.orgs .orgs-form .errorlist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--org-text-danger);
}

/* The form-level error summary — the sentence a refused submit is read from.
 *
 * .errorlist above is the PER-FIELD message, which only helps somebody already
 * looking at that field. This is the block at the top of the form, and on a
 * page eleven fields long it is the only thing that can tell an applicant how
 * many answers need attention and give them a way back to each one.
 *
 * Colour repeats the .orgs-badge--danger pairing exactly — --org-text-danger
 * on rgba(255, 128, 128, 0.12) — rather than inventing a red. Every token in
 * this file is contrast-COMPUTED by TestMeasuredContrast, and a new hex is a
 * value nothing has measured.
 *
 * Colour is never the only cue: the panel also carries a border-inline-start
 * weight, so the block still reads as a refusal in greyscale and to a
 * red-blind reader. Same discipline as the .orgs-sim state lines.
 *
 * The focus ring comes free from `.orgs [tabindex]:focus-visible` near the top
 * of this file, which is why this block declares none of its own. */
.orgs .orgs-error-summary {
  border: 1px solid rgba(255, 128, 128, 0.45);
  border-inline-start: 3px solid var(--org-text-danger);
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 128, 128, 0.12);
  padding: 1rem 1.15rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.orgs .orgs-error-summary__title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--org-text-danger);
}

/* `p.` is load-bearing, and this is the FOURTH instance of that trap in this
 * file. `.orgs .orgs-form p { display: flex; flex-direction: column }` is
 * (0,2,1); a plain `.orgs .orgs-error-summary__text` is (0,2,0) and LOSES, so
 * this paragraph would become a flex column and the count sentence would break
 * onto its own line away from the panel's rhythm. The `p.` qualifier takes it
 * to (0,3,1). See the note on .orgs-estimate__fallback, which shipped visible
 * for exactly this reason. */
.orgs .orgs-error-summary p.orgs-error-summary__text {
  display: block;
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.6;
  color: var(--org-text-body);
}

.orgs .orgs-error-summary__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

/* 44px per row, because each row is a link an applicant taps to get back to
 * the answer that was refused — WCAG 2.2 SC 2.5.8. Wrapping rather than
 * truncating: at 320px the label and its message do not share a line, and a
 * message clipped to fit is the message that says WHY. */
.orgs .orgs-error-summary__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.15rem 0.5rem;
  min-block-size: var(--org-tap);
  line-height: 1.5;
}

/* Underlined, and in the highest-contrast text token rather than the usual
 * link blue: --org-text-link is measured against the card surface, not against
 * this panel's red tint, and the underline carries "this is a link" without
 * asking a colour to do it. */
.orgs .orgs-error-summary__link {
  color: var(--org-text-heading);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.orgs .orgs-error-summary__detail {
  font-size: 0.88rem;
  color: var(--org-text-body);
}

.orgs .orgs-field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.orgs .orgs-field__label {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--org-text-heading);
}

/* ------------------------------------------------------------------
 * 12b. Two-column field grid
 * ------------------------------------------------------------------
 * A flat single column is right for a three-field form and wrong for eleven:
 * it turns short answers — a two-letter country code, a seat count — into
 * full-width inputs whose box says "write a paragraph here".
 *
 * The grid lives on an INNER wrapper rather than on .orgs-form itself. The
 * form stays the flex column it already is for every other page in this app,
 * so nothing here can reach provision.html's `{{ form.as_p }}` markup.
 *
 * Every span rule below is declared UNCONDITIONALLY. Only the column count
 * sits inside the breakpoint, because `grid-column: 1 / -1` is a no-op in a
 * single-column grid — and an @media block adds NO specificity, so a span
 * written inside one and repeated outside it would be silently dead.
 */

.orgs .orgs-form__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.1rem;
  min-inline-size: 0;
}

.orgs .orgs-form__grid > .orgs-field--wide,
.orgs .orgs-form__grid > .orgs-fieldset {
  grid-column: 1 / -1;
}

/* Short answers keep a short box even in a wide track. The cap is on the
   CONTROL, not the field, so the label and help text still use the full
   column width and do not wrap early. */
.orgs .orgs-field--compact input,
.orgs .orgs-field--compact select {
  max-inline-size: 14rem;
}

@media (min-width: 44rem) {
  .orgs .orgs-form__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ------------------------------------------------------------------
 * 12c. Choice group (fieldset + legend)
 * ------------------------------------------------------------------
 * A <fieldset> is what a set of related checkboxes belongs in, and it is also
 * the only wrapper that is VALID here: Django renders CheckboxSelectMultiple
 * as a <div>, and `{{ form.as_p }}` put that inside a <p>, where the parser
 * auto-closed the paragraph and reparented the group out as a sibling with no
 * field styling on it at all.
 *
 * `display` is left alone. A <legend> is not an ordinary child — browsers lift
 * it into the fieldset border — and turning the fieldset into a flex or grid
 * container is where that rendering gets inconsistent. Spacing is done with
 * margins on the children instead.
 */

.orgs .orgs-fieldset {
  /* A fieldset's default min-width is min-content, which lets a long choice
     label blow out a grid track. */
  min-inline-size: 0;
  margin: 0;
  padding: 0.9rem 1.15rem 1.1rem;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 255, 255, 0.03);
}

.orgs .orgs-fieldset > * {
  margin-block: 0;
}

.orgs .orgs-fieldset > * + * {
  margin-block-start: 0.5rem;
}

.orgs .orgs-fieldset__legend {
  padding-inline: 0.35rem;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--org-text-heading);
}

/* The widget's own markup is `<div id="…"><div><label><input>…`. None of those
   can carry a class, so the grid is addressed through the wrapper this
   template puts around it rather than through a Django-generated id. */
.orgs .orgs-choices > div {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem;
}

.orgs .orgs-choices label {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  min-block-size: var(--org-tap);
  padding: 0.55rem 0.85rem;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-sm);
  background-color: var(--org-surface-inset);
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--org-text-heading);
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.orgs .orgs-choices label:hover,
.orgs .orgs-choices label:focus-within {
  border-color: var(--org-brand);
  background-color: rgba(106, 168, 255, 0.08);
}

@media (min-width: 44rem) {
  .orgs .orgs-choices > div {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ------------------------------------------------------------------
 * 12d. Consent panel
 * ------------------------------------------------------------------
 * The lawful-basis attestation. It is a consent STEP, not one more field, and
 * it reads as "[x] statement" rather than as a label stranded above a lone
 * box.
 *
 * Declared on its own class rather than left to the
 * `p:has(input[type="checkbox"])` rule above: that rule is right for
 * provision.html's as_p form, but a legally required control should not depend
 * on :has() support to look like one.
 */

/* Who is accepting, stated above the box that accepts. The checkbox label is
 * static — interpolating form values into a <label> needs JavaScript this form
 * does not ship — so this line carries the applicant's own name, role and
 * organization, rendered server-side.
 *
 * The `p.` qualifier is load-bearing, and this is the FOURTH instance of the
 * trap .orgs-estimate__fallback documents. This paragraph sits inside
 * .orgs-form, where `.orgs .orgs-form p { display: flex; flex-direction:
 * column; margin: 0 }` is (0,2,1); a plain `.orgs .orgs-consent__who` is
 * (0,2,0) and LOSES, taking `margin: 0` with it. Spacing is still the
 * .orgs-field gap's job here, so margin stays 0 either way — the qualifier is
 * what makes the font-size, colour and measure below actually reachable
 * alongside a `display` this rule owns rather than inherits.
 */
.orgs .orgs-form p.orgs-consent__who {
  display: block;
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--org-text-muted);
  max-inline-size: 68ch;
}

.orgs .orgs-consent {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  min-block-size: var(--org-tap);
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--org-border-card);
  border-inline-start: 3px solid var(--org-brand);
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 255, 255, 0.03);
  cursor: pointer;
}

.orgs .orgs-consent input[type="checkbox"] {
  margin-block-start: 0.1rem;
}

.orgs .orgs-consent__text {
  font-size: 0.9rem;
  font-weight: 500;
  line-height: 1.6;
  color: var(--org-text-body);
}

.orgs .orgs-form__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-block-start: 0.25rem;
}

/* ------------------------------------------------------------------
 * 12e. Live cost estimate (apply form)
 * ------------------------------------------------------------------
 * The panel that answers "what will this cost?" directly above the button
 * that authorises a card hold. It is INSET rather than raised: it summarises
 * the fields around it, and a second raised card inside the form card would
 * read as a separate offer.
 *
 * Rows are a definition list, so the label↔amount pairing survives a screen
 * reader and a 320px viewport, where each pair stacks instead of a two-column
 * grid collapsing into ambiguity. Amounts are tabular-nums so the column does
 * not jitter as the browser repaints a new total.
 *
 * Colour: labels take --org-text-muted (5.75:1 on the composited card) and
 * amounts take --org-text-heading, both already measured by
 * TestMeasuredContrast. No new hex.
 */

.orgs .orgs-estimate {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-sm);
  background-color: var(--org-surface-inset);
}

.orgs .orgs-estimate__title {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--org-text-heading);
  margin: 0;
}

.orgs .orgs-estimate__list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
}

.orgs .orgs-estimate__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

/* The unpriceable state — one attribute, both paths.
 *
 * `data-estimate-state` is rendered server-side and then maintained by
 * js/org-quote.js, so a malformed pricing table and a server that answered
 * `ok: false` mid-edit look identical to the applicant instead of one of them
 * printing "None" over blank amounts.
 *
 * Specificity is load-bearing here, for the same reason the `[hidden]` rule
 * above documents — and this panel supplies the third instance of that trap.
 * The fallback is a <p> INSIDE .orgs-form, so it is swept up by
 * `.orgs .orgs-form p { display: flex }` at (0,2,1). A plain
 * `.orgs .orgs-estimate__fallback` hiding rule is (0,2,0) and LOSES to it, so
 * the sentence rendered on every priceable panel — measured in Chromium as
 * computed `display: flex` with the text visible under a working total. The
 * `p.` qualifier takes the hiding rule to (0,3,1).
 *
 * Reading it: an element selector beats nothing, but it is the tie-breaker
 * once the class counts are equal. Pinned by test_applicant_quote.py::
 * TestAMalformedPricingTableNeverReachesTheApplicant, which resolves the
 * cascade rather than asserting the selector exists. */
.orgs .orgs-estimate p.orgs-estimate__fallback {
  display: none;
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--org-text-body);
}

.orgs .orgs-estimate[data-estimate-state="unavailable"] .orgs-estimate__list {
  display: none;
}

.orgs .orgs-estimate[data-estimate-state="unavailable"] p.orgs-estimate__fallback {
  display: block;
}

/* An unselected add-on row is `hidden`, and a class rule with a `display`
 * declaration BEATS the user-agent `[hidden] { display: none }` on
 * specificity — so without this the attribute would do nothing and every
 * add-on would appear priced whether or not it was ticked. Pinned by
 * test_applicant_quote.py::test_a_hidden_row_is_actually_hidden. */
.orgs .orgs-estimate__row[hidden] {
  display: none;
}

.orgs .orgs-estimate__row--total {
  margin-block-start: 0.35rem;
  padding-block-start: 0.6rem;
  border-block-start: 1px solid var(--org-border-card);
}

.orgs .orgs-estimate__label {
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--org-text-muted);
  margin: 0;
  min-inline-size: 0;
}

.orgs .orgs-estimate__row--total .orgs-estimate__label {
  font-weight: 700;
  color: var(--org-text-body);
}

.orgs .orgs-estimate__value {
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.5;
  color: var(--org-text-heading);
  font-variant-numeric: tabular-nums;
  margin: 0;
  text-align: end;
}

.orgs .orgs-estimate__row--total .orgs-estimate__value {
  font-size: clamp(1.15rem, 1rem + 0.6vw, 1.45rem);
  font-weight: 800;
}

/* The savings comparison.
 *
 * Set apart from the cost rows above by a rule and a heading, because it is a
 * different KIND of statement: everything above it is what we will charge,
 * everything in it is a comparative claim about someone else's list price. A
 * buyer skimming must not read the two as one column of our own figures.
 *
 * Colour: --org-text-ok (#2fd37a) measures 9.94:1 on --org-surface-inset
 * (#0d1430), the panel's own background — comfortably past AA, and past AAA
 * for body text. It is checked by TestMeasuredContrast against the lighter
 * glass surface too, so it stays legible if this block is ever reused on a
 * card. The saving is the one figure here worth colouring; the sub-row stays
 * muted so the pair reads as one statement with a footnote rather than two
 * competing numbers. */
.orgs .orgs-estimate__savings {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-block-start: 0.35rem;
  padding-block-start: 0.75rem;
  border-block-start: 1px solid var(--org-border-card);
}

/* Nothing to claim right now — hidden whole, heading and disclosure with it,
 * rather than left as a headed section over an empty list. The rows stay in
 * the DOM so a larger seat count can bring the claim back without a reload,
 * which is the same reason the add-on rows are hidden rather than dropped. */
.orgs .orgs-estimate__savings[data-savings-state="none"] {
  display: none;
}

.orgs .orgs-estimate__subtitle {
  font-size: 0.9rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--org-text-body);
  margin: 0;
}

.orgs .orgs-estimate__value--saving {
  color: var(--org-text-ok);
}

/* The qualifier row: same pair shape, deliberately quieter. */
.orgs .orgs-estimate__row--sub {
  margin-block-start: -0.2rem;
}

.orgs .orgs-estimate__label--sub,
.orgs .orgs-estimate__value--sub {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--org-text-muted);
}

/* ------------------------------------------------------------------
 * 13. Empty states
 * ------------------------------------------------------------------ */

.orgs .orgs-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  text-align: center;
  padding: clamp(1.75rem, 6vw, 3rem) 1.25rem;
  border: 1px dashed var(--org-border-strong);
  border-radius: var(--org-radius-card);
  background-color: rgba(255, 255, 255, 0.02);
}

.orgs .orgs-empty__icon {
  color: var(--org-brand);
  opacity: 0.85;
}

.orgs .orgs-empty__title {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--org-text-heading);
  margin: 0;
}

.orgs .orgs-empty__text {
  color: var(--org-text-muted);
  line-height: 1.65;
  max-inline-size: 52ch;
  margin: 0;
}

/* ------------------------------------------------------------------
 * 14. Public acquisition surface (/teams/)
 * ------------------------------------------------------------------ */

.orgs .orgs-hero {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  align-items: center;
}

@media (min-width: 62rem) {
  .orgs .orgs-hero {
    grid-template-columns: 1.15fr 1fr;
  }
}

.orgs .orgs-hero__body {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  min-inline-size: 0;
}

.orgs .orgs-hero__title {
  font-size: clamp(1.9rem, 1.2rem + 3.4vw, 3.25rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.025em;
  color: var(--org-text-heading);
  margin: 0;
}

.orgs .orgs-hero__lede {
  font-size: clamp(1rem, 0.95rem + 0.4vw, 1.2rem);
  line-height: 1.65;
  color: var(--org-text-body);
  max-inline-size: 56ch;
  margin: 0;
}

.orgs .orgs-hero__actions {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  align-items: stretch;
}

@media (min-width: 30rem) {
  .orgs .orgs-hero__actions {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
  }
}

/* The aside stacks the decorative illustration ABOVE the pricing card. The
   card is the load-bearing half — it carries the rate table, or the "apply
   and we will quote you" copy while INSTITUTIONAL_PRICING_PUBLIC is off — so
   the art never displaces it, it only precedes it. */
.orgs .orgs-hero__aside {
  min-inline-size: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(1rem, 3vw, 1.5rem);
}

/* The asset is a transparent WebP drawn for the #0b1020 page background, so
   it needs no plate, no border and no background of its own. It is purely
   decorative (empty alt + aria-hidden in the template) and is capped rather
   than stretched: past ~30rem it stops being an illustration beside the copy
   and starts being a banner above it. */
.orgs .orgs-hero__art {
  display: block;
  inline-size: 100%;
  max-inline-size: 30rem;
  margin-inline: auto;
}

.orgs .orgs-hero__art-img {
  display: block;
  inline-size: 100%;
  /* The intrinsic 4:3 width/height on the element reserves the box before
     the bytes arrive; `block-size: auto` hands the ratio back to the image
     once CSS owns the width, so the pricing card below can never be shoved
     down mid-load. */
  block-size: auto;
}

.orgs .orgs-features {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.85rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 44rem) {
  .orgs .orgs-features {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* WHAT A SEAT INCLUDES. Deliberately the same material as .orgs-card — glass
   surface, card radius, the top-accent seam — so "included" reads as part of
   the same object as the pricing card it sits under. The add-on cards below
   are built from a different material on purpose; see section 14b. */
.orgs .orgs-feature {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 1.3rem 1.15rem 1.2rem;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-card);
  background-color: var(--org-surface-card);
  background-image: var(--org-glass);
  box-shadow: var(--org-shadow-card);
  min-inline-size: 0;
  transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}

/* The house top-accent seam, matched to .orgs-card::before.
   `transform-origin: center` rather than that rule's `left center`: there is
   no logical keyword for transform-origin, and centre is the one value that
   reads identically in the 35+ locales this ships to. */
.orgs .orgs-feature::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 3px;
  background: var(--org-gradient-cta);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.35s ease;
}

.orgs .orgs-feature:hover,
.orgs .orgs-feature:focus-within {
  transform: translateY(-4px);
  border-color: var(--org-border-strong);
  box-shadow: var(--org-shadow-card-hover);
}

.orgs .orgs-feature:hover::before,
.orgs .orgs-feature:focus-within::before {
  transform: scaleX(1);
}

/* A tinted plate behind the icon, so the glyph reads as an object rather than
   as a stray stroke floating above the title. Sized in rem and set with
   inline-size/block-size, NOT min-block-size: it is decorative, not a tap
   target, and declaring it as one would be a lie to the 44px audit. */
.orgs .orgs-feature__icon-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  flex: 0 0 auto;
  inline-size: 2.85rem;
  block-size: 2.85rem;
  border-radius: var(--org-radius-sm);
  border: 1px solid rgba(106, 168, 255, 0.28);
  background-color: rgba(106, 168, 255, 0.12);
  margin-block-end: 0.35rem;
}

.orgs .orgs-feature__icon {
  color: var(--org-brand);
}

.orgs .orgs-feature__title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--org-text-heading);
  margin: 0;
}

.orgs .orgs-feature__text {
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--org-text-muted);
  margin: 0;
}

/* ------------------------------------------------------------------
 * 14b. Optional add-ons (/teams/)
 * ------------------------------------------------------------------
 * A DIFFERENT kind of thing from the cards above: an optional purchase, not
 * an included benefit. A reader who cannot tell the two apart at a glance has
 * been told the opposite of what the copy says, so the treatment differs on
 * every axis that carries meaning:
 *
 *   included (.orgs-feature)   add-on (.orgs-addon)
 *   ------------------------   --------------------------------
 *   brand BLUE                 accent PURPLE
 *   glass surface              flat inset surface
 *   seam across the TOP        rail down the INLINE-START edge
 *   square icon tile ABOVE     round medallion BESIDE the title
 *   hover LIFTS the card       hover WARMS the surface, no lift
 *   three-up grid              two-up grid
 *
 * No new colour is introduced: --org-text-accent and --org-brand-2 are both
 * already in the token set TestMeasuredContrast checks, so these rules
 * inherit a measured pass instead of asserting a fresh one.
 */

.orgs .orgs-addons {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.9rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 44rem) {
  .orgs .orgs-addons {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.orgs .orgs-addon {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-inline-size: 0;
  padding: 1.35rem 1.25rem;
  padding-inline-start: 1.5rem;
  border: 1px solid var(--org-border-card);
  border-inline-start: 3px solid var(--org-text-accent);
  border-radius: var(--org-radius-card);
  background-color: var(--org-surface-inset);
  transition: border-color 0.25s ease, background-color 0.25s ease;
}

.orgs .orgs-addon:hover,
.orgs .orgs-addon:focus-within {
  border-color: var(--org-border-strong);
  /* Declared AFTER the shorthand above so the rail keeps its own colour. */
  border-inline-start-color: var(--org-brand-2);
  background-color: rgba(155, 109, 255, 0.08);
}

.orgs .orgs-addon__head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-inline-size: 0;
}

.orgs .orgs-addon__medallion {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  inline-size: 2.6rem;
  block-size: 2.6rem;
  border-radius: 50%;
  border: 1px solid rgba(155, 109, 255, 0.35);
  background-color: rgba(155, 109, 255, 0.14);
}

.orgs .orgs-addon__icon {
  color: var(--org-text-accent);
}

.orgs .orgs-addon__title {
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--org-text-heading);
  margin: 0;
  min-inline-size: 0;
  overflow-wrap: anywhere;
}

.orgs .orgs-addon__tagline {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--org-text-body);
  margin: 0;
}

.orgs .orgs-addon__benefits {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.orgs .orgs-addon__benefit {
  position: relative;
  padding-inline-start: 1.55rem;
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--org-text-muted);
}

/* The tick is DRAWN from two logical borders rather than set as a `content`
   glyph: a pseudo-element character is announced by some screen readers, and
   these are already list items — the tick is decoration on top of semantics
   that carry themselves. Logical borders also mirror correctly in RTL. */
.orgs .orgs-addon__benefit::before {
  content: "";
  position: absolute;
  inset-inline-start: 0.3rem;
  inset-block-start: 0.3rem;
  inline-size: 0.4rem;
  block-size: 0.72rem;
  border-inline-end: 2px solid var(--org-text-accent);
  border-block-end: 2px solid var(--org-text-accent);
  transform: rotate(45deg);
}

/* Pushed to the foot of the card so both prices sit on one line across the
   pair, whatever length the benefit lists happen to be. Rendered only when
   INSTITUTIONAL_PRICING_PUBLIC is on. */
.orgs .orgs-addon__price {
  margin: 0;
  margin-block-start: auto;
  padding-block-start: 0.65rem;
  border-block-start: 1px solid var(--org-border-card);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--org-text-body);
}

.orgs .orgs-price-note {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--org-text-body);
  margin: 0;
}

/* The fee-and-trial sentence and the tax qualifier. Given real visual weight
   because they are a compliance contract, not decoration. */
.orgs .orgs-disclosure {
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 255, 255, 0.03);
  padding: 1rem 1.15rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/* ------------------------------------------------------------------
 * 15. Provisioning report
 * ------------------------------------------------------------------ */

.orgs .orgs-report {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.orgs .orgs-report__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.7rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--org-border-card);
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 255, 255, 0.03);
  font-size: 0.92rem;
  overflow-wrap: anywhere;
}

.orgs .orgs-report__status {
  font-weight: 700;
  color: var(--org-text-heading);
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
}

.orgs .orgs-report__email {
  color: var(--org-text-heading);
  font-weight: 600;
}

.orgs .orgs-report__role {
  color: var(--org-text-muted);
}

.orgs .orgs-report__detail {
  color: var(--org-text-muted);
  flex-basis: 100%;
}

.orgs .orgs-report__summary {
  font-weight: 600;
  color: var(--org-text-heading);
  margin: 0;
}

/* ------------------------------------------------------------------
 * 16. Decision history timeline
 * ------------------------------------------------------------------ */

.orgs .orgs-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.orgs .orgs-timeline__item {
  position: relative;
  padding: 0.85rem 1.05rem;
  padding-inline-start: 1.35rem;
  border: 1px solid var(--org-border-card);
  border-inline-start: 3px solid var(--org-brand-2);
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 255, 255, 0.03);
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.orgs .orgs-timeline__head {
  font-weight: 700;
  color: var(--org-text-heading);
}

.orgs .orgs-timeline__meta {
  font-size: 0.85rem;
  color: var(--org-text-muted);
  overflow-wrap: anywhere;
}

.orgs .orgs-timeline__reason {
  color: var(--org-text-body);
  line-height: 1.6;
  margin: 0;
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------------
 * 16b. Identity-check panel (review_detail.html)
 * ------------------------------------------------------------------
 * Evidence for a human decision, so it is dressed to be READ rather than
 * skimmed: no chart, no progress bar, no colour-as-the-only-signal.
 *
 * There is deliberately no score BAR. A bar needs a per-row width, and a
 * per-row width needs either an inline `style=` (dropped outright by
 * `style-src-attr`, so it would work in dev and silently vanish in
 * production) or a nonced <style> block emitting a custom property per row
 * — which `test_org_templates_styling.py::test_no_inline_style_element`
 * forbids in every template under templates/organizations/. Both routes cost
 * a CSP exception to gain a decoration; the number, stated in the same unit
 * as the threshold beside it, carries more.
 *
 * The three empty states get three DIFFERENT treatments for the same reason
 * the template gives them three different sentences. --error is the loud one:
 * a check that did not run is the state most easily mistaken for a clean
 * result, and it is the mistake that approves the duplicate.
 *
 * Every colour is an existing --org-* token. The status tokens used here are
 * contrast-measured against --org-surface-glass-top by TestMeasuredContrast.
 */

/* Worn alongside .orgs-card, so the surface, padding and top-accent seam are
 * already handled. What this adds is a scroll anchor: the row badges link to
 * other organizations' review pages, and a reviewer who follows one and comes
 * back should land on the panel rather than under the sticky page header. */
.orgs .orgs-sim {
  scroll-margin-block-start: 1.5rem;
}

.orgs .orgs-sim__intro {
  margin: 0 0 1rem;
  color: var(--org-text-body);
  font-size: 0.92rem;
  line-height: 1.6;
}

/* The state lines. Colour is never the only cue — each carries its own
 * border-inline-start weight, and the error state additionally carries an
 * icon, so the distinction survives greyscale and colour-blindness. */
.orgs .orgs-sim__state {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0;
  padding-block: 0.75rem;
  padding-inline: 1rem;
  border-radius: var(--org-radius-sm);
  border: 1px solid var(--org-border-card);
  border-inline-start: 4px solid var(--org-border-strong);
  background-color: var(--org-surface-inset);
  color: var(--org-text-body);
  font-size: 0.92rem;
  line-height: 1.55;
}

.orgs .orgs-sim__state--error {
  border-color: rgba(255, 128, 128, 0.45);
  border-inline-start-color: var(--org-text-danger);
  background-color: rgba(255, 128, 128, 0.12);
  color: var(--org-text-danger);
  font-weight: 600;
}

/* "The check ran against an empty or partly-indexed corpus." Distinct from
 * --error (which did not run at all) and pitched LOUDER than --off, because
 * the severity of these four states is not the order they read in.
 *
 * MEASURED at 1280px, all four: --error paints #ff8080 text on a red-tinted
 * panel; --off paints #9aa2bb (muted); --clear paints #2fd37a. A state left
 * on the BASE rule paints #b9bfd3 — ordinary body text on a neutral
 * rgba(255,255,255,0.16) border, i.e. the calmest of the set, and brighter
 * than the harmless switched-off state. An unindexed corpus is a
 * near-clearance a reviewer will act on, so it must not be the quietest
 * thing on the panel; only a small pill would be carrying the alarm. */
.orgs .orgs-sim__state--warn {
  border-color: rgba(255, 200, 0, 0.45);
  border-inline-start-color: var(--org-text-warn);
  background-color: rgba(255, 200, 0, 0.12);
  color: var(--org-text-warn);
}

.orgs .orgs-sim__state--off {
  border-inline-start-color: var(--org-text-muted);
  color: var(--org-text-muted);
}

.orgs .orgs-sim__state--clear {
  border-inline-start-color: var(--org-text-ok);
  color: var(--org-text-ok);
}

.orgs .orgs-sim__state-icon {
  flex: 0 0 auto;
  margin-block-start: 0.1rem;
}

/* One match. */
.orgs .orgs-sim__list {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.orgs .orgs-sim__row {
  padding: 1rem;
  border-radius: var(--org-radius-sm);
  border: 1px solid var(--org-border-card);
  background-color: var(--org-surface-inset);
}

.orgs .orgs-sim__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  margin-block-end: 0.75rem;
}

.orgs .orgs-sim__name {
  color: var(--org-text-link);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  /* 44px tap target on a phone without stretching the inline link box on a
   * pointer device, where these rows can sit close together. */
  min-block-size: var(--org-tap);
  display: inline-flex;
  align-items: center;
}

.orgs .orgs-sim__name:hover,
.orgs .orgs-sim__name:focus-visible {
  color: var(--org-text-accent);
}

/* Mobile-first: the three scores stack, then go three-up once there is room.
 * The breakdown is the point of the feature, so it is never collapsed behind
 * a disclosure — a reviewer must be able to see at a glance whether two
 * organizations share a building or merely a similar name. */
.orgs .orgs-sim__scores {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.5rem;
  margin: 0 0 0.85rem;
}

@media (min-width: 30rem) {
  .orgs .orgs-sim__scores {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.orgs .orgs-sim__score {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding-block: 0.4rem;
  padding-inline: 0.65rem;
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 255, 255, 0.04);
}

@media (min-width: 30rem) {
  .orgs .orgs-sim__score {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15rem;
  }
}

.orgs .orgs-sim__score-label {
  margin: 0;
  color: var(--org-text-muted);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.orgs .orgs-sim__score-value {
  margin: 0;
  color: var(--org-text-heading);
  font-size: 1.15rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.orgs .orgs-sim__score--combined {
  background-color: rgba(155, 109, 255, 0.12);
}

.orgs .orgs-sim__score--combined .orgs-sim__score-value {
  color: var(--org-text-accent);
  font-size: 1.35rem;
}

/* The exact-match tells. Usually the strongest evidence on the page, so they
 * are given real weight rather than filed as fine print. */
.orgs .orgs-sim__signals {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0 0 0.6rem;
  padding-inline-start: 1.1rem;
  list-style: disc;
}

.orgs .orgs-sim__signal {
  color: var(--org-text-body);
  font-size: 0.9rem;
  line-height: 1.5;
}

.orgs .orgs-sim__no-signals {
  margin: 0 0 0.6rem;
  color: var(--org-text-muted);
  font-size: 0.88rem;
  line-height: 1.5;
}

.orgs .orgs-sim__exact {
  margin: 0;
  color: var(--org-text-muted);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}

/* The contact-email tells on the applicant detail card. They sit OUTSIDE the
 * identity panel above, because they are about the applicant alone and must
 * render in the ordinary zero-match state too — see review_detail.html.
 *
 * Warn, not danger: this is advisory and refuses nobody anything, and plenty
 * of legitimate small organizations run on Gmail. Styling it as an error
 * would make a reviewer either over-weight it or learn to dismiss it.
 *
 * NO new colour: --org-text-warn is already in the token set TestMeasuredContrast
 * checks against the composited card surface, so this inherits a measured pass
 * rather than asserting a fresh one. */
.orgs .orgs-flags {
  border: 1px solid var(--org-text-warn);
  border-inline-start-width: 4px;
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 200, 0, 0.08);
  padding: 0.85rem 1rem;
  margin-block-start: 1.25rem;
}

.orgs .orgs-flags__lead {
  margin: 0 0 0.45rem;
  color: var(--org-text-warn);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.orgs .orgs-flags__list {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0;
  padding-inline-start: 1.1rem;
  list-style: disc;
}

.orgs .orgs-flag {
  color: var(--org-text-body);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* ------------------------------------------------------------------
 * 17. Learner performance chrome
 * ------------------------------------------------------------------
 * This page also links dashboard.css for the 12-chart registry. These rules
 * only dress the identity header, so nothing here competes with the chart
 * layout that stylesheet owns.
 */

.orgs .orgs-learner-head {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.orgs .orgs-learner-head__identity {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}

/* ------------------------------------------------------------------
 * 17b. Staff org-preview banner and switch
 * ------------------------------------------------------------------
 * Rendered only inside a Keduka staff preview, which exists only when
 * ORG_STAFF_PREVIEW_ENABLED is on (it defaults to DEBUG, so: not in
 * production). See organizations/staff_preview.py.
 *
 * It has to read as an INTERRUPTION rather than as page furniture, because a
 * preview carries a real org_admin's write access into an organization the
 * viewer does not belong to — provisioning from here mints accounts and
 * emails them. So it takes the warn token, a full border rather than the
 * single accent stripe .orgs-note uses, and sits above the page heading.
 *
 * NO new colour is introduced: --org-text-warn is already in the token set
 * that TestMeasuredContrast checks against the composited card surface, so
 * this banner inherits a measured pass instead of asserting a fresh one.
 */

.orgs .orgs-preview-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.25rem;
  border: 1px solid var(--org-text-warn);
  border-inline-start-width: 5px;
  border-radius: var(--org-radius-sm);
  background-color: rgba(255, 200, 0, 0.08);
  padding: 0.95rem 1.1rem;
  margin-block-end: 1.75rem;
}

.orgs .orgs-preview-banner__body {
  /* Claims the row so the button is pushed to the far edge, but yields on a
   * narrow viewport rather than forcing a horizontal scroll. */
  flex: 1 1 22rem;
  min-inline-size: 0;
}

.orgs .orgs-preview-banner__title {
  display: block;
  font-weight: 700;
  color: var(--org-text-warn);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  font-size: 0.78rem;
  margin-block-end: 0.3rem;
}

.orgs .orgs-preview-banner__text {
  margin: 0;
  color: var(--org-text-body);
  line-height: 1.6;
}

.orgs .orgs-preview-banner__form {
  margin: 0;
  flex: 0 0 auto;
}

/* The staff tools block is fenced off from the customer-facing content above
 * it, so a reviewer can never mistake it for part of the page they are
 * evaluating. */
.orgs .orgs-preview-switch {
  border-block-start: 1px dashed var(--org-border-strong);
  padding-block-start: 1.5rem;
}

.orgs .orgs-preview-switch__form {
  margin: 0;
}

/* ------------------------------------------------------------------
 * 18. Reduced motion
 * ------------------------------------------------------------------
 * Every transition above is decorative. Under `reduce` they are removed
 * outright rather than shortened — the accent stripe simply renders in its
 * final state.
 */

@media (prefers-reduced-motion: reduce) {
  .orgs *,
  .orgs *::before,
  .orgs *::after {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }

  .orgs .orgs-card::before,
  .orgs .orgs-feature::before {
    transform: scaleX(1);
  }

  .orgs .orgs-btn:hover {
    transform: none;
  }

  /* The hover lift is motion; the tick on .orgs-addon__benefit is a STATIC
     rotate that draws the glyph, so it is deliberately left alone — nulling
     it would erase the mark rather than calm it. */
  .orgs .orgs-feature:hover,
  .orgs .orgs-feature:focus-within {
    transform: none;
  }
}

/* ------------------------------------------------------------------
 * 19. Forced colors / high contrast
 * ------------------------------------------------------------------ */

@media (forced-colors: active) {
  .orgs .orgs-card,
  .orgs .orgs-stat,
  .orgs .orgs-table-wrap,
  .orgs .orgs-nav__link,
  .orgs .orgs-list__link,
  .orgs .orgs-feature,
  .orgs .orgs-feature__icon-tile,
  .orgs .orgs-addon,
  .orgs .orgs-addon__medallion {
    border: 1px solid CanvasText;
  }

  /* Hand the checkbox back to the platform outright.
   *
   * In forced-colors the user has chosen their own palette, and a control we
   * paint ourselves opts out of it: --org-gradient-cta and the tick ink are
   * both overridden to the same system colour, so "checked" and "unchecked"
   * can end up indistinguishable for precisely the users who most need them
   * apart. Restoring `appearance` is better than guessing at CanvasText /
   * Highlight equivalents, because the OS already knows how a checked
   * checkbox should look in that mode. The tick is hidden with it, or it
   * would paint on top of the native mark. */
  .orgs .orgs-form input[type="checkbox"] {
    appearance: auto;
    -webkit-appearance: auto;
  }

  .orgs .orgs-form input[type="checkbox"]::before {
    display: none;
  }

  .orgs .orgs-btn {
    border: 1px solid ButtonText;
  }
}

/* ------------------------------------------------------------------
 * 20. Light appearance
 * ------------------------------------------------------------------
 *
 * `.orgs` was the LAST page root still listed in theme.css section D2, the
 * "dark islands" block that re-declares the dark palette on stylesheets
 * with no light palette of their own. That is why the System / Light / Dark
 * toggle appeared to do nothing on /kais/org/. This section is the
 * migration, and `.orgs` came out of D2 in the SAME change — leaving a
 * migrated root listed there is the documented `.auth-card` bug inverted
 * (auth.css went light while `.auth-card` stayed listed, so `--kais-text`
 * held at #ffffff inside it and an `<h1 class="text-white">` rendered white
 * on a near-white card at 1.02:1).
 *
 * TWO BLOCKS, AND THE SCOPING IS THE WHOLE CONVENTION
 * ---------------------------------------------------
 * `:root[data-theme="light"] .orgs` is the explicit opt-in;
 * `@media (prefers-color-scheme: light) { :root[data-theme="auto"] .orgs }`
 * is the System branch. THE MEDIA QUERY IS NEVER UNSCOPED: a bare `:root`
 * inside it is live for a light-OS visitor who explicitly chose Dark, and
 * base.html is hard-dark outside this root class, so it would paint a
 * bright island inside dark chrome. The two blocks are spelled out twice
 * because the contrast sweep resolves tokens to opaque hex and cannot
 * follow an indirection; test_org_css_light.py diffs them per selector.
 *
 * MOSTLY TOKENS, DELIBERATELY
 * ---------------------------
 * organizations.css consumes `--org-*` and nothing else — grep it, there is
 * not one `var(--` outside that namespace — so one token block re-inks all
 * 2500 lines above. What tokens cannot reach is the ~55 hard-coded literals
 * in component rules, and only the ones whose LIGHT rendering is broken get
 * a rule here. Two things are left alone on purpose: the brand gradient and
 * its dark ink (7.81:1 / 5.43:1 — the one control that had no defect), and
 * the coloured status TINTS, because an 8% wash of a saturated colour over
 * white is already a good light tint.
 *
 * The templates under templates/organizations/ use zero Tailwind utilities
 * — every class is `.orgs-*` — so nothing here is exposed to theme.css's
 * section-B utility remap. That is checked, not assumed.
 *
 * Dark mode is byte-identical: every rule below is ADDITIVE and none edits
 * a base declaration. Contract: tests/test_organizations/test_org_css_light.py
 * ------------------------------------------------------------------ */

:root[data-theme="light"] .orgs {
  color-scheme: light;

  /* Surfaces. #ffffff for the card because every panel below layers a
     dark-alpha veil on it, and those veils need somewhere to be visible. */
  --org-bg-page: #f1f5f9;
  --org-bg-alt: #e8eef6;
  --org-surface-card: #ffffff;
  /* The composited top edge of --org-glass over --org-surface-card, and
     DERIVED rather than eyeballed: test_org_css_light.py recomputes it from
     the gradient's first stop, exactly as #202745 is #121939 under 6% white. */
  --org-surface-glass-top: #f5f6f6;
  --org-surface-inset: #eef2f8;

  /* Text. Every one of these is contrast-COMPUTED against ALL FIVE light
     surfaces, not just the card: dark ink reads best on the whitest surface,
     so the card is the easy case and the page / alt / inset washes bind.
     Worst measured pairing is --org-text-danger on --org-bg-alt at 5.54:1.

     --org-text-warn moves to the GOLD ink (#854d0e), not theme.css's
     --warn-ink (#9a3412): that one is a red-orange and would be nearly
     indistinguishable from --org-text-danger (#b91c1c), which on this
     stylesheet is the difference between "an unindexed corpus" and "the
     check did not run". Dark keeps its yellow; the amber TINTS underneath
     this ink are deliberately left as they are, because an 8% wash of
     #ffc800 over white is #fffbeb — already a good light-mode amber. */
  --org-text-heading: #0f172a;
  --org-text-body: #334155;
  --org-text-muted: #47536b;
  --org-text-accent: #6d28d9;
  --org-text-link: #1d4ed8;
  --org-text-ok: #166534;
  --org-text-warn: #854d0e;
  --org-text-danger: #b91c1c;

  /* 5.08:1 at worst on these surfaces, against the 3:1 SC 1.4.11 asks of a
     focus indicator. */
  --org-focus-ring: #0369a1;

  /* The white-alpha veils invert to black-alpha, which is theme.css's own
     rule: a rgba(255,255,255,.1) hairline is invisible on a white card.
     --org-control-border is the edge of a control WE draw, so SC 1.4.11
     holds it to 3:1 against what is adjacent; 0.55 measures 3.84:1 on
     --org-surface-inset and 4.00:1 on --org-surface-card, which is the same
     bar the dark value clears at 3.79:1 and 3.57:1. */
  --org-border-card: rgba(15, 23, 42, 0.1);
  --org-border-strong: rgba(15, 23, 42, 0.18);
  --org-control-border: rgba(15, 23, 42, 0.55);
  --org-glass: linear-gradient(
    180deg,
    rgba(15, 23, 42, 0.04),
    rgba(15, 23, 42, 0.015)
  );
  --org-gradient-hero:
    radial-gradient(1200px 600px at 80% -10%, rgba(155, 109, 255, 0.1), transparent),
    radial-gradient(900px 500px at -10% 10%, rgba(106, 168, 255, 0.12), transparent),
    var(--org-bg-page);
  --org-shadow-card: 0 10px 30px rgba(15, 23, 42, 0.1);
  --org-shadow-card-hover: 0 25px 60px rgba(31, 45, 92, 0.18);
}

/* The white veils, inverted. Each base rule paints rgba(255,255,255,.02-.12);
   over a #ffffff card every one composites straight back to #ffffff, so the
   table header band, the row hover, the neutral button and nine panels stop
   existing. No text is harmed, which is why no contrast sweep catches it.
   -------------------------------------------------- */
:root[data-theme="light"] .orgs .orgs-table thead th {
  background-color: rgba(15, 23, 42, 0.05);
}

:root[data-theme="light"] .orgs .orgs-table tbody tr:hover {
  background-color: rgba(15, 23, 42, 0.05);
}

:root[data-theme="light"] .orgs .orgs-btn--neutral {
  background: rgba(15, 23, 42, 0.05);
}

:root[data-theme="light"] .orgs .orgs-btn--neutral:hover {
  background: rgba(15, 23, 42, 0.1);
}

:root[data-theme="light"] .orgs .orgs-message {
  background-color: rgba(15, 23, 42, 0.03);
}

:root[data-theme="light"] .orgs .orgs-badge {
  background-color: rgba(15, 23, 42, 0.05);
}

:root[data-theme="light"] .orgs .orgs-fieldset {
  background-color: rgba(15, 23, 42, 0.03);
}

:root[data-theme="light"] .orgs .orgs-consent {
  background-color: rgba(15, 23, 42, 0.03);
}

:root[data-theme="light"] .orgs .orgs-empty {
  background-color: rgba(15, 23, 42, 0.03);
}

:root[data-theme="light"] .orgs .orgs-disclosure {
  background-color: rgba(15, 23, 42, 0.03);
}

:root[data-theme="light"] .orgs .orgs-report__row {
  background-color: rgba(15, 23, 42, 0.03);
}

:root[data-theme="light"] .orgs .orgs-timeline__item {
  background-color: rgba(15, 23, 42, 0.03);
}

:root[data-theme="light"] .orgs .orgs-sim__score {
  background-color: rgba(15, 23, 42, 0.04);
}

/* EVERYTHING BELOW THIS LINE MUST STAY BELOW IT.

   A light rule is `:root[data-theme="light"] .orgs .orgs-x` = (0,4,0). The
   base modifiers it sits above are `.orgs .orgs-x--variant` = (0,3,0), so the
   veils just written OUTRANK them: without these eight rules a success, a
   warning and an error message would render identically, and all four status
   badges would lose their fill. `.orgs-badge--ok` and `.orgs-badge` are BOTH
   (0,4,0) once the theme prefix is applied, so source order — not
   specificity — is what settles it. This is the bug workout.css shipped on
   its passed / failed level tiles; test_org_css_light.py pins the order.
   -------------------------------------------------- */
:root[data-theme="light"] .orgs .orgs-message[data-tag~="success"] {
  background-color: rgba(22, 101, 52, 0.08);
}

:root[data-theme="light"] .orgs .orgs-message[data-tag~="warning"] {
  background-color: rgba(133, 77, 14, 0.08);
}

:root[data-theme="light"] .orgs .orgs-message[data-tag~="error"] {
  background-color: rgba(185, 28, 28, 0.08);
}

:root[data-theme="light"] .orgs .orgs-badge--ok {
  border-color: rgba(22, 101, 52, 0.55);
  background-color: rgba(22, 101, 52, 0.1);
}

:root[data-theme="light"] .orgs .orgs-badge--warn {
  border-color: rgba(133, 77, 14, 0.55);
  background-color: rgba(133, 77, 14, 0.1);
}

:root[data-theme="light"] .orgs .orgs-badge--danger {
  border-color: rgba(185, 28, 28, 0.55);
  background-color: rgba(185, 28, 28, 0.1);
}

:root[data-theme="light"] .orgs .orgs-badge--info {
  border-color: rgba(29, 78, 216, 0.55);
  background-color: rgba(29, 78, 216, 0.1);
}

:root[data-theme="light"] .orgs .orgs-sim__score--combined {
  background-color: rgba(109, 40, 217, 0.1);
}

/* The three review actions. #2fd37a measures 1.86:1 on white at FULL
   opacity, so no alpha of the dark sheet's bright status colours can draw a
   boundary on a light page — the fill and the border both move to the inks.
   Measured: border 3.58 / 3.84 / 3.48:1 against the card, where the DARK
   sheet's own borders manage 2.76 / 2.38 / 3.16:1, and each label clears AA
   on its repainted fill (6.14 / 5.45 / 5.90:1). Hover is repainted too: a
   resting-state-only fix is correct until a pointer touches it.
   -------------------------------------------------- */
:root[data-theme="light"] .orgs .orgs-btn--approve {
  background: rgba(22, 101, 52, 0.1);
  border-color: rgba(22, 101, 52, 0.7);
}

:root[data-theme="light"] .orgs .orgs-btn--approve:hover {
  background: rgba(22, 101, 52, 0.18);
}

:root[data-theme="light"] .orgs .orgs-btn--reject {
  background: rgba(185, 28, 28, 0.1);
  border-color: rgba(185, 28, 28, 0.7);
}

:root[data-theme="light"] .orgs .orgs-btn--reject:hover {
  background: rgba(185, 28, 28, 0.18);
}

:root[data-theme="light"] .orgs .orgs-btn--warn {
  background: rgba(133, 77, 14, 0.1);
  border-color: rgba(133, 77, 14, 0.7);
}

:root[data-theme="light"] .orgs .orgs-btn--warn:hover {
  background: rgba(133, 77, 14, 0.18);
}

/* Hover and focus washes that land within ~1.05:1 of a light surface. These
   are the ONLY feedback each control gives, and :focus-within is the
   keyboard half of the same affordance — so the two keep identical bodies.
   -------------------------------------------------- */
:root[data-theme="light"] .orgs .orgs-btn--ghost:hover {
  background: rgba(29, 78, 216, 0.1);
}

:root[data-theme="light"] .orgs .orgs-choices label:hover,
:root[data-theme="light"] .orgs .orgs-choices label:focus-within {
  background-color: rgba(29, 78, 216, 0.1);
}

:root[data-theme="light"] .orgs .orgs-addon:hover,
:root[data-theme="light"] .orgs .orgs-addon:focus-within {
  background-color: rgba(109, 40, 217, 0.1);
}

/* /kais/teams/ is public and indexable, so its feature plates are the light
   theme's shop window. The glyph is aria-hidden with a visible title beside
   it, so SC 1.4.11 does not bind — but --org-brand on a 12% wash of itself
   reads at about 1.8:1 over white, which looks broken rather than subtle.
   -------------------------------------------------- */
:root[data-theme="light"] .orgs .orgs-feature__icon-tile {
  border-color: rgba(29, 78, 216, 0.3);
  background-color: rgba(29, 78, 216, 0.1);
}

:root[data-theme="light"] .orgs .orgs-feature__icon {
  color: var(--org-text-link);
}

@media (prefers-color-scheme: light) {
  :root[data-theme="auto"] .orgs {
    color-scheme: light;

    /* Surfaces. #ffffff for the card because every panel below layers a
       dark-alpha veil on it, and those veils need somewhere to be visible. */
    --org-bg-page: #f1f5f9;
    --org-bg-alt: #e8eef6;
    --org-surface-card: #ffffff;
    /* The composited top edge of --org-glass over --org-surface-card, and
       DERIVED rather than eyeballed: test_org_css_light.py recomputes it from
       the gradient's first stop, exactly as #202745 is #121939 under 6% white. */
    --org-surface-glass-top: #f5f6f6;
    --org-surface-inset: #eef2f8;

    /* Text. Every one of these is contrast-COMPUTED against ALL FIVE light
       surfaces, not just the card: dark ink reads best on the whitest surface,
       so the card is the easy case and the page / alt / inset washes bind.
       Worst measured pairing is --org-text-danger on --org-bg-alt at 5.54:1.

       --org-text-warn moves to the GOLD ink (#854d0e), not theme.css's
       --warn-ink (#9a3412): that one is a red-orange and would be nearly
       indistinguishable from --org-text-danger (#b91c1c), which on this
       stylesheet is the difference between "an unindexed corpus" and "the
       check did not run". Dark keeps its yellow; the amber TINTS underneath
       this ink are deliberately left as they are, because an 8% wash of
       #ffc800 over white is #fffbeb — already a good light-mode amber. */
    --org-text-heading: #0f172a;
    --org-text-body: #334155;
    --org-text-muted: #47536b;
    --org-text-accent: #6d28d9;
    --org-text-link: #1d4ed8;
    --org-text-ok: #166534;
    --org-text-warn: #854d0e;
    --org-text-danger: #b91c1c;

    /* 5.08:1 at worst on these surfaces, against the 3:1 SC 1.4.11 asks of a
       focus indicator. */
    --org-focus-ring: #0369a1;

    /* The white-alpha veils invert to black-alpha, which is theme.css's own
       rule: a rgba(255,255,255,.1) hairline is invisible on a white card.
       --org-control-border is the edge of a control WE draw, so SC 1.4.11
       holds it to 3:1 against what is adjacent; 0.55 measures 3.84:1 on
       --org-surface-inset and 4.00:1 on --org-surface-card, which is the same
       bar the dark value clears at 3.79:1 and 3.57:1. */
    --org-border-card: rgba(15, 23, 42, 0.1);
    --org-border-strong: rgba(15, 23, 42, 0.18);
    --org-control-border: rgba(15, 23, 42, 0.55);
    --org-glass: linear-gradient(
      180deg,
      rgba(15, 23, 42, 0.04),
      rgba(15, 23, 42, 0.015)
    );
    --org-gradient-hero:
      radial-gradient(1200px 600px at 80% -10%, rgba(155, 109, 255, 0.1), transparent),
      radial-gradient(900px 500px at -10% 10%, rgba(106, 168, 255, 0.12), transparent),
      var(--org-bg-page);
    --org-shadow-card: 0 10px 30px rgba(15, 23, 42, 0.1);
    --org-shadow-card-hover: 0 25px 60px rgba(31, 45, 92, 0.18);
  }

  /* The white veils, inverted. Each base rule paints rgba(255,255,255,.02-.12);
     over a #ffffff card every one composites straight back to #ffffff, so the
     table header band, the row hover, the neutral button and nine panels stop
     existing. No text is harmed, which is why no contrast sweep catches it.
     -------------------------------------------------- */
  :root[data-theme="auto"] .orgs .orgs-table thead th {
    background-color: rgba(15, 23, 42, 0.05);
  }

  :root[data-theme="auto"] .orgs .orgs-table tbody tr:hover {
    background-color: rgba(15, 23, 42, 0.05);
  }

  :root[data-theme="auto"] .orgs .orgs-btn--neutral {
    background: rgba(15, 23, 42, 0.05);
  }

  :root[data-theme="auto"] .orgs .orgs-btn--neutral:hover {
    background: rgba(15, 23, 42, 0.1);
  }

  :root[data-theme="auto"] .orgs .orgs-message {
    background-color: rgba(15, 23, 42, 0.03);
  }

  :root[data-theme="auto"] .orgs .orgs-badge {
    background-color: rgba(15, 23, 42, 0.05);
  }

  :root[data-theme="auto"] .orgs .orgs-fieldset {
    background-color: rgba(15, 23, 42, 0.03);
  }

  :root[data-theme="auto"] .orgs .orgs-consent {
    background-color: rgba(15, 23, 42, 0.03);
  }

  :root[data-theme="auto"] .orgs .orgs-empty {
    background-color: rgba(15, 23, 42, 0.03);
  }

  :root[data-theme="auto"] .orgs .orgs-disclosure {
    background-color: rgba(15, 23, 42, 0.03);
  }

  :root[data-theme="auto"] .orgs .orgs-report__row {
    background-color: rgba(15, 23, 42, 0.03);
  }

  :root[data-theme="auto"] .orgs .orgs-timeline__item {
    background-color: rgba(15, 23, 42, 0.03);
  }

  :root[data-theme="auto"] .orgs .orgs-sim__score {
    background-color: rgba(15, 23, 42, 0.04);
  }

  /* EVERYTHING BELOW THIS LINE MUST STAY BELOW IT.

     A light rule is `:root[data-theme="light"] .orgs .orgs-x` = (0,4,0). The
     base modifiers it sits above are `.orgs .orgs-x--variant` = (0,3,0), so the
     veils just written OUTRANK them: without these eight rules a success, a
     warning and an error message would render identically, and all four status
     badges would lose their fill. `.orgs-badge--ok` and `.orgs-badge` are BOTH
     (0,4,0) once the theme prefix is applied, so source order — not
     specificity — is what settles it. This is the bug workout.css shipped on
     its passed / failed level tiles; test_org_css_light.py pins the order.
     -------------------------------------------------- */
  :root[data-theme="auto"] .orgs .orgs-message[data-tag~="success"] {
    background-color: rgba(22, 101, 52, 0.08);
  }

  :root[data-theme="auto"] .orgs .orgs-message[data-tag~="warning"] {
    background-color: rgba(133, 77, 14, 0.08);
  }

  :root[data-theme="auto"] .orgs .orgs-message[data-tag~="error"] {
    background-color: rgba(185, 28, 28, 0.08);
  }

  :root[data-theme="auto"] .orgs .orgs-badge--ok {
    border-color: rgba(22, 101, 52, 0.55);
    background-color: rgba(22, 101, 52, 0.1);
  }

  :root[data-theme="auto"] .orgs .orgs-badge--warn {
    border-color: rgba(133, 77, 14, 0.55);
    background-color: rgba(133, 77, 14, 0.1);
  }

  :root[data-theme="auto"] .orgs .orgs-badge--danger {
    border-color: rgba(185, 28, 28, 0.55);
    background-color: rgba(185, 28, 28, 0.1);
  }

  :root[data-theme="auto"] .orgs .orgs-badge--info {
    border-color: rgba(29, 78, 216, 0.55);
    background-color: rgba(29, 78, 216, 0.1);
  }

  :root[data-theme="auto"] .orgs .orgs-sim__score--combined {
    background-color: rgba(109, 40, 217, 0.1);
  }

  /* The three review actions. #2fd37a measures 1.86:1 on white at FULL
     opacity, so no alpha of the dark sheet's bright status colours can draw a
     boundary on a light page — the fill and the border both move to the inks.
     Measured: border 3.58 / 3.84 / 3.48:1 against the card, where the DARK
     sheet's own borders manage 2.76 / 2.38 / 3.16:1, and each label clears AA
     on its repainted fill (6.14 / 5.45 / 5.90:1). Hover is repainted too: a
     resting-state-only fix is correct until a pointer touches it.
     -------------------------------------------------- */
  :root[data-theme="auto"] .orgs .orgs-btn--approve {
    background: rgba(22, 101, 52, 0.1);
    border-color: rgba(22, 101, 52, 0.7);
  }

  :root[data-theme="auto"] .orgs .orgs-btn--approve:hover {
    background: rgba(22, 101, 52, 0.18);
  }

  :root[data-theme="auto"] .orgs .orgs-btn--reject {
    background: rgba(185, 28, 28, 0.1);
    border-color: rgba(185, 28, 28, 0.7);
  }

  :root[data-theme="auto"] .orgs .orgs-btn--reject:hover {
    background: rgba(185, 28, 28, 0.18);
  }

  :root[data-theme="auto"] .orgs .orgs-btn--warn {
    background: rgba(133, 77, 14, 0.1);
    border-color: rgba(133, 77, 14, 0.7);
  }

  :root[data-theme="auto"] .orgs .orgs-btn--warn:hover {
    background: rgba(133, 77, 14, 0.18);
  }

  /* Hover and focus washes that land within ~1.05:1 of a light surface. These
     are the ONLY feedback each control gives, and :focus-within is the
     keyboard half of the same affordance — so the two keep identical bodies.
     -------------------------------------------------- */
  :root[data-theme="auto"] .orgs .orgs-btn--ghost:hover {
    background: rgba(29, 78, 216, 0.1);
  }

  :root[data-theme="auto"] .orgs .orgs-choices label:hover,
  :root[data-theme="auto"] .orgs .orgs-choices label:focus-within {
    background-color: rgba(29, 78, 216, 0.1);
  }

  :root[data-theme="auto"] .orgs .orgs-addon:hover,
  :root[data-theme="auto"] .orgs .orgs-addon:focus-within {
    background-color: rgba(109, 40, 217, 0.1);
  }

  /* /kais/teams/ is public and indexable, so its feature plates are the light
     theme's shop window. The glyph is aria-hidden with a visible title beside
     it, so SC 1.4.11 does not bind — but --org-brand on a 12% wash of itself
     reads at about 1.8:1 over white, which looks broken rather than subtle.
     -------------------------------------------------- */
  :root[data-theme="auto"] .orgs .orgs-feature__icon-tile {
    border-color: rgba(29, 78, 216, 0.3);
    background-color: rgba(29, 78, 216, 0.1);
  }

  :root[data-theme="auto"] .orgs .orgs-feature__icon {
    color: var(--org-text-link);
  }
}
/* ------------------------------------------------------------------
 * 21. Print
 * ------------------------------------------------------------------ */

@media print {
  .orgs .orgs-page {
    background: none;
    color: #000000;
  }

  .orgs .orgs-card,
  .orgs .orgs-stat,
  .orgs .orgs-table-wrap {
    box-shadow: none;
    border: 1px solid #999999;
    background: none;
  }
}
