/* ==========================================================================
   Forceware — design system + landing page
   Loaded after Bootstrap, so these rules intentionally win the cascade.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

/* THE `hidden` ATTRIBUTE MEANS HIDDEN, EVERYWHERE.
   ------------------------------------------------------------------------
   The browser's own rule is `[hidden] { display: none }` and it loses to ANY
   author rule that sets display -- which is most components here. `.btn` is
   `display: inline-flex`, so a button with the attribute set stays on screen
   while `el.hidden` reads true: the markup says hidden, the DOM agrees, and
   the thing is visible.

   This had been patched selector by selector -- six rules across this file,
   one of them noting it "has cost three debugging sessions" -- and the
   seventh was a submit button offering to spend 100 credits on a dialog that
   had just said there was nothing to fetch.

   `!important` because the whole point is to outrank the component rule that
   would otherwise win. Anything that needs to be laid out must not carry the
   attribute; that is what the attribute is for. */
[hidden] { display: none !important; }

:root {
  /* surfaces */
  --bg: #0A0F1E;
  --bg-elev: #0E1526;
  --surface: #131C33;
  --surface-2: #18223D;
  --border: rgb(var(--ink) / .09);
  --border-strong: rgb(var(--ink) / .17);

  /* The colour every wash, hover and track is a tint of: white on the dark
     theme, slate on the light one. Written as rgb(var(--ink) / .07) rather
     than a fixed rgba so one value flips all of them. A wash on the accent
     gradient (a primary button's cost badge, its busy spinner) stays white in
     both themes and does not use it. */
  --ink: 255 255 255;
  --header-bg: rgba(10, 15, 30, .78);
  --surface-fade: rgba(19, 28, 51, .35);
  /* Sunk below the surface: an input, a code panel. */
  --recess: rgba(0, 0, 0, .3);
  /* A raised panel's shadow: a menu, a dialog, a card lifted off the page. */
  --shadow: rgba(0, 0, 0, .95);

  /* ink */
  --text: #E9EEFA;
  --text-dim: #9DA9C5;
  --text-faint: #717E9D;

  /* accents */
  --accent: #4DA3FF;
  --violet: #7C6BFF;
  --teal: #2FD9C3;
  --amber: #FFB454;
  --rose: #FF6B8A;

  /* Accents as text: a lighter tint to read on a dark surface, a darker one
     on a light surface. */
  --accent-hover: #7FBEFF;
  --rose-text: #FFC2CE;
  --teal-text: #AEF5E8;
  --warn-border: #7a5c12;
  --warn-text: #f0c674;

  /* Every dropdown's caret. See "Dropdowns" below for why it is ours and not
     the platform's. Hardcoded #9DA9C5 is --text-dim: a data: URI is opaque to
     the cascade, so a var() inside it would not resolve. */
  --caret: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239DA9C5' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  color-scheme: dark;
}

:root {
  /* Rounded the way Salesforce's own UI now is (SLDS 2): generous corners on
     anything that holds content, pills for anything you press. */
  --radius-sm: 12px;
  --radius: 20px;
  --radius-lg: 24px;
  --maxw: 1160px;
  --side-nav-w: 280px;
  /* Between the workspace pages' floating panels, and around them. */
  --app-gap: 12px;
  /* Top padding inside both workspace panels: the side nav and the page. */
  --app-pad-top: 20px;

  --font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;
}

/* ---- Light theme ---------------------------------------------------------
   Set by the switcher in the header (theme.js) as data-theme="light" on
   <html>. Dark is the default and needs no attribute. Only tokens change
   here: a rule that needs its own light value is a colour that should have
   been a token. */
:root[data-theme="light"] {
  color-scheme: light;

  --bg: #F4F6FB;
  --bg-elev: #FFFFFF;
  --surface: #FFFFFF;
  --surface-2: #EEF2F8;
  --ink: 15 23 42;
  --border: rgb(var(--ink) / .12);
  --border-strong: rgb(var(--ink) / .22);
  --header-bg: rgba(255, 255, 255, .82);
  --surface-fade: rgba(238, 242, 248, .6);
  --recess: rgb(var(--ink) / .04);
  --shadow: rgba(15, 23, 42, .28);

  --text: #0F172A;
  --text-dim: #475569;
  --text-faint: #64748B;

  --accent: #1F6FEB;
  --violet: #6550EA;
  --teal: #0E9F8E;
  --amber: #B7791F;
  --rose: #D6336C;

  --accent-hover: #1857C0;
  --rose-text: #9F1239;
  --teal-text: #0F766E;
  --warn-border: #D69E2E;
  --warn-text: #8A5A00;

  /* #475569 is the light --text-dim, for the same reason as the dark one. */
  --caret: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

html {
  font-size: 16px;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 { margin: 0; line-height: 1.15; letter-spacing: -.022em; font-weight: 660; }
p { margin: 0; }
img { max-width: 100%; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- layout primitives ---------- */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: 24px;
}

.section { padding-block: 104px; }
.section--tight { padding-block: 72px; }

.section-head { max-width: 660px; margin-bottom: 56px; }
.section-head--center { margin-inline: auto; text-align: center; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 18px;
}
.eyebrow::before {
  content: "";
  width: 22px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent));
}
.section-head--center .eyebrow::before { display: none; }

.section-title { font-size: clamp(1.9rem, 3.6vw, 2.65rem); }
.section-sub {
  margin-top: 18px;
  color: var(--text-dim);
  font-size: 1.06rem;
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 24px;
  border-radius: 999px;
  font-size: .95rem;
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform .16s ease, box-shadow .16s ease, background .16s ease, border-color .16s ease;
  white-space: nowrap;
}
.btn:hover { transform: translateY(-1px); }

.btn--primary {
  background: linear-gradient(135deg, var(--accent), var(--violet));
  color: #fff;
  box-shadow: 0 8px 26px -10px rgba(77, 163, 255, .85);
}
.btn--primary:hover { color: #fff; box-shadow: 0 14px 34px -10px rgba(77, 163, 255, .95); }

.btn--ghost {
  background: rgb(var(--ink) / .04);
  border-color: var(--border-strong);
  color: var(--text);
}
.btn--ghost:hover { background: rgb(var(--ink) / .09); color: var(--text); }

.btn--sm { padding: 9px 18px; font-size: .875rem; }

/* ---------- header / nav ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--header-bg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}

.nav {
  display: flex;
  align-items: center;
  gap: 20px;
  height: 68px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  color: var(--text);
  font-weight: 680;
  font-size: 1.06rem;
  letter-spacing: -.02em;
}
.brand:hover { color: var(--text); }
/* The PNG lockup already contains the wordmark, so height alone sizes it and
   width:auto keeps the 686x200 aspect ratio. The width/height attributes on the
   tag reserve the right space before it loads. */
/* Two logos, one shown per theme: the original's lettering is white, the
   light one's (forceware-io-light.png) is the light theme's --text.
   Doubled classes, because .brand__logo below sets display: block and would
   otherwise show both. */
.brand__logo.brand__logo--light { display: none; }
:root[data-theme="light"] .brand__logo.brand__logo--dark { display: none; }
:root[data-theme="light"] .brand__logo.brand__logo--light { display: block; }

.brand__logo {
  height: 38px;
  width: auto;
  display: block;
}
.auth__brand .brand__logo { height: 44px; }
.site-footer .brand__logo { height: 34px; }

@media (max-width: 420px) {
  .brand__logo { height: 32px; }
}

/* A workspace page's breadcrumbs, in the header where the links were. Placed
   as the links are, after the logo; the trail's own bottom margin is for when
   it sat above a page, so it goes. */
.nav__crumbs { margin: 0 auto 0 18px; min-width: 0; }
.nav__crumbs .ws__crumbs { margin: 0; flex-wrap: wrap; }

.nav__menu {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 auto 0 18px;
  padding: 0;
  list-style: none;
}
.nav__link {
  display: block;
  padding: 8px 14px;
  border-radius: 8px;
  color: var(--text-dim);
  font-size: .93rem;
  font-weight: 500;
}
.nav__link:hover { color: var(--text); background: rgb(var(--ink) / .06); }
.nav__link.is-active { color: var(--text); background: rgba(77, 163, 255, .12); }

.nav__actions { display: flex; align-items: center; gap: 10px; }
.nav__signin { color: var(--text-dim); font-size: .93rem; font-weight: 500; padding: 8px 6px; }
.nav__signin:hover { color: var(--text); }

.nav__toggle {
  display: none;
  width: 42px;
  height: 42px;
  align-items: center;
  justify-content: center;
  background: rgb(var(--ink) / .05);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  color: var(--text);
  cursor: pointer;
}

/* ---------- hero ---------- */

.hero {
  position: relative;
  padding-block: 96px 88px;
  overflow: hidden;
}
.hero::before,
.hero::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  pointer-events: none;
  z-index: 0;
}
.hero::before {
  width: 620px; height: 620px;
  top: -280px; left: -160px;
  background: radial-gradient(circle, rgba(77, 163, 255, .28), transparent 68%);
}
.hero::after {
  width: 560px; height: 560px;
  top: -180px; right: -200px;
  background: radial-gradient(circle, rgba(124, 107, 255, .24), transparent 68%);
}
.hero > .wrap { position: relative; z-index: 1; }

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr);
  gap: 64px;
  align-items: center;
}

.hero__badge {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 6px 14px 6px 7px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: rgb(var(--ink) / .04);
  font-size: .82rem;
  color: var(--text-dim);
  margin-bottom: 26px;
}
.hero__badge b {
  padding: 3px 9px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--accent), var(--violet));
  color: #fff;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .04em;
}

.hero__title {
  font-size: clamp(2.35rem, 5.1vw, 3.65rem);
  letter-spacing: -.032em;
}
.hero__title em {
  font-style: normal;
  background: linear-gradient(120deg, var(--accent), var(--teal));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero__sub {
  margin-top: 22px;
  font-size: 1.12rem;
  color: var(--text-dim);
  max-width: 33em;
}

.hero__cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 34px; }

.hero__note {
  margin-top: 20px;
  font-size: .87rem;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ---------- hero console mock ---------- */

.console {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, var(--surface-2), var(--bg-elev));
  box-shadow: 0 40px 80px -34px var(--shadow);
  overflow: hidden;
}

.console__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--border);
  background: rgb(var(--ink) / .03);
}
.console__dot { width: 10px; height: 10px; border-radius: 50%; background: #303B58; }
.console__dot:nth-child(1) { background: #FF5F57; }
.console__dot:nth-child(2) { background: #FEBC2E; }
.console__dot:nth-child(3) { background: #28C840; }
.console__title {
  margin-left: 8px;
  font-family: var(--mono);
  font-size: .78rem;
  color: var(--text-faint);
}

.console__body { padding: 20px; display: grid; gap: 16px; }

.org-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: rgb(var(--ink) / .025);
}
.org-row__name { font-size: .9rem; font-weight: 600; }
.org-row__meta { font-family: var(--mono); font-size: .74rem; color: var(--text-faint); }
.org-row__spacer { margin-left: auto; }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: .72rem;
  font-weight: 600;
  font-family: var(--mono);
  border: 1px solid transparent;
}
.pill--ok    { color: var(--teal);   background: rgba(47, 217, 195, .12); border-color: rgba(47, 217, 195, .3); }
.pill--warn  { color: var(--amber);  background: rgba(255, 180, 84, .12); border-color: rgba(255, 180, 84, .3); }
.pill--info  { color: var(--accent); background: rgba(77, 163, 255, .12); border-color: rgba(77, 163, 255, .3); }
.pill--danger { color: var(--rose-text); background: color-mix(in srgb, var(--rose) 12%, transparent); border-color: color-mix(in srgb, var(--rose) 30%, transparent); }
.pill--muted { color: var(--text-faint); background: rgb(var(--ink) / .05); border-color: var(--border); }


.diff {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--recess);
  padding: 14px 16px;
  font-family: var(--mono);
  font-size: .79rem;
  line-height: 1.85;
  overflow-x: auto;
}
.diff > div { white-space: nowrap; }
.diff__label {
  color: var(--text-faint);
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.diff__add { color: var(--teal); }
.diff__del { color: var(--rose); }
.diff__mod { color: var(--amber); }
.diff__dim { color: var(--text-faint); }

/* ---------- logo / compat strip ---------- */

.strip {
  border-block: 1px solid var(--border);
  background: rgb(var(--ink) / .015);
  padding-block: 30px;
}
.strip__label {
  text-align: center;
  font-family: var(--mono);
  font-size: .73rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 20px;
}
.strip__items {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px 14px;
}
.strip__item {
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: .87rem;
  color: var(--text-dim);
  background: rgb(var(--ink) / .03);
}

/* ---------- audience split ---------- */

.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; }

.audience {
  position: relative;
  padding: 34px 32px 30px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, var(--surface), var(--surface-fade));
  overflow: hidden;
}
.audience::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--violet));
}
.audience--admin::before { background: linear-gradient(90deg, var(--teal), var(--accent)); }

.audience__icon {
  width: 46px; height: 46px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: rgba(77, 163, 255, .12);
  border: 1px solid rgba(77, 163, 255, .28);
  color: var(--accent);
  margin-bottom: 18px;
}
.audience--admin .audience__icon {
  background: rgba(47, 217, 195, .12);
  border-color: rgba(47, 217, 195, .28);
  color: var(--teal);
}

.audience__title { font-size: 1.4rem; }
.audience__sub { margin-top: 10px; color: var(--text-dim); font-size: .97rem; }

.checklist { list-style: none; margin: 24px 0 0; padding: 0; display: grid; gap: 13px; }
.checklist li {
  display: flex;
  gap: 11px;
  font-size: .95rem;
  color: var(--text-dim);
}
.checklist svg { flex: none; margin-top: 4px; color: var(--accent); }
.audience--admin .checklist svg { color: var(--teal); }
.checklist b { color: var(--text); font-weight: 600; }

/* ---------- feature cards ---------- */

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
}

.card {
  padding: 28px 26px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  transition: transform .18s ease, border-color .18s ease, background .18s ease;
}
.card:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  background: var(--surface-2);
}
.card__icon {
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: rgb(var(--ink) / .05);
  border: 1px solid var(--border);
  color: var(--accent);
  margin-bottom: 18px;
}
.card__title { font-size: 1.06rem; margin-bottom: 9px; }
.card__text { color: var(--text-dim); font-size: .93rem; }

/* ---------- steps ---------- */

.steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; counter-reset: step; }

.step {
  position: relative;
  padding: 30px 26px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: rgb(var(--ink) / .022);
}
.step__num {
  display: inline-grid;
  place-items: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  font-family: var(--mono);
  font-size: .82rem;
  font-weight: 700;
  color: var(--accent);
  background: rgba(77, 163, 255, .12);
  border: 1px solid rgba(77, 163, 255, .3);
  margin-bottom: 16px;
}
.step__title { font-size: 1.08rem; margin-bottom: 9px; }
.step__text { color: var(--text-dim); font-size: .93rem; }

/* ---------- CLI band ---------- */

.cli-grid {
  display: grid;
  grid-template-columns: minmax(0, .88fr) minmax(0, 1.12fr);
  gap: 56px;
  align-items: center;
}

.terminal {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: #060A15;
  box-shadow: 0 30px 60px -30px var(--shadow);
  overflow: hidden;
}
.terminal__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  background: rgb(var(--ink) / .03);
}
.terminal__body {
  margin: 0;
  padding: 20px;
  font-family: var(--mono);
  font-size: .82rem;
  line-height: 1.95;
  color: var(--text-dim);
  overflow-x: auto;
}
.terminal__body .t-prompt { color: var(--violet); }
.terminal__body .t-cmd    { color: var(--text); }
.terminal__body .t-flag   { color: var(--accent); }
.terminal__body .t-ok     { color: var(--teal); }
.terminal__body .t-warn   { color: var(--amber); }
.terminal__body .t-dim    { color: var(--text-faint); }

/* ---------- security ---------- */

.sec-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; }
/* Two blocks, centred under their heading: the Contact section's email and phone. */
.sec-grid--two { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 640px; margin-inline: auto; }
.sec {
  padding: 24px 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: rgb(var(--ink) / .022);
}
.sec__title {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: .98rem;
  font-weight: 640;
  margin-bottom: 10px;
}
.sec__title svg { color: var(--teal); flex: none; }
.sec__text { color: var(--text-dim); font-size: .89rem; }

/* ---------- final CTA ---------- */

.cta {
  position: relative;
  padding: 68px 40px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  text-align: center;
  background:
    radial-gradient(90% 130% at 50% 0%, rgba(77, 163, 255, .2), transparent 62%),
    linear-gradient(180deg, var(--surface-2), var(--bg-elev));
  overflow: hidden;
}
.cta__title { font-size: clamp(1.75rem, 3.4vw, 2.4rem); }
.cta__sub { margin: 16px auto 0; max-width: 46em; color: var(--text-dim); }
.cta__actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-top: 30px; }
.cta__note { margin-top: 18px; font-size: .85rem; color: var(--text-faint); }

/* ---------- footer ---------- */

.site-footer {
  border-top: 1px solid var(--border);
  background: var(--bg-elev);
  padding-block: 56px 34px;
}
.footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
  gap: 40px 28px;
}
.footer__blurb { margin-top: 14px; color: var(--text-dim); font-size: .92rem; max-width: 30em; }
.footer__col h4 {
  font-size: .78rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 16px;
}
.footer__col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
.footer__col a { color: var(--text-dim); font-size: .93rem; }
.footer__col a:hover { color: var(--text); }

.footer__base {
  margin-top: 44px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  gap: 14px 24px;
  justify-content: space-between;
  align-items: center;
  font-size: .85rem;
  color: var(--text-faint);
}
.footer__legal { max-width: 62ch; }

/* ---------- responsive ---------- */

@media (max-width: 980px) {
  .hero__grid, .cli-grid { grid-template-columns: minmax(0, 1fr); gap: 44px; }
  .cards, .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sec-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  /* The open menu grows the sticky header instead of overlaying it, so the
     links and the action buttons can never collide. */
  .nav { flex-wrap: wrap; justify-content: space-between; }
  /* Keep the toggle on the first row beside the brand: it follows the menu in
     DOM order (so the menu is reachable right after the button in the tab
     order), which without this would wrap it below the opened panel. */
  .brand { order: 1; }
  .nav__toggle { display: inline-flex; order: 2; }
  .nav__menu { order: 3; }
  .nav__actions { order: 4; }
  .nav__menu, .nav__actions { display: none; }

  .site-header[data-open="true"] .nav { height: auto; padding-bottom: 16px; }
  .site-header[data-open="true"] .nav__menu,
  .site-header[data-open="true"] .nav__actions {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    flex-basis: 100%;
    margin: 0;
    gap: 6px;
  }
  .site-header[data-open="true"] .nav__menu { padding-top: 8px; }
  .site-header[data-open="true"] .nav__link { padding: 11px 12px; }
  .site-header[data-open="true"] .nav__actions {
    padding-top: 10px;
    border-top: 1px solid var(--border);
  }
  .site-header[data-open="true"] .nav__signin { padding: 10px 12px; }
  .site-header[data-open="true"] .btn { width: 100%; }
}

@media (max-width: 680px) {
  .section { padding-block: 72px; }
  .hero { padding-block: 64px 60px; }
  .split, .cards, .steps, .sec-grid { grid-template-columns: minmax(0, 1fr); }
  .cta { padding: 48px 24px; }
  .footer__grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .hero__cta .btn, .cta__actions .btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }
  .btn:hover, .card:hover { transform: none; }
}

/* ---------- simple content pages (Privacy, Error, …) ---------- */

.page { padding-block: 72px 96px; }
.page h1 { font-size: clamp(1.8rem, 3.4vw, 2.4rem); margin-bottom: 20px; }
.page h2 { font-size: 1.35rem; margin: 32px 0 12px; }
.page h3 { font-size: 1.1rem; margin: 28px 0 10px; }
.page p { color: var(--text-dim); margin-bottom: 14px; max-width: 68ch; }
.page strong { color: var(--text); }
.page code {
  font-family: var(--mono);
  font-size: .88em;
  padding: 2px 7px;
  border-radius: 6px;
  background: rgb(var(--ink) / .07);
  border: 1px solid var(--border);
  color: var(--text);
}
.text-danger { color: var(--rose); }

/* ---------- sign-in pages ---------- */

.auth {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  padding: 40px 20px;
  background:
    radial-gradient(60% 50% at 50% 0%, rgba(77, 163, 255, .16), transparent 70%),
    var(--bg);
}

.auth__card {
  width: 100%;
  max-width: 430px;
  padding: 38px 34px 32px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, var(--surface-2), var(--bg-elev));
  box-shadow: 0 40px 80px -40px var(--shadow);
}

.auth__brand { margin-bottom: 26px; }
.auth__title { font-size: 1.6rem; margin-bottom: 10px; }
.auth__sub { color: var(--text-dim); font-size: .96rem; }
.auth__email { color: var(--text); font-weight: 600; overflow-wrap: anywhere; }

.auth__form { display: flex; flex-direction: column; margin-top: 26px; }

.auth__label {
  font-size: .84rem;
  font-weight: 600;
  color: var(--text-dim);
  margin-bottom: 8px;
}

.auth__input {
  width: 100%;
  padding: 13px 15px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  /* background-COLOR, not the shorthand: the shorthand resets background-image,
     and this class outranks the bare `select` rule that paints the caret. Any
     control that can be a <select> sets its colour this way. */
  background-color: var(--recess);
  color: var(--text);
  font-size: 1rem;
  font-family: inherit;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.auth__input::placeholder { color: var(--text-faint); }
.auth__input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(77, 163, 255, .22);
}

/* A Lightning page drawn from its definition. Regions side by side, the
   components in each stacked in the order the file declares them. */
.flx { display: grid; gap: 14px; }

.flx__head {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.flx__fact { font-size: .85rem; color: var(--text); }
.flx__fact-label {
  margin-right: 6px;
  color: var(--text-faint);
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* --regions is the count the drawing wrote. They collapse to one column on a
   narrow screen rather than scrolling sideways. */
.flx__regions {
  display: grid;
  gap: 14px;
  grid-template-columns: 1fr;
}
@media (min-width: 720px) {
  .flx__regions {
    grid-template-columns: repeat(var(--regions, 1), minmax(0, 1fr));
  }
}

.flx__region {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  padding: 12px 14px;
}
.flx__region-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 10px;
  font-size: .9rem;
}
.flx__region-type { color: var(--text-faint); font-size: .75rem; font-weight: 400; }
.flx__none { margin: 0; color: var(--text-faint); font-size: .875rem; font-style: italic; }

.flx__cmp {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.flx__cmp + .flx__cmp { margin-top: 8px; }
.flx__cmp-name { font-weight: 600; font-size: .875rem; }
/* force: is Salesforce's own; a package's namespace is not. */
.flx__cmp-ns {
  margin-left: 8px;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: .75rem;
}
/* Which components the page places, and whether we hold them. Live, not part
   of the stored drawing. */
.flx__parts {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 14px;
  margin: 0 0 14px;
  font-size: .8125rem;
}
.flx__parts-label {
  color: var(--text-faint);
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.flx__part { color: var(--text-dim); }
.flx__part--absent { margin-left: 6px; color: var(--amber); font-size: .75rem; }

.flx__cmp-id {
  margin-left: 8px;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: .72rem;
}

/* Which flow, which related list, how many rows -- the useful half. */
.flx__props {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 2px 10px;
  margin: 8px 0 0;
  font-size: .8125rem;
}
.flx__props dt { color: var(--text-faint); }
.flx__props dd { margin: 0; color: var(--text-dim); overflow-wrap: anywhere; }

/* The commit a pull would bring: sha then subject, on one line. */
/* A commit on the org facts, so a sha reads as a sha rather than as prose. */
.orgfacts__sha {
  font-family: var(--mono);
  font-size: .85rem;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1px 7px;
}

/* Have, then Incoming: one per line, labels aligned so the two shas line up
   under each other and can be read against one another at a glance. */
.branch__commits { display: grid; gap: 6px; margin: 0 0 4px; }
/* sha, then the label. The shas line up because the first column is the code
   chip and every short sha is the same width. */
.branch__commit {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
}
.branch__commit-label { color: var(--text-dim); font-size: .85rem; }
.branch__commit code {
  justify-self: start;
  font-family: var(--mono);
  font-size: .8125rem;
  color: var(--text-faint);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1px 7px;
}
/* The one arriving is the subject of the dialog, so it is the one in full ink. */
.branch__commit--incoming code { color: var(--text); border-color: var(--border-strong); }

/* Where a sha would be, when there is not one. Italic so it reads as an
   absence rather than as a value. */
.branch__commit-unknown { color: var(--text-faint); font-size: .8125rem; font-style: italic; }

/* ==========================================================================
   Dropdowns
   --------------------------------------------------------------------------
   THE TRAP: padding-right does not move a native <select>'s caret. The browser
   pins the arrow a fixed distance from the border and stops the text short of
   it, so adding padding moves the text and leaves the arrow exactly where it
   was, still against the edge. This was found and fixed three separate times —
   .snapshots__select, the compare dialog, the metadata-setup version picker —
   before it was written down. It is one rule now.

   THE FIX: turn the platform's caret off and paint one. Then it can be
   positioned, it takes the page's ink rather than the OS's, and every dropdown
   in the app looks like the same control.

   Applies to every <select>, so a new one is right without doing anything.
   A class that styles a select must set background-COLOR rather than the
   `background` shorthand, or it resets the caret out of existence.
   ========================================================================== */
select {
  appearance: none;
  -webkit-appearance: none;
  background-image: var(--caret);
  background-repeat: no-repeat;
  /* 12px in from the border, and 34px of padding: the caret's 12px, the 12px
     it is inset by, and ~10px of air before the longest option's text. */
  background-position: right 12px center;
  padding-right: 34px;
}
/* The open list is painted by the platform, which does not inherit the page's
   colours -- without this the options are black on white under a dark control. */
select option { background-color: var(--surface-2); color: var(--text); }

.auth__input--code {
  font-family: var(--mono);
  font-size: 1.6rem;
  letter-spacing: .42em;
  text-align: center;
  padding-inline: 10px;
}

.auth__submit { width: 100%; margin-top: 20px; }

/* A form on a workspace page rather than in the sign-in card: a readable
   width, left-aligned, buttons their own size (Connect a repository). */
.auth__form--page { max-width: 640px; }
.auth__form--page .auth__submit { width: auto; align-self: flex-start; }

.auth__note {
  display: flex;
  gap: 9px;
  margin-top: 22px;
  font-size: .84rem;
  color: var(--text-faint);
  line-height: 1.5;
}
.auth__note svg { flex: none; margin-top: 3px; }

.auth__error,
.auth__ok {
  border-radius: var(--radius-sm);
  padding: 11px 14px;
  font-size: .89rem;
  margin-bottom: 18px;
}
/* The box lives on the list, not the container, so an error area with nothing
   in it takes up no space without needing an :empty rule that whitespace breaks. */
.auth__error { padding: 0; border: 0; background: none; margin-bottom: 0; }
.auth__error ul {
  list-style: none;
  margin: 0 0 18px;
  padding: 11px 14px;
  border-radius: var(--radius-sm);
  color: var(--rose-text);
  background: rgba(255, 107, 138, .12);
  border: 1px solid rgba(255, 107, 138, .35);
  font-size: .89rem;
}
.auth__error li + li { margin-top: 4px; }
.auth__ok {
  color: var(--teal-text);
  background: rgba(47, 217, 195, .12);
  border: 1px solid rgba(47, 217, 195, .32);
  margin-top: 18px;
}

.auth__field-error { color: var(--rose); font-size: .84rem; margin-top: 8px; }
.auth__field-error:empty { display: none; }

.auth__secondary { margin-top: 18px; text-align: center; }
.auth__link-btn {
  background: none;
  border: 0;
  padding: 4px;
  color: var(--accent);
  font: inherit;
  font-size: .9rem;
  cursor: pointer;
}
.auth__link-btn:hover { color: var(--accent-hover); text-decoration: underline; }

.auth__alt {
  margin-top: 14px;
  text-align: center;
  font-size: .88rem;
  color: var(--text-faint);
}

.auth__legal {
  max-width: 430px;
  text-align: center;
  font-size: .78rem;
  color: var(--text-faint);
}

/* Signed-in state in the main site nav. */
.nav__user {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: .9rem;
  color: var(--text-dim);
  max-width: 190px;
}
.nav__user span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nav__signout {
  background: none;
  border: 0;
  padding: 8px 6px;
  color: var(--text-dim);
  font: inherit;
  font-size: .93rem;
  font-weight: 500;
  cursor: pointer;
}
.nav__signout:hover { color: var(--text); }

/* ---------- workspaces ---------- */

.ws { padding-block: 56px 96px; }

.ws__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  padding-bottom: 28px;
  margin-bottom: 32px;
  border-bottom: 1px solid var(--border);
}
/* .eyebrow uppercases its text, which is wrong for an email address — it reads
   as shouting and misstates an address people may treat as case-sensitive. */
.ws__signed-in {
  text-transform: none;
  letter-spacing: .01em;
  overflow-wrap: anywhere;
}
.ws__title { font-size: clamp(1.7rem, 3.2vw, 2.2rem); }
.ws--app .ws__title { font-size: 1.5rem; }

/* A title with one small action on its own row, right-aligned: the tool
   pages' "Back to tools". The block takes the header's full width so the
   action reaches the right edge. */
.ws__head-main { flex: 1 1 100%; min-width: 0; }
.ws__titlebar { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
/* A tool's org picker sits at the right beside the way back, not centred
   between it and the title. */
.ws__titlebar > .snapshots { margin-left: auto; }
.ws__titlebar > .tool-org { margin-left: auto; }
/* The orgs a tool can't run on until they are reconnected, under the picker. */
.tool-org { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.tool-org__disconnected { margin: 0; font-size: .78rem; color: var(--text-faint); text-align: right; }
.ws__sub { margin-top: 10px; color: var(--text-dim); max-width: 54ch; font-size: .96rem; }
/* On a workspace page the description runs the width of the page, and no
   rule divides the header from what follows. */
.ws--app .ws__sub { max-width: none; }
.ws--app .ws__head { border-bottom: 0; padding-bottom: 0; margin-bottom: 20px; }

.ws__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}

.ws__card {
  display: flex;
  flex-direction: column;
  padding: 24px 22px 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  transition: transform .18s ease, border-color .18s ease, background .18s ease;
}
.ws__card:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  background: var(--surface-2);
}

/* New Scratch Org's Dev Hub step: one row per Dev Hub. */
.scratch__hubs { border: 0; margin: 0 0 8px; padding: 0; display: grid; gap: 8px; }
.scratch__hub {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  cursor: pointer;
}
.scratch__hub:has(input:checked) { border-color: var(--accent); }
.scratch__hub-type { margin-left: auto; color: var(--text-dim); font-size: .88rem; }

/* The IDE's setup step: two choices at a readable width, left-aligned, and a
   button its own size -- not the sign-in form's full-width column. */
.idesetup { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; margin-top: 8px; }
.idesetup__options { border: 0; margin: 0; padding: 0; display: grid; gap: 10px; width: 100%; max-width: 640px; }
.idesetup__option {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius);
  cursor: pointer; text-align: left;
}
.idesetup__option input { margin-top: 4px; }
.idesetup__option:has(input:checked) { border-color: var(--accent); }
.idesetup__name { display: block; font-weight: 600; }
.idesetup__scope { display: flex; align-items: center; gap: 10px; cursor: pointer; }
.idesetup__scope + input + .btn { margin-top: 14px; }
.idesetup__desc { display: block; margin-top: 4px; font-size: .86rem; color: var(--text-dim); line-height: 1.5; }

/* The card that adds one: first in its grid (New Scratch Org). Dashed, so it
   reads as a place for a card rather than a card; the whole card is the link. */
.ws__card--new {
  padding: 0;
  border-style: dashed;
  background: transparent;
}
.ws__card--new:hover { border-color: var(--accent); }
.ws__card-new {
  flex: 1;
  min-height: 150px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 24px 22px;
  color: var(--text-dim);
  font-weight: 600;
  text-decoration: none;
}
.ws__card--new:hover .ws__card-new { color: var(--accent); }

.ws__card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}
.ws__name {
  font-size: 1.08rem;
  overflow-wrap: anywhere;
}
.ws__card-head .pill { margin-left: auto; flex: none; }

.ws__desc {
  color: var(--text-dim);
  font-size: .92rem;
  flex: 1;
}

.ws__meta {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  font-size: .82rem;
  color: var(--text-faint);
}
.ws__meta-item { display: inline-flex; align-items: center; gap: 7px; }
.ws__id {
  margin-left: auto;
  font-family: var(--mono);
  font-size: .74rem;
  overflow-wrap: anywhere;
}

.ws__empty {
  padding: 56px 32px;
  text-align: center;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: rgb(var(--ink) / .02);
}
/* The action an empty page exists to offer. */
.ws__empty-action { margin-top: 18px; }
.ws__empty-note { margin-top: 10px; font-size: .85rem; color: var(--text-faint); }
.btn--lg { padding: 12px 20px; font-size: .95rem; }
.btn__cost {
  margin-left: 10px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .18);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
}

.ws__empty-title { font-size: 1.25rem; margin-bottom: 10px; }
.ws__empty-text { color: var(--text-dim); max-width: 46ch; margin-inline: auto; font-size: .94rem; }

@media (max-width: 560px) {
  .ws__head { align-items: stretch; }
  .ws__head .btn { width: 100%; }
}

/* ---------- workspace detail ---------- */

.ws__link { color: var(--text); }
.ws__link:hover { color: var(--accent); }

/* The whole card is a hit target for the name link, so the pointer and the
   lift on hover stay consistent with the list's card styling. */
.ws__card:has(.ws__link:hover) { border-color: var(--accent); }

/* The trail and the actions that belong to what it names, on one line.
   The spacing below belongs to the row, not to its children: the menu button is
   taller than a line of crumbs, so leaving each with its own 22px put the row's
   height and two margins between the trail and the name under it. */

.ws__crumbs {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 22px;
  font-size: .88rem;
  color: var(--text-faint);
}
.ws__crumbs a { color: var(--text-dim); }
.ws__crumbs a:hover { color: var(--text); }

.ws__title .pill { vertical-align: middle; margin-left: 10px; }

/* A refresh of this member is paid for and still owed. Sits before the name
   because that is where the eye already is, and it is sized off the heading so
   it stays proportionate as the title scales with the viewport. */
.ws__spin {
  vertical-align: baseline;
  width: .62em;
  height: .62em;
  margin-right: .32em;
  color: var(--accent, #6aa9ff);
  animation: btn-spin 1.1s linear infinite;
}

/* Not the `hidden` attribute. The browser's rule that implements it is written
   for HTML elements and does not reach the SVG namespace, so <svg hidden> is
   hidden in name only — and setting .hidden from script does not reliably
   remove it either, so the spinner could be neither shown nor put away. A
   class behaves the same on both sides of that line. */
.ws__spin--idle { display: none; }

/* The shape and its title still say what is happening, so there is nothing to
   replace when the animation is dropped. */
@media (prefers-reduced-motion: reduce) {
  .ws__spin { animation: none; }
}

.ws__sysid {
  margin-top: 12px;
  font-family: var(--mono);
  font-size: .78rem;
  color: var(--text-faint);
}

.ws__section {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 1.15rem;
  margin: 40px 0 20px;
}
.ws__count {
  display: inline-grid;
  place-items: center;
  min-width: 26px;
  height: 22px;
  padding-inline: 8px;
  border-radius: 999px;
  background: rgb(var(--ink) / .07);
  border: 1px solid var(--border);
  font-family: var(--mono);
  font-size: .76rem;
  color: var(--text-dim);
}

.ws__facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 14px;
  margin: 0;
  font-size: .88rem;
}
.ws__facts dt { color: var(--text-faint); }
.ws__facts dd { margin: 0; color: var(--text-dim); overflow-wrap: anywhere; }
.ws__url { font-family: var(--mono); font-size: .8rem; }

.ws__members { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.ws__member {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: rgb(var(--ink) / .022);
  font-size: .92rem;
}
.ws__avatar {
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  flex: none;
  border-radius: 50%;
  background: rgba(77, 163, 255, .12);
  border: 1px solid rgba(77, 163, 255, .28);
  color: var(--accent);
}
.ws__member-email { overflow-wrap: anywhere; }
.ws__member-seen { margin-left: auto; color: var(--text-faint); font-size: .82rem; white-space: nowrap; }

@media (max-width: 560px) {
  .ws__member { flex-wrap: wrap; }
  .ws__member-seen { margin-left: 42px; }
}

/* ---------- modal dialog ---------- */

.modal {
  width: min(520px, calc(100vw - 32px));
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, var(--surface-2), var(--bg-elev));
  color: var(--text);
  box-shadow: 0 40px 90px -40px var(--shadow);
}
.modal::backdrop {
  background: rgba(5, 8, 17, .72);
  backdrop-filter: blur(3px);
}

.modal__form { display: flex; flex-direction: column; padding: 26px 26px 22px; }

.modal__head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 8px;
}
.modal__title { font-size: 1.3rem; }
.modal__close {
  margin-left: auto;
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  flex: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgb(var(--ink) / .04);
  color: var(--text-dim);
  cursor: pointer;
}
.modal__close:hover { color: var(--text); background: rgb(var(--ink) / .09); }

.modal__sub { color: var(--text-dim); font-size: .92rem; margin-bottom: 22px; }

.modal__label-gap { margin-top: 18px; }
.modal__optional {
  font-weight: 400;
  color: var(--text-faint);
  text-transform: none;
  letter-spacing: 0;
}
.modal__textarea { resize: vertical; min-height: 84px; line-height: 1.5; }

/* What a confirmation is confirming: the types, one per line, each with its own
   price. A total alone is a number to take on trust. */
.modal__text { margin: 0 0 12px; color: var(--text-dim); font-size: .9rem; }
.modal__list {
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.modal__list li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  font-size: .875rem;
}
.modal__list li + li { border-top: 1px solid var(--border); }
.modal__cost { color: var(--text-faint); font-variant-numeric: tabular-nums; }

.modal__actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 26px;
}

@media (max-width: 460px) {
  .modal__actions { flex-direction: column-reverse; }
  .modal__actions .btn { width: 100%; }
}

/* What an org is, under its name. Two columns, and each fact stacks its label
   over its value — so a column reads as one column all the way down rather than
   as label-and-value pairs that happen to sit side by side.
   No wider than the page's minimum width: on a wide window the page stretches,
   and two columns stretched with it put the facts far apart. */
.orgfacts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px 40px;
  /* The page's minimum width, less its 28px padding each side. */
  max-width: calc(var(--maxw) - var(--side-nav-w) - 56px);
  /* Room before the alpha navigation that follows it on the org page. */
  margin-bottom: 44px;
}
.orgfacts__col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.orgfacts__item { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.orgfacts__label {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.orgfacts__value { font-size: .9375rem; color: var(--text); overflow-wrap: anywhere; }
.orgfacts__value--url { font-family: var(--mono); font-size: .85rem; }
.orgfacts__value .pill { margin-left: 6px; }
/* A fact edited in place: its value, then a pencil; the pencil swaps it for a
   small form (inline-edit.js). */
.orgfacts__editable { display: inline-flex; align-items: center; gap: 6px; }
.orgfacts__pencil {
  display: grid; place-items: center; width: 26px; height: 26px; padding: 0;
  border: 0; border-radius: var(--radius-sm); background: none; color: var(--text-faint); cursor: pointer;
}
.orgfacts__pencil:hover, .orgfacts__pencil:focus-visible { color: var(--text); background: rgb(var(--ink) / .06); }
.orgfacts__form { display: grid; gap: 8px; margin-top: 2px; }
.orgfacts__form[hidden] { display: none; }
.orgfacts__form-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.orgfacts__form .snapshots__select { min-width: 140px; }
.orgfacts__note { margin: 0; max-width: 46ch; font-size: .78rem; color: var(--text-faint); line-height: 1.45; }


@media (max-width: 720px) {
  /* Two columns of stacked facts becomes one; the labels keep them apart. */
  .orgfacts { grid-template-columns: 1fr; gap: 14px; }
}

/* ---------- tabs ---------- */

.ws__head--detail { border-bottom: 0; padding-bottom: 8px; margin-bottom: 20px; }
/* The actions menu on the name's row, not the bottom line's: the header
   aligns its ends to the top here, and the name block takes the room it needs
   without pushing the menu onto a line of its own. */
.ws__head--detail { flex-wrap: nowrap; align-items: flex-start; }
.ws__head--detail > :first-child { flex: 1 1 auto; min-width: 0; }


.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 32px;
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }

.tabs__tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--text-dim);
  font-size: .94rem;
  font-weight: 550;
  white-space: nowrap;
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.tabs__tab:hover { color: var(--text); }
.tabs__tab.is-active {
  color: var(--text);
  border-bottom-color: var(--accent);
}

.tabs__count {
  display: inline-grid;
  place-items: center;
  min-width: 22px;
  height: 20px;
  padding-inline: 7px;
  border-radius: 999px;
  background: rgb(var(--ink) / .07);
  border: 1px solid var(--border);
  font-family: var(--mono);
  font-size: .72rem;
  color: var(--text-dim);
}
.tabs__tab.is-active .tabs__count {
  background: rgba(77, 163, 255, .14);
  border-color: rgba(77, 163, 255, .3);
  color: var(--accent);
}

/* ---------- activity feed ---------- */

.feed { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }

.feed__item {
  display: flex;
  gap: 14px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: rgb(var(--ink) / .022);
}

.feed__dot {
  width: 8px; height: 8px;
  flex: none;
  margin-top: 7px;
  border-radius: 50%;
  background: var(--teal);
  box-shadow: 0 0 0 3px rgba(47, 217, 195, .14);
}
.feed__dot--fail {
  background: var(--rose);
  box-shadow: 0 0 0 3px rgba(255, 107, 138, .14);
}

.feed__body { min-width: 0; }
.feed__text { font-size: .93rem; overflow-wrap: anywhere; }
.feed__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 5px;
  font-size: .78rem;
  color: var(--text-faint);
}
.feed__type { font-family: var(--mono); }
.feed__list {
  margin: 8px 0 0;
  padding-left: 18px;
  font-size: .84rem;
  color: var(--text-dim, inherit);
  overflow-wrap: anywhere;
}
.feed__list li + li { margin-top: 3px; }
.feed__actions { margin-top: 8px; }

/* ---------- account avatar ---------- */

.avatar {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--violet));
  color: #fff;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .02em;
  /* Two uppercase letters sit slightly high in most UI faces; nudge for optics. */
  line-height: 1;
  text-transform: uppercase;
  user-select: none;
}

.nav__user { gap: 0; max-width: none; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- account menu ---------- */

.menu { position: relative; }

.menu__trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px 4px 4px;
  border: 1px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  list-style: none;                 /* hides the default disclosure triangle */
  transition: background .15s ease, border-color .15s ease;
}
.menu__trigger::-webkit-details-marker { display: none; }
.menu__trigger:hover { background: rgb(var(--ink) / .06); border-color: var(--border); }

.menu__chevron {
  color: var(--text-dim);
  transition: transform .18s ease;
}
.menu[open] .menu__trigger { background: rgb(var(--ink) / .07); border-color: var(--border-strong); }
.menu[open] .menu__chevron { transform: rotate(180deg); }

.menu__panel {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 60;
  min-width: 240px;
  padding: 6px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  box-shadow: 0 26px 50px -24px var(--shadow);
}

.menu__header { padding: 10px 12px 8px; display: grid; gap: 2px; }
.menu__name { font-size: .92rem; font-weight: 600; overflow-wrap: anywhere; }
.menu__email { font-size: .8rem; color: var(--text-faint); overflow-wrap: anywhere; }

.menu__sep { height: 1px; margin: 6px 0; border: 0; background: var(--border); }

.menu__item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-dim);
  font: inherit;
  font-size: .91rem;
  text-align: left;
  cursor: pointer;
}
.menu__item svg { flex: none; color: var(--text-faint); }
.menu__item:hover { background: rgb(var(--ink) / .07); color: var(--text); }
.menu__item:hover svg { color: var(--accent); }

.menu__item--button { font-family: inherit; }

/* A heading over a group of items. Worth having once a menu holds actions of
   different kinds: reading credits from an org and repairing its connection are
   not the same sort of thing, and a flat list makes the reader sort them out
   for themselves every time they open it.
   The rule sits above the heading rather than below it, so a group is held
   together by the space around it instead of being boxed. */
.menu__section {
  margin: 0;
  padding: 12px 12px 5px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.menu__section + * { margin-top: 0; }
.menu__section:not(:first-child) {
  margin-top: 6px;
  border-top: 1px solid var(--border);
}
/* The first heading has nothing above it to be separated from. */
.menu__panel > .menu__section:first-child { padding-top: 6px; }

/* An action that does not apply right now. Shown rather than hidden: a menu
   whose contents change is one a reader has to re-read, and "reconnect" being
   there but inert says the org is connected — which is the thing they wanted to
   know. Its title says why. */
.menu__item.is-disabled {
  color: var(--text-faint);
  cursor: default;
}
.menu__item.is-disabled:hover { background: none; color: var(--text-faint); }
.menu__item.is-disabled:hover svg { color: var(--text-faint); }

/* A disabled button in a menu is greyed the same way. */
.menu__item:disabled,
.menu__item[disabled] { color: var(--text-faint); cursor: default; }
.menu__item:disabled:hover,
.menu__item[disabled]:hover { background: none; color: var(--text-faint); }
.menu__item:disabled:hover svg,
.menu__item[disabled]:hover svg { color: var(--text-faint); }

.avatar--lg { width: 56px; height: 56px; font-size: 1.25rem; }
/* Forceware's own work in the activity feed: IO, in the brand's teal. */
.avatar--system { background: linear-gradient(135deg, var(--teal), var(--accent)); }
.avatar--fail { box-shadow: 0 0 0 2px var(--rose); }

/* ---------- narrow content pages ---------- */

.wrap--narrow { max-width: 720px; }

/* A workspace page takes the whole window beside its side nav, less 20px a
   side; how narrow it may get is set with the rest of the format, under
   "Workspace pages". */
.wrap--app { max-width: none; padding-inline: 20px; }

.profile__id { display: flex; align-items: center; gap: 18px; }

.detail {
  display: grid;
  grid-template-columns: minmax(140px, auto) 1fr;
  gap: 12px 24px;
  margin: 0;
  padding: 20px 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: rgb(var(--ink) / .022);
  font-size: .93rem;
}
.detail dt { color: var(--text-faint); }
.detail dd { margin: 0; color: var(--text); overflow-wrap: anywhere; }
.detail dd .pill { margin-left: 8px; }

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; }
.stat {
  padding: 20px 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.stat__label { display: block; font-size: .8rem; color: var(--text-faint); margin-bottom: 8px; }
.stat__value { display: block; font-size: 1.7rem; font-weight: 680; letter-spacing: -.02em; }
/* The allowance after a count: "3 / 5". */
.stat__of { font-size: 1rem; font-weight: 500; color: var(--text-faint); letter-spacing: 0; }

.ws__note { margin-top: 28px; font-size: .87rem; color: var(--text-faint); }
/* A note directly under a section heading explains that heading, so it sits
   right below it -- not 28px away, as if it began something new. Both
   margins, because they collapse into the larger. */
.ws__section:has(+ .ws__note) { margin-bottom: 4px; }
.ws__section + .ws__note { margin-top: 0; }
/* A note that introduces a table is part of the table, not a paragraph that
   happens to sit above one. Without this they touch. */
.ws__note + .table,
.ws__note + .cmp__table-wrap { margin-top: 14px; }

@media (max-width: 520px) {
  .menu__panel { min-width: 0; width: calc(100vw - 32px); right: -8px; }
  .detail { grid-template-columns: 1fr; gap: 4px 0; }
  .detail dd { margin-bottom: 12px; }
}

/* ---------- section heading with an action ---------- */

.section-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 40px 0 20px;
}
.ws__section--flush { margin: 0; }

/* ---------- submitted button ---------- */

.btn.is-busy,
.btn.is-refreshing,
.btn:disabled {
  opacity: .65;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* A spinner rather than only dimming, so a slow network still reads as working
   rather than as a dead button. */
.btn.is-busy::before,
.btn.is-refreshing::before {
  content: "";
  width: 14px;
  height: 14px;
  flex: none;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: #fff;
  animation: btn-spin .7s linear infinite;
}

@keyframes btn-spin { to { transform: rotate(360deg); } }

/* The whole page while a data-busy-page form's answer is coming (forms.js):
   dimmed, unclickable, a progress cursor, and a spinner beside the picker
   that was used, so it reads as working rather than as frozen. */
body.is-page-busy { cursor: progress; }
body.is-page-busy main { pointer-events: none; }
body.is-page-busy main > * { opacity: .55; transition: opacity .15s ease; }
form[data-busy-page].is-busy { position: relative; }
form[data-busy-page].is-busy::after {
  content: "";
  display: inline-block;
  width: 16px; height: 16px;
  margin-left: 10px;
  vertical-align: middle;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  animation: btn-spin .7s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .btn.is-busy::before,
  .btn.is-refreshing::before { animation: none; border-top-color: rgba(255, 255, 255, .35); }
}

/* A one-time code field that has been handed off looks inert while the request
   is in flight, without being `disabled` before the value is submitted. */
.auth__input[readonly],
.auth__input:disabled {
  opacity: .6;
  cursor: not-allowed;
}

/* ---------- data table ---------- */

.tabs--spaced { margin-top: 36px; }
.ws__note--top { margin-top: 0; margin-bottom: 18px; }

.table {
  width: 100%;
  /* Widths come from the columns, not from whichever value happens to be
     longest on this page — otherwise paging by letter makes the table jump. */
  table-layout: fixed;
  border-collapse: collapse;
  font-size: .9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.table thead th {
  text-align: left;
  padding: 11px 16px;
  background: rgb(var(--ink) / .04);
  border-bottom: 1px solid var(--border);
  font-size: .78rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 600;
}
/* A row's header cell is part of the row: the same padding and the same rule
   under it. Written for td only, a <th scope="row"> -- the holder on the
   permission map, the monitor's name -- sat in its row with no line under it,
   so the first column read as unruled. */
.table td,
.table tbody th { padding: 11px 16px; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
.table tbody tr:last-child td,
.table tbody tr:last-child th { border-bottom: 0; }
.table tbody tr:hover { background: rgb(var(--ink) / .03); }
/* Left, matching the header: `.table thead th` outranks this selector on
   specificity, so a right-aligned value never lined up with its own column
   heading. */
.table__num { text-align: left; font-family: var(--mono); font-size: .84rem; }
.table__dim { color: var(--text-faint); font-size: .84rem; white-space: nowrap; }

.col-type      { width: 44%; }
.col-count     { width: 12%; }
.col-state     { width: 20%; }
.col-refreshed { width: 24%; }

/* The setup table has six columns where the org list has four, so it declares
   its own rather than bending a shared set that is right where it is used. */
/* The cost columns carry a unit now, so they need the room for it. */
.col-setup-type    { width: 85%; }
.col-setup-enabled { width: 15%; }

/* Permission architecture. Declared rather than left to the fixed layout's
   equal split: a holder name is the longest thing on the page -- 
   "MuleSoftPublishInvocableActionsC2CPermSet" is forty characters -- and at an
   equal share of four columns it broke mid-word, which is what made the first
   version of that page unreadable. The name gets nearly half the row and the
   two number columns get only what a two-digit figure needs. */
.col-pmap-holder { width: 44%; }
.col-pmap-kind   { width: 14%; }
.col-pmap-level  { width: 15%; }
.col-pmap-allows { width: 27%; }

.col-pmap-object { width: 60%; }
.col-pmap-count  { width: 20%; }

/* A row header is a label, not a heading over a column, so it aligns with the
   cells beside it and with its own column heading.

   `.table thead th` declared left and nothing declared it for the body, so
   every th[scope="row"] fell back to the browser's centre -- which put the
   first column of the monitors list, the monitor page, the compare tables and
   the permission tables out of line with every heading above them. Fixed here
   rather than per page: they share the table, so they share the fault. */
.table tbody th { text-align: left; }

/* A name never breaks mid-word. Overflowing the cell is better than
   shattering the name: the row grows, the name stays legible, and the title
   attribute carries the API name for anything that still will not fit. */
.table th[scope="row"] { overflow-wrap: normal; word-break: keep-all; }

/* Centred in the header too: `.table thead th` is more specific than a class
   alone and left-aligned the heading over a centred column. */
.table__mid,
.table thead th.table__mid { text-align: center; }

/* Headings stay on one line. "Compare cost" wrapping to two made the header row
   twice as tall as it needed to be and left the "i" beside a word rather than
   beside the heading it explains. The cells below still wrap — a type name has
   to. */
.table--setup thead th { white-space: nowrap; }

/* One checkbox, one form, so it can submit itself. */
.switch-form { display: inline-flex; align-items: center; gap: 8px; margin: 0; }
.switch {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}
.switch:disabled { cursor: default; opacity: .5; }
.btn--tiny { padding: 3px 8px; font-size: .75rem; }

/* The API version, above the type switches on the setup page. One decision
   that applies to every snapshot of the org, where everything below it is a
   decision per type — so it reads as a panel rather than as another row. */
/* The Setup tab's count of what is switched on, at the end of the letters
   just before the filter: it takes the auto margin, the filter follows it. */
.setup__count { margin-left: auto; color: var(--text-faint); font-size: .84rem; white-space: nowrap; }
.setup__count + .alpha__filter { margin-left: 0; }
.setup__api {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 20px;
  margin-bottom: 22px;
  padding: 14px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
/* Takes the slack so the control keeps its natural width, and may shrink to
   one column before the form drops beneath it. */
.setup__api-said { flex: 1 1 320px; min-width: 0; }
.setup__api-title { margin: 0 0 4px; font-size: .95rem; }
.setup__api-note { margin: 0; color: var(--text-dim); font-size: .85rem; }

.setup__api-form {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  flex: 0 0 auto;
}
.setup__api-select {
  /* Caret and padding-right come from the `select` rule. */
  padding: 7px 34px 7px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: .85rem;
}
.setup__api-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* .btn--tiny is sized for a table cell. Beside a control this tall it reads as
   cramped, so the button gets its own padding and matches the select's height. */
.setup__api-form .btn {
  padding: 7px 18px;
  font-size: .85rem;
  border-radius: var(--radius-sm);
}

.setup__api-fixed { margin: 0; font-family: var(--mono); color: var(--text-dim); }

/* An "i" beside a heading that needs a sentence of explanation. Focusable, so
   the sentence is reachable without a mouse. */
.info {
  position: relative;
  display: inline-flex;
  /* The only gap: the markup puts the icon against the label with no text node
     between them, so this is the whole distance rather than an addition to a
     space the newline put there. */
  margin-left: 4px;
  color: var(--text-faint);
  vertical-align: -2px;
  cursor: help;
}
.info:hover, .info:focus-visible { color: var(--accent); }

/* Drawn rather than left to the browser. A native title waits a second or two
   and gives no control over where it lands; an explanation nobody waits long
   enough to see is not an explanation. */
.info::after {
  content: attr(data-tip);
  position: absolute;
  top: calc(100% + 9px);
  right: 0;
  z-index: 70;
  width: max-content;
  max-width: 250px;
  padding: 9px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-elev);
  box-shadow: 0 18px 40px -20px var(--shadow);
  color: var(--text);
  font-size: .78rem;
  font-weight: 400;
  line-height: 1.45;
  /* A heading may be centred or right-aligned; a sentence is neither. */
  text-align: left;
  text-transform: none;
  letter-spacing: normal;
  white-space: normal;
  opacity: 0;
  visibility: hidden;
  transition: opacity .12s ease;
  pointer-events: none;
}
.info:hover::after,
.info:focus-visible::after { opacity: 1; visibility: visible; }

@media (prefers-reduced-motion: reduce) {
  .info::after { transition: none; }
}

.pill--muted { color: var(--text-faint); background: rgb(var(--ink) / .05); border-color: var(--border); }

/* ---------- usage meters ---------- */

.meters { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }

/* The same grid and the same horizontal padding as a row, so the headers sit
   over the columns they name rather than near them. The app's table headers
   for the type, since this reads as one even though it is not marked up as
   one. */
.meters__head {
  display: grid;
  grid-template-columns: 390px minmax(0, 1fr);
  gap: 16px;
  padding: 11px 17px;
  border-bottom: 1px solid var(--border);
  font-size: .78rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* The header is a control, so it looks like one on hover and says which way
   it is sorting. The arrow is on the active column only — an arrow on every
   header says nothing about which one is in force. */
.meters__sort {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}
.meters__sort:hover { color: var(--text); }

.meters__sort[data-direction="asc"]::after  { content: " \2191"; }
.meters__sort[data-direction="desc"]::after { content: " \2193"; }
.meters__sort[data-direction="asc"],
.meters__sort[data-direction="desc"] { color: var(--text); }

/* Two columns, and the first is a FIXED width rather than a fraction: each row
   is its own grid, so only an absolute value puts every bar at the same two x
   positions down the list. That alignment is the whole point — bars that start
   and end together can be compared by length without reading a single number. */
.meter {
  display: grid;
  grid-template-columns: 390px minmax(0, 1fr);
  align-items: center;
  gap: 16px;
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: rgb(var(--ink) / .02);
}

/* One line, always. A wrapped name makes the row two lines tall and the list
   stops being scannable — and with the bar and its numbers already stacked in
   the second column, a row that grows is a row that drifts out of step with
   its neighbours.

   Truncated rather than shrunk, and recoverable: the full API name and the
   raw counts are on the row's title. At 390px almost nothing truncates — the
   longest name here, "Hourly Published Standard Volume Platform Events", is
   47 characters. min-width:0 is required — a grid item
   defaults to min-content, which refuses to shrink and lets the text push the
   column wider instead of ellipsing. */
.meter__name {
  font-size: .88rem;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The bar and its numbers, stacked. */
.meter__usage { display: grid; gap: 6px; min-width: 0; }

/* Thin track, data-end rounded and anchored at the left baseline. */
.meter__track {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: rgb(var(--ink) / .07);
  overflow: hidden;
}
.meter__fill {
  display: block;
  height: 100%;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
  min-width: 2px;
}
/* Reserved status steps. Each row prints its percentage, so these are a second
   reading of the same number rather than the only one. */
.meter__fill--warning  { background: var(--amber); }
.meter__fill--critical { background: var(--rose); }

/* Spanning the bar above it: the percentage under where the bar starts, the
   count under where it ends. */
.meter__value {
  display: flex;
  align-items: baseline;
  gap: 10px;
  justify-content: space-between;
  white-space: nowrap;
}
/* Values wear text tokens, never the mark's colour. */
.meter__value strong { font-family: var(--mono); font-size: .86rem; color: var(--text); }
.meter__of { font-family: var(--mono); font-size: .76rem; color: var(--text-faint); }

/* Movement since the last reading. Sits between the percentage and the count
   because it belongs to both: it is the rate the one is climbing and the
   other is filling. */
.meter__change {
  margin-right: auto;
  font-family: var(--mono);
  font-size: .76rem;
  color: var(--accent);
}
/* A counter that went down did not refund anything — its window rolled over. */
.meter__change.is-reset { color: var(--text-dim); }

@media (max-width: 720px) {
  /* A 260px name column leaves nothing for the bar on a phone, so the two
     stack. The bars still align with each other — they just align at the left
     edge of the row instead of after the name. The headers go with them:
     two words over one stacked column name nothing. */
  .meter { grid-template-columns: 1fr; gap: 6px; }
  .meters__head { display: none; }
  .table thead { display: none; }
  .table td { display: block; padding: 6px 14px; border-bottom: 0; }
  .table tbody tr { display: block; border-bottom: 1px solid var(--border); padding: 8px 0; }
}

/* ---------- alphabet paging ---------- */

.alpha {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 18px;
  margin-bottom: 18px;
}
.alpha__label { font-size: .84rem; color: var(--text-faint); }

/* The filter, at the end of the line. margin-left:auto rather than a float, so
   it stays right as the letters wrap and drops below them rather than
   overlapping when the row runs out of width. */
.alpha__filter {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 0 auto;
  white-space: nowrap;
}
.filter__check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: .85rem;
  color: var(--text-dim);
  cursor: pointer;
}
.filter__check:hover { color: var(--text); }

/* Left-aligned and first in the row: the alphabet is the navigation, so it
   starts where the eye starts rather than being pushed right by a label that is
   no longer there. */
.alpha__pages {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 2px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.alpha__page {
  display: grid;
  place-items: center;
  min-width: 28px;
  height: 28px;
  padding-inline: 6px;
  border-radius: 6px;
  /* The page's own font, a size up from the rest of the bar. */
  font-size: .9rem;
  color: var(--text-dim);
}
a.alpha__page:hover { color: var(--text); background: rgb(var(--ink) / .07); }

.alpha__page.is-current {
  font-weight: 700;
  color: var(--text);
  background: rgba(77, 163, 255, .14);
  border: 1px solid rgba(77, 163, 255, .32);
  cursor: default;
}

/* ---------- row action ---------- */

/* Keeps the value left and the action hard right inside one cell. */
.cell-split {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.icon-btn {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgb(var(--ink) / .04);
  color: var(--text-dim);
  cursor: pointer;
  transition: color .15s ease, background .15s ease, border-color .15s ease;
}
.icon-btn:hover {
  color: var(--accent);
  background: rgba(77, 163, 255, .12);
  border-color: rgba(77, 163, 255, .32);
}

/* Credit balance in the account menu. */
.menu__credits {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  padding: 5px 9px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgb(var(--ink) / .04);
  font-size: .78rem;
  color: var(--text-dim);
  align-self: flex-start;
}
.menu__credits:hover { color: var(--text); border-color: var(--border-strong); }
.menu__credits svg { color: var(--text-faint); flex: none; }
.menu__credits strong { font-family: var(--mono); color: var(--text); }

/* ---------- plan chooser ---------- */

.plans {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* 190px, not wider: five plans share one row inside --maxw, so Enterprise
     does not wrap onto a row of its own. */
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 16px;
}

.plan {
  display: flex;
  flex-direction: column;
  padding: 24px 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.plan.is-current { border-color: rgba(77, 163, 255, .4); background: var(--surface-2); }

.plan__head { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
/* Every head the height of one with a pill in it, so the prices line up across
   the row whether or not a card says "free" or "current". */
.plan__head { min-height: 28px; }
.plan__name { font-size: 1.05rem; }
.plan__head .pill { margin-left: auto; }

.plan__price { display: flex; align-items: baseline; gap: 6px; }
.plan__price strong { font-size: 1.75rem; font-weight: 680; letter-spacing: -.02em; }
.plan__per { font-size: .84rem; color: var(--text-faint); }

/* What a plan allows: orgs and members, the count bold. */
.plan__includes {
  flex: 1;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 6px;
  color: var(--text-dim);
  font-size: .92rem;
}
.plan__includes strong { color: var(--text); font-weight: 650; }
.plan__action { margin-top: 20px; width: 100%; }

/* A refresh that cannot run right now stays put and says why, rather than
   vanishing and leaving the row looking like it never had the option. */
.icon-btn:disabled {
  opacity: .4;
  cursor: not-allowed;
}
.icon-btn:disabled:hover {
  color: var(--text-dim);
  background: rgb(var(--ink) / .04);
  border-color: var(--border);
}

/* The refresh form is only a wrapper for one icon button. */
.cell-form { display: inline-flex; margin: 0; }

/* ---- workspace settings ------------------------------------------------ */
.setting {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px 22px;
  background: var(--surface);
}

.setting__title {
  margin: 0 0 6px;
  font-size: 1rem;
  font-weight: 620;
  letter-spacing: -.01em;
}

.setting__text {
  margin: 0;
  max-width: 62ch;
  color: var(--text-dim);
  font-size: .875rem;
  line-height: 1.55;
}

.setting__facts {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 12px;
  margin: 18px 0 0;
  padding: 14px 0 0;
  border-top: 1px solid var(--border);
}

.setting__facts dt {
  color: var(--text-dim);
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .07em;
}

.setting__facts dd {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  margin: 0;
}

.setting__payer { font-size: .9rem; font-weight: 560; }

.setting__balance,
.setting__hint,
.setting__note {
  color: var(--text-dim);
  font-size: .8rem;
}

.setting__note { margin: 16px 0 0; max-width: 62ch; line-height: 1.55; }

/* Wraps to its own line on a narrow screen rather than squeezing the button. */
.setting__form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  margin-top: 18px;
}

/* ---- connect an org ---------------------------------------------------- */
/* Connecting lives on the workspace header, not in a tab. .ws__head is already
   space-between with a single child, so this becomes the right-hand one.

   Icon only, so it has to be legible as a control without a label: the base
   .menu__trigger is transparent until hover, which is fine in a hero where it
   is a secondary action beside a named subject, and not fine as the only way
   to add an org. A visible rim and fill is the whole difference between a
   button and a mark.

   Declared after the base .menu__trigger rules so the hover and [open] states
   win at equal specificity rather than by !important. */
.ws__menu { flex: none; align-self: flex-start; }

.ws__menu-trigger {
  padding: 9px;
  border-color: var(--border-strong);
  background: rgb(var(--ink) / .04);
  color: var(--text);
}
.ws__menu-trigger:hover,
.menu[open] .ws__menu-trigger {
  border-color: var(--border-strong);
  background: rgb(var(--ink) / .1);
}

/* ---- error page -------------------------------------------------------- */
.errorpage { text-align: center; }

.errorpage__code {
  margin: 0 0 4px;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: 2.25rem;
  font-weight: 600;
  letter-spacing: -.02em;
}

.errorpage__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 22px;
}

.errorpage__ref {
  margin: 18px 0 0;
  color: var(--text-faint);
  font-size: .75rem;
}

/* ---- metadata members -------------------------------------------------- */
.find {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
}

.find__label {
  color: var(--text-dim);
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .07em;
}

/* Gives up width on a narrow screen instead of pushing the button off. */
.find__input { flex: 1 1 16rem; min-width: 0; margin: 0; }

.find__clear { color: var(--text-dim); font-size: .8rem; }

.table__id { font-family: var(--mono); font-size: .78rem; }

.table__note {
  margin-top: 12px;
  color: var(--text-faint);
  font-size: .78rem;
}

/* ---- one metadata member ----------------------------------------------- */
.item__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px 20px;
  margin-bottom: 22px;
}

/* Pushed right on a wide screen, dropping under the title on a narrow one. */
.snapshots {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.snapshots__label {
  color: var(--text-dim);
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .07em;
}

.snapshots__select {
  /* Caret and padding-right come from the `select` rule. */
  padding: 8px 34px 8px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background-color: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: .85rem;
}

.code {
  overflow-x: auto;          /* long lines scroll rather than widening the page */
  margin: 0;
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-elev);
  color: var(--text-dim);
  font-family: var(--mono);
  font-size: .8rem;
  line-height: 1.55;
}

/* ---------- metadata table: ids, exact times, per-row actions ---------- */

.table__when { white-space: nowrap; font-variant-numeric: tabular-nums; }
.table__actions { text-align: right; }
.table__actions form { display: inline; }

/* A row action, not a page action: reads as an icon until you reach for it. */
.iconbtn {
  display: inline-grid; place-items: center;
  width: 28px; height: 28px; padding: 0;
  border: 1px solid transparent; border-radius: 8px;
  background: transparent; color: var(--text-faint);
  cursor: pointer;
}
.iconbtn:hover { color: var(--text); background: rgb(var(--ink) / .07); border-color: var(--border); }
.iconbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The header's theme switcher: an .iconbtn a size up, to sit beside the
   avatar. One icon of the two shows, by the theme it would switch to. */
.theme-switch { width: 34px; height: 34px; color: var(--text-dim); }
.theme-switch__moon { display: none; }
:root[data-theme="light"] .theme-switch__sun { display: none; }
:root[data-theme="light"] .theme-switch__moon { display: block; }

.notice {
  margin: 0 0 18px; padding: 11px 15px;
  border: 1px solid var(--border-strong); border-left: 3px solid var(--amber);
  border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text-dim); font-size: .9375rem;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ---------- one member of a metadata type ---------- */

.facts { margin: 0 0 30px; padding: 0; }

/* Two columns of facts, each its own <dl> so the pairs stay associated.
   Column widths are equal rather than content-sized, so the two label
   gutters line up down the page instead of drifting apart. */
.facts--split { display: grid; grid-template-columns: 1fr 1fr; gap: 0 44px; }
.facts__col { margin: 0; padding: 0; }
/* The columns, with the provenance rows directly beneath. */
.facts--joined { margin-bottom: 0; }
.facts__row { padding: 9px 0; border-bottom: 1px solid var(--border); }

/* Label above the value, not beside it. A side-by-side label reserves a fixed
   gutter the value can never use, so a long API name or a namespaced developer
   name has to wrap or spill inside whatever is left. Stacked, the value gets
   the whole column. */
.facts__row dt {
  margin: 0 0 2px; color: var(--text-faint);
  font-size: .75rem; text-transform: uppercase; letter-spacing: .05em;
}
.facts__row dd {
  margin: 0; color: var(--text);
  /* Namespaced names have no spaces to break at. */
  overflow-wrap: anywhere;
}
.facts__by { margin-left: 8px; color: var(--text-faint); font-size: .875rem; }

.tag {
  display: inline-block; margin-left: 8px; padding: 2px 9px;
  border-radius: 999px; font-size: .75rem;
  background: rgb(var(--ink) / .06); color: var(--text-dim);
}
.tag--gone { background: rgba(255, 107, 138, .14); color: var(--rose-text); }

@media (max-width: 900px) {
  /* One column below this: two columns of label+value in a narrow viewport
     leaves no room for either. */
  .facts--split { grid-template-columns: 1fr; gap: 0; }
}


/* ---------- permission set sections ---------- */

.sections { margin: 0 0 34px; }

.sec {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); margin-bottom: 8px;
}
.sec[open] { background: var(--bg-elev); }

.sec__head {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; cursor: pointer; list-style: none;
  font-weight: 550; color: var(--text);
}
.sec__head::-webkit-details-marker { display: none; }
.sec__head:hover { color: var(--text); }
.sec__head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--radius-sm); }

.sec__title { flex: 1 1 auto; }

/* Count and chevron both sit at the right edge, count first. */
.sec__count {
  flex: 0 0 auto; min-width: 2.5rem; text-align: right;
  color: var(--text-dim); font-size: .875rem; font-variant-numeric: tabular-nums;
}
.sec__none    { color: var(--text-faint); }
.sec__pending { color: var(--amber); font-size: .8125rem; }
.sec__na      { color: var(--text-faint); font-size: .8125rem; font-style: italic; }

.sec__chevron { flex: 0 0 auto; color: var(--text-faint); transition: transform .15s ease; }
.sec[open] .sec__chevron { transform: rotate(180deg); }

.sec__body { padding: 0 16px 16px; border-top: 1px solid var(--border); padding-top: 14px; }
.sec__note {
  margin: 0 0 12px; padding: 9px 13px; border-radius: var(--radius-sm);
  background: rgba(255, 180, 84, .09); border: 1px solid rgba(255, 180, 84, .22);
  color: var(--text-dim); font-size: .875rem; max-width: 78ch;
}
.sec__empty { margin: 0; color: var(--text-faint); font-size: .9375rem; }
.sec__scroll { overflow-x: auto; }
.table--tight th, .table--tight td { padding: 7px 12px; font-size: .8125rem; }

/* The qualified API name: monospaced so namespaces line up down the column. */
.table__api { font-family: var(--mono); font-size: .8125rem; }

/* One line and an ellipsis, the full value in the cell's title. The same
   choice as .bundle__name, for a table cell: a long developer name wrapped or
   broken mid-word reads as two names, and it pushed into the date column on
   Flow's member list. On the member list's name and developer name cells.
   A class rather than a change to .table__api, because a
   CustomObject's field table uses that too and has no title to fall back on. */
.table__clip { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* ---------- which capture a member page is showing ---------- */

/* margin-left:auto rather than a float, so it stays right-aligned against the
   title and drops below it when the header wraps. */
.snapshot-of {
  margin-left: auto; display: grid; gap: 2px; justify-items: end;
  text-align: right; align-self: start;
}
.snapshot-of__label {
  color: var(--text-faint); font-size: .75rem;
  text-transform: uppercase; letter-spacing: .05em;
}
.snapshot-of__when {
  color: var(--text); font-size: .9375rem; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 700px) {
  .snapshot-of { margin-left: 0; justify-items: start; text-align: left; }
}

/* The snapshot picker and the refresh that supersedes it, grouped so they move
   together as the header wraps. */
.snapshot-bar {
  /* The picker and the actions menu sit on one line, the menu to its right.
     The gap is wide because the two are unrelated: one chooses which moment to
     look at, the other spends credits asking for a newer one. Close together
     they read as a pair of controls that belong to each other. */
  display: flex;
  align-items: center;
  gap: 20px;
  margin-left: auto;
}
.snapshot-bar .snapshots { margin-left: 0; }

/* Icon-only, so square rather than inheriting the avatar trigger's lopsided
   padding — and given the primary treatment, because what is behind it spends
   credits. A faint icon reads as decoration; this one is the paid action on
   the page and should be the thing the eye lands on after the name. */
.snapshot-menu__trigger {
  padding: 9px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--accent), var(--violet));
  color: #fff;
  box-shadow: 0 8px 26px -10px rgba(77, 163, 255, .85);
}
.snapshot-menu__trigger:hover {
  box-shadow: 0 10px 30px -10px rgba(77, 163, 255, 1);
  filter: brightness(1.07);
}
.snapshot-menu[open] .snapshot-menu__trigger {
  background: linear-gradient(135deg, var(--accent), var(--violet));
  border-color: #fff3;
}

/* A refresh already paid for cannot be bought again: the control stays visible
   so its absence is not mistaken for a missing feature, but reads as inert. */
.iconbtn:disabled,
.menu__item:disabled {
  opacity: .45;
  cursor: not-allowed;
}
.iconbtn:disabled:hover,
.menu__item:disabled:hover {
  background: none;
  border-color: transparent;
  color: inherit;
}
.menu__item:disabled:hover svg { color: var(--text-faint); }

/* A member that is a file: the Apex class body, as of the snapshot selected. */
.body-panel {
  margin-top: 26px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  overflow: hidden;
}
.body-panel__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.body-panel__title { margin: 0; font-size: .95rem; font-weight: 600; }
.body-panel__meta { font-size: .8rem; color: var(--text-faint); }
.body-panel__empty { margin: 0; padding: 14px; color: var(--text-faint); font-size: .88rem; }
/* A binary file that is an image, shown as itself under its size and type. */
.body-panel__image { display: block; max-width: 100%; padding: 0 14px 14px; }
.body-panel__code {
  margin: 0;
  padding: 14px;
  /* Source does not reflow: wrapping it would change what it says, so it
     scrolls sideways. No height cap: a cap clipped the file at 560px with an
     overlay scrollbar that macOS fades out, so a 136-line class simply looked
     like it stopped at line 27. The page scrolls; this does not need to. */
  overflow-x: auto;
  overflow-y: hidden;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .82rem;
  line-height: 1.55;
  tab-size: 4;
  color: var(--text-dim);
}
/* Always shown rather than the overlay bar macOS fades out. No
   scrollbar-width here: setting it makes Chrome ignore these rules. */
.body-panel__code::-webkit-scrollbar { height: 12px; }
.body-panel__code::-webkit-scrollbar-track { background: transparent; }
.body-panel__code::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border: 3px solid var(--surface-2);
  border-radius: 6px;
}
.body-panel__code::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }

/* Choosing what to compare against what. */
.cmp-pick {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px;
  margin-bottom: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.cmp-pick__side { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cmp-pick__label {
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.cmp-pick__vs { color: var(--text-faint); }
.cmp-pick__cost { margin-left: 8px; opacity: .85; font-size: .82rem; }
.cmp-note { margin: 0 0 18px; font-size: .85rem; color: var(--text-faint); }

/* One pair of headings for every table below, so the two sides never swap. */
/* One table carries the whole comparison, so the column widths are declared
   once and the header is the table's own thead. There is nothing left to keep
   in step with anything else. */
:root {
  --cmp-col-name: 22%;
  --cmp-col-value: 39%;
}

.cmp__when--before { color: var(--text-dim); }
.cmp__title { margin: 22px 0 10px; font-size: .95rem; font-weight: 600; }
.cmp__count { margin-left: 8px; font-weight: 400; font-size: .82rem; color: var(--text-faint); }
.cmp__same { padding: 14px; border-radius: var(--radius); background: var(--surface-2); }

/* Sections: both captures in one table, rows matched on what they are about.
   Object Settings is eight columns wide, so the table scrolls itself rather
   than pushing the page sideways. */
/* No border and no padding: a frame here would inset this table by a pixel or
   two against the fields table above it, which has none, and the columns would
   stop lining up down the page. The header row and the row tints give it enough
   shape without one. */
.cmp__table-wrap { overflow-x: auto; }
.cmp__grid { font-size: .88rem; margin: 0; }
.cmp__grid td, .cmp__grid th { overflow-wrap: anywhere; }

/* The thing, then one column per capture — on the same tracks as the header
   and the fields table above, so every column on the page lines up from top to
   bottom. Three tables sharing one set of widths is the only way the eye can
   follow a capture straight down the page. */
.cmp__col-thing { width: var(--cmp-col-name); }
.cmp__col-state { width: var(--cmp-col-value); }

/* One capture rather than two, so the grants column takes what the second
   capture's column would have had. */
.sec__col-grant { width: calc(var(--cmp-col-value) * 2); }

/* A detail page has two columns where a comparison has three, so the name
   keeps the three-column share of 22% and gets a quarter of the table to hold
   a toggle, an indent and names like FORCEWR__CICDEnvironments__c — which
   wrapped mid-word and then twice more, while the grants beside them sat in a
   column three times wider than "Read, Create" needs. Split evenly instead:
   the same tracks for every section, so the columns still line up straight
   down the page, but on the proportion this page actually has. */
.sections .cmp__col-thing { width: 46%; }
.sections .sec__col-grant { width: 54%; }
.cmp__state-head { font-weight: 600; text-align: left; }
.cmp__grid thead th {
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: var(--surface);
  z-index: 1;
}

/* A section's name, spanning the table. Inside the table rather than above it,
   so it cannot drift off the tracks everything else sits on.
   Its underline is the only rule in the body, which is what separates one
   section from the next now that no row carries a tint of its own. */
.cmp__section > th {
  text-align: left;
  font-size: .8125rem;
  font-weight: 600;
  padding-top: 32px;
  color: var(--text);
  border-bottom: 1px solid var(--border-strong);
}
.cmp__section:first-child > th { padding-top: 7px; }
/* The toggle leads the name as a gutter rather than as a word in it. Inline,
   a name too long for the column broke to the next line and left the control
   sitting alone on the one above; as a flex item it cannot be orphaned, and
   the name wraps beside it. */
.cmp__thing { font-weight: 400; text-align: left; display: flex; align-items: baseline; gap: 7px; }
.cmp__state { text-align: left; font-size: .95rem; line-height: 1.4; }

/* Every line is plain. What differs is already said by the marks and by the
   permissions named in one column and not the other; tinting the row as well
   said the same thing twice and put a band of colour across a page that reads
   better without one. */

/* Granted, refused, and never mentioned — on the same tokens the source diff
   uses for added and removed, so one reader learns one pair of colours. The
   third is not an X on purpose: a permission set that says nothing about an
   object has not denied it. */
.cmp__yes { color: var(--teal); }
/* Named for what it means, not "no": .cmp__no is already the line-number
   column in the source panes, and that rule is defined later — so this one lost
   the cascade and every cross rendered as a grey, right-aligned, sticky line
   number. */
.cmp__deny { color: var(--rose); }
.cmp__absent { color: var(--text-faint); }

/* A value that is neither yes nor no — a tab's visibility. Normal ink, not
   dim: it is the answer, not a footnote. */
.cmp__value { font-size: .8rem; color: var(--text); }

/* This side holds something the other does not — the same fact a list cell
   marks on the permission only one capture grants, so it gets the same
   treatment. One rule, learned once: teal and bold means "this capture has it
   and the other does not".
   A tick and a cross already carry their own colour, which says what the answer
   was rather than that it moved; those take the weight and keep the hue. */
.cmp__value.cmp__moved { color: var(--teal); font-weight: 700; }
.cmp__yes.cmp__moved, .cmp__deny.cmp__moved { font-weight: 700; }

/* A field's earlier value. Dimmed, not struck through: it was true at the time
   and the capture it sits under says when. */
.cmp__was { color: var(--text-dim); }

/* An object carrying its own field permissions. The toggle sits in the name
   column so the two capture columns stay exactly as wide as every other row. */
.cmp__toggle {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  border-radius: 4px;
  width: 17px;
  height: 17px;
  padding: 0;
  font-size: .8rem;
  line-height: 1;
  cursor: pointer;
  vertical-align: baseline;
  flex: none;
}
/* A row with nothing folded under it keeps the control's place empty rather
   than closing it up, so every name in the column starts at the same x whether
   or not it has one. Ragged left edges made the list read as two interleaved
   tables. Parent rows only: a child is indented past the gutter already. */
.cmp__grid tr:not(.cmp__child) > .cmp__thing:not(:has(.cmp__toggle))::before {
  content: "";
  flex: none;
  width: 17px;
}

.cmp__toggle:hover { color: var(--text); border-color: var(--border-strong); }
.cmp__toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }


/* Indented to the width of the toggle plus its gap, so a field lines up under
   its object's name rather than under the control that opened it. */
.cmp__child .cmp__thing { padding-left: 36px; font-weight: 400; color: var(--text-dim); }

/* What a folded row is, where its object holds more than one sort of them.
   Leading the name, boxed and fixed-width, so the labels line up into a gutter
   instead of ragging along after names of different lengths. */
.cmp__kind {
  display: inline-block;
  min-width: 72px;
  flex: none;
  margin-right: 2px;
  padding: 1px 6px;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: .68rem;
  text-align: center;
  color: var(--text-faint);
  vertical-align: 1px;
}

/* Several permissions on one thing, named. Reads as words, so it is set left
   and at text size rather than centred like a tick. */
.cmp__state--text { text-align: left; font-size: .8125rem; line-height: 1.45; }
.cmp__list { color: var(--text-dim); }

/* A permission only this capture grants. Marking the word rather than the cell
   is the point: a highlighted cell says the line changed, a highlighted word
   says which permission it was. */
.cmp__only { color: var(--teal); font-weight: 700; }

.cmp__none { margin: 0; font-size: .85rem; color: var(--text-faint); }

/* Source: two panes, each filling half the width and scrolling its own long
   lines. Both files stay fully visible at any width. */
/* Names for the two panes, on the panes' own tracks — half each, flush with the
   left edge of the pane each one names and with the section title above them.
   Indenting them to where the code starts put them over the code but out of
   line with everything else on the page. */
.cmp__pane-heads {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  margin-bottom: 6px;
  font-size: .8rem;
  font-weight: 600;
}
.cmp__pane-heads > span { padding-left: 1px; }
.cmp__pane-heads > span:first-child { color: var(--text-dim); }

.cmp__panes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  overflow: hidden;
}
.cmp__pane {
  min-width: 0;                       /* or the content sets the column width */
  overflow-x: auto;
  overflow-y: hidden;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .8rem;
  line-height: 1.55;
}
.cmp__pane + .cmp__pane { border-left: 1px solid var(--border-strong); }

/* Always shown rather than the overlay bar macOS fades out: it is also the
   signal that a line continues past the edge. No scrollbar-width here --
   setting it makes Chrome ignore these rules and use an overlay bar. */
.cmp__pane::-webkit-scrollbar { height: 12px; }
.cmp__pane::-webkit-scrollbar-track { background: transparent; }
.cmp__pane::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border: 3px solid var(--surface-2);
  border-radius: 6px;
}
.cmp__pane::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }

.cmp__row {
  display: flex;
  align-items: flex-start;
  /* max-content so a long line widens the row rather than wrapping, which is
     what gives the pane something to scroll. */
  min-width: max-content;
  width: 100%;
  /* Every row is exactly one line tall whether or not it has any text in it.
     Without this an empty row -- one side of an added or removed line -- has
     nothing to give it height and collapses, and the two files stop lining up
     from that point down. That is the whole value of a side-by-side view. */
  min-height: 1.55em;
}
.cmp__row--new  { background: rgba(47, 217, 195, .11); }
.cmp__row--gone { background: rgba(255, 107, 138, .11); }
.cmp__no {
  flex: 0 0 3.2rem;
  padding-right: 10px;
  text-align: right;
  color: var(--text-faint);
  user-select: none;                  /* copying a pane must not take the numbers */
  /* Stays put while the code scrolls under it, so a line is still identifiable
     once you have scrolled away from the start of it. */
  position: sticky;
  left: 0;
  background: inherit;
}
.cmp__text {
  white-space: pre;
  padding-right: 14px;
  color: var(--text-dim);
}

@media (max-width: 720px) {
  /* Two panes do not fit; the tables scroll rather than crushing the text. */
  .cmp__grid { font-size: .84rem; }
  /* The name column gives up width first: a permission's name wraps, a tick
     and a short list do not. */
  .cmp__col-thing { width: 34%; }
}

/* A dialog with two columns in it. The base 520px is sized for a single column
   of fields, which is right for the others and cramped for this one: it would
   put two org names and two timestamps in half the width they read best at.

   Three quarters of THE PAGE, not of the viewport. The page is --maxw wide and
   everything behind this dialog lines up inside that, so 75vw is the wrong
   measure: on a 1500px window it comes to 1134px against a 1160px page, which
   is the full width of what the reader can see and reads as no change at all.
   Against --maxw it is 870px, which is visibly three quarters.

   Never wider than the window either, which is what takes care of small
   screens: below about 1160px the viewport is the smaller of the two and wins
   on its own, with the same 16px gutter every other dialog keeps. */
.modal--wide { width: min(calc(var(--maxw) * .75), calc(100vw - 32px)); }
/* Between the default 520px and --wide: a form with a long text, as a new work item. */
.modal--medium { width: min(720px, calc(100vw - 32px)); }

/* The compare dialog: this org, and another org to compare with. */
.cmp-two { display: grid; gap: 14px; }
/* The From side is fixed -- this org -- shown in the field's shape, not a field. */
.cmp-two__fixed, .cmp-pick__fixed { display: inline-flex; align-items: center; padding-right: 10px; color: var(--muted); cursor: default; }
.cmp-two__side { display: grid; gap: 6px; }

.cmp-two__label {
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-faint);
}
@media (min-width: 560px) {
  .cmp-two { grid-template-columns: 1fr 1fr; gap: 16px; }
}

/* A stored comparison is a receipt as much as a result. */
.cmp__receipt { margin: 0 0 10px; color: var(--text-dim); }
.cmp__receipt strong { color: var(--text); }

/* A comparison that found a difference: the one worth looking at. */
.tag--differ { color: var(--accent); border-color: var(--accent); }

/* Each side of a comparison: the capture's name, and under it the moment. One
   line would be wider than the column and .table__dim does not wrap. */
.cmp-side__name { display: block; }
.cmp-side__at {
  display: block;
  font-size: .8rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

/* A refresh that has been asked for and not yet answered. The control is
   disabled while it waits, so the turning is the only thing that says the
   click landed — and the page no longer reloads to say it. */
.is-refreshing svg { animation: btn-spin 1.1s linear infinite; }

@media (prefers-reduced-motion: reduce) {
  .is-refreshing svg { animation: none; }
}

/* The switch while its answer is in flight. The spinner occupies the switch's
   own box so the row does not resize as it swaps, and the switch is hidden
   rather than left showing a state nothing has saved yet. */
.switch__wait {
  color: var(--accent, #6aa9ff);
  animation: btn-spin 1.1s linear infinite;
  vertical-align: middle;
}

/* Not the `hidden` attribute — see the note in the markup. */
.switch__wait--idle { display: none; }

@media (prefers-reduced-motion: reduce) {
  .switch__wait { animation: none; }
}

/* A save that did not land. Says so in the page's own voice rather than in an
   alert, and sits where the other notices sit. */
.notice--warn {
  border-color: var(--warn-border);
  color: var(--warn-text);
}

/* An action that belongs to a panel rather than to the page: right-aligned
   above whatever the panel lists, so it sits in the same place whether the list
   is empty or long. */
.panel-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-bottom: 14px;
}
/* Actions that lead a page rather than close a panel: the IDE's setup step. */
.panel-actions--start { justify-content: flex-start; margin-top: 18px; }

/* TEMPORARY, with the Diffplex panel. A line that was edited rather than added
   or removed — the case the current alignment cannot express, so there has
   never been a style for it. Distinct from both so the difference between the
   two panels is visible at a glance. */
.cmp__row--edit {
  background: rgba(240, 198, 116, .10);
  box-shadow: inset 2px 0 0 rgba(240, 198, 116, .55);
}

/* TEMPORARY, with the Diffplex panel. Two readings of one diff, chosen by a
   pair of icons sitting at the right-hand end of the heading — beside the
   counts they belong to rather than floating above the panes. */
.diffview {
  float: right;
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 6px;
}

.diffview__btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  padding: 3px 7px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
}

/* A wee bigger than the 15px the markup asks for (2026-10-09): the switch
   was easy to miss. Sized here rather than in each page's svg, so the flow,
   Lightning page, layout and comparison switches stay the same. */
.diffview__btn { padding: 5px 9px; }
.diffview__btn svg { width: 18px; height: 18px; }

.diffview__btn:hover { color: var(--text); }
.diffview__btn.is-on { background: var(--surface-2, rgb(var(--ink) / .07)); color: var(--text); }
.diffview__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* The browser's `hidden` rule is a UA style, so any author rule that sets
   display beats it — and these three all set grid. Without this the panel the
   toggle "hid" stays on screen, which is the same trap as an <svg hidden>:
   the attribute is set, the property reads true, and the thing is visible. */

/* One column rather than two, so a long line has the whole panel to run in. */
.cmp__pane--inline { width: 100%; }

/* Which side a line belongs to, in the margin, so the reading works without
   colour — the same information the two columns carry by position. */
.cmp__sign {
  display: inline-block;
  width: 1.1em;
  text-align: center;
  color: var(--text-faint);
  user-select: none;
}

/* The comparison's own layout choice, above everything it applies to. */
.cmp__views {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 12px;
}


/* Hidden with the attribute rather than by not rendering, so the group can be
   present for one type and absent for another without a second markup path. */


/* Which way a line moved between two captures, as a band across the whole row.
   The marks in the cells already say it; this is so a page of two hundred rows
   can be skimmed rather than read.

   Set on the cells rather than the <tr>: a row's own background sits behind its
   cells, and any cell with a background of its own — a section band, a hover —
   would punch a hole through it.

   The same three tints the diff panes use, so green means the same thing in the
   structured view and in the file underneath it. */
.cmp__tr--add > th,
.cmp__tr--add > td { background: rgba(47, 217, 195, .11); }

.cmp__tr--del > th,
.cmp__tr--del > td { background: rgba(255, 107, 138, .11); }

.cmp__tr--mod > th,
.cmp__tr--mod > td { background: rgba(240, 198, 116, .10); }

/* A bar in the margin, so the three are told apart without relying on colour.
   On the first cell only, which is where the eye enters the row. */
.cmp__tr--add > th:first-child { box-shadow: inset 2px 0 0 rgba(47, 217, 195, .55); }
.cmp__tr--del > th:first-child { box-shadow: inset 2px 0 0 rgba(255, 107, 138, .55); }
.cmp__tr--mod > th:first-child { box-shadow: inset 2px 0 0 rgba(240, 198, 116, .55); }

/* A flow, drawn from its own file. The palette is the page's, not the
   diagram's: a node's type is a class here and a colour in the theme, so this
   follows light and dark like everything else. */
.flow__scroll {
  /* Both directions. A wide flow shrunk to fit is a picture of a flow rather
     than a readable one, so it is drawn at its own size and reached by
     scrolling — seeing all of it at once was never the goal. */
  overflow: auto;
  max-height: 70vh;
  padding: 8px;

  /* Its width is the panel's, never the drawing's. Without this, a flex or
     grid ancestor grew to the svg's full width, the box never overflowed, and
     the body's overflow-x: hidden clipped the diagram with no scrollbar at
     all. inline-size containment stops the drawing's width reaching the
     ancestors; min-width / max-width cover a browser without it. */
  contain: inline-size;
  min-width: 0;
  max-width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2, rgb(var(--ink) / .02));

  /* Dragged to pan, by flow-pan.js; the cursor says so. */
  cursor: grab;
}
.flow__scroll.is-panning { cursor: grabbing; user-select: none; }

/* Always visible, never an overlay. The system scrollbar on macOS is hidden
   until it is used, so a diagram that ran past the edge simply looked cut off.
   The standard properties only where ::-webkit-scrollbar is not understood
   (Firefox): set anywhere else, current Chrome drops the ::-webkit-scrollbar
   styling below and falls back to the invisible overlay bar. */
@supports not selector(::-webkit-scrollbar) {
  .flow__scroll {
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
  }
}

.flow__scroll::-webkit-scrollbar { width: 12px; height: 12px; }
.flow__scroll::-webkit-scrollbar-track { background: transparent; }
.flow__scroll::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border: 3px solid var(--surface);
  border-radius: 6px;
}
.flow__scroll::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }

/* Its natural size, not shrunk to the panel. The size is the svg's own width
   and height attributes: with a viewBox alone an inline svg takes its
   container's width, which drew a wide flow scaled down until its text could
   not be read. max-width: none so nothing upstream squeezes it back. */
.flow { display: block; max-width: none; }

/* The panel clips its own overflow, which would cut the scroller's bar off. */
.body-panel:has(.flow__scroll) { overflow: visible; }

.flow__edge { fill: none; stroke: var(--text-faint); stroke-width: 1.5; }
.flow__arrow { fill: var(--text-faint); }
.flow__edge-label { fill: var(--text-dim); font-size: 11px; }

.flow__box { fill: var(--surface); stroke: var(--border-strong); stroke-width: 1.5; }
.flow__spine { fill: var(--border-strong); }
.flow__kind { fill: var(--text-faint); font-size: 10px; letter-spacing: .06em; }
.flow__label { fill: var(--text); font-size: 13px; }

/* One accent per element type, the same hues the rest of the app uses. */
.flow__node--start     .flow__box   { stroke: var(--accent-teal, #2fd9c3); }
.flow__node--start     .flow__spine,
.flow__node--start     .flow__kind  { fill: var(--accent-teal, #2fd9c3); }

.flow__node--screen    .flow__box   { stroke: var(--accent, #6aa9ff); }
.flow__node--screen    .flow__spine,
.flow__node--screen    .flow__kind  { fill: var(--accent, #6aa9ff); }

.flow__node--decision  .flow__box   { stroke: #f0c674; }
.flow__node--decision  .flow__spine,
.flow__node--decision  .flow__kind  { fill: #f0c674; }

.flow__node--action    .flow__box   { stroke: #c4a3ff; }
.flow__node--action    .flow__spine,
.flow__node--action    .flow__kind  { fill: #c4a3ff; }

.flow__node--assignment .flow__box  { stroke: #7ec8a9; }
.flow__node--assignment .flow__spine,
.flow__node--assignment .flow__kind { fill: #7ec8a9; }

.flow__node--records   .flow__box   { stroke: #5bc0de; }
.flow__node--records   .flow__spine,
.flow__node--records   .flow__kind  { fill: #5bc0de; }

.flow__node--loop      .flow__box   { stroke: #f0a868; }
.flow__node--loop      .flow__spine,
.flow__node--loop      .flow__kind  { fill: #f0a868; }

.flow__node--danger    .flow__box   { stroke: #ff6b8a; }
.flow__node--danger    .flow__spine,
.flow__node--danger    .flow__kind  { fill: #ff6b8a; }

/* What the diagram is, said before it is read rather than under it. Quiet
   enough not to compete with the drawing, present enough to be seen first. */
.flow__note {
  margin: 0 0 14px;
  padding: 9px 12px;
  border-left: 2px solid var(--warn-border);
  border-radius: 0 4px 4px 0;
  background: rgba(240, 198, 116, .07);
  color: var(--text-dim);
  font-size: .82rem;
  line-height: 1.5;
}

/* A flow comparison. The left bar is the diff indicator, and it is the only
   thing on the drawing wearing these three colours: green added, red removed,
   yellow changed, each of them thicker than the plain bar an unchanged element
   keeps. The bar is drawn wider in the SVG itself, so the difference survives
   a screenshot and a printer.

   Which is why the per-type accents come off a comparison. Two of them are
   already these very colours — a decision is yellow, a fault path is red — and
   an element that is merely a decision must not read as changed. On a
   comparison the drawing goes monochrome and the bar does the talking. */
.flow--diff .flow__box   { stroke: var(--border-strong); fill: var(--surface); }
.flow--diff .flow__kind  { fill: var(--text-faint); }
.flow--diff .flow__spine { fill: var(--border-strong); }

.flow--diff .flow__node--add .flow__spine { fill: #2fd9c3; }
.flow--diff .flow__node--del .flow__spine { fill: #ff6b8a; }
.flow--diff .flow__node--mod .flow__spine { fill: #f0c674; }

/* Connectors say it by weight and dash instead, for the same reason: the three
   colours belong to the bars. Added is drawn firmly, removed is dashed and
   receding — which is also how a removed connector reads with no colour at
   all. */
.flow--diff .flow__edge--add { stroke: var(--text-dim); stroke-width: 2.5; }
.flow--diff .flow__edge--del { stroke: var(--text-faint); stroke-width: 1.5; stroke-dasharray: 5 4; opacity: .65; }


/* A bundle: the files down one side, the one being read beside them. Stacks on
   a narrow screen, where a fixed sidebar would leave the code in a gutter. */
/* The list is as wide as its longest file name, with a floor so a bundle of
   two short names does not look like a stray column, and a ceiling so one
   absurd name cannot squeeze the code out of the page. Sized to content rather
   than to a number picked by eye: these names are the component's name plus a
   suffix, so their length is the org's to decide, not ours. */
.bundle { display: grid; grid-template-columns: minmax(200px, max-content) 1fr; gap: 0; }

@media (max-width: 720px) { .bundle { grid-template-columns: 1fr; } }

.bundle__files {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px;
  border-right: 1px solid var(--border);
  max-height: 70vh;
  overflow-y: auto;
  max-width: 420px;
}

@media (max-width: 720px) {
  .bundle__files { border-right: 0; border-bottom: 1px solid var(--border); max-height: none; }
}

.bundle__file {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 9px;
  border: 0;
  border-radius: 5px;
  background: none;
  color: var(--text-dim);
  font: inherit;
  font-size: .82rem;
  text-align: left;
  cursor: pointer;
}

.bundle__file:hover { background: var(--surface-2, rgb(var(--ink) / .04)); color: var(--text); }
.bundle__file.is-on { background: var(--surface-2, rgb(var(--ink) / .06)); color: var(--text); }

/* The file being read is named as well as highlighted: colour alone is not a
   state, and this list is read by people scanning for one name. */
.bundle__file.is-on .bundle__name { font-weight: 600; }

/* Never wrapped: a file name broken across two lines stops looking like one
   name, and this list is read by scanning it. Past the ceiling above it
   ellipsises instead, and the button carries the full name as its title. */
.bundle__name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bundle__size { color: var(--text-faint); font-variant-numeric: tabular-nums; flex: none; }

.bundle__body { min-width: 0; }



/* One part of a bundle in a comparison: its name, its state, and its own diff
   under it. Closed when it did not move, so a nine-file bundle with one edit
   opens as one diff and eight lines. */
.bundle__part { border: 1px solid var(--border); border-radius: 7px; margin-bottom: 8px; overflow: hidden; }

.bundle__part-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 9px 12px;
  cursor: pointer;
  font-size: .85rem;
}

.bundle__part-head::-webkit-details-marker { display: none; }
.bundle__part-name { color: var(--text); }
.bundle__part-state { color: var(--text-faint); font-size: .8rem; }


/* ---------------------------------------------------------------------------
   The object page: a section menu on the left, one section on the right.

   Object Manager's shape, and it is the right one here for the same reason it
   is right there -- an object has a dozen unrelated lists hanging off it, and
   stacking them makes the page a scroll rather than a place to look something
   up.
   --------------------------------------------------------------------------- */

.objview {
  display: grid;
  /* Wide enough for "Fields & Relationships", the longest entry the menu has,
     on one line. The labels do not wrap -- a two-line entry in a list of
     one-line entries reads as a different kind of thing. */
  grid-template-columns: 196px minmax(0, 1fr);
  gap: 0 28px;
  align-items: start;
}

/* Sticky so the menu is still there after scrolling a 43-row field table. The
   offset clears the page header. */
.objnav {
  display: flex;
  flex-direction: column;
  gap: 1px;
  position: sticky;
  top: 16px;
  padding-right: 16px;
  border-right: 1px solid var(--border);
}

.objnav__item {
  appearance: none;
  display: flex;
  align-items: center;
  width: 100%;
  padding: 7px 10px;
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--text-faint);
  font: inherit;
  font-size: .84rem;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}

/* Ellipsis rather than wrap if a label ever outgrows the column: the menu
   keeps its shape, and the full text is the section heading a click away. */
.objnav__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.objnav__item:hover { color: var(--text); background: var(--surface-2, rgb(var(--ink) / .04)); }

.objnav__item.is-on {
  background: var(--surface-2, rgb(var(--ink) / .07));
  color: var(--text);
  font-weight: 600;
}

.objnav__item:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* The browser's `hidden` is a UA style and any author rule setting display
   beats it. .objpane does not set display itself, but this is the trap that
   has cost three debugging sessions on this site, so it is written down rather
   than relied on. See docs/pages.md. */

.objpane__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 14px;
}

.objpane__title { margin: 0; font-size: 1.02rem; }
.objpane__meta { font-size: .8rem; color: var(--text-faint); }

/* One column on a narrow screen: the menu becomes a row above the section
   rather than a 210px column squeezing the table next to it. */
@media (max-width: 800px) {
  .objview { grid-template-columns: minmax(0, 1fr); gap: 16px; }

  .objnav {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    padding-right: 0;
    padding-bottom: 12px;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }

  .objnav__item { width: auto; }
}

/* A section Object Manager has and this capture cannot answer. Dimmed in the
   menu so it does not read as an empty section -- "the org has none" and "we
   never fetched it" mean opposite things, and the menu must not make them look
   alike. Not hidden: leaving them out would make the page quietly disagree
   with Setup about what an object has. */
.objnav__label--absent { opacity: .5; }
.objnav__item.is-on .objnav__label--absent { opacity: .8; }

.objpane__absent {
  margin: 0;
  padding: 14px 16px;
  border: 1px dashed var(--border);
  border-radius: 6px;
  color: var(--text-faint);
  font-size: .88rem;
  line-height: 1.5;
}

.objpane__absent strong { color: var(--text); }

/* A section with more than one table -- Buttons, Links and Actions is web
   links and action overrides -- names each of them. */
.objpane__caption {
  margin: 18px 0 8px;
  font-size: .85rem;
  font-weight: 600;
  color: var(--text-faint);
}

.objpane__caption:first-of-type { margin-top: 0; }

/* A yes/no column carried by a mark rather than a word. Right-aligned so the
   marks line up as a column the eye can scan, which a centred or left-aligned
   checkbox beside variable-width text does not. */
.table__mark { text-align: right; white-space: nowrap; }

/* A drawn mark, not a disabled checkbox. A disabled control is greyed to say
   "you cannot use this", which left checked and unchecked too close to read at
   a glance -- and it was never a control: the page is a capture being read.
   Absent where the answer is no, so the column carries only the marks. */
.tick {
  color: var(--teal);
  vertical-align: -2px;
}

/* ---------------------------------------------------------------------------
   A page layout, drawn the way Setup draws one.

   HTML rather than SVG: the file already says which section and which column
   every field is in, so there is no layout to compute -- and a grid of real
   elements wraps, selects, scales and reads aloud, which fixed coordinates do
   not.
   --------------------------------------------------------------------------- */

.lay { display: flex; flex-direction: column; gap: 18px; }

.lay__section {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

/* The section bar Setup puts above every group of fields. */
.lay__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 0;
  padding: 9px 14px;
  background: var(--surface-2, rgb(var(--ink) / .05));
  border-bottom: 1px solid var(--border);
  font-size: .875rem;
  font-weight: 600;
}

/* Two columns filled downwards and two filled across look identical once
   filled, so the arrangement is named rather than drawn. */
.lay__style { font-size: .72rem; font-weight: 400; color: var(--text-faint); }

.lay__cols {
  display: grid;
  grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
  gap: 0 28px;
  padding: 12px 14px;
}

.lay__col { display: flex; flex-direction: column; }

.lay__slot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px dashed var(--border);
  font-size: .8125rem;
  min-height: 1.2rem;
}

.lay__col > .lay__slot:last-child { border-bottom: 0; }

/* A gap the administrator left. It holds its space and says nothing, which is
   exactly what it does on the real layout. */
.lay__slot--blank { border-bottom-style: dotted; opacity: .35; }

.lay__field { font-family: var(--mono); font-size: .78rem; }

.lay__slot--readonly .lay__field { color: var(--text-faint); }

/* Salesforce marks a required field with a red rule. The word carries it too:
   colour on its own is not a label. */
.lay__req {
  flex: none;
  padding-left: 8px;
  border-left: 2px solid var(--rose);
  color: var(--rose);
  font-size: .7rem;
}

.lay__ro { flex: none; color: var(--text-faint); font-size: .7rem; }

.lay__none { margin: 0; padding: 12px 14px; color: var(--text-faint); font-size: .85rem; }

.lay__related { display: flex; flex-direction: column; padding: 4px 14px 12px; }

.lay__list {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 7px 0;
  border-bottom: 1px dashed var(--border);
  font-size: .8125rem;
}

.lay__related > .lay__list:last-child { border-bottom: 0; }

.lay__cells {
  color: var(--text-faint);
  font-size: .72rem;
  text-align: right;
  min-width: 0;
}

/* One column on a narrow screen: two 1fr columns of field names squeeze into
   nothing long before the page does. */
@media (max-width: 760px) {
  .lay__cols { grid-template-columns: minmax(0, 1fr); gap: 0; }
}

/* The one item in the menu that takes something away. Coloured on hover rather
   than at rest: a red line sitting in a list of ordinary actions reads as a
   warning about the whole menu, and this is a normal thing to do deliberately,
   not a hazard to be steered away from. */
.menu__item--danger:hover,
.menu__item--danger:focus-visible { color: var(--rose); }

.menu__item--danger:hover svg,
.menu__item--danger:focus-visible svg { color: var(--rose); }

/* The balance beside the account it belongs to. Quieter than the name and on
   its own line, because the name answers "who pays" and the number answers
   "can they" -- two questions, read in that order. */
.orgfacts__aside {
  display: block;
  margin-top: 2px;
  color: var(--text-faint);
  font-size: .75rem;
}

/* The account a refresh of this org is charged to, bottom left of the card.
   The SystemId keeps the right-hand side -- it has margin-left: auto -- so
   this simply sits first and stays left. */
.ws__charged {
  font-family: var(--mono);
  font-size: .74rem;
  color: var(--text-faint);
}

/* ---- automation execution map ------------------------------------------ */

/* A vertical timeline rather than a drawn graph. The order of execution is a
   straight line with no branching, and HTML gives selectable text, wrapping
   and a sane phone layout for free -- none of which an SVG would. FlowDiagram
   stays SVG because a flow is an arbitrary graph; this is a list. */

.amap__head { margin-bottom: 18px; }
.amap__title { font-size: 1.1rem; margin-bottom: 4px; }
.amap__sub { color: var(--text-dim); font-size: .88rem; max-width: 62ch; }

.amap__picker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
  margin-bottom: 20px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
}
.amap__label { color: var(--text-faint); font-size: .8rem; text-transform: uppercase; letter-spacing: .05em; }
.amap__select {
  padding: 8px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: .9rem;
  max-width: 100%;
}

.amap__count { margin-bottom: 14px; color: var(--text-dim); font-size: .9rem; }

.amap__collisions { margin-bottom: 20px; }
.amap__collisions-title { font-size: .95rem; margin-bottom: 8px; }
.amap__collision-list { margin: 0; padding-left: 18px; display: grid; gap: 6px; font-size: .88rem; }

.amap__steps { list-style: none; margin: 0; padding: 0; }

/* The connector is a border on the number's column, stopped on the last step
   so the line does not hang past the end. */
.amap__step { display: flex; gap: 14px; }
.amap__step:not(:last-child) .amap__num::after {
  content: "";
  position: absolute;
  top: 28px;
  bottom: -18px;
  left: 50%;
  width: 1px;
  background: var(--border);
}
.amap__num {
  position: relative;
  flex: none;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-faint);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
}
.amap__step.has-items .amap__num {
  border-color: var(--accent);
  color: var(--text);
}

.amap__body { padding-bottom: 18px; min-width: 0; flex: 1; }
.amap__step-title { font-size: .95rem; margin-bottom: 4px; }

.amap__none { color: var(--text-faint); font-size: .85rem; }
.amap__note { color: var(--text-dim); font-size: .82rem; margin-top: 4px; max-width: 70ch; }

.amap__items { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 6px; }
.amap__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: .88rem;
}
.amap__item.is-off { border-left-color: var(--border-strong); opacity: .65; }
.amap__kind {
  color: var(--text-faint);
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
}
.amap__name { font-family: var(--mono); color: var(--text); overflow-wrap: anywhere; }
.amap__detail { color: var(--text-dim); font-size: .8rem; overflow-wrap: anywhere; }
.amap__writes {
  color: var(--accent);
  font-size: .78rem;
  font-family: var(--mono);
}

.amap__limits {
  margin-top: 22px;
  padding: 14px 16px;
  border: 1px dashed var(--border-strong);
  border-radius: 12px;
}
.amap__limits-title { font-size: .9rem; margin-bottom: 8px; color: var(--text-dim); }
.amap__limits ul { margin: 0; padding-left: 18px; display: grid; gap: 7px; }
.amap__limits li { color: var(--text-dim); font-size: .84rem; max-width: 78ch; }

@media (max-width: 640px) {
  .amap__picker { flex-direction: column; align-items: stretch; }
  .amap__select { width: 100%; }
}

/* ---- tools tab: one card per tool -------------------------------------- */

/* Each tool is a page of its own, so each card is a link and the whole card is
   the target — a name you have to hit exactly is a worse button than the box
   around it. */
.tools__grid {
  list-style: none;
  margin: 0 0 22px;
  padding: 0;
  display: grid;
  gap: 12px;
  /* Compact tiles (2026-10-09): a card per tool, and there will be many. */
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

.tools__card { display: flex; }

.tools__link {
  display: flex;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  color: inherit;
  text-decoration: none;
  transition: border-color .16s ease, background .16s ease, transform .16s ease;
}
.tools__link:hover {
  border-color: var(--border-strong);
  background: var(--surface-2);
  transform: translateY(-1px);
}

.tools__icon {
  flex: none;
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  color: var(--accent);
}

.tools__icon svg { width: 18px; height: 18px; }
.tools__body { display: grid; gap: 3px; min-width: 0; align-content: start; }
.tools__name { font-weight: 640; font-size: .92rem; }
/* Two lines at most; the whole description is the card's title. */
.tools__desc {
  color: var(--text-dim); font-size: .8rem; line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tools__meta {
  color: var(--text-faint);
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  /* One line; the whole of it is the title. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.tools__more { color: var(--text-faint); font-size: .85rem; }

/* A card that is not a link: no lift on hover, nothing to suggest a click.
   The Effective Access Explorer, until the tool exists and while its
   connecting user lacks what it reads. */
.tools__link--off { cursor: default; }
.tools__link--off:hover { border-color: var(--border); background: var(--surface); transform: none; }
/* A tool's state in the meta line: a pill, and at most one short line under
   it -- never a block, which is what made one card twice the height of the
   rest. The long explanation is the pill's title. */
.tools__state { display: flex; align-items: center; gap: 8px; margin-top: 2px; white-space: nowrap; }
.tools__state .pill { margin: 0; }
.tools__check { display: inline; margin: 0; }
.tools__check button {
  appearance: none; border: 0; padding: 0; background: none;
  color: var(--accent); font: inherit; font-size: .76rem; cursor: pointer;
}
.tools__check button:hover { text-decoration: underline; }

/* ---- limits ------------------------------------------------------------ */

/* The picker at the left end, the actions at the right. .snapshots normally
   right-aligns itself with margin-left:auto — which is what every other page
   wants and what crowds this one, so it is cleared here and .snapshot-bar
   keeps its own auto to hold the far end. */
.limits__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 20px;
  margin-bottom: 16px;
}
.limits__bar > .snapshots { margin-left: 0; }

/* A window running, said rather than implied by two dead buttons. */
.limits__watching {
  align-self: center;
  color: var(--text-dim);
  font-size: .85rem;
  white-space: nowrap;
}

/* Two pickers stacked in the dialog, on the same label-and-select as the
   reading picker so they read as the same kind of control. */
#monitorLimitsDialog .modal__body { display: grid; gap: 12px; }
#monitorLimitsDialog .snapshots { margin-left: 0; }
#monitorLimitsDialog .snapshots__label { min-width: 48px; }

/* The panel of prose around the button, the headline meter, the threshold
   callout and the grouping were all removed on 2026-09-19: the tab is the
   readings, and everything that read them back to you was noise. The button
   now sits on .limits__bar beside the reading picker. */


/* ---- one limit over time ----------------------------------------------- */

/* A row opens its own history, so it has to look like it does something. */
.meter--live { cursor: pointer; }
.meter--live:hover { background: rgb(var(--ink) / .05); border-color: var(--border-strong); }
.meter--live:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

#limitSeriesDialog { max-width: 720px; width: calc(100vw - 32px); }

.series {
  display: block;
  width: 100%;
  height: 200px;
  margin: 4px 0 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: rgb(var(--ink) / .02);
}
/* vector-effect keeps the stroke one pixel wide: the viewBox is stretched to
   the dialog's width, and without it the line thins as the box widens. */
.series__line {
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.series__fill { fill: rgba(77, 163, 255, .14); }

.series__axis {
  display: flex;
  justify-content: space-between;
  color: var(--text-faint);
  font-size: .76rem;
  font-family: var(--mono);
}

/* The y scale beside the plot. Written down because the line is scaled to
   what was used rather than to the allowance: without a number at the top,
   a climb from 1 to 7 has the same shape as one from 1 to 7,000. */
.series__plot { display: flex; align-items: stretch; gap: 8px; }
.series__y {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 2px 0 8px;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: .72rem;
  text-align: right;
  min-width: 42px;
}
.series__plot .series { flex: 1; margin-top: 0; }
.series__axis-label { color: var(--text-faint); text-transform: none; font-family: inherit; }

/* The plot area is the whole window, so the part with no line yet is the part
   that has not happened. Ruled so the empty half reads as "still to come"
   rather than as a rendering fault. */
.series {
  background:
    repeating-linear-gradient(
      to right,
      rgb(var(--ink) / .05) 0 1px,
      transparent 1px 25%),
    rgb(var(--ink) / .02);
}

/* Who to tell when a limit crosses a line. */
.monitor__who { border: 0; padding: 0; margin: 0; display: grid; gap: 6px; }
.monitor__member {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: .88rem;
  cursor: pointer;
}
.monitor__role { color: var(--text-faint); font-size: .76rem; margin-left: auto; }

/* ---------- DML Simulator ---------- */

/* Everything you set up. A fieldset so that while a simulation runs, one
   disabled attribute turns off every control; the class dims it and takes
   the links (Change, a user's name) out of reach too. */
.sim__setup { margin: 0; padding: 0; border: 0; min-width: 0; }
.sim__setup.is-busy { opacity: .5; pointer-events: none; user-select: none; }

/* The step pickers: a row each with space between, labels in one column and
   every control the same width, so they line up down the page. */
.sim__steps { display: grid; gap: 12px; justify-items: start; margin-bottom: 8px; }
.sim__steps .snapshots { margin-left: 0; }
.sim__steps .snapshots__label { flex: none; width: 110px; }
.sim__steps .snapshots__select,
.sim__steps .auth__input { width: 320px; max-width: 100%; }
.sim__steps .ws__note { margin: 0; }

/* The result and its recommendation as one block, one type: everything
   inherits the notice's size and colour; the recommendation sits under a rule. */
.sim__result p { margin: 0; }
.sim__result p + p { margin-top: 4px; }
.sim__verdict .pill { margin: 0 6px 0 0; }
.sim__advice { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.sim__advice ul { margin: 6px 0 0; padding-left: 18px; }
.sim__stack { white-space: pre-wrap; overflow-wrap: anywhere; }
.sim__spinner {
  display: inline-block; width: 14px; height: 14px; margin-right: 8px; vertical-align: -2px;
  border-radius: 50%; border: 2px solid var(--border-strong); border-top-color: var(--accent);
  animation: btn-spin .7s linear infinite;
}

/* ---------- A Salesforce-style record form (the DML Simulator) ----------
   An imitation of SLDS -- Salesforce's design system -- on a white card, so
   the form reads as the page the user would be on. Salesforce's own
   stylesheet is not loaded: its global resets would restyle this whole site.
   Everything is scoped under .sf. */

.sf {
  --sf-text: #181818; --sf-weak: #444; --sf-label: #3e3e3c; --sf-border: #c9c9c9;
  --sf-band: #f3f3f3; --sf-brand: #0176d3; --sf-brand-dark: #014486; --sf-focus: #1b96ff;
  --sf-error: #ba0517; --sf-warn-bg: #fef1e8; --sf-warn: #8c4b02;
  background: #fff; color: var(--sf-text);
  border: 1px solid #dddbda; border-radius: 4px;
  box-shadow: 0 2px 2px rgba(0, 0, 0, .1);
  font-family: -apple-system, BlinkMacSystemFont, "Salesforce Sans", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: .8125rem; line-height: 1.5;
  overflow: hidden;
}
.sf__header {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; background: #f3f3f3; border-bottom: 1px solid #dddbda;
}
.sf__icon {
  display: grid; place-items: center; width: 32px; height: 32px; border-radius: 4px;
  background: #7f8de1; color: #fff; flex: none;
}
.sf__eyebrow { color: var(--sf-weak); font-size: .75rem; }
.sf__title { margin: 0; font-size: 1.125rem; font-weight: 700; line-height: 1.25; color: var(--sf-text); }
.sf__as { margin-left: auto; color: var(--sf-weak); font-size: .75rem; }
.sf__body { padding: 12px 16px 16px; }
.sf__hint { color: var(--sf-weak); font-size: .75rem; margin: 0 0 8px; display: block; }
.sf__prompt { margin: 8px 0; font-size: .875rem; }
.sf__section + .sf__section { margin-top: 12px; }
.sf__band {
  margin: 8px 0; padding: 4px 12px; border-radius: 4px;
  background: var(--sf-band); color: var(--sf-text);
  font-size: .875rem; font-weight: 400;
}
.sf__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 32px; padding: 0 12px; }
@media (max-width: 720px) { .sf__grid { grid-template-columns: 1fr; } }
.sf__field { display: grid; gap: 2px; min-width: 0; }
.sf__label { color: var(--sf-label); font-size: .75rem; }
.sf__required { color: var(--sf-error); text-decoration: none; border: 0; margin-right: 2px; cursor: help; }
.sf__input {
  width: 100%; min-height: 32px; padding: 0 12px;
  background: #fff; color: var(--sf-text);
  border: 1px solid var(--sf-border); border-radius: 4px;
  font: inherit; line-height: 30px;
}
textarea.sf__input { padding: 6px 12px; line-height: 1.5; resize: vertical; }
.sf__input:focus { outline: 0; border-color: var(--sf-focus); box-shadow: 0 0 3px #0176d3; }
.sf__checkbox { justify-self: start; width: 16px; height: 16px; margin: 8px 0; accent-color: #0176d3; }
.sf__warning {
  margin: 0 16px 12px; padding: 8px 12px; border-radius: 4px;
  background: var(--sf-warn-bg); color: var(--sf-warn); font-size: .8125rem;
}
.sf__check { display: flex; align-items: center; gap: 6px; margin-top: 6px; color: var(--sf-text); }
.sf__footer {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 12px 16px; background: #f3f3f3; border-top: 1px solid #dddbda;
}
.sf__button {
  display: inline-flex; align-items: center; min-height: 32px; padding: 0 16px;
  border: 1px solid var(--sf-border); border-radius: 4px; background: #fff;
  color: var(--sf-brand); font: inherit; font-weight: 400; text-decoration: none; cursor: pointer;
}
.sf__button:hover { background: #f3f3f3; }
.sf__button--brand { background: var(--sf-brand); border-color: var(--sf-brand); color: #fff; }
.sf__button--brand:hover { background: var(--sf-brand-dark); border-color: var(--sf-brand-dark); }
.sf__button:disabled { background: #c9c9c9; border-color: #c9c9c9; color: #fff; cursor: not-allowed; }

/* ---- Board ---------------------------------------------------------------
   A workspace's lanes, side by side. Its own class because nothing else here
   lays columns out horizontally: .ws__grid wraps its cards onto new rows, and
   a board must not — a lane that wraps under another no longer reads as the
   next stage. So the lanes share the board's width equally, never narrower
   than 240px, and the board scrolls sideways when there are more than fit. */
.board {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow-x: auto;
  border-top: 1px solid var(--border);
}
/* The lanes, side by side: the scroller above holds them and, grouped, the swimlanes under them. */
.board__lanes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex: 1 0 auto;
  align-items: stretch;
  min-width: min-content;
}

/* ---- Workspace pages ------------------------------------------------------
   Every page inside a workspace shares one format: the side nav on the left,
   the page beside it at the window's full width, the site header widened to
   match, and no footer. A page opts in with `ws ws--app` on its section and
   `wrap wrap--app` on its wrap. Scoped by :has so no other page changes.

   Each level from body down is a column that hands its leftover height to the
   next, so the side nav and the page run to the bottom of the window.

   The side nav and the page are two rounded panels floating on the page's
   background, a --app-gap apart and from every edge: the layout of
   Salesforce's own UI (SLDS 2), rather than areas ruled off from each other. */
body:has(.ws--app) { display: flex; flex-direction: column; min-height: 100vh; }
body:has(.ws--app) > main { flex: 1; display: flex; flex-direction: column; }
.ws--app { flex: 1; display: flex; gap: var(--app-gap); padding: var(--app-gap); }
/* Never narrower than the site, side nav included: --maxw less its width. */
.ws--app > .wrap {
  flex: 1;
  min-width: calc(var(--maxw) - var(--side-nav-w));
  /* The same top as the side nav's, so the two panels' first lines start
     level. */
  padding-block: var(--app-pad-top) 64px;
  padding-inline: 28px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elev);
}

/* The site header follows the page out to the window's width, so the logo
   and nav line up with the breadcrumbs instead of sitting in a centred column
   above a page that spans the window. */
body:has(.ws--app) .site-header .wrap { max-width: none; padding-inline: 20px; }
body:has(.ws--app) .site-footer { display: none; }

/* The board fills the rest of its panel below the heading, and runs edge to
   edge: out through the panel's 28px padding to its sides, its bottom corners
   rounded to the panel's so the columns end inside the curve. The breadcrumbs
   and title above keep the padding. */
.ws--board > .wrap { display: flex; flex-direction: column; padding-bottom: 0; }
/* What a change redraws in place (Board.cshtml #boardRegion): the notice and the board, filling the page. */
.ws--board .board__region { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.ws--board .board {
  flex: 1;
  margin-inline: -28px;
  border-radius: 0 0 calc(var(--radius) - 1px) calc(var(--radius) - 1px);
}

/* A fixed column of links down the left of a page. Its own class because
   nothing here had one: .bundle__files is a list inside a panel, not a column
   of the page. The links inside are .menu__item under a .menu__section, the
   same look as every other list of places on the site.

   Sticky rather than fixed: it stays in the page's flow, so the page beside
   it needs no margin to clear it, and it holds still under the site header
   (68px and its 1px border, plus the gap) while the page scrolls.

   A rounded panel like the page beside it, and its links are pills. */
.side-nav {
  flex: 0 0 var(--side-nav-w);
  position: sticky;
  top: calc(69px + var(--app-gap));
  align-self: flex-start;
  height: calc(100vh - 69px - 2 * var(--app-gap));
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--app-pad-top) 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elev);
}
.side-nav .menu__item { font-size: .85rem; padding-block: 8px; border-radius: 999px; }
.side-nav__count { margin-left: auto; }
/* A collapsing group of places: Work. Its heading is a .menu__item that
   toggles rather than goes anywhere, the chevron at the right turned up while
   it is open. */
.side-nav__group > summary { list-style: none; cursor: pointer; }
.side-nav__group > summary::-webkit-details-marker { display: none; }
.side-nav__group-chevron { margin-left: auto; color: var(--text-faint); transition: transform .18s ease; }
.side-nav__group[open] .side-nav__group-chevron { transform: rotate(180deg); }
.side-nav__group { display: flex; flex-direction: column; gap: 2px; }
/* A place with a page and places under it (Connected Orgs, Tools) looks as
   Work does; its name is a link filling the row up to the count and the
   chevron, which fold it. */
.side-nav__group-link {
  display: flex;
  align-items: center;
  gap: inherit;
  flex: 1;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}
.side-nav__group-head .side-nav__count + .side-nav__group-chevron { margin-left: 6px; }

.side-nav__places {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow-y: auto;
}
/* Workspace Settings, at the foot of the nav: a band the nav's full width,
   out through its padding, its bottom corners the nav's own so a hover or the
   active fill runs into the curve rather than stopping short of it as a pill. */
.side-nav .side-nav__foot {
  /* auto, not .menu__item's 100%: a percentage ignores the negative margins,
     and the band would stop short of the right edge. */
  width: auto;
  margin: 0 -10px -14px;
  padding: 14px 22px;
  border-top: 1px solid var(--border);
  border-radius: 0 0 calc(var(--radius) - 1px) calc(var(--radius) - 1px);
}
/* A place under another — Board's Backlog, Sprints… — indented beneath it
   and a step smaller. */
.side-nav .side-nav__child { padding-left: 34px; font-size: .82rem; padding-block: 6px; }
.side-nav .menu__item.is-active svg { color: var(--accent); }
.side-nav .menu__item.is-active { background: rgb(var(--ink) / .07); color: var(--text); }

/* The workspace switcher at the top of the side nav: the heading it replaced,
   now a .menu trigger the nav's width with the chevron at the right. Its panel
   drops below it across the nav, rather than out to the right like a header
   menu's. No overflow on .side-nav, or the panel would be clipped. */
.side-nav__switch { margin-bottom: 6px; }
.side-nav__switch .menu__trigger {
  width: 100%;
  justify-content: space-between;
  padding: 8px 10px 8px 12px;
  border-radius: 999px;
}
.side-nav__name {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: .86rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.side-nav__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Personal or shared (_WorkspaceKind): before a workspace's name in the side
   nav's switcher and its list; after it in the workspace page's title; at the
   right of a Workspaces or Boards card, where the pill was. */
.ws-kind { flex: none; color: var(--text-faint); }
.ws__kind { margin-left: auto; }
.ws__title-kind { margin-left: 10px; vertical-align: -2px; }
.side-nav__switch .menu__panel { left: 0; right: 0; top: calc(100% + 4px); min-width: 0; }

/* Columns of one surface, not cards: no gap, radius or background of their
   own, only a rule between them. A lane is a stage of the workflow — part of
   the board's structure — and a card reads as something that can be picked up
   and moved, which is what work items will be. */
.board__lane {
  flex: 1 1 0;
  min-width: 240px;
  display: flex;
  flex-direction: column;
  min-height: 420px;
}
.board__lane + .board__lane { border-left: 1px solid var(--border); }

/* A lane collapsed (its arrows): a narrow column with its name standing on end; its cards hidden. */
.board__lane.is-collapsed { flex: 0 0 48px; min-width: 48px; }
.board__lane.is-collapsed .board__head { flex-direction: column; align-items: center; padding: 12px 6px; height: 100%; border-bottom: 0; }
.board__lane.is-collapsed .board__heading { flex: none; order: 2; }
.board__lane.is-collapsed .board__name { writing-mode: vertical-rl; white-space: nowrap; }
.board__lane.is-collapsed .board__org,
.board__lane.is-collapsed .board__menu,
.board__lane.is-collapsed > .board__items { display: none; }

/* The lane after the last: + to add one (admins). */
.board__add-lane { flex: 0 0 56px; display: flex; justify-content: center; padding-top: 12px; border-left: 1px solid var(--border); }

/* Grouped (Group in the toolbar): the lanes keep their headings; a swimlane per group under them,
   its name and count across the board, then a column per lane in line with the lanes above. */
.board.is-grouped .board__lanes { flex: none; }
.board.is-grouped .board__lane { min-height: 0; }
.board.is-grouped .board__lane > .board__items { display: none; }
.board__swims { display: flex; flex-direction: column; min-width: min-content; }
.board__swim-head {
  display: flex; align-items: center; gap: 8px; padding: 10px 16px 6px;
  font-size: .85rem; font-weight: 600; border-top: 1px solid var(--border);
}
.board__swim-head .board__count { margin-left: 0; }
.board__swim-row { display: flex; }
.board__swim-row > .board__items { flex: 1 1 0; min-width: 240px; min-height: 64px; }
.board__swim-row > .board__items + .board__items { border-left: 1px solid var(--border); }
.board__swim-row > .board__items.is-collapsed { flex: 0 0 48px; min-width: 48px; padding: 0; }
.board__swim-row > .board__items.is-collapsed > * { display: none; }
.board__swim-row > .board__add-lane { padding: 0; }

/* The header band runs unbroken across the board, so the lane names read as
   one row of column headings. */
.board__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 10px 10px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

.board__name {
  flex: 1;
  margin: 0;
  font-size: .95rem;
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* The board scrolls sideways, and a scroller clips in both directions, so the
   lane menu's panel has to fit inside the lane: narrower than a menu's usual
   240px, and the lane's min-height leaves room below it. */
.board__head .menu__panel { min-width: 200px; }

.board__items {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
}

/* The lane's name with its count, and an environment lane's org beneath. */
.board__heading { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.board__count { margin-left: 6px; font-size: .8rem; font-weight: 500; color: var(--text-faint); }
.board__org {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: .76rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--teal-text);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.board__org:hover { text-decoration: underline; }
.board__actions { display: flex; gap: 8px; }

/* Workspace Settings → Board Management: a lane per row, its actions small
   and on one line at the right. */
.lanes { margin-bottom: 16px; }
.lanes__num { text-align: right; font-variant-numeric: tabular-nums; }
.lanes__actions { display: flex; justify-content: flex-end; align-items: center; gap: 6px; white-space: nowrap; }
.lanes__actions .btn { padding: 5px 12px; font-size: .8rem; }
.lanes__move { display: flex; gap: 4px; margin: 0; }
.settings__notice { margin-top: 16px; }
.board__key-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.board__key-form .auth__input { width: 140px; }
.board__key-form .auth__error { flex-basis: 100%; }

/* The first work lane's last place: where a new work item goes, drawn as the
   outline of a card. */
/* A lane's + (every work lane): a new work item there, drawn as the outline of a card. */
.board__new {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  background: none;
  font: inherit;
  cursor: pointer;
  padding: 10px 12px;
  border: 1px dashed var(--border-strong);
  border-radius: 10px;
  color: var(--text-faint);
  font-size: .86rem;
  text-decoration: none;
}
.board__new:hover { border-color: var(--accent); color: var(--accent-hover); background: rgb(var(--ink) / .04); }

/* A work item: a card, which is what can be picked up and moved (the lanes
   are not cards, see .board__lane). */
.board__card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: var(--shadow);
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
}
.board__card[draggable="true"] { cursor: grab; }
.board__card:hover { border-color: var(--accent); }
.board__card.is-dragging { opacity: .4; }
.board__card-title { font-size: .88rem; line-height: 1.35; overflow-wrap: anywhere; }
/* The card's link fills it (its ::after), so the whole card opens the item; the tools sit above it. */
.board__card-link { color: inherit; text-decoration: none; padding-right: 52px; }
.board__card-link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.board__card-link:focus-visible { outline: none; }
.board__card:has(.board__card-link:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.board__card-tools { position: absolute; top: 6px; right: 6px; z-index: 1; display: flex; gap: 2px; opacity: 0; transition: opacity .12s; }
.board__card:hover .board__card-tools,
.board__card:focus-within .board__card-tools,
.board__card-tools:has(details[open]) { opacity: 1; }
.board__card-right { display: flex; align-items: center; gap: 6px; }
/* Under the title, as Jira's card: the Epic (a purple lozenge), labels, the due date (red when past, amber within two days). */
.board__card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
.board__epic { max-width: 100%; padding: 1px 6px; border-radius: 4px; background: rgb(143 107 216 / .18); color: #8f6bd8; font-size: .7rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board__label { padding: 1px 6px; border-radius: 4px; background: rgb(var(--ink) / .08); color: var(--text-faint); font-size: .7rem; }
.board__due { display: inline-flex; align-items: center; gap: 4px; font-size: .74rem; font-weight: 600; color: var(--text-faint); }
.board__due.is-soon { color: var(--warn-text); }
.board__due.is-late { color: var(--rose-text); }
.board__points { min-width: 20px; padding: 1px 6px; border-radius: 999px; background: rgb(var(--ink) / .1); color: var(--text); font-size: .7rem; font-weight: 600; text-align: center; }
.board__card[hidden] { display: none; }

/* A small square icon button: a lane's collapse and ···, a card's ✎ and ···, + add lane. */
.board__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border: 1px solid transparent; border-radius: 6px;
  background: none; color: var(--text-faint); cursor: pointer; list-style: none;
}
.board__icon::-webkit-details-marker { display: none; }
.board__icon:hover, .board__menu[open] > .board__icon { background: rgb(var(--ink) / .07); color: var(--text); }
.board__icon--add { width: 32px; height: 32px; border-color: var(--border); }
.board__card .board__icon { background: var(--surface); }
.board__card .board__icon:hover { background: var(--surface-2); }
/* The menus' panels are placed over the page by board.js (the board scrolls and would clip them). */
.board__menu .menu__panel { min-width: 220px; max-height: 60vh; overflow-y: auto; }
.board__menu .menu__item .wi-priority { margin-right: 4px; }

/* A work item's priority (_WorkItemPriority), as Jira colours it. */
.wi-priority { display: inline-flex; align-items: center; }
.wi-priority--critical { color: var(--rose-text); }
.wi-priority--high { color: var(--warn-text); }
.wi-priority--medium { color: #d4a72c; }
.wi-priority--low { color: var(--accent); }

/* The toolbar over the board: Search board, the people on it, Filter and Group. */
.board__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0 0 14px; }
.board__search {
  display: flex; align-items: center; gap: 6px; height: 34px; padding: 0 10px; width: 200px;
  border: 1px solid var(--border-strong); border-radius: 8px; background: var(--surface); color: var(--text-faint);
}
.board__search:focus-within { border-color: var(--accent); }
.board__search input { flex: 1; min-width: 0; border: 0; outline: none; background: none; color: var(--text); font: inherit; font-size: .86rem; }
.board__people { display: flex; align-items: center; padding-left: 6px; }
.board__person { margin-left: -6px; border: 2px solid var(--bg-elev); cursor: pointer; padding: 0; font: inherit; font-size: .6rem; }
.board__person:hover { transform: translateY(-2px); z-index: 1; }
.board__person.is-on { box-shadow: 0 0 0 2px var(--accent); z-index: 2; }
.board__person--none { display: inline-flex; align-items: center; justify-content: center; background: rgb(var(--ink) / .12); color: var(--text-faint); }
.board__tool-btn { display: inline-flex; align-items: center; gap: 6px; height: 34px; list-style: none; }
.board__tool-btn::-webkit-details-marker { display: none; }
.board__tool .menu__panel { left: 0; right: auto; min-width: 200px; }
.board__tool-count { padding: 0 6px; border-radius: 999px; background: var(--accent); color: #fff; font-size: .72rem; font-weight: 600; }
.board__check { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.board__check input { margin: 0; }
/* A Scrum board's active sprint, at the toolbar's right: its name (the goal on hover), days left, Complete sprint. */
.board__sprint { margin-left: auto; display: flex; align-items: center; gap: 10px; }

/* ---- Backlog (Pages/Workspace/Backlog.cshtml), as Jira's -------------------------------------
   A box per sprint -- the active one, then those to come -- then the backlog: its head (name,
   dates, Active, count and points, its actions), then a row per work item, then + Create. */
.backlog { display: flex; flex-direction: column; gap: 16px; }
.backlog__group { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.backlog__group.is-over { border-color: var(--accent); background: rgb(var(--ink) / .03); }
.backlog__head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 12px 14px; }
.backlog__name { margin: 0; font-size: .95rem; font-weight: 600; }
.backlog__dates, .backlog__count { font-size: .8rem; color: var(--text-faint); }
.backlog__state { padding: 1px 8px; border-radius: 999px; background: rgb(var(--ink) / .1); font-size: .72rem; font-weight: 600; }
.backlog__actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.backlog__actions form { margin: 0; }
.backlog__goal { margin: -6px 14px 10px; font-size: .84rem; color: var(--text-faint); }
.backlog__items { list-style: none; margin: 0; padding: 0; min-height: 8px; }
.backlog__row {
  display: flex; align-items: center; gap: 10px; padding: 7px 14px; border-top: 1px solid var(--border);
  font-size: .86rem; background: var(--surface);
}
.backlog__row[draggable="true"] { cursor: grab; }
.backlog__row:hover { background: rgb(var(--ink) / .03); }
.backlog__row.is-dragging { opacity: .4; }
.backlog__key { font-size: .78rem; font-weight: 600; color: var(--text-faint); text-decoration: none; white-space: nowrap; }
.backlog__title { flex: 1; min-width: 0; color: var(--text); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.backlog__title:hover, .backlog__key:hover { text-decoration: underline; }
.backlog__lane { padding: 1px 8px; border-radius: 4px; background: rgb(var(--ink) / .08); font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .03em; white-space: nowrap; }
.backlog__lane.is-env { color: var(--teal-text); }
.backlog__create { display: flex; align-items: center; gap: 8px; margin: 0; padding: 8px 14px; border-top: 1px solid var(--border); color: var(--text-faint); }
.backlog__create input { flex: 1; border: 0; outline: none; background: none; color: var(--text); font: inherit; font-size: .86rem; }
.board__fields--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ---- Summary (Pages/Workspace/Summary.cshtml), as Jira's: cards of counts, each with its bar. ---- */
.summary { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; }
.summary__card { padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.summary__card--wide { grid-column: 1 / -1; }
.summary__title { margin: 0 0 10px; font-size: .95rem; font-weight: 600; }
.summary__line { margin: 6px 0 0; font-size: .85rem; color: var(--text-faint); }
.summary__line b { color: var(--text); }
.summary__bar { height: 8px; border-radius: 999px; background: rgb(var(--ink) / .1); overflow: hidden; margin-top: 10px; }
.summary__bar > span { display: block; height: 100%; background: var(--teal-text); }
.summary__counts { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.summary__count { display: grid; grid-template-columns: minmax(80px, 140px) 1fr 36px; align-items: center; gap: 10px; font-size: .85rem; }
.summary__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.summary__track { height: 8px; border-radius: 999px; background: rgb(var(--ink) / .08); overflow: hidden; }
.summary__track > span { display: block; height: 100%; background: var(--accent); }
.summary__value { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
.summary__count--env .summary__track > span { background: var(--teal-text); }
.summary__count--critical .summary__track > span { background: var(--rose-text); }
.summary__count--high .summary__track > span { background: var(--warn-text); }
.summary__count--medium .summary__track > span { background: #d4a72c; }
.summary__count--bug .summary__track > span { background: var(--rose-text); }
.summary__count--story .summary__track > span { background: var(--teal-text); }
.summary__count--epic .summary__track > span { background: #8f6bd8; }
.summary__count--none .summary__name { color: var(--text-faint); }
.summary__due { list-style: none; margin: 0; padding: 0; }
.summary__due li { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-top: 1px solid var(--border); font-size: .86rem; }
.summary__due li:first-child { border-top: 0; }
.board__sprint-name { font-weight: 600; font-size: .9rem; }
.board__sprint-left { font-size: .8rem; color: var(--text-faint); }
.board__card-foot { display: flex; align-items: center; justify-content: space-between; min-height: 22px; }
.board__card-key { display: flex; align-items: center; gap: 6px; min-width: 0; }
/* Priority as its word, quiet unless it is High or Critical. */
.board__priority { font-size: .72rem; color: var(--text-faint); }
.board__priority--high { color: var(--warn-text); }
.board__priority--critical { color: var(--rose-text); font-weight: 600; }
.board__fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.board__fields .auth__input { width: 100%; }
.board__key { font-size: .76rem; font-weight: 600; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.avatar--sm { width: 22px; height: 22px; font-size: .6rem; }

/* While a card is dragged: the lane it would land in, and the lanes that will
   not take it (an environment lane is entered only by promotion). */
.board__items.is-over { background: rgb(var(--ink) / .04); }
.board__items.is-closed { opacity: .45; }

/* The item dialog: lane beside the number; two pickers on a row; Remove at the
   left of the actions. */
.board__dialog-lane { margin-left: 8px; font-size: .85rem; font-weight: 500; color: var(--text-faint); }
.modal__actions .board__remove { margin-right: auto; color: var(--rose-text); }

/* ---- The assistant panel --------------------------------------------------
   A third column of every workspace page, at the right: a rounded panel like
   the side nav, sticky under the header, beside the page rather than over it.
   Its log scrolls; the working row and the reply box stay at its foot. */
.assistant {
  order: 3;
  flex: 0 0 380px;
  position: sticky;
  top: calc(69px + var(--app-gap));
  align-self: flex-start;
  height: calc(100vh - 69px - 2 * var(--app-gap));
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 14px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elev);
  min-width: 0;
}
.assistant[hidden] { display: none; }
.assistant__head { display: flex; align-items: center; gap: 4px; }
.assistant__title { flex: 1; font-size: .78rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint); }
.assistant__icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--text-faint);
  cursor: pointer;
}
.assistant__icon:hover { background: rgb(var(--ink) / .07); color: var(--text); }
.assistant__log { flex: 1; }
.assistant__status { margin: 0; min-height: 1.2em; }
.assistant__status a { color: inherit; font-weight: 600; }
/* With the panel open the page beside it gives up its width, not its floor. */
.ws--app:has(> .assistant:not([hidden])) > .wrap { min-width: 0; }
.assistant-switch.is-active { color: var(--accent); }

/* ---- The New work item wizard --------------------------------------------
   A conversation in the modal, in place of the form: the AI's lines on the
   left, the member's on the right; the reply box and Send below. */
.wizard__toggle { margin-left: auto; margin-right: 6px; align-self: center; white-space: nowrap; text-decoration: none; }
.modal__head .wizard__toggle + .modal__close { margin-left: 0; }
.wizard { display: flex; flex-direction: column; gap: 10px; min-height: 0; overflow: hidden; }
.wizard__input, .wizard__foot { flex: none; }
.wizard[hidden] { display: none; }
.wizard__log {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 4px 2px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: .9rem;
  line-height: 1.5;
}
/* As the IDE's chat: the AI's lines plain, the member's in a bubble at the right. */
.wizard__line { white-space: pre-wrap; overflow-wrap: anywhere; }
.wizard__line--ai { align-self: stretch; }
.wizard__line--me {
  align-self: flex-end;
  max-width: 90%;
  padding: 6px 10px;
  border-radius: 8px;
  background: rgb(var(--ink) / .09);
}
/* What it looked at: small, muted, an icon each. */
.wizard__looked { display: flex; flex-direction: column; gap: 2px; font-size: .76rem; color: var(--text-faint); }
.wizard__looked svg { vertical-align: -1px; }
/* Working: the provider's turning glyph, a status word, the seconds. */
.wizard__working { flex: none; display: flex; align-items: center; gap: 6px; min-height: 22px; font-size: .85rem; color: var(--text-dim); }
.wizard__working[hidden] { display: none; }
.wizard__glyph { display: inline-block; width: 14px; text-align: center; font-size: .95rem; }
.wizard__glyph--claude { color: #d97757; }
.wizard__glyph--codex { color: var(--text); }
.wizard__glyph--gemini { color: #6d9eeb; }
.wizard__input { width: 100%; resize: none; font-size: .9rem; }
.wizard__foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 36px; }
.wizard__status { color: var(--rose-text); font-size: .85rem; }
.wizard__status--done { color: var(--teal-text); }
.wizard__input:disabled { opacity: .5; }

/* ---- A work item ---------------------------------------------------------
   Its type as an icon, coloured by type, on the cards and its page. */
.wi-type { display: inline-grid; place-items: center; flex: none; }
.wi-type--story { color: var(--teal-text); }
.wi-type--bug { color: var(--rose-text); }
.wi-type--task { color: var(--accent-hover); }
.wi-type--epic { color: #8f6bd8; }

/* Its page: the fields and criteria on the left, type, priority, assignee and
   the facts on the right. */
.wi__heading { min-width: 0; }
.wi__eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 4px;
  font-size: .85rem;
  font-weight: 600;
  color: var(--text-faint);
}
.wi { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 32px; margin-top: 24px; align-items: start; }
.wi fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
.wi__main, .wi__fields { display: flex; flex-direction: column; }
.wi__main .auth__input, .wi__fields .auth__input { width: 100%; }
.wi__criteria { list-style: decimal; margin: 0 0 8px; padding-left: 22px; display: flex; flex-direction: column; gap: 6px; }
.wi__criteria li::marker { color: var(--text-faint); font-size: .85rem; }
.wi__criterion { position: relative; }
.wi__criterion .auth__input { padding-right: 36px; }
.wi__criterion-remove {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--text-faint);
  cursor: pointer;
}
.wi__criterion-remove:hover { background: rgb(var(--ink) / .07); color: var(--text); }
.wi__main:disabled .wi__criterion-remove { display: none; }
.wi__add { align-self: flex-start; }
.wi__actions { display: flex; justify-content: flex-end; margin-top: 16px; }
.wi__side { display: flex; flex-direction: column; gap: 20px; }
.wi__facts { margin: 0; }
.wi__facts .facts__row { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: .86rem; }
.wi__facts dt { color: var(--text-faint); }
.wi__facts dd { margin: 0; text-align: right; overflow-wrap: anywhere; }

/* Comments: avatar, name and time, the text as written. */
.wi__comments { max-width: 820px; margin-top: 24px; }
.wi__thread { list-style: none; margin: 0 0 24px; padding: 0; display: flex; flex-direction: column; gap: 18px; }
.wi__comment { display: flex; gap: 12px; }
.wi__comment-body { flex: 1; min-width: 0; }
.wi__comment-head { display: flex; align-items: center; gap: 10px; margin: 0 0 4px; font-size: .85rem; color: var(--text-faint); }
.wi__comment-head strong { color: var(--text); font-weight: 600; }
.wi__comment-remove { margin: 0 0 0 auto; }
.wi__comment-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.5; }
.wi__history { margin-top: 24px; }

/* ---- Limits Center -------------------------------------------------------
   Built from the Limits tab's pieces (.limits__bar, .meters, .stats) plus the
   few things it has that the tab did not: the moment the reading was taken,
   the tiles' colour, the filters and the collapsible groups. */
.limits__asof { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--text-dim); font-size: .9rem; }
/* "Reading limits…" beside the spinner, only while it turns: the spinner is
   .ws__spin--idle (display: none) the rest of the time. */
.limits__reading { display: none; color: var(--accent); }
.limits__asof .ws__spin { width: 15px; height: 15px; margin-right: 0; }
.ws__spin:not(.ws__spin--idle) + .limits__reading { display: inline; }

/* Get Latest Limits says what it is doing while a reading is owed, with the
   button spinner .btn.is-busy draws — .is-refreshing is what refresh-watch.js
   sets on the button it posted, and what the server draws on a reload. */
.limits__get .limits__get-busy { display: none; }
.limits__get.is-refreshing .limits__get-idle { display: none; }
.limits__get.is-refreshing .limits__get-busy { display: inline; }

/* A tile's count in the band it counts, only while it is above 0. */
.stat__value--critical { color: var(--rose); }
.stat__value--warning { color: var(--amber); }
.stat__note { display: block; margin-top: 4px; color: var(--text-dim); font-size: .85rem; }

.limits__levels { margin-top: 0; }

.limits__filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 16px;
  margin: 14px 0 18px;
}
.limits__groups { flex: 1 1 100%; margin: 0; flex-wrap: wrap; }
.limits__search { max-width: 320px; }

/* A group of limits: its name, how many, how many need attention. A
   <details>, so it collapses with no script. */
.limits__group { margin-bottom: 18px; }
.limits__group > summary { list-style: none; cursor: pointer; }
.limits__group > summary::-webkit-details-marker { display: none; }
.limits__group-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
}

/* The org's name and instance under its alias, "Name | instance". */
.orghead__sub { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; max-width: none; }
.orghead__pipe { color: var(--text-faint); }
.orghead__kind { color: var(--accent); vertical-align: -2px; margin-right: 4px; }

/* ---- Access Comparer -----------------------------------------------------
   Toolware's Access Comparator, in this site's colours: green for granted
   (its #2e844a), violet for implied (#5a1ba9), a warm tint for a row that
   differs (#fef6ed). access-comparer.js draws everything inside .acmp. */
.acmp { display: grid; gap: 18px; margin-top: 18px; }
.acmp__token { display: none; }
.acmp__panel {
  padding: 18px 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.acmp__panel-title { margin: 0 0 14px; font-size: 1rem; }

.acmp__pickers { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
/* A, B, then Compare on the same row; "Show differences only" under Compare.
   The column starts a label's height down, so the button sits level with the
   pickers. */
.acmp__pickrow { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 14px; align-items: start; }
.acmp__go { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; padding-top: calc(.75rem * 1.5 + 6px); }
.acmp__go .btn { min-height: 40px; padding-inline: 22px; }
@media (max-width: 768px) {
  .acmp__pickers, .acmp__pickrow { grid-template-columns: minmax(0, 1fr); }
  .acmp__go { padding-top: 0; }
}
.acmp__picker { display: grid; gap: 6px; }
.acmp__select { width: 100%; }
.acmp__user { position: relative; }
/* A user box: the search icon inside its end, and a checkmark before it once
   one user is chosen. */
.acmp__user-input { width: 100%; padding-right: 72px; }
.acmp__user-search {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  display: grid; place-items: center; width: 30px; height: 30px; padding: 0;
  border: 0; border-radius: var(--radius-sm); background: none; color: var(--text-dim); cursor: pointer;
}
.acmp__user-search:hover:not(:disabled) { color: var(--text); background: rgb(var(--ink) / .06); }
.acmp__user-search:disabled { cursor: default; opacity: .6; }
.acmp__user-check { position: absolute; top: 50%; right: 40px; transform: translateY(-50%); display: grid; color: var(--teal-text); }
.acmp__user.is-picked .acmp__user-input { border-color: color-mix(in srgb, var(--teal-text) 55%, var(--border)); }
.acmp__user-note { margin: 4px 0 0; font-size: .8rem; color: var(--text-faint); }
.acmp__suggest { top: calc(100% + 4px); left: 0; right: 0; min-width: 0; margin: 0; list-style: none; max-height: 300px; overflow-y: auto; }
.acmp__none { padding: 9px 12px; }

.acmp__results-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.acmp__export > summary { list-style: none; }
.acmp__export > summary::-webkit-details-marker { display: none; }
.acmp__export > summary.is-disabled { opacity: .5; pointer-events: none; }
.acmp__pairs { margin: 0; padding-left: 18px; display: grid; gap: 4px; color: var(--text); }
.acmp__pairnote { margin: 8px 0 0; color: var(--text-faint); font-size: .86rem; }

.acmp__filters { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 14px; }
.acmp__find { flex: 1 1 240px; max-width: 360px; }

/* An open section lists every row, with no scroll of its own: the page is
   the only thing that scrolls. clip, not hidden: hidden would make the card a
   scroll container and stop the table's head sticking under the site header. */
.acmp__card { border: 1px solid var(--border); border-radius: var(--radius-sm); margin-bottom: 10px; overflow: clip; }
.acmp__card-head { display: flex; align-items: center; gap: 12px; padding: 10px 14px; background: var(--surface-2); }
.acmp__toggle { display: flex; align-items: center; gap: 8px; flex: 1; padding: 0; border: 0; background: none; color: var(--text); font: inherit; font-weight: 600; text-align: left; cursor: pointer; }
.acmp__chevron { display: inline-block; width: 1em; color: var(--text-faint); transition: transform .15s ease; }
.acmp__chevron.is-open { transform: rotate(90deg); }
.acmp__meta { display: inline-flex; align-items: center; gap: 8px; color: var(--text-dim); font-size: .86rem; }
.acmp__listed { margin-top: 10px; color: var(--text-faint); font-size: .8rem; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.acmp__linkbtn { padding: 0; border: 0; background: none; color: var(--accent); font: inherit; cursor: pointer; }
.acmp__linkbtn:hover { text-decoration: underline; }
.acmp__spin { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--border-strong); border-top-color: var(--accent); animation: btn-spin .8s linear infinite; }

.acmp__table { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: .88rem; }
.acmp__table th, .acmp__table td { padding: 8px 12px; border-top: 1px solid var(--border); text-align: left; vertical-align: top; overflow-wrap: anywhere; }
.acmp__table thead th { position: sticky; top: 69px; z-index: 1; background: var(--surface); font-weight: 600; }
.acmp__table th.acmp__name, .acmp__table td.acmp__name { width: 36%; }
.acmp__letter {
  display: inline-grid; place-items: center; width: 18px; height: 18px; margin-right: 6px;
  border-radius: 50%; background: var(--accent); color: #fff; font-size: .7rem; font-weight: 700;
}
.acmp__sub, .acmp__count { display: block; font-weight: 400; color: var(--text-faint); font-size: .8rem; }
.acmp__note { color: var(--text-dim); font-size: .84rem; }
.acmp__empty { color: var(--text-faint); font-style: italic; }
.acmp__row--diff td { background: color-mix(in srgb, var(--amber) 9%, transparent); }
.acmp__heading td { color: var(--text-faint); font-weight: 700; font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; }
.acmp__indent { padding-left: calc(12px + 1.25rem) !important; }
.acmp__object { display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: none; color: var(--text); font: inherit; cursor: pointer; text-align: left; }
/* The object's chevron is a fixed width, so its field summary lines up under
   the object's name, not under the chevron. */
.acmp__object .acmp__chevron { width: 14px; flex: none; }
.acmp__fieldmeta { display: block; margin-top: 2px; padding-left: 20px; color: var(--text-faint); font-size: .8rem; }

.acmp__value { color: var(--text-faint); }
.acmp__value.is-on { color: var(--teal-text); font-weight: 650; }
.acmp__flags { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.acmp__flag {
  display: inline-grid; place-items: center; min-width: 24px; height: 20px; padding: 0 4px;
  border-radius: 4px; font-size: .7rem; font-weight: 700;
  color: var(--text-faint); background: rgb(var(--ink) / .06);
}
.acmp__flag.is-on { color: var(--teal-text); background: color-mix(in srgb, var(--teal) 16%, transparent); }
.acmp__flag.is-implied { outline: 1px dashed var(--teal); outline-offset: -1px; }
.acmp__implied {
  display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 999px; font-size: .7rem; font-weight: 600;
  color: var(--violet); background: color-mix(in srgb, var(--violet) 14%, transparent);
}
.acmp__granted { display: block; margin-top: 3px; color: var(--text-faint); font-size: .78rem; }
.acmp__noeffect { display: block; margin-top: 3px; color: var(--warn-text); font-size: .78rem; }
.acmp__muted { color: var(--text-faint); }
.acmp__shimmer { display: block; height: 10px; margin: 4px 0; border-radius: 4px; background: rgb(var(--ink) / .08); animation: acmp-shimmer 1.2s ease-in-out infinite; }
@keyframes acmp-shimmer { 50% { opacity: .4; } }

/* ---- External Jobs ------------------------------------------------------ */

/* The list. */
.ejobs__col-name { width: 40%; }
.ejobs__col-org { width: 22%; }
.ejobs__col-version { width: 10%; }
.ejobs__col-modified { width: 18%; }
.ejobs__col-actions { width: 10%; }
.ejobs__desc { display: block; margin-top: 2px; font-size: .8rem; color: var(--text-faint); }

/* The canvas and the chosen step's settings, side by side. */
.ejob__status { margin-left: auto; font-size: .8rem; color: var(--text-faint); white-space: nowrap; }
.ejob__status + .btn, .ejob__status ~ .btn { margin-left: 0; }
.ejob__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.ejob__token { display: none; }
.ejob {
  display: grid;
  /* Resources | canvas | settings; either side closes. */
  grid-template-columns: 250px minmax(0, 1fr) 520px;
  gap: 16px;
  align-items: start;
}
/* A side closed: the canvas takes its width. */
.ejob.is-panel-closed { grid-template-columns: 250px minmax(0, 1fr); }
.ejob.is-toolbox-closed { grid-template-columns: minmax(0, 1fr) 520px; }
.ejob.is-toolbox-closed.is-panel-closed { grid-template-columns: minmax(0, 1fr); }
.ejob__toolbox[hidden] { display: none; }

/* The Resources pane: Flow Builder's Manager tab. */
.ejob__toolbox {
  padding: 14px 14px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.ejob__toolbox .btn { width: 100%; justify-content: center; margin-bottom: 12px; }
.ejob__res-group { margin-bottom: 12px; }
.ejob__res-group-title { margin: 0 0 4px; font-size: .72rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-faint); }
.ejob__res-empty { margin: 0; font-size: .8rem; color: var(--text-faint); }
.ejob__res {
  display: grid; width: 100%; gap: 1px; padding: 6px 8px; border: 0; border-radius: 6px;
  background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.ejob__res:hover, .ejob__res:focus-visible { background: rgb(var(--ink) / .06); }
.ejob__res-name { font-size: .86rem; font-weight: 600; overflow-wrap: anywhere; }
.ejob__res-type { font-size: .74rem; color: var(--text-faint); }
@media (max-width: 1300px) { .ejob, .ejob.is-panel-closed, .ejob.is-toolbox-closed { grid-template-columns: minmax(0, 1fr); } }

.ejob__canvas {
  min-height: 60vh;
  max-height: none;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* A faint grid, as a canvas has. */
  background:
    radial-gradient(circle, rgb(var(--ink) / .09) 1px, transparent 1.2px) 0 0 / 18px 18px,
    var(--surface);
  cursor: grab;
}
.ejob__flow { display: flex; flex-direction: column; align-items: center; padding: 28px 24px 40px; min-width: max-content; }

.ejob__node {
  position: relative;
  width: 280px;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  background: var(--bg-elev);
  box-shadow: var(--shadow);
}
.ejob__node.is-selected { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(77, 163, 255, .22), var(--shadow); }
.ejob__node--start { width: 200px; border-radius: 999px; }
.ejob__node-body {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 12px 14px; border: 0; background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.ejob__node--start .ejob__node-body { justify-content: center; padding: 10px 14px; }
.ejob__node-icon {
  display: grid; place-items: center; flex: none; width: 34px; height: 34px; border-radius: 9px;
  color: #fff; background: var(--accent);
}
.ejob__node-icon--start { background: #2e8b57; border-radius: 50%; width: 28px; height: 28px; }
.ejob__node-icon--getRecords { background: #e0507a; }
.ejob__node-icon--updateRecords { background: #e07a2e; }
.ejob__node-text { display: grid; gap: 1px; min-width: 0; }
.ejob__node-type { font-size: .7rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-faint); }
.ejob__node-label { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ejob__node-detail { font-size: .78rem; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ejob__node--start .ejob__node-text { display: block; }
.ejob__node--start .ejob__node-label, .ejob__node--start .ejob__node-detail { display: none; }
.ejob__node--start .ejob__node-type { font-size: .85rem; color: var(--text); text-transform: none; letter-spacing: 0; }
.ejob__node-remove {
  position: absolute; top: 6px; right: 6px; display: grid; place-items: center; width: 24px; height: 24px; padding: 0;
  border: 0; border-radius: 6px; background: none; color: var(--text-faint); cursor: pointer; opacity: 0;
}
.ejob__node:hover .ejob__node-remove, .ejob__node-remove:focus-visible { opacity: 1; }
.ejob__node-remove:hover { color: var(--rose-text); background: rgb(var(--ink) / .06); }

.ejob__connector { position: relative; display: flex; flex-direction: column; align-items: center; }
.ejob__line { width: 2px; height: 18px; background: var(--border-strong); }
.ejob__add {
  display: grid; place-items: center; width: 24px; height: 24px; padding: 0;
  border: 1px solid var(--border-strong); border-radius: 50%; background: var(--bg-elev); color: var(--text-dim);
  font-size: 1rem; line-height: 1; cursor: pointer;
}
.ejob__add:hover, .ejob__add[aria-expanded="true"] { color: #fff; background: var(--accent); border-color: var(--accent); }
.ejob__menu { position: absolute; top: 46px; left: 50%; right: auto; bottom: auto; transform: translateX(-50%); z-index: 60; width: 280px; min-width: 0; display: grid; }
.ejob__menu .menu__item { display: grid; gap: 1px; text-align: left; }
.ejob__menu-hint { font-size: .75rem; color: var(--text-faint); font-weight: 400; }
.ejob__end {
  padding: 6px 18px; border: 1px dashed var(--border-strong); border-radius: 999px;
  font-size: .8rem; color: var(--text-faint);
}

/* No scroll of its own: the page is the only thing that scrolls (the canvas
   pans, which is different). */
.ejob__panel {
  padding: 16px 18px 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.ejob__panel-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 12px; }
.ejob__panel[hidden] { display: none; }
.ejob__panel-close {
  display: grid; place-items: center; width: 28px; height: 28px; padding: 0;
  border: 0; border-radius: 6px; background: none; color: var(--text-faint); cursor: pointer;
}
.ejob__panel-close:hover { color: var(--text); background: rgb(var(--ink) / .06); }
.ejob__panel-title { margin: 0; font-size: 1rem; }
.ejob__field { display: grid; gap: 4px; margin-bottom: 10px; min-width: 0; }
.ejob__field .snapshots__select { width: 100%; }
.ejob__text { margin: 0 0 10px; font-size: .86rem; color: var(--text-dim); }
.ejob__muted { color: var(--text-faint); }
.ejob__error { margin: -4px 0 10px; font-size: .8rem; color: var(--rose-text); }
.ejob__group { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.ejob__group-title { margin: 0 0 10px; font-size: .78rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-faint); }
.ejob__row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 8px; align-items: end; }
/* A condition on one row: what is tested, how, against what, and remove. */
.ejob__row--condition { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr) auto; }
.ejob__row--condition > div > .ejob__field { margin-bottom: 8px; }
.ejob__row .ejob__field { margin-bottom: 8px; }
.ejob__row-remove {
  margin-bottom: 8px; width: 28px; height: 34px; padding: 0; border: 0; border-radius: 6px;
  background: none; color: var(--text-faint); font-size: 1.1rem; cursor: pointer;
}
.ejob__row-remove:hover { color: var(--rose-text); background: rgb(var(--ink) / .06); }
.ejob__find { width: 100%; margin-bottom: 8px; }
.ejob__checks { display: grid; gap: 2px; }
.ejob__check { display: flex; align-items: center; gap: 8px; padding: 4px 2px; font-size: .86rem; }
.ejob__check[hidden] { display: none; }

/* The job forms (New Job, Details): labels in one column, every field the same
   width and lined up at the right edge. */
.ejobs__form .snapshots {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  align-items: center;
  gap: 4px 14px;
  margin: 0 0 12px;
}
.ejobs__form .snapshots .snapshots__select { width: 100%; justify-self: end; }
.ejobs__form .snapshots .field-validation-valid,
.ejobs__form .snapshots .field-validation-error { grid-column: 2; }

/* External Jobs: branches and loops on the canvas, schedules and runs. */
.ejob__branches { display: flex; align-items: flex-start; gap: 28px; padding: 10px 16px 6px; border-top: 2px solid var(--border-strong); border-bottom: 2px solid var(--border-strong); }
.ejob__branch { display: flex; flex-direction: column; align-items: center; min-width: 220px; }
.ejob__loop { display: flex; flex-direction: column; align-items: center; padding: 10px 18px; border: 2px dashed var(--border-strong); border-radius: 14px; }
.ejob__branch-label {
  margin: 4px 0 2px; padding: 2px 10px; border-radius: 999px; background: rgb(var(--ink) / .06);
  font-size: .72rem; font-weight: 600; color: var(--text-dim); white-space: nowrap;
}
.ejob__branch-label--end { margin-top: 6px; }
.ejob__node-icon--assignment { background: #7a5ae0; }
.ejob__node-icon--decision { background: #d97706; }
.ejob__node-icon--loop { background: #0d9488; }
.ejob__node-icon--createRecords { background: #2563eb; }
.ejob__node-icon--sendEmail { background: #64748b; }
.ejob__area { width: 100%; resize: vertical; font: inherit; }
.ejob__hint code, .ejob__text code { font-size: .78rem; }

.ejobs__bar { display: flex; gap: 8px; margin-bottom: 14px; }
.ejobs__actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.ejobs__actions form { margin: 0; }
.ejobs__counts { display: flex; gap: 28px; margin: 12px 0 18px; }
.ejobs__counts div { display: grid; gap: 2px; }
.ejobs__counts dt { font-size: .72rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-faint); }
.ejobs__counts dd { margin: 0; font-size: 1.2rem; font-weight: 600; }
.ejobs__log { margin: 0 0 16px; padding-left: 20px; font-size: .86rem; color: var(--text-dim); }
.ejobs__changes td { vertical-align: top; }
.ejobs__json { margin: 0; white-space: pre-wrap; word-break: break-word; font-family: var(--mono); font-size: .75rem; color: var(--text-dim); }
.ejobs__id { display: block; font-size: .75rem; color: var(--text-faint); }
.ejobs__failed td { background: color-mix(in srgb, var(--rose) 8%, transparent); }

/* External Jobs: a fault path, a Web Action's rows, a test's answer. */
.ejob__fault {
  display: flex; flex-direction: column; align-items: center; margin: 6px 0 4px; padding: 8px 18px;
  border: 2px dashed color-mix(in srgb, var(--rose) 55%, transparent); border-radius: 14px;
}
.ejob__branch-label--fault { color: var(--rose-text); background: color-mix(in srgb, var(--rose) 14%, transparent); }
.ejob__node-icon--webAction { background: #0891b2; }
.ejob__row--pair { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) auto auto; }
.ejob__row--method { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 8px; }
.ejob__secret { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; font-size: .78rem; color: var(--text-dim); white-space: nowrap; }
.ejob__test-body { max-height: none; padding: 10px; border: 1px solid var(--border); border-radius: 8px; background: rgb(var(--ink) / .03); }

/* A disabled menu item's reason, on a line of its own under it. */
.menu__item.is-disabled:has(.menu__note) { flex-wrap: wrap; row-gap: 2px; }
.menu__note { flex-basis: 100%; padding-left: 25px; font-size: .75rem; color: var(--text-faint); }

/* ---- Pipelines (docs/pipelines.md): the Board as the pipeline ---------------------------------------- */

/* A card's Ready To Promote, what it is doing while it moves, and how the last hop ended. Above the
   card's stretched link, so the box and the links take the click. */
.board__promo { position: relative; z-index: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-size: .76rem; }
.board__ready { margin: 0; }
.board__ready-label { display: inline-flex; align-items: center; gap: 6px; color: var(--text-dim); cursor: pointer; }
.board__ready-label:has(input:disabled) { cursor: default; opacity: .7; }
.board__ready-label input { margin: 0; accent-color: var(--accent); }
.board__promo-run { display: inline-flex; align-items: center; gap: 6px; color: var(--accent); font-weight: 600; }
.board__promo-run .ws__spin, .pkg__running .ws__spin, .pkg__hops .ws__spin, .pkgb .ws__spin { width: 14px; height: 14px; margin: 0; }
.board__promo-failed { padding: 1px 6px; border-radius: 4px; background: color-mix(in srgb, var(--rose) 14%, transparent); color: var(--rose-text); font-weight: 600; text-decoration: none; }
.board__promo-done { padding: 1px 6px; border-radius: 4px; background: rgba(47, 217, 195, .12); color: var(--teal); font-weight: 600; }
.board__promo-mark { color: var(--accent); font-weight: 600; text-decoration: none; }
.board__promo-mark:hover { text-decoration: underline; }
/* A lane's role on the route, under its name. */
.board__role { display: inline-block; margin-top: 2px; padding: 0 6px; border-radius: 4px; background: rgb(var(--ink) / .08); color: var(--text-dim); font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }

/* Board Management: a lane's pipeline column and its dialog. */
.lanes__pipe { font-size: .8rem; }
.lanes__role { display: inline-block; margin-right: 6px; font-weight: 600; }
.lanes__dim { color: var(--text-faint); }
.lanes__warn { display: block; margin-top: 4px; color: var(--warn-text); }
.lanes__radios { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.lanes__members { display: flex; flex-direction: column; gap: 4px; max-height: 160px; overflow: auto; padding: 6px 0 6px 22px; }

/* A work item's Package tab. */
.pkg-tab { display: flex; flex-direction: column; gap: 22px; }
.pkg__now { display: flex; flex-direction: column; gap: 10px; padding: 14px 16px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface); }
.pkg__running { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--accent); font-weight: 600; }
.pkg__line { margin: 0; color: var(--text-dim); }
.pkg__ready { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin: 0; }
.pkg__ready .board__ready-label { font-weight: 600; color: var(--text); }
.pkg__hint { color: var(--text-faint); font-size: .85rem; }
.pkg__failed { padding: 10px 12px; border-radius: 8px; background: color-mix(in srgb, var(--rose) 8%, transparent); }
.pkg__failed p { margin: 0 0 6px; }
.pkg__failed strong { color: var(--rose-text); }
.pkg { display: flex; flex-direction: column; gap: 12px; }
.pkg__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.pkg__title { margin: 0; font-size: 1.05rem; }
.pkg__h3 { margin: 4px 0 0; font-size: .9rem; }
.pkg__h4 { margin: 10px 0 4px; font-size: .82rem; color: var(--text-dim); }
.pkg__sub { margin: 2px 0 0; color: var(--text-faint); font-size: .85rem; }
.pkg__actions { display: flex; gap: 8px; align-items: center; }
.pkg__actions form { margin: 0; }
.pkg__table td, .pkg__table th { font-size: .85rem; }
.pkg__table tr.is-failed td:first-child { color: var(--rose-text); }
.pkg__more td { padding-top: 0; border-top: none; }
.pkg__more summary { cursor: pointer; color: var(--text-dim); font-size: .8rem; }
.pkg__list { margin: 4px 0 0; padding-left: 18px; font-size: .85rem; line-height: 1.5; }
.pkg__checks { list-style: none; padding-left: 0; }
.pkg__state { display: inline-block; min-width: 62px; padding: 0 6px; margin-right: 6px; border-radius: 4px; font-size: .72rem; font-weight: 600; text-align: center; background: rgb(var(--ink) / .08); color: var(--text-dim); }
.pkg__state--new { background: rgba(47, 217, 195, .12); color: var(--teal); }
.pkg__state--changed { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); }
.pkg__state--delete { background: color-mix(in srgb, var(--rose) 14%, transparent); color: var(--rose-text); }
.pkg__dim { color: var(--text-faint); }
.pkg__ok { margin: 6px 0 0; color: var(--teal); font-weight: 600; }
.pkg__note, .pkg__deletions { padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; }

/* Build package: the dialog keeps its first height; its lists scroll inside it (rule: modal height). */
.pkgb .modal__form { height: min(82vh, 700px); }
.pkgb__tabs { display: flex; gap: 4px; margin: 14px 0 8px; border-bottom: 1px solid var(--border); }
.pkgb__tab { padding: 6px 10px; border: none; border-bottom: 2px solid transparent; background: none; color: var(--text-dim); cursor: pointer; font: inherit; font-size: .85rem; }
.pkgb__tab.is-active { border-bottom-color: var(--accent); color: var(--text); font-weight: 600; }
.pkgb__panes { flex: 1 1 auto; min-height: 0; overflow: auto; }
.pkgb__pane { display: flex; flex-direction: column; gap: 8px; }
.pkgb__filter { margin: 0; }
.pkgb__tree { display: flex; flex-direction: column; font-size: .85rem; }
.pkgb__type { display: flex; align-items: center; gap: 6px; padding: 4px 2px; border-radius: 6px; cursor: pointer; }
.pkgb__type:hover { background: rgb(var(--ink) / .05); }
.pkgb__twist { width: 12px; color: var(--text-faint); }
.pkgb__members { display: flex; flex-direction: column; padding-left: 36px; }
.pkgb__member { display: flex; align-items: center; gap: 6px; padding: 2px 0; }
.pkgb__dim { color: var(--text-faint); }
.pkgb__note { margin: 6px 0; color: var(--text-faint); }
.pkgb__note.loading { display: flex; align-items: center; gap: 8px; }
.pkgb__hint { margin: 0; color: var(--text-faint); font-size: .8rem; }
.pkgb__xml { font-family: var(--mono); font-size: .78rem; }
.pkgb__count { margin: 8px 0 4px; color: var(--text-dim); font-size: .85rem; }
.pkgb__del summary { cursor: pointer; color: var(--text-dim); font-size: .85rem; }

/* Releases: the release being assembled, then production. */
.rel { display: flex; flex-direction: column; gap: 14px; margin-bottom: 26px; }
.rel__route { display: flex; flex-wrap: wrap; align-items: stretch; gap: 12px; }
.rel__stop { display: flex; flex-direction: column; gap: 2px; min-width: 220px; padding: 12px 14px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface); }
.rel__stop--prod { border-style: dashed; }
.rel__label { color: var(--text-faint); font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; }
.rel__org { color: var(--text-dim); font-size: .8rem; }
.rel__note { margin-top: 4px; color: var(--text-faint); font-size: .8rem; max-width: 36ch; }
.rel__arrow { align-self: center; color: var(--text-faint); font-size: 1.4rem; }
.rel__sum { margin: 0; color: var(--text-dim); }
.rel__sum a { margin-left: 8px; }

/* Pipelines: the route, left to right. */
.route { display: flex; gap: 10px; margin: 0 0 26px; padding: 0 0 6px; list-style: none; overflow-x: auto; }
.route__lane { position: relative; display: flex; flex-direction: column; gap: 2px; min-width: 190px; padding: 12px 14px; border: 1px dashed var(--border); border-radius: 12px; color: var(--text-dim); }
.route__lane--env { border-style: solid; background: var(--surface); color: var(--text); }
.route__lane--release { border-color: var(--accent); }
.route__lane--prod { border-style: dashed; border-color: var(--teal); }
.route__kind { color: var(--text-faint); font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; }
.route__org { color: var(--text-dim); font-size: .8rem; }
.route__facts { margin: 8px 0 0; font-size: .78rem; }
.route__facts div { display: flex; flex-direction: column; margin-bottom: 4px; }
.route__facts dt { color: var(--text-faint); }
.route__facts dd { margin: 0; }
.route__warn dd { color: var(--warn-text); }
