/* =============================================================================
   Design tokens — IHM CAT
   Extracted verbatim from the approved prototype. Colour values are the brand
   identity and must not be changed without design approval.
   ========================================================================== */

:root {
  /* Navy — primary brand scale */
  --navy-950: #06101f;
  --navy-900: #0a2351;
  --navy-800: #102d63;
  --navy-700: #1a57a8;

  --brand: #0a2351;
  --brand-secondary: #1a57a8;
  --brand-accent: #2d7dd2;
  --brand-highlight: #7db8f0;
  --brand-light: #eef4fb;

  /* Silver — neutral scale */
  --silver-50: #f8fafc;
  --silver-100: #f1f5f9;
  --silver-200: #e2e8f0;
  --silver-300: #cbd5e1;
  --silver-400: #94a3b8;
  --silver-500: #64748b;
  --silver-600: #475569;
  --silver-700: #334155;
  --silver-800: #1e293b;
  --silver-900: #0f172a;

  /* Status scales */
  --emerald-50: #ecfdf5;
  --emerald-100: #d1fae5;
  --emerald-600: #059669;
  --emerald-800: #065f46;

  --amber-50: #fffbeb;
  --amber-100: #fef3c7;
  --amber-600: #d97706;
  --amber-800: #92400e;

  /* Classification label colours (four-category system) */
  --label-relevant-bg: #fee2e2;
  --label-relevant-fg: #991b1b;
  --label-not-bg: var(--emerald-100);
  --label-not-fg: var(--emerald-800);
  --label-review-bg: var(--amber-100);
  --label-review-fg: var(--amber-800);
  --label-additional-bg: #fef08a;
  --label-additional-fg: #854d0e;

  --danger: #dc2626;

  /* Shape and depth */
  --radius: 14px;
  --shadow-card: 0 1px 3px rgba(10, 35, 81, 0.08), 0 8px 24px rgba(10, 35, 81, 0.06);
  --shadow-hover: 0 4px 12px rgba(10, 35, 81, 0.12), 0 16px 40px rgba(10, 35, 81, 0.1);

  /* Focus ring — WCAG 2.4.7 (focus visible). Deliberately high-contrast. */
  --focus-ring: 0 0 0 3px #fff, 0 0 0 6px var(--brand-accent);
  --focus-ring-dark: 0 0 0 3px var(--navy-950), 0 0 0 6px var(--brand-highlight);

  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

/* =============================================================================
   Base — reset, typography, containers, accessibility primitives
   ========================================================================== */

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

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-sans);
  color: var(--silver-700);
  line-height: 1.6;
  background: #fff;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  color: var(--navy-900);
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: 700;
}

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

a:hover {
  text-decoration: underline;
}

img {
  max-width: 100%;
}

.container {
  max-width: 1140px;
  margin: 0 auto;
  padding: 0 24px;
}

.container-narrow {
  max-width: 820px;
  margin: 0 auto;
  padding: 0 24px;
}

/* -----------------------------------------------------------------------------
   Keyboard focus.

   The prototype had no visible focus states, which fails WCAG 2.4.7 and makes
   the site unusable by keyboard. `:focus-visible` shows the ring for keyboard
   users without putting a ring on every mouse click.
   -------------------------------------------------------------------------- */
:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: 6px;
}

/* On dark backgrounds the white inner ring would disappear. */
.hero :focus-visible,
footer :focus-visible,
.stats :focus-visible {
  box-shadow: var(--focus-ring-dark);
}

/* -----------------------------------------------------------------------------
   `hidden` means hidden.

   The browser's own `[hidden] { display: none }` sits in the user-agent
   stylesheet, so ANY author rule that sets `display` beats it — `.btn` declares
   `display: inline-flex`, which means a button with the `hidden` attribute was
   still on screen and still clickable. Found on the enquiries screen, where
   "Reopen enquiry" appeared next to "Close enquiry" on an open enquiry and
   offered an action the server would refuse.

   `!important` because the whole point is to win against a component's own
   `display`. Anything that needs to be laid out must not be marked `hidden`.
   -------------------------------------------------------------------------- */
[hidden] {
  display: none !important;
}

/* -----------------------------------------------------------------------------
   Screen-reader-only text and the skip link.
   -------------------------------------------------------------------------- */
.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;
}

.skip-link {
  position: absolute;
  left: 12px;
  top: -100px;
  z-index: 200;
  background: var(--navy-900);
  color: #fff;
  padding: 12px 20px;
  border-radius: 0 0 8px 8px;
  font-weight: 600;
  font-size: 14px;
  transition: top 0.15s ease-in-out;
}

.skip-link:focus {
  top: 0;
  text-decoration: none;
}

/* -----------------------------------------------------------------------------
   Reduced motion.

   The page uses smooth scrolling, hover transforms and a fade animation. Honour
   the user's system preference — vestibular motion disorders are a real
   accessibility concern (WCAG 2.3.3).
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Spacing helpers retained from the prototype. */
.mt-s {
  margin-top: 18px;
}
.mt-m {
  margin-top: 28px;
}
.mt-l {
  margin-top: 40px;
}

.prose p {
  margin-bottom: 14px;
}
/* `h2.h-as-h3` is a heading promoted from h3 to close a gap in the document
   outline. It must keep the size and spacing it had — see components.css. */
.prose h3,
.prose h2.h-as-h3 {
  margin: 22px 0 8px;
  font-size: 18px;
}
/* Terms of service uses ordered lists where the numbering is part of the
   meaning: the contract-formation steps and the order of precedence. */
.prose ul,
.prose ol {
  margin: 0 0 14px 20px;
}
.prose li {
  margin-bottom: 7px;
}

/* Marks unresolved legal text awaiting counsel — see docs/LEGAL_CONTENT_REVIEW.md */
.placeholder {
  color: #b45309;
  background: #fffbeb;
  padding: 0 4px;
  border-radius: 3px;
  font-style: italic;
  font-size: 0.95em;
}

/* =============================================================================
   Layout — header, navigation, hero, sections, stats, footer
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--silver-200);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 68px;
}

.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.logo:hover {
  text-decoration: none;
}

.logo-mark {
  height: 44px;
  width: auto;
  display: block;
  flex-shrink: 0;
}

.logo-name {
  font-weight: 800;
  font-size: 16px;
  color: var(--navy-900);
  letter-spacing: 0.5px;
  white-space: nowrap;
}

.nav-links {
  display: flex;
  gap: 2px;
  align-items: center;
  list-style: none;
}

.nav-links-wrap {
  min-width: 0;
}

.nav-links a {
  display: block;
  color: var(--silver-600);
  font-size: 13px;
  font-weight: 500;
  padding: 7px 9px;
  border-radius: 8px;
  transition: 0.15s;
  white-space: nowrap;
}

.nav-links a:hover {
  color: var(--navy-900);
  background: var(--silver-100);
  text-decoration: none;
}

/* aria-current="page" is the accessible source of truth; the class is cosmetic. */
.nav-links a[aria-current='page'] {
  color: var(--brand-secondary);
  background: var(--brand-light);
}

/* -----------------------------------------------------------------------------
   The `More` group — administrator-created pages.

   A disclosure, not a hover menu. There is deliberately no `:hover` rule that
   opens it: a hover menu cannot be opened from a keyboard and cannot be opened
   at all by touch. `<details open>` is the only thing that shows the list, and
   that state comes from a click, from Enter or Space, or from the script.

   The panel is absolutely positioned so opening it cannot push the header wider
   and cannot introduce a horizontal scrollbar. `right: 0` anchors it to the end
   of the row, which is where the group sits.
   -------------------------------------------------------------------------- */
.nav-more {
  position: relative;
  display: flex;
  align-items: center;
}

.nav-more-disclosure > summary {
  display: flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  list-style: none;
  color: var(--silver-600);
  font-size: 13px;
  font-weight: 500;
  padding: 7px 9px;
  border-radius: 8px;
  transition: 0.15s;
  white-space: nowrap;
}

.nav-more-disclosure > summary::-webkit-details-marker {
  display: none;
}

.nav-more-disclosure > summary:hover,
.nav-more-disclosure[open] > summary {
  color: var(--navy-900);
  background: var(--silver-100);
}

.nav-more-disclosure > summary:focus-visible {
  outline: 2px solid var(--brand-secondary);
  outline-offset: 2px;
}

.nav-more-disclosure[data-current='true'] > summary {
  color: var(--brand-secondary);
  background: var(--brand-light);
}

.nav-more-disclosure[open] > summary span {
  transform: rotate(180deg);
}

.nav-more-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  min-width: 220px;
  max-width: min(320px, calc(100vw - 32px));
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: 10px;
  box-shadow: 0 12px 30px rgba(15, 27, 45, 0.12);
  padding: 6px;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.nav-more-menu a {
  display: block;
  padding: 8px 10px;
  border-radius: 7px;
  color: var(--silver-700);
  font-size: 13.5px;
  white-space: normal;
}

.nav-more-menu a:hover {
  background: var(--silver-100);
  color: var(--navy-900);
  text-decoration: none;
}

.nav-more-menu a[aria-current='page'] {
  color: var(--brand-secondary);
  background: var(--brand-light);
}

/* Inside the mobile menu the group is part of the column, so the panel is in
   the flow rather than floating over it. */
.nav-more-mobile {
  display: block;
}

.nav-more-mobile .nav-more-disclosure > summary {
  padding: 10px 12px;
  font-size: 14.5px;
  color: var(--silver-700);
  justify-content: space-between;
}

.nav-more-mobile .nav-more-menu {
  position: static;
  border: none;
  box-shadow: none;
  padding: 2px 0 2px 12px;
  min-width: 0;
  max-width: none;
  background: transparent;
}

.nav-cta {
  display: flex;
  gap: 8px;
  align-items: center;
  /* Never squeezed out by a long link row: sign out must always be reachable. */
  flex: none;
}

.nav-cta .btn {
  padding: 9px 15px;
}

.menu-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
  color: var(--navy-900);
}

.menu-toggle svg {
  width: 26px;
  height: 26px;
  stroke: currentColor;
  display: block;
}

.mobile-menu {
  display: none;
  flex-direction: column;
  gap: 2px;
  padding: 12px 0;
  border-top: 1px solid var(--silver-200);
  list-style: none;
}

.mobile-menu a {
  display: block;
  padding: 10px 12px;
  border-radius: 8px;
  color: var(--silver-700);
  font-size: 14.5px;
}

.mobile-menu a:hover {
  background: var(--silver-100);
  text-decoration: none;
}

.mobile-menu.is-open {
  display: flex;
}

/* -----------------------------------------------------------------------------
   Sections
   -------------------------------------------------------------------------- */
.section {
  padding: 72px 0;
}
.section-sm {
  padding: 48px 0;
}
.bg-white {
  background: #fff;
}
.bg-silver {
  background: var(--silver-50);
}
.bg-light {
  background: var(--brand-light);
}

.sec-head {
  max-width: 680px;
  margin-bottom: 14px;
}
.sec-head.center {
  margin: 0 auto 14px;
  text-align: center;
}
.sec-head h2 {
  font-size: clamp(24px, 3.5vw, 34px);
}
.sec-head p {
  margin-top: 14px;
  color: var(--silver-600);
  font-size: 16px;
}

/* -----------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.hero {
  background: linear-gradient(
    135deg,
    var(--navy-950) 0%,
    var(--navy-900) 55%,
    var(--brand-secondary) 130%
  );
  color: #fff;
  position: relative;
  overflow: hidden;
}

.hero::after {
  content: '';
  position: absolute;
  right: -120px;
  top: -120px;
  width: 520px;
  height: 520px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow:
    0 0 0 80px rgba(255, 255, 255, 0.03),
    0 0 0 160px rgba(255, 255, 255, 0.02);
  pointer-events: none;
}

.hero .container,
.hero .container-narrow {
  position: relative;
  z-index: 1;
}

.hero h1 {
  color: #fff;
  font-size: clamp(30px, 5vw, 54px);
}

.hero p.lead {
  color: var(--silver-300);
  font-size: clamp(16px, 2vw, 20px);
  margin-top: 18px;
  max-width: 640px;
}

.hero-pad {
  padding: 84px 24px;
}
.hero-pad-sm {
  padding: 60px 24px;
}

.highlight {
  color: var(--brand-highlight);
}

.hero-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 44px;
}

.hero-text {
  min-width: 0;
  max-width: 660px;
}

.hero-logo img {
  width: 340px;
  max-width: 34vw;
  height: auto;
  display: block;
  background: #fff;
  border-radius: 22px;
  padding: 24px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.33);
}

.hero-note {
  color: var(--silver-400);
  font-size: 12.5px;
  margin-top: 18px;
}

.hero-actions {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 28px;
}

/* -----------------------------------------------------------------------------
   Stats bar
   -------------------------------------------------------------------------- */
.stats {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(6, 16, 31, 0.5);
}

.stats .container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  padding-top: 22px;
  padding-bottom: 22px;
}

.stat {
  text-align: center;
}
.stat b {
  display: block;
  font-size: 26px;
  color: #fff;
  font-weight: 800;
}
.stat span {
  display: block;
  font-size: 11.5px;
  color: var(--silver-400);
  margin-top: 2px;
}
.stat em {
  display: block;
  font-size: 11px;
  color: var(--silver-500);
  font-style: normal;
}

/* -----------------------------------------------------------------------------
   Grid helpers
   -------------------------------------------------------------------------- */
.grid {
  display: grid;
  gap: 22px;
}
.grid-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid-4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* -----------------------------------------------------------------------------
   Server-rendered listings

   The news and resource listings come from the database, so the number of
   cards is not known when this stylesheet is written. `auto-fill` with a
   minimum track width lets the row decide for itself, which is what the fixed
   .grid-2/3/4 helpers cannot do.

   These were used by the news listing before they existed here, which meant the
   cards stacked as plain blocks and the pager had no layout. Found while
   building the resources listing on the same shell.
   -------------------------------------------------------------------------- */
.card-grid {
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 32px;
  font-size: 13px;
  color: var(--silver-600);
}

/* -----------------------------------------------------------------------------
   CTA strip
   -------------------------------------------------------------------------- */
.cta-strip {
  background: var(--brand-light);
  border-top: 1px solid var(--silver-200);
  border-bottom: 1px solid var(--silver-200);
}

.cta-strip .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  padding-top: 36px;
  padding-bottom: 36px;
}

/* -----------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--navy-950);
  color: #c6d4e7;
  padding: clamp(52px, 6vw, 72px) 0 28px;
}

/* A stable brand column and a separate horizontal navigation grid. The
   optional CMS-managed group joins the inner grid without pushing one lonely
   column onto a new desktop row. */
.foot-grid {
  display: grid;
  grid-template-columns: minmax(260px, 1.15fr) repeat(auto-fit, minmax(150px, 1fr));
  align-items: start;
  gap: clamp(32px, 4vw, 56px);
  margin-bottom: 44px;
}

/* Current builds wrap the link groups in a semantic navigation region. Keep
   the direct-child fallback above until every long-running server image has
   been rebuilt with the shared renderer. */
.foot-grid:has(> .foot-navigation) {
  grid-template-columns: minmax(260px, 1.15fr) minmax(0, 2.85fr);
  gap: clamp(48px, 7vw, 96px);
}

.foot-navigation {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 32px clamp(28px, 4vw, 56px);
  min-width: 0;
}

.site-footer h2 {
  color: #f8fbff;
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin-bottom: 18px;
}

.foot-links {
  list-style: none;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 11px;
}

.foot-links a {
  color: #dbe7f6;
  font-size: 14px;
  line-height: 1.5;
  text-decoration-color: transparent;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 4px;
  transition:
    color 160ms ease,
    text-decoration-color 160ms ease;
}

.foot-links a:hover,
.foot-links a:focus-visible {
  color: #fff;
  text-decoration-line: underline;
  text-decoration-color: #69a7ff;
}

.foot-brand p {
  font-size: 14px;
  line-height: 1.65;
  color: #c6d4e7;
  margin-top: 16px;
  max-width: 340px;
}

.foot-logo-chip {
  display: inline-flex;
  background: #fff;
  border-radius: 12px;
  padding: 6px 8px;
  flex-shrink: 0;
}

.foot-logo-chip img {
  height: 44px;
  width: auto;
  display: block;
}

.foot-brand .foot-ai {
  font-size: 12.5px;
  color: #d6e2f0;
  background: rgba(125, 184, 240, 0.08);
  border: 1px solid rgba(125, 184, 240, 0.28);
  border-radius: 10px;
  padding: 14px 16px;
  margin-top: 20px;
  max-width: 340px;
}

.foot-bottom {
  border-top: 1px solid rgba(185, 211, 239, 0.18);
  padding-top: 24px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 12.5px;
  line-height: 1.5;
  color: #adbed4;
}

/* -----------------------------------------------------------------------------
   Responsive.

   The navigation needs ~1120px for its full desktop layout, so it collapses to
   the hamburger EARLIER than the content grids, which only need to stack below
   880px. Using one breakpoint for both caused the header to overflow.
   -------------------------------------------------------------------------- */
@media (max-width: 1120px) {
  .nav-links,
  .nav-cta .btn-ghost {
    display: none;
  }

  .menu-toggle {
    display: block;
  }
}

@media (max-width: 900px) {
  .hero-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .hero-logo {
    display: none;
  }
}

@media (max-width: 880px) {
  .grid-2,
  .grid-3,
  .grid-4,
  .stats .container,
  .cta-strip .container {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
  }

  .foot-grid,
  .foot-grid:has(> .foot-navigation) {
    grid-template-columns: minmax(0, 1fr);
    gap: 38px;
  }

  .foot-brand p,
  .foot-brand .foot-ai {
    max-width: 620px;
  }

  .foot-navigation {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .stats .container {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 480px) {
  .logo-name {
    display: none;
  }

  .nav-cta .btn {
    padding: 8px 12px;
    font-size: 13px;
  }

  /* One column at 375px keeps long legal and CMS-managed labels readable
     without pushing the page sideways. */
  .foot-navigation {
    grid-template-columns: minmax(0, 1fr);
    gap: 26px;
  }

  .foot-bottom {
    align-items: flex-start;
    flex-direction: column;
  }
}

/* =============================================================================
   Components — buttons, badges, cards, labels, notices, steps, tables, forms,
   FAQ disclosure, output rows
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-weight: 600;
  font-size: 14px;
  font-family: inherit;
  padding: 10px 18px;
  border-radius: 9px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: 0.15s;
  white-space: nowrap;
  text-decoration: none;
}

.btn:hover {
  text-decoration: none;
}

.btn:disabled,
.btn[aria-disabled='true'] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

.btn-primary {
  background: var(--brand-secondary);
  color: #fff;
  box-shadow: 0 1px 2px rgba(10, 35, 81, 0.2);
}

.btn-primary:hover:not(:disabled) {
  background: var(--navy-800);
  transform: translateY(-1px);
}

.btn-secondary {
  background: #fff;
  color: var(--navy-900);
  border-color: var(--silver-300);
}

.btn-secondary:hover:not(:disabled) {
  border-color: var(--brand-accent);
  color: var(--brand-secondary);
}

.btn-ghost {
  background: transparent;
  color: var(--silver-600);
}

.btn-ghost:hover:not(:disabled) {
  color: var(--navy-900);
  background: var(--silver-100);
}

.btn-outline-white {
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.4);
}

.btn-outline-white:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.1);
  border-color: #fff;
}

.btn-lg {
  padding: 14px 28px;
  font-size: 15px;
}

.btn-block {
  width: 100%;
}

/* -----------------------------------------------------------------------------
   Badges and pills
   -------------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  padding: 6px 13px;
  border-radius: 999px;
  background: var(--brand-light);
  color: var(--brand-secondary);
  margin-bottom: 16px;
}

.badge-light {
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.badge-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--emerald-600);
}

.pill {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 999px;
}
.pill-em {
  background: var(--emerald-100);
  color: var(--emerald-800);
}
.pill-am {
  background: var(--amber-100);
  color: var(--amber-800);
}

/* -----------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */
.card {
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  transition: 0.2s;
  padding: 26px;
}

.card-hover:hover {
  box-shadow: var(--shadow-hover);
  transform: translateY(-3px);
  border-color: var(--silver-300);
}

.card-icon {
  font-size: 30px;
  line-height: 1;
  display: block;
}

/* -----------------------------------------------------------------------------
   Classification labels — the four-category output system.
   Colour alone must never carry the meaning (WCAG 1.4.1), so the label always
   contains its text.
   -------------------------------------------------------------------------- */
.label {
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.05em;
  padding: 5px 11px;
  border-radius: 7px;
  white-space: nowrap;
}

.label-relevant {
  background: var(--label-relevant-bg);
  color: var(--label-relevant-fg);
}
.label-not {
  background: var(--label-not-bg);
  color: var(--label-not-fg);
}
.label-review {
  background: var(--label-review-bg);
  color: var(--label-review-fg);
}
.label-additional {
  background: var(--label-additional-bg);
  color: var(--label-additional-fg);
}

/* -----------------------------------------------------------------------------
   Notices
   -------------------------------------------------------------------------- */
.notice {
  border-radius: 11px;
  padding: 16px 18px;
  font-size: 13.5px;
  line-height: 1.6;
}

.notice-info {
  background: var(--brand-light);
  border: 1px solid #cfe0f5;
  color: var(--navy-800);
}

.notice-ai {
  background: var(--silver-100);
  border: 1px dashed var(--silver-400);
  color: var(--silver-600);
  font-size: 13px;
}

.notice-legal {
  background: var(--amber-50);
  border: 1px solid var(--amber-100);
  color: var(--amber-800);
}

.notice-legal strong {
  color: #7c2d12;
}

.notice-error {
  background: #fef2f2;
  border: 1px solid #fecaca;
  color: #991b1b;
}

.notice-success {
  background: var(--emerald-50);
  border: 1px solid var(--emerald-100);
  color: var(--emerald-800);
}

/* -----------------------------------------------------------------------------
   Check lists
   -------------------------------------------------------------------------- */
.check-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 13px;
  margin-top: 8px;
}

.check-list li {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  font-size: 14.5px;
  color: var(--silver-700);
}

.check-ico {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--emerald-100);
  color: var(--emerald-600);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 800;
  margin-top: 1px;
}

/* -----------------------------------------------------------------------------
   Process steps
   -------------------------------------------------------------------------- */
.step {
  display: flex;
  gap: 22px;
  align-items: flex-start;
  margin-bottom: 20px;
}

.step-num {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--navy-900);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 14px;
  box-shadow: var(--shadow-card);
}

.step-body {
  flex: 1;
  min-width: 0;
}

.step-phase {
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--brand-secondary);
}

.step-body h3,
.step-body h2.h-as-h3 {
  font-size: 18px;
  margin-top: 3px;
}

.step-detail {
  margin-top: 13px;
  background: var(--silver-50);
  border: 1px solid var(--silver-200);
  border-radius: 10px;
  padding: 13px 15px;
  font-size: 13.5px;
  color: var(--silver-600);
}

/* -----------------------------------------------------------------------------
   Tables. Wide tables scroll inside their own container so the page body never
   scrolls horizontally.
   -------------------------------------------------------------------------- */
.table-scroll {
  overflow-x: auto;
  border-radius: var(--radius);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}

thead tr {
  background: var(--navy-900);
  color: #fff;
}

th {
  text-align: left;
  padding: 14px 18px;
  font-weight: 600;
  font-size: 13px;
}

td {
  padding: 13px 18px;
  border-top: 1px solid var(--silver-100);
  color: var(--silver-700);
}

tbody tr:nth-child(even) {
  background: var(--silver-50);
}

td.aspect {
  font-weight: 700;
  color: var(--navy-800);
}

/* -----------------------------------------------------------------------------
   Illustrative output rows
   -------------------------------------------------------------------------- */
.out-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 11px 13px;
  border-radius: 9px;
  background: var(--silver-50);
  border: 1px solid var(--silver-100);
  margin-bottom: 9px;
}

.out-row .meta {
  min-width: 0;
}

.out-row .meta b {
  display: block;
  font-size: 12.5px;
  color: var(--navy-800);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.out-row .meta span {
  font-size: 11.5px;
  color: var(--silver-500);
}

/* -----------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */
.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.field.full {
  grid-column: 1 / -1;
}

.flbl {
  font-size: 13px;
  font-weight: 600;
  color: var(--navy-800);
}

.flbl .req {
  color: var(--danger);
}

.input,
select,
textarea {
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--silver-300);
  border-radius: 9px;
  font-size: 14px;
  font-family: inherit;
  color: var(--silver-800);
  background: #fff;
  transition: 0.15s;
}

.input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--brand-accent);
  box-shadow: 0 0 0 3px rgba(45, 125, 210, 0.12);
}

/* Invalid fields are marked with aria-invalid, so style from that attribute —
   the visual state and the accessible state can then never disagree. */
.input[aria-invalid='true'],
select[aria-invalid='true'],
textarea[aria-invalid='true'] {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.12);
}

textarea {
  resize: vertical;
  min-height: 96px;
}

.hint {
  font-size: 12px;
  color: var(--silver-500);
}

.field-error {
  font-size: 12px;
  color: var(--danger);
  font-weight: 500;
}

/* -----------------------------------------------------------------------------
   Headings promoted from h3 to h2.

   Six pages went straight from h1 to h3, which leaves a hole in the document
   outline: someone navigating by heading hears a level that has no parent. The
   sections were always peers, so they are h2 now.

   The LEVEL is what assistive technology announces; the SIZE is what everyone
   else sees, and that must not move. `1.17em` is the browser's default h3 size,
   which is what these headings rendered at before — the stylesheet sets colour,
   weight and spacing for headings but no per-level size. Any inline size on an
   individual heading still wins, as it did.
   -------------------------------------------------------------------------- */
.h-as-h3 {
  font-size: 1.17em;
}

.chk {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: 13px;
  color: var(--silver-600);
}

.chk input {
  margin-top: 3px;
  flex-shrink: 0;
}

/* Honeypot. Hidden from people, reachable by naive bots. `display:none` is
   avoided because some bots skip such fields; this keeps it off-screen instead. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* -----------------------------------------------------------------------------
   Contact page: details card beside the form.

   `minmax(0, …)` on both tracks rather than the bare `1fr 2fr` this replaced.
   A default `1fr` track is `minmax(auto, 1fr)`, whose floor is the content's
   own minimum width — so a long unbroken string such as an email address can
   push a track wider than its share and take the page with it.
   -------------------------------------------------------------------------- */
.contact-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: 40px;
  align-items: start;
}

@media (max-width: 880px) {
  .form-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  /* One column, and the details card first — a visitor on a phone should be
     able to call or email without scrolling past the whole form. */
  .contact-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
  }
}

/* -----------------------------------------------------------------------------
   FAQ disclosure.

   Built on <button> + hidden panel so it is keyboard operable and announced
   correctly. The prototype used a div with an onclick handler, which was
   unreachable by keyboard.
   -------------------------------------------------------------------------- */
.faq-item {
  border: 1px solid var(--silver-200);
  border-radius: 11px;
  margin-bottom: 12px;
  overflow: hidden;
  background: #fff;
}

.faq-q {
  width: 100%;
  padding: 16px 20px;
  font-weight: 600;
  font-family: inherit;
  color: var(--navy-900);
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: center;
  font-size: 14.5px;
  text-align: left;
  background: none;
  border: none;
}

.faq-q:hover {
  background: var(--silver-50);
}

.faq-q .tw {
  flex-shrink: 0;
  transition: 0.2s;
  color: var(--brand-secondary);
  font-size: 20px;
  line-height: 1;
}

.faq-q[aria-expanded='true'] .tw {
  transform: rotate(45deg);
}

.faq-a {
  padding: 0 20px 18px;
  color: var(--silver-600);
  font-size: 14px;
}

.faq-a[hidden] {
  display: none;
}

/* --------------------------------------------------- legal page helpers ----
   Used by the privacy policy. These have no prototype counterpart: that page
   was owner-supplied boilerplate carved into the site later, so the styling
   below follows the existing design system rather than copying anything.

   Both classes were referenced in the markup and defined nowhere, so the
   table of contents rendered as an unstyled bullet list and the statutory
   references were indistinguishable from body copy. */

/* Table of contents for a long legal document. `.privacy-toc` came first and is
   kept so the privacy page is untouched; `.legal-toc` is the same treatment
   under a name that does not claim to belong to one page. */
.privacy-toc,
.legal-toc {
  background: var(--silver-50);
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  padding: 22px 26px;
  margin-bottom: 32px;
}

.privacy-toc h2,
.legal-toc h2 {
  font-size: 16px;
  margin-bottom: 12px;
}

.privacy-toc ul,
.legal-toc ul {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 4px 28px;
}

.privacy-toc li,
.legal-toc li {
  font-size: 13.5px;
  line-height: 1.7;
}

.privacy-toc a,
.legal-toc a {
  color: var(--silver-700);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

.privacy-toc a:hover,
.legal-toc a:hover {
  color: var(--brand-secondary);
  border-bottom-color: var(--brand-secondary);
}

/* Legal boilerplate quotes third-party policy URLs in full, and a bare URL is
   one unbreakable token. At 390px the longest is 408px wide and pushed the
   whole page sideways — a horizontal scrollbar on the privacy policy.
   Pre-existing in the owner-supplied text; fixed here rather than by rewording,
   because that copy is authoritative (docs/DECISIONS.md D-005). */
.prose a,
.prose p,
.prose li {
  overflow-wrap: anywhere;
}

/* Statutory citations sitting under a heading. Set apart from the body copy
   they qualify, without becoming a heading themselves. */
.legal-reference {
  font-size: 12.5px;
  color: var(--silver-500);
  font-style: italic;
  margin-top: -2px;
  margin-bottom: 6px;
}

@media (max-width: 880px) {
  .privacy-toc,
  .legal-toc {
    padding: 18px 20px;
  }
  .privacy-toc ul,
  .legal-toc ul {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* =============================================================================
   Signed-in screens — portal and administrator
   Reuses the public design system; adds only what the application needs.
   ========================================================================== */

.app-main {
  min-height: 70vh;
  background: var(--silver-50);
  padding-bottom: 64px;
}

.app-head {
  background: linear-gradient(
    135deg,
    var(--navy-950) 0%,
    var(--navy-900) 70%,
    var(--brand-secondary) 140%
  );
  color: #fff;
  padding: 36px 0 30px;
}

.app-head h1 {
  color: #fff;
  font-size: clamp(24px, 3.5vw, 34px);
}

.app-lead {
  color: var(--silver-300);
  margin-top: 8px;
  max-width: 620px;
}

.app-main > .container > [data-status],
.app-main [data-status] {
  margin: 20px auto 0;
}

/* -----------------------------------------------------------------------------
   Administrator sign-in — the isolated shell on admin.ihm-cat.com

   One centred panel and nothing else. There is no site navigation, no footer,
   no registration link and no route back to the company portal on this page,
   because that host serves none of them. The panel keeps the product's own
   colours and type so an administrator can see at a glance that they are on the
   right system.

   Sized in `clamp()` and capped by `max-width`, so the same markup is a centred
   card at 1280px and a full-width panel at 375px with no horizontal overflow
   and no separate mobile layout to maintain.
   -------------------------------------------------------------------------- */
/* The shared `.app-main` reserves space under the signed-in screens' content.
   This page centres itself in the viewport instead, and that 64px would put the
   panel permanently off-centre and add a scrollbar to a page that fits. */
[data-shell='admin-auth'] .app-main {
  padding-bottom: 0;
}

.auth-panel-wrap {
  align-items: center;
  box-sizing: border-box;
  display: flex;
  justify-content: center;
  /* 68px is the header above it, so the panel is centred in what is left. */
  min-height: calc(100vh - 68px);
  padding: clamp(24px, 6vw, 72px) 20px;
}

.auth-panel {
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: 14px;
  box-shadow: var(--shadow-card);
  max-width: 460px;
  overflow: hidden;
  width: 100%;
}

.auth-panel-head {
  background: linear-gradient(
    135deg,
    var(--navy-950) 0%,
    var(--navy-900) 70%,
    var(--brand-secondary) 140%
  );
  color: #fff;
  padding: 28px clamp(20px, 5vw, 30px) 26px;
}

.auth-panel-head h1 {
  color: #fff;
  font-size: clamp(21px, 4vw, 26px);
  margin: 0;
}

.auth-lead {
  color: var(--silver-300);
  font-size: 14.5px;
  line-height: 1.55;
  margin-top: 10px;
}

.auth-panel-body {
  padding: 26px clamp(20px, 5vw, 30px) 30px;
}

/* The header is the product mark alone: no navigation, nothing to space it
   against, so it sits at the start rather than being pushed apart. */
.app-header-admin-auth .app-topbar {
  justify-content: flex-start;
}

/* Signed-in application header. The area and the person are separate facts. */
.app-topbar {
  height: 68px;
}

.app-area-name {
  border-left: 1px solid var(--silver-300);
  color: var(--navy-700);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  margin-left: 4px;
  padding: 5px 0 5px 14px;
  white-space: nowrap;
}

.app-header-nav {
  border-top: 1px solid var(--silver-200);
}

.app-nav-links {
  gap: 8px;
  padding: 7px 0 8px;
  width: 100%;
}

.app-header-admin .app-nav-links {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

.app-nav-direct > a,
.app-nav-group summary {
  border-radius: 8px;
  color: var(--silver-600);
  cursor: pointer;
  display: flex;
  font-size: 13px;
  font-weight: 600;
  justify-content: center;
  padding: 8px 12px;
  text-align: center;
  user-select: none;
}

.app-nav-direct > a:hover,
.app-nav-group summary:hover,
.app-nav-group details[open] > summary {
  background: var(--silver-100);
  color: var(--navy-900);
  text-decoration: none;
}

.app-nav-direct > a[aria-current='page'],
.app-nav-group details[data-current='true'] > summary {
  background: var(--brand-light);
  color: var(--brand-secondary);
}

.app-nav-group {
  min-width: 0;
  position: relative;
}

.app-nav-group summary {
  align-items: center;
  gap: 7px;
  list-style: none;
}

.app-nav-group summary::-webkit-details-marker {
  display: none;
}

.app-nav-group details[open] summary span {
  transform: rotate(180deg);
}

.app-nav-menu {
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: 10px;
  box-shadow: var(--shadow-card);
  left: 0;
  list-style: none;
  min-width: 220px;
  padding: 7px;
  position: absolute;
  top: calc(100% + 5px);
  z-index: 60;
}

.app-nav-menu a {
  display: block;
  padding: 9px 11px;
}

.app-nav-group:last-child .app-nav-menu {
  left: auto;
  right: 0;
}

.signed-in {
  align-items: baseline;
  color: var(--silver-500);
  display: flex;
  font-size: 12px;
  gap: 5px;
  white-space: nowrap;
}

.who {
  font-size: 13px;
  color: var(--navy-800);
  white-space: nowrap;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A long company name is 200px of unwrappable text. On a narrow screen that,
   plus the logo, Sign out and the menu button, is wider than the viewport and
   pushed the whole page sideways. The name is not needed to operate the app —
   it is confirmation of who is signed in — so it goes first. */
@media (max-width: 560px) {
  .signed-in {
    display: none;
  }
}

@media (max-width: 1120px) {
  .app-header-nav {
    display: none;
  }

  .mobile-nav-group details {
    border-bottom: 1px solid var(--silver-200);
  }

  .mobile-nav-group summary {
    justify-content: space-between;
    padding: 10px 12px;
    text-align: left;
  }

  .mobile-nav-group .app-nav-menu {
    background: var(--silver-50);
    border: 0;
    border-radius: 8px;
    box-shadow: none;
    min-width: 0;
    padding: 4px 8px 9px 18px;
    position: static;
  }
}

/* Dashboard tiles. */
.stat-card {
  text-align: center;
  padding: 20px;
}
.stat-card b {
  display: block;
  font-size: 30px;
  color: var(--navy-900);
  font-weight: 800;
}
.stat-card span {
  display: block;
  font-size: 12.5px;
  color: var(--silver-500);
  margin-top: 4px;
}

.card-title {
  font-size: 15px;
  margin-bottom: 10px;
}

/* Definition grid used on both detail screens. */
.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px 28px;
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  padding: 22px;
  box-shadow: var(--shadow-card);
}
.detail-grid dt {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--silver-500);
  font-weight: 700;
}
.detail-grid dd {
  margin-top: 4px;
  color: var(--silver-800);
  font-size: 14.5px;
}

/* Status pills. Colour never carries the meaning alone — the text is the label. */
.pill-ok {
  background: var(--emerald-100);
  color: var(--emerald-800);
}
.pill-bad {
  background: #fee2e2;
  color: #991b1b;
}
.pill-busy {
  background: var(--brand-light);
  color: var(--brand-secondary);
}
.pill-wait {
  background: var(--silver-200);
  color: var(--silver-700);
}

.btn-sm {
  padding: 5px 11px;
  font-size: 12.5px;
}

.action-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 12px;
}

/*
 * A control group that sits INSIDE an .action-row - a file input and its
 * submit button, say - and must line up with the plain buttons beside it.
 *
 * It keeps .action-row's centring and wrapping and drops the row's own
 * `margin-top`. That margin is the whole defect: on a nested row it is part
 * of the item's outer box, so `align-items: center` centres the box INCLUDING
 * the margin and the group ends up sitting half the margin lower than every
 * button next to it.
 */
.action-row-inline {
  display: inline-flex;
  gap: 8px;
  margin-top: 0;
}

td.empty {
  color: var(--silver-500);
  font-style: italic;
}

/* Released result versions. */
.version-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.version-head h3 {
  font-size: 16px;
}

.file-list {
  list-style: none;
  margin-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.file-list li {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 12px;
  background: var(--silver-50);
  border: 1px solid var(--silver-100);
  border-radius: 9px;
}
.file-name {
  font-weight: 600;
  color: var(--navy-800);
  font-size: 13.5px;
}
.checksum {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  color: var(--silver-500);
  margin-left: auto;
}

/* Human-review queue. */
.review-item {
  border: 1px solid var(--silver-200);
  border-radius: 11px;
  padding: 16px;
  margin-top: 12px;
  background: var(--silver-50);
}
.review-controls {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 10px;
}
.review-controls select {
  max-width: 220px;
}
.review-controls .input {
  flex: 1;
  min-width: 220px;
}

.radio-desc {
  display: block;
  font-size: 12.5px;
  color: var(--silver-600);
  margin-top: 2px;
}

@media (max-width: 880px) {
  .detail-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .checksum {
    margin-left: 0;
  }
}

/* ------------------------------------------------------------------ messages
   The thread is the official record of correspondence about a request. Message
   bodies are inserted with textContent, so `pre-wrap` is what preserves the
   line breaks the author typed, and `overflow-wrap` stops a long unbroken
   string from widening the page. */

.thread {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 460px;
  overflow-y: auto;
  padding: 4px 2px;
}

.msg {
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  padding: 10px 13px;
  max-width: 46em;
}

.msg-mine {
  background: var(--brand-light);
  border-color: #d6e4f6;
  align-self: flex-end;
}

.msg-theirs {
  background: #fff;
  align-self: flex-start;
}

.msg-head {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: baseline;
  margin-bottom: 4px;
}

.msg-author {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--navy-900);
}

.msg-when {
  font-size: 12px;
  color: var(--silver-500);
  white-space: nowrap;
}

.msg-body {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--silver-800);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.unread-list {
  margin: 6px 0 0;
  padding-left: 18px;
}

.unread-list li {
  margin-top: 2px;
}

/* ------------------------------------------------------- request form ------
   Choice cards, consent panel and upload box.
   Values taken verbatim from the approved prototype
   (docs/source/ihm-tool-preview-original.html); the markup differs because
   these are real controls rather than a click-through mock. */

/* A native radio wrapped in its own label, so the whole card is a click target
   and a screen reader announces the control with its description — no JS, and
   no `onclick` on a div as the prototype had. */
.radio-card {
  border: 1px solid var(--silver-300);
  border-radius: 11px;
  padding: 15px;
  cursor: pointer;
  transition: 0.15s;
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.radio-card:hover {
  border-color: var(--brand-accent);
}

/* `.sel` is applied by script to mirror the checked state, because a parent
   cannot be selected from a child in CSS everywhere we support. `:has()` does
   the same thing natively where available — both are listed so the card is
   never left looking unselected. */
.radio-card.sel,
.radio-card:has(input:checked) {
  border-color: var(--brand-secondary);
  background: var(--brand-light);
  box-shadow: 0 0 0 1px var(--brand-secondary);
}

/* The ring goes on the card, because the radio itself is only 13px and its
   focus outline is easy to miss against the border. */
.radio-card:has(input:focus-visible) {
  box-shadow: var(--focus-ring);
}

.radio-card input {
  margin-top: 3px;
}

.radio-card b {
  color: var(--navy-900);
  font-size: 14px;
}

.radio-card p {
  font-size: 12.5px;
  color: var(--silver-600);
  margin-top: 2px;
}

.consent-box {
  border: 1px solid var(--amber-100);
  background: var(--amber-50);
  border-radius: 11px;
  padding: 16px;
  margin-top: 6px;
}

/* ---------------------------------------------------------- upload box ----
   The prototype's dashed drop area, driven by a real `<label for>` instead of
   an inline onclick. The input stays in the accessibility tree and keeps
   keyboard focus; it is only visually removed, never `display: none`, which
   would make it unreachable by keyboard. */
.upload-input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.upload {
  display: block;
  border: 2px dashed var(--silver-300);
  border-radius: 12px;
  padding: 30px;
  text-align: center;
  cursor: pointer;
  transition: 0.15s;
  background: var(--silver-50);
}

.upload:hover {
  border-color: var(--brand-accent);
  background: var(--brand-light);
}

/* Focus lands on the hidden input, so the visible ring must be drawn on the
   label that follows it. Without this the box would be operable by keyboard
   with no indication of where focus is. */
.upload-input:focus-visible + .upload {
  border-color: var(--brand-accent);
  background: var(--brand-light);
  box-shadow: var(--focus-ring);
}

.upload svg {
  width: 34px;
  height: 34px;
  stroke: var(--brand-secondary);
  margin-bottom: 8px;
}

.upload-primary {
  display: block;
  font-weight: 600;
  font-size: 14px;
  color: var(--navy-900);
}

.upload-hint {
  display: block;
  font-size: 12.5px;
  color: var(--silver-600);
  margin-top: 4px;
}

/* Set once a file is chosen. Colour alone does not carry the meaning — the
   filename itself is the signal. */
.upload.has-file {
  border-style: solid;
  border-color: var(--brand-secondary);
  background: var(--brand-light);
}

@media (prefers-reduced-motion: reduce) {
  .radio-card,
  .upload {
    transition: none;
  }
}

/* -----------------------------------------------------------------------------
   Quota meter.

   A real <meter>-role element rather than a decorative bar: the numbers live in
   aria-valuenow/valuemax/valuetext and are repeated in visible text beneath it,
   so the figure is never carried by the fill width alone.
   -------------------------------------------------------------------------- */
.quota-meter {
  margin-top: 12px;
  height: 12px;
  border-radius: 999px;
  background: var(--silver-200);
  overflow: hidden;
}

.quota-meter-fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--brand-secondary);
  transition: width 200ms ease;
}

/* A full allowance is a state worth noticing, not just a longer bar. */
.quota-meter[aria-valuenow][aria-valuemax]:not([aria-valuemax='0']) .quota-meter-fill {
  background: var(--brand-secondary);
}

@media (prefers-reduced-motion: reduce) {
  .quota-meter-fill {
    transition: none;
  }
}

/* -----------------------------------------------------------------------------
   Gates (Task 9B.3)

   Cards rather than a table row, because a gate carries two independent states
   plus health evidence plus what it is currently running, and a row wide enough
   for all of it stops being readable on a phone. The grid collapses to one
   column below 720px; nothing scrolls sideways.
   -------------------------------------------------------------------------- */
.gate-family {
  margin-top: 26px;
}
.gate-family h3 {
  margin-bottom: 4px;
}

.gate-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 16px;
  margin-top: 14px;
}

.gate-card {
  padding: 18px 20px;
  /* Long codes and references must wrap rather than widen the grid track. */
  min-width: 0;
  overflow-wrap: anywhere;
}

.gate-title {
  font-size: 15.5px;
  margin: 0 0 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: baseline;
}

.gate-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  background: var(--silver-100);
  border: 1px solid var(--silver-200);
  border-radius: 6px;
  padding: 2px 7px;
}

/*
   The two badges. Health and occupancy are separate facts and are shown as
   separate badges — colour is reinforcement, never the message, because each
   badge's text IS its state.
*/
.gate-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 10px;
}

.gate-facts {
  margin-top: 12px;
}
.gate-facts dt {
  font-size: 11.5px;
}
.gate-facts dd {
  font-size: 13.5px;
}

.gate-actions {
  margin-top: 14px;
  flex-wrap: wrap;
  gap: 8px;
}

/* An amber notice for something that needs a decision but is not an error. */
.notice-warn {
  background: var(--amber-50);
  border: 1px solid var(--amber-100);
  color: var(--amber-800);
}

/* Modification 19 (P2A-09; R19-CO-19): a suspended company's portal is
   read-only. The shell puts this banner first in every page's main region and
   marks the body; every control marked `data-write-control` is then hidden.
   The server refuses those writes whatever the page shows. */
.suspended-banner {
  background: var(--amber-50);
  border-bottom: 1px solid var(--amber-100);
  color: var(--amber-800);
  padding: 12px 0;
  font-size: 14px;
  line-height: 1.5;
}

body[data-company-suspended='true'] [data-write-control] {
  display: none !important;
}

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

/* ---------------------------------------------------------------------------
   Client status timeline (Task 9C.2)

   Wraps rather than scrolls: on a 375px screen eight steps cannot sit on one
   line, and a horizontally scrolling progress indicator hides the end of its
   own sequence. Flex-wrap keeps every step visible and keeps the page free of
   horizontal overflow.
   --------------------------------------------------------------------------- */
.status-timeline {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
}

.timeline-step {
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--line, #d8dee6);
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--muted, #5b6672);
  background: transparent;
}

.timeline-done {
  border-color: var(--ok-line, #b7d9c0);
  background: var(--ok-bg, #eef7f0);
  color: var(--ok-text, #1f5130);
}

.timeline-current {
  border-color: var(--accent, #1f4f82);
  background: var(--accent-bg, #eaf1f9);
  color: var(--accent, #1f4f82);
  font-weight: 600;
}

/* A request that ended without reaching "Result ready" — Rejected, Failed,
   Cancelled or Result expired. Marked distinctly so it does not read as a step
   still to come. */
.timeline-ended {
  border-color: var(--warn-line, #e2c9a0);
  background: var(--warn-bg, #fdf5e7);
  color: var(--warn-text, #7a5312);
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Statistics dashboards (Task 10B)

   Hand-drawn inline SVG, no charting library and no CDN request — the site
   ships no third-party runtime and the privacy notice depends on that staying
   true.

   Everything below wraps rather than scrolls the page. A dashboard is the
   easiest place to introduce horizontal overflow at 375px, so every grid is
   `auto-fit` with a minimum column and every table sits in its own
   `overflow-x: auto` wrapper.
   --------------------------------------------------------------------------- */

.filter-bar fieldset {
  border: 0;
  margin: 0;
  padding: 0;
}

.filter-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 12px;
}

/* Figures. `minmax(0, …)` on the column so a long value cannot push the grid
   wider than its container. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 10px 20px;
  margin: 0 0 12px;
}

.stat-grid dt {
  font-size: 0.82rem;
  color: var(--muted, #5b6672);
  margin: 0;
}

.stat-grid dd {
  margin: 0 0 8px;
  font-size: 1.05rem;
  font-weight: 600;
  /* A long "Not available (0 of 0)" must wrap, not widen the page. */
  overflow-wrap: anywhere;
}

.statistics-dashboard .stat-grid {
  gap: 12px;
}

.statistics-dashboard .stat-metric {
  min-width: 0;
  padding: 14px 16px;
  border: 1px solid var(--line, #e3e8ee);
  border-radius: 12px;
  background: linear-gradient(145deg, #ffffff 0%, #f7f9fc 100%);
}

.statistics-dashboard .stat-metric dd {
  margin: 4px 0 0;
  color: var(--navy, #0c2c55);
  font-size: 1.2rem;
  font-variant-numeric: tabular-nums;
}

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

.stats-chart-grid > .card {
  min-width: 0;
  margin-top: 0 !important;
}

.stats-chart-card {
  overflow: hidden;
}

.definition-list dt {
  font-weight: 600;
  margin-top: 10px;
}

.definition-list dd {
  margin: 2px 0 0;
  color: var(--muted, #5b6672);
  font-size: 0.9rem;
}

.chart-wrap {
  margin: 12px 0;
  /* The SVG scales to this box; nothing inside it is a fixed pixel width. */
  max-width: 100%;
}

.chart {
  display: block;
  max-width: 100%;
  height: auto;
  overflow: visible;
}

.chart-label {
  fill: var(--muted, #5b6672);
}

.chart-value {
  fill: var(--ink, #1c2530);
  font-weight: 600;
}

.chart-bar {
  fill: var(--accent, #1f4f82);
}

/* The second series is HATCHED as well as tinted, so the two stay
   distinguishable in greyscale and to a colour-blind reader — colour is never
   the only signal. */
.chart-bar-secondary {
  stroke: var(--accent, #1f4f82);
  stroke-width: 0.3;
}

.chart-hatch-bg {
  fill: var(--ok-bg, #eef7f0);
}

.chart-hatch-line {
  fill: var(--accent, #1f4f82);
}

.chart-legend {
  margin: 4px 0 0;
  font-size: 0.85rem;
  color: var(--muted, #5b6672);
}

.chart-empty {
  margin: 12px 0;
  font-style: italic;
}

/* The two quantities have different units and therefore different scales. */
.trend-chart {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin-top: 14px;
}

.trend-panel {
  min-width: 0;
  padding: 14px 14px 6px;
  border: 1px solid var(--line, #e3e8ee);
  border-radius: 12px;
  background: #fbfcfe;
}

.trend-panel-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.trend-panel-heading h3 {
  margin: 0;
  color: var(--ink, #1c2530);
  font-size: 0.95rem;
  text-transform: capitalize;
}

.trend-panel-heading span {
  color: var(--muted, #5b6672);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}

.trend-plot {
  display: block;
  width: 100%;
  height: auto;
  margin-top: 4px;
}

.trend-grid-line {
  stroke: #dbe3ec;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.trend-axis-label {
  fill: var(--muted, #5b6672);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.trend-area {
  stroke: none;
  opacity: 0.14;
}

.trend-area-primary {
  fill: #1f5b91;
}

.trend-area-secondary {
  fill: #16736b;
}

.trend-line {
  fill: none;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.trend-line-primary,
.trend-point-primary {
  stroke: #1f5b91;
}

.trend-line-secondary,
.trend-point-secondary {
  stroke: #16736b;
}

.trend-point {
  fill: #ffffff;
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

/* Compact part-to-whole chart. The text legend carries the actual meaning. */
.donut-chart {
  display: grid;
  grid-template-columns: minmax(140px, 180px) minmax(0, 1fr);
  align-items: center;
  gap: 20px;
  min-height: 190px;
}

.donut-plot {
  display: block;
  width: 100%;
  height: auto;
  max-width: 180px;
  margin: auto;
}

.donut-track,
.donut-segment {
  fill: none;
  stroke-width: 16;
}

.donut-track {
  stroke: #e8edf3;
}

.donut-segment {
  transform: rotate(-90deg);
  transform-origin: 60px 60px;
  stroke-linecap: butt;
}

.donut-total {
  fill: var(--navy, #0c2c55);
  font-size: 19px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.donut-total-label {
  fill: var(--muted, #5b6672);
  font-size: 8px;
  text-transform: uppercase;
}

.donut-legend {
  display: grid;
  gap: 9px;
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.donut-legend li {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 0.86rem;
}

.donut-key {
  width: 10px;
  height: 10px;
  border-radius: 3px;
}

.donut-key-label {
  min-width: 0;
  overflow-wrap: anywhere;
}

.donut-legend strong {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.donut-segment-1 {
  stroke: #174f83;
}
.donut-segment-2 {
  stroke: #16736b;
}
.donut-segment-3 {
  stroke: #b86f12;
}
.donut-segment-4 {
  stroke: #a7445b;
}
.donut-segment-5 {
  stroke: #6a59a3;
}
.donut-segment-6 {
  stroke: #3d79b4;
}
.donut-segment-7 {
  stroke: #5d7d39;
}
.donut-segment-8 {
  stroke: #6b7580;
}
.donut-key-1 {
  background: #174f83;
}
.donut-key-2 {
  background: #16736b;
}
.donut-key-3 {
  background: #b86f12;
}
.donut-key-4 {
  background: #a7445b;
}
.donut-key-5 {
  background: #6a59a3;
}
.donut-key-6 {
  background: #3d79b4;
}
.donut-key-7 {
  background: #5d7d39;
}
.donut-key-8 {
  background: #6b7580;
}

/* The horizontal bar chart. HTML rather than SVG, so labels wrap instead of
   overrunning their column — see the note on barChart in charts.ts. */
.bar-chart {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.bar-row {
  display: grid;
  grid-template-columns: minmax(6rem, 11rem) 1fr auto;
  align-items: center;
  gap: 10px;
}

.bar-label {
  font-size: 0.85rem;
  /* Wraps rather than overflows; the row grows to fit. */
  overflow-wrap: anywhere;
}

.bar-track {
  display: block;
  height: 14px;
  min-width: 0;
  border-radius: 3px;
  background: var(--line, #e3e8ee);
  overflow: hidden;
}

.bar-fill {
  display: block;
  height: 100%;
  background: var(--accent, #1f4f82);
}

.bar-value {
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
  font-weight: 600;
}

/* At 375px the label column would squeeze the bar to nothing, so the row
   becomes two lines: label and value together, bar beneath. */
@media (max-width: 480px) {
  .bar-row {
    grid-template-columns: 1fr auto;
  }

  .bar-track {
    grid-column: 1 / -1;
    grid-row: 2;
  }
}

@media (max-width: 900px) {
  .stats-chart-grid,
  .trend-chart {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 520px) {
  .donut-chart {
    grid-template-columns: 1fr;
  }

  .donut-plot {
    max-width: 160px;
  }
}

.chart-data {
  margin-top: 8px;
}

.chart-data summary {
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--accent, #1f4f82);
  /* This is the only way to reach a chart's underlying numbers, so it has to
     be comfortably tappable. The text alone measured 23px tall on a 375px
     viewport; the padding brings the target to a usable size without changing
     how the line reads. */
  display: inline-block;
  padding: 8px 4px;
  min-height: 24px;
}

.progress {
  display: block;
  width: 100%;
  height: 12px;
  border-radius: 999px;
  background: var(--line, #e3e8ee);
  overflow: hidden;
  margin: 6px 0;
}

.progress-fill {
  display: block;
  height: 100%;
  background: var(--accent, #1f4f82);
}

/* The live-snapshot card is visually distinct from the historical cards, so
   nobody reads a current gate count as a period average. */
.card-snapshot {
  border-left: 4px solid var(--accent, #1f4f82);
}

/* Tables scroll inside their own box; the PAGE never scrolls sideways. */
.table-wrap {
  overflow-x: auto;
  margin-top: 8px;
}

.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;
}

@media (max-width: 480px) {
  .stat-grid {
    grid-template-columns: 1fr;
  }
  .filter-row {
    grid-template-columns: 1fr;
  }
}

/* =============================================================================
   Pages — the content-management screen.

   Two presentations of one list. The table is the desktop view; below the
   tablet breakpoint it is replaced by stacked cards carrying the same facts,
   because a ten-column table on a phone is either unreadable or a sideways
   scroll through the whole page. Neither presentation ever makes the PAGE
   scroll horizontally: wide content scrolls inside its own box.
   ========================================================================== */

.kpi-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.kpi-card {
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  padding: 16px 18px;
  box-shadow: var(--shadow-card);
  min-width: 0;
}

.kpi-label {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--silver-600);
  font-weight: 600;
}

.kpi-value {
  font-size: 30px;
  font-weight: 800;
  color: var(--navy-900);
  line-height: 1.15;
  margin: 4px 0 2px;
}

.kpi-note {
  font-size: 12px;
  color: var(--silver-600);
}

.cms-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr) auto;
  gap: 12px;
  align-items: end;
  margin-bottom: 8px;
}

.cms-toolbar .field {
  margin: 0;
  min-width: 0;
}

.cms-toolbar-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* The table scrolls inside its own box; the page body never scrolls sideways. */
.cms-table-wrap {
  overflow-x: auto;
  margin-top: 12px;
  border-radius: var(--radius);
}

.cms-table {
  min-width: 100%;
}

.cms-table td {
  vertical-align: top;
}

.cms-page-name {
  display: block;
  font-weight: 600;
  color: var(--navy-900);
}

.cms-page-template {
  display: block;
  font-size: 12px;
  color: var(--silver-600);
}

.action-row-tight {
  gap: 6px;
  flex-wrap: wrap;
}

/* Cards replace the table below the tablet breakpoint. */
.cms-card-list {
  display: none;
  flex-direction: column;
  gap: 12px;
  margin-top: 12px;
}

.cms-card {
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  padding: 14px 16px;
  box-shadow: var(--shadow-card);
}

.cms-card-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 10px;
}

.cms-card-head h3 {
  font-size: 15px;
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.cms-card-facts {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: 4px 12px;
  font-size: 13px;
  margin-bottom: 12px;
}

.cms-card-facts dt {
  color: var(--silver-600);
}

.cms-card-facts dd {
  color: var(--navy-900);
  overflow-wrap: anywhere;
}

/* ---- detail: editing column and publication panel ---------------------- */

.cms-detail {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 28px;
  align-items: start;
  margin-top: 16px;
}

.cms-main {
  min-width: 0;
}

.cms-side {
  min-width: 0;
  position: sticky;
  top: 16px;
}

.cms-panel {
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow-card);
  max-height: calc(100vh - 32px);
  overflow-y: auto;
}

.cms-panel h3 {
  margin-top: 0;
}

.cms-panel h4 {
  margin-top: 20px;
  padding-top: 14px;
  border-top: 1px solid var(--silver-200);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--silver-600);
}

.cms-editor-actions {
  margin-top: 20px;
}

.cms-history-heading {
  margin-top: 32px;
}

.cms-preview-frame {
  width: 100%;
  height: 70vh;
  border: 1px solid var(--silver-300);
  background: #fff;
  max-width: 100%;
}

/* ---- the structured block editor --------------------------------------- */

.block-card {
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  background: #fff;
  margin-bottom: 12px;
  overflow: hidden;
}

.block-card-invalid {
  border-color: #b3261e;
  box-shadow: 0 0 0 2px rgba(179, 38, 30, 0.12);
}

.block-card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 12px;
  background: var(--silver-100);
  border-bottom: 1px solid var(--silver-200);
}

.block-toggle {
  display: flex;
  align-items: baseline;
  gap: 10px;
  background: none;
  border: none;
  font-family: inherit;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: 7px;
  text-align: left;
  min-width: 0;
}

.block-toggle:focus-visible {
  outline: 2px solid var(--brand-secondary);
  outline-offset: 2px;
}

.block-type {
  font-weight: 700;
  color: var(--navy-900);
  font-size: 14px;
}

.block-position {
  font-size: 12px;
  color: var(--silver-600);
}

.block-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.block-body {
  padding: 14px 12px 4px;
}

.repeater {
  border: 1px solid var(--silver-200);
  border-radius: var(--radius);
  padding: 12px;
  margin-top: 8px;
}

.repeater-item + .repeater-item {
  border-top: 1px solid var(--silver-200);
  padding-top: 12px;
  margin-top: 12px;
}

.repeater-label {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--silver-600);
}

.add-block {
  position: relative;
}

.add-block-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  min-width: 220px;
  background: #fff;
  border: 1px solid var(--silver-200);
  border-radius: 10px;
  box-shadow: 0 12px 30px rgba(15, 27, 45, 0.14);
  padding: 6px;
  list-style: none;
}

.add-block-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  font-family: inherit;
  font-size: 13.5px;
  padding: 9px 10px;
  border-radius: 7px;
  cursor: pointer;
  color: var(--navy-900);
}

.add-block-item:hover,
.add-block-item:focus-visible {
  background: var(--silver-100);
}

/* ---- the confirmation dialog ------------------------------------------- */

.btn-danger {
  background: #b3261e;
  color: #fff;
  border-color: #8f1d17;
}

.btn-danger:hover:not(:disabled) {
  background: #8f1d17;
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(10, 22, 40, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  overflow-y: auto;
}

.modal {
  background: #fff;
  border-radius: 14px;
  padding: 24px;
  width: min(560px, 100%);
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  box-shadow: 0 24px 60px rgba(10, 22, 40, 0.35);
}

.modal h2 {
  margin-top: 0;
  font-size: 19px;
}

.modal p {
  font-size: 14px;
  color: var(--silver-700);
  margin-bottom: 10px;
}

.modal-subject {
  font-size: 13.5px;
  background: var(--silver-100);
  border: 1px solid var(--silver-200);
  border-radius: 8px;
  padding: 10px 12px;
  color: var(--navy-900);
  overflow-wrap: anywhere;
}

.modal-form {
  margin-top: 12px;
}

.modal-actions {
  margin-top: 18px;
}

.slug-preview {
  display: block;
  font-size: 14px;
  background: var(--silver-100);
  border: 1px solid var(--silver-200);
  border-radius: 8px;
  padding: 9px 12px;
  color: var(--navy-900);
}

/* The page behind a modal neither scrolls nor can be reached. */
body[data-modal-open] {
  overflow: hidden;
}

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

@media (max-width: 1100px) {
  .cms-detail {
    grid-template-columns: minmax(0, 1fr);
  }

  .cms-side {
    position: static;
  }

  .cms-panel {
    max-height: none;
  }
}

@media (max-width: 880px) {
  .kpi-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .cms-toolbar {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Below the tablet breakpoint the table is replaced, not squeezed. */
  .cms-table-wrap {
    display: none;
  }

  .cms-card-list {
    display: flex;
  }
}

@media (max-width: 480px) {
  .kpi-row {
    grid-template-columns: minmax(0, 1fr);
  }

  .cms-card-facts {
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
  }

  .cms-card-facts dd {
    margin-bottom: 6px;
  }

  .modal {
    padding: 18px;
  }
}

/* ===========================================================================
   Revision comparison — Content → Legal documents
   ---------------------------------------------------------------------------
   MEANING IS NOT CARRIED BY COLOUR.

   Four independent signals mark every line, and any one of them is enough:

     1. semantics   — <ins> and <del>, which assistive technology announces
     2. a marker    — a visible "+" or "−" in the gutter
     3. a label     — .sr-only text ("Added:", "Removed:") for screen readers
     4. a border    — a thick left rule on changed lines, thin on unchanged

   Colour is the fifth and the least of them, so the panel is still readable in
   monochrome, under any colour-vision deficiency, and when a forced-colours
   mode discards the palette entirely.

   NO HORIZONTAL PAGE OVERFLOW.

   Long lines WRAP rather than extend the page — a policy body contains prose,
   not code, and a document that pushes the viewport sideways on a phone is
   unusable. `.diff-scroll` keeps `overflow-x: auto` as a safety net for an
   unbreakable token, so the scroll is confined to the panel and never the page.
   =========================================================================== */

.diff-scroll {
  overflow-x: auto;
  max-width: 100%;
  border: 1px solid var(--line, #d9dee5);
  border-radius: 6px;
  background: #fff;
}

.diff {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.55;
}

.diff-line {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr);
  gap: 8px;
  padding: 1px 10px 1px 0;
  border-left: 3px solid transparent;
}

.diff-mark {
  text-align: center;
  user-select: none;
  opacity: 0.75;
}

.diff-text {
  display: block;
  min-width: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  text-decoration: none;
}

.diff-line-add {
  border-left-color: #1a7f37;
  background: #e9f5ec;
}

.diff-line-remove {
  border-left-color: #b42318;
  background: #fdeceb;
}

.diff-line-same {
  border-left-color: #e6e9ee;
  color: #56606e;
}

/* An empty line still needs height, or a removed blank line vanishes. */
.diff-text:empty::after {
  content: ' ';
  white-space: pre;
}

@media (max-width: 480px) {
  .diff {
    font-size: 12px;
  }

  .diff-line {
    grid-template-columns: 1.25rem minmax(0, 1fr);
    gap: 6px;
  }
}

/* ===========================================================================
   .table-scroll — the class the markup already asked for
   ---------------------------------------------------------------------------
   Seventeen pages wrap a wide table in `<div class="table-scroll">`, and until
   now that class had NO RULE ANYWHERE. The markup expressed the intent and the
   stylesheet never implemented it, so every one of those tables pushed the
   whole document sideways on a narrow screen: at 375px the admin content page
   measured 465px of scrollWidth, and the horizontal scroll was on the page
   rather than on the table.

   It was invisible on a desktop, which is where it was looked at.

   `min-width: 0` is the load-bearing half. A grid or flex child defaults to
   `min-width: auto`, meaning it refuses to shrink below its content — so
   `overflow-x: auto` alone would have done nothing here: the box would simply
   have grown to the width of the table and taken the page with it.
   =========================================================================== */

.table-scroll {
  overflow-x: auto;
  max-width: 100%;
  min-width: 0;
  -webkit-overflow-scrolling: touch;
  /* A positioning context, and it is not cosmetic.
     `.sr-only` is absolutely positioned. Inside a `<th>` with no positioned
     ancestor it resolves against the initial containing block, so it escapes
     this scroller and is laid out at the far edge of the FULL table width —
     which kept `documentElement.scrollWidth` at 465px on a 375px viewport even
     after the table itself was contained. `body.scrollWidth` read 375 the whole
     time, which is why it looked fixed and was not. */
  position: relative;
}

/* Contain the screen-reader labels.
   `.sr-only` is absolutely positioned; without a positioned ancestor it
   resolves against the initial containing block and can sit at the far edge of
   an already-too-wide page, which is how it showed up in the overflow audit. */
.diff-line {
  position: relative;
}

/* ===========================================================================
   Long unbreakable strings inside rendered legal documents
   ---------------------------------------------------------------------------
   Section 21 of the approved privacy notice cites the Digital Services
   Coordinator by full URL — 89 characters with no space in it. At 375px that
   single token measured 720px wide and pushed the whole page sideways, while
   every element's bounding box stayed inside the viewport: it is the inline
   content that overflows, not a box, which is why an element-rect audit finds
   nothing to blame.

   `anywhere` rather than `break-word`: it also lets the browser count the long
   token when sizing the line box, so a table cell containing a URL shrinks
   instead of forcing its column wide.
   =========================================================================== */

.prose {
  overflow-wrap: anywhere;
}

/* The document fingerprint is 64 unbreakable hex characters.
   It sits outside `.prose` — it is chrome, not document text — so the rule
   above did not reach it, and at 375px it measured 391px inside a 327px box
   and was the last thing pushing the page sideways.

   The privacy page no longer shows a fingerprint, so `[data-privacy-hash]` is
   gone from this selector; the legal pages still do. */
[data-legal-hash] {
  overflow-wrap: anywhere;
}

/* Notification bell in either signed-in header, and its unread badge. The
   administrator and company centres share this styling; nothing here is scoped
   to one area. */
.notify-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 36px;
  height: 36px;
  color: inherit;
}
.notify-bell svg {
  width: 22px;
  height: 22px;
  stroke: currentColor;
}
.notify-count {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--danger, #b42318);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}
.notify-toast {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 60;
  padding: 10px 14px;
  border-radius: var(--radius, 8px);
  background: var(--ink, #111);
  color: #fff;
  font-size: 14px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
}
.notify-toast a {
  color: #fff;
  text-decoration: underline;
}
tr.notify-unread td:first-child {
  font-weight: 600;
}
.pill-err {
  background: #fde8e6;
  color: #8a1c14;
}

/* -----------------------------------------------------------------------------
   Dataset panel (Modification 8) - the imported workbook rows
   -------------------------------------------------------------------------- */
.dataset-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 16px;
}
.dataset-toolbar .input {
  flex: 1 1 240px;
  max-width: 420px;
}
.dataset-toolbar select {
  width: auto;
}
.dataset-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}
.dataset-pager {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 12px;
}
.dataset-pager select {
  width: auto;
}
.dataset-table td {
  vertical-align: top;
}
.dataset-table .input-sm {
  padding: 6px 8px;
  min-width: 200px;
  font-size: 13px;
}
.dataset-row-deleted td {
  color: var(--silver-600, #6b7280);
}
.dataset-deleted {
  text-decoration: line-through;
}
.dataset-row-invalid td {
  background: #fff7f5;
}
.dataset-error {
  color: #8a1c14;
  font-size: 13px;
}

/* ---------------------------------------------------------------------------
   Gate configuration form (Modification 9)

   `.field-error` already exists in components.css and is not restated here —
   two definitions of one class is how they drift. What is new is the pair that
   makes the form's rules VISIBLE before a save rather than after it: the
   invalid outline that accompanies `aria-invalid`, and the disabled styling on
   the path and family fields when this gate's state would refuse them.

   In both cases the colour is reinforcement only. `aria-invalid` and the error
   text carry the meaning, and a disabled control is announced as disabled.
   -------------------------------------------------------------------------- */
[data-gate-config-form] [aria-invalid='true'] {
  border-color: var(--danger);
}

[data-gate-config-form] select:disabled,
[data-gate-config-form] input:disabled,
[data-gate-config-form] textarea:disabled {
  background: var(--silver-100);
  color: var(--silver-700);
  cursor: not-allowed;
}

/* =============================================================================
   Administrator workspaces — banner, tabs, panel, phase track, side panel

   The six shared primitives of Modification 12. Every rule here is component
   CSS: no screen owns anything in this file, and nothing in it names a
   request, a gate or a company.

   IMPORTED LAST, DELIBERATELY.
   `buildStyles()` concatenates `main.css`'s @imports in listed order, so this
   sheet must be the last one. Imported anywhere else it would lose specificity
   ties to `app.css` and the failure would show up as "the tab looks wrong on
   one page".

   THE SINGLE SCROLL SURFACE
   The DOCUMENT scrolls. No `.ws-panel` rule sets `overflow-y`, no grid track
   is anything but `minmax(0, …)`, and the tab strip never makes the PAGE
   scroll sideways — it wraps on a wide screen and scrolls inside itself on a
   narrow one. A tabbed layout is the classic place a second scrollbar appears,
   because "one panel visible" invites "and it fills the viewport".

   COLOUR NEVER CARRIES THE MEANING ALONE
   The selected tab has weight and an underline as well as colour; every phase
   state has its own marker shape and border weight as well as its own colour,
   and its state is in text.

   BREAKPOINTS
   Only the four the site already uses — 1120, 1100, 880 and 480. Five is
   already a lot to keep coherent, and a sixth would have to be honoured by
   every screen that adopts these components.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Workspace head — the banner and the tab strip, together

   "Keep the applicable workspace banner and horizontal tab bar visible while
   the selected panel is being used on desktop" (spec `:1350`), restated as an
   acceptance test at `:1433`. Sticky, not fixed, so the two of them scroll off
   nothing and the DOCUMENT remains the only scroll surface — the alternative,
   a fixed head over a panel with its own scroller, is the double scrolling
   `:1352` forbids.

   Two conditions, both from 05 §5.6: it paints an opaque background token,
   because it sits over content; and it goes `position: static` no later than
   1120px, where the desktop navigation row is already gone and a sticky head
   plus a tab strip would eat most of a phone's viewport.

   Below the sticky header (`z-index: 50`), so the site chrome still wins.
   -------------------------------------------------------------------------- */
.ws-head {
  position: sticky;
  top: 0;
  z-index: 40;
  padding-top: 20px;
  background: var(--silver-50);
}

/* -----------------------------------------------------------------------------
   Summary banner

   The facts that stay true on every tab: the record's identifier and up to
   four labelled cells. There is no button in here — owner decision OD-11 —
   because a control visible from every tab is the duplication the
   canonical-ownership rule forbids, in a stronger form.
   -------------------------------------------------------------------------- */
.ws-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 28px;
  padding: 18px 24px;
  border-radius: var(--radius);
  background: linear-gradient(
    135deg,
    var(--navy-950) 0%,
    var(--navy-900) 70%,
    var(--brand-secondary) 160%
  );
  color: #fff;
}

.ws-banner-id {
  margin: 0;
  min-width: 0;
  font-size: clamp(20px, 2.6vw, 30px);
  font-weight: 700;
  line-height: 1.15;
  /* A long reference wraps rather than widening the page. */
  overflow-wrap: anywhere;
}

.ws-banner-facts {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  grid-template-rows: auto auto;
  gap: 3px 24px;
  margin: 0;
  flex: 1 1 340px;
  min-width: 0;
}

/* One rule per cell, including the first, which separates the cells from the
   identifier. */
.ws-banner-facts > dt,
.ws-banner-facts > dd {
  min-width: 0;
  padding-left: 22px;
  border-left: 1px solid rgba(255, 255, 255, 0.18);
}

.ws-banner-label {
  margin: 0;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--silver-300);
}

.ws-banner-value {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: #fff;
  overflow-wrap: anywhere;
}

/* A cell's second line (Modification 19, D-10): since when the Next step has
   stood, or how many rows were not accepted. Same contrast as the label. */
.ws-banner-note {
  display: block;
  margin-top: 2px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--silver-300);
}

/* -----------------------------------------------------------------------------
   Tab list

   On a wide screen the strip wraps rather than scrolling — a horizontally
   scrolling indicator hides the end of its own sequence, which is the same
   reasoning the client status timeline records for itself.

   On a narrow screen the specification is explicit and governs: "On narrow
   screens, tabs become an accessible overflow menu or horizontally scrollable
   tab list with the current step kept visible" (spec `:1417`). So below 880px
   it becomes the scrollable list, with `overflow-x` ON THE STRIP and never on
   an ancestor, so the PAGE still never scrolls sideways. `workspace-tabs.ts`
   keeps the selected tab in view.
   -------------------------------------------------------------------------- */
.ws-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 6px;
  margin: 22px 0 0;
  padding: 0;
  border-bottom: 1px solid var(--silver-200);
}

.ws-tab {
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 3px solid transparent;
  border-radius: 8px 8px 0 0;
  /* Comfortably above the 24px minimum the chart disclosure records, and at
     the 44px normally asked of a screen's primary navigation. */
  min-height: 44px;
  padding: 12px 14px;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  color: var(--silver-600);
  cursor: pointer;
}

.ws-tab:hover {
  color: var(--navy-800);
  background: var(--silver-100);
}

/* Weight and an underline, not only colour. */
.ws-tab[aria-selected='true'] {
  color: var(--brand-secondary);
  border-bottom-color: var(--brand-secondary);
  font-weight: 700;
}

/* -----------------------------------------------------------------------------
   Panel

   Stays in normal flow. No `overflow-y`, no `height: 100vh`, no nested
   scroller: the document scrolls, and nothing inside the workspace has a
   scrollbar of its own.
   -------------------------------------------------------------------------- */
.ws-panel {
  margin-top: 24px;
}

/* One live region per panel, beside the controls that write to it — owner
   decision OD-12. `setStatus` hides it when the message is empty, and a hidden
   region announces nothing, so an empty region between actions is correct.

   Selected on the ATTRIBUTE, not on the class: `setStatus` ASSIGNS
   `className = 'notice notice-<kind>'`, so a class-based rule would apply
   until the first message and then silently stop. */
[data-panel-status] {
  margin: 0 0 16px;
}

/* -----------------------------------------------------------------------------
   Phase progress track

   ONE track, the active one, inside the selected panel. Completed is a filled
   disc with a check, current a heavier ring with a centre dot, blocked and
   ended their own marks — so the states differ in shape and border weight
   before any colour is involved, and each carries its state as text.
   -------------------------------------------------------------------------- */
.ws-track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  margin: 0 0 22px;
  padding: 0 0 20px;
  border-bottom: 1px solid var(--silver-200);
  list-style: none;
}

.ws-track-step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 0 6px;
  text-align: center;
}

/* The connector to the next step, drawn behind the markers. */
.ws-track-step::after {
  content: '';
  position: absolute;
  top: 13px;
  left: 50%;
  width: 100%;
  height: 2px;
  /* --silver-300 measures 1.5:1 on white, below the 3:1 WCAG 1.4.11 asks of
     a non-text indicator. --silver-400 clears it. */
  background: var(--silver-400);
}

.ws-track-step:last-child::after {
  display: none;
}

.ws-track-step-done::after {
  background: var(--emerald-600);
}

.ws-track-mark {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  /* Same 3:1 reasoning as the connector: the marker is the state indicator,
     so its ring has to be visible, not merely tasteful. */
  border: 2px solid var(--silver-500);
  border-radius: 999px;
  background: #fff;
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
}

.ws-track-step-done .ws-track-mark {
  border-color: var(--emerald-600);
  background: var(--emerald-600);
  color: #fff;
}

.ws-track-step-current .ws-track-mark {
  border-width: 4px;
  border-color: var(--brand-secondary);
  color: var(--brand-secondary);
  font-size: 10px;
}

.ws-track-step-blocked .ws-track-mark {
  border-width: 4px;
  border-color: var(--amber-600);
  background: var(--amber-50);
  color: var(--amber-800);
}

.ws-track-step-ended .ws-track-mark {
  border-width: 4px;
  border-color: var(--danger);
  color: var(--danger);
}

.ws-track-step-future .ws-track-mark {
  border-style: dashed;
}

.ws-track-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--silver-500);
  overflow-wrap: anywhere;
}

.ws-track-step-done .ws-track-label {
  color: var(--emerald-800);
}

.ws-track-step-current .ws-track-label {
  color: var(--brand-secondary);
}

.ws-track-step-blocked .ws-track-label {
  color: var(--amber-800);
}

.ws-track-step-ended .ws-track-label {
  color: var(--danger);
}

.ws-track-time {
  font-size: 11.5px;
  color: var(--silver-500);
}

/* Server-authored, shown verbatim. */
.ws-track-blocker {
  font-size: 12px;
  font-weight: 500;
  color: var(--amber-800);
  overflow-wrap: anywhere;
}

/* -----------------------------------------------------------------------------
   Side panel

   NON-MODAL on desktop — owner decision OD-13. It does not cover the record,
   it does not lock the page behind it, and it carries no backdrop, because
   keeping the record readable beside the fields is the whole reason those
   actions were classified as side-panel work rather than as modals.

   It scrolls internally when its own content is longer than the viewport. That
   is the overlay's own surface, not a second scroller inside the workspace:
   the panel is `position: fixed` and is not part of the panel flow the
   single-scroll rule governs.

   `z-index` sits BELOW `.modal-backdrop` (100). The two are never open at
   once — `openSidePanel` refuses while the dialog is open — and if that ever
   failed, the dialog would still be the thing on top.
   -------------------------------------------------------------------------- */
.ws-side-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: min(420px, 100%);
  padding: 22px 24px;
  background: #fff;
  border-left: 1px solid var(--silver-200);
  box-shadow: -18px 0 48px rgba(10, 22, 40, 0.18);
  overflow-y: auto;
}

.ws-side-panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.ws-side-panel-title {
  margin: 0;
  font-size: 19px;
}

.ws-side-panel-close {
  appearance: none;
  flex: none;
  width: 36px;
  height: 36px;
  border: 1px solid var(--silver-200);
  border-radius: 9px;
  background: #fff;
  color: var(--silver-600);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

.ws-side-panel-close:hover {
  background: var(--silver-100);
  color: var(--navy-800);
}

.ws-side-panel-lead {
  margin: 0;
  font-size: 14px;
  color: var(--silver-700);
}

.ws-side-panel-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

.ws-side-panel-actions {
  margin-top: auto;
  padding-top: 6px;
}

/* -----------------------------------------------------------------------------
   Messages panel — Modification 19 (P1-27; R19-LC-18)

   The request's thread, on both request pages, beside every tab. It wears the
   side panel's surface and its narrow-screen sheet (the rules above and below)
   but is its own component (`messages-panel.ts`): it stays open across tabs.
   It sits BELOW the shared side panel (90) and the dialog (100), so a form or
   a confirmation opened from the record is always the thing on top.

   `.ws-side-panel` sets `display: flex`, which would override the `hidden`
   attribute's own rule, so the closed state is restated here.

   The handle is fixed to the viewport's corner so it is reachable from every
   tab and at any scroll; its place in the document keeps it in the tab order
   right after the record's head.
   -------------------------------------------------------------------------- */
.ws-msg-panel {
  z-index: 85;
}

.ws-msg-panel[hidden] {
  display: none;
}

.ws-msg-handle {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 80;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 8px 24px rgba(10, 22, 40, 0.18);
}

.ws-msg-count[hidden] {
  display: none;
}

.ws-msg-panel .thread {
  flex: 1 1 auto;
}

/* The page behind the messages SHEET neither scrolls nor can be reached; on a
   desktop the panel is non-modal and the record stays scrollable. */
body[data-messages-sheet-open] {
  overflow: hidden;
}

/* -----------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

/* The head un-sticks before the desktop navigation row disappears: on a
   narrow screen a sticky banner plus a tab strip consumes most of the
   viewport, which is the opposite of the problem this modification is for. */
@media (max-width: 1120px) {
  .ws-head {
    position: static;
    padding-top: 0;
  }
}

@media (max-width: 880px) {
  /* Spec `:1417`: a horizontally scrollable tab list with the current step
     kept visible. `overflow-x` sits on the STRIP, never on an ancestor, so the
     page itself still cannot scroll sideways, and `workspace-tabs.ts` scrolls
     the selected tab back into view.

     A scroll container clips its descendants at its PADDING box, and the focus
     ring is drawn 6px outside a control — so the padding is what stops the
     ring being cut off, and the negative margin puts the strip back where it
     was. The strip's own baseline goes with it: at this width the selected
     tab's underline is the line, and one line is enough. */
  .ws-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: thin;
    border-bottom: 0;
    padding: 6px;
    margin: 16px -6px 0;
  }

  .ws-tab {
    flex: 0 0 auto;
  }

  .ws-banner-facts {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    grid-template-rows: none;
    grid-template-columns: minmax(0, auto) minmax(0, 1fr);
    gap: 6px 14px;
  }

  .ws-banner-facts > dt,
  .ws-banner-facts > dd {
    padding-left: 0;
    border-left: 0;
  }

  /* Stacked, so no connector dangles at the end of a wrapped row. */
  .ws-track {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    gap: 12px;
  }

  .ws-track-step {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    padding: 0;
    text-align: left;
  }

  .ws-track-step::after {
    display: none;
  }

  /* The accessible full-screen sheet the specification permits on a narrow
     screen — owner decision OD-13, which took option A with option C's
     narrow-screen behaviour. It covers the viewport, so here it IS modal:
     `side-panel.ts` adds `aria-modal`, traps Tab and sets `data-sheet-open`
     while this rule is the one in force. */
  .ws-side-panel {
    inset: 0;
    width: 100%;
    border-left: 0;
    box-shadow: none;
  }
}

/* The page behind the SHEET neither scrolls nor can be reached — the same
   mechanism `body[data-modal-open]` already uses for the dialog, under its own
   flag so the two overlays stay distinguishable. There is deliberately no such
   rule for the desktop side panel: keeping the record readable and scrollable
   beside the fields is the whole point of the non-modal choice. */
body[data-sheet-open] {
  overflow: hidden;
}

@media (max-width: 480px) {
  .ws-tab {
    min-height: 44px;
    padding: 10px 12px;
    font-size: 14px;
  }

  .ws-side-panel {
    padding: 18px 16px;
  }
}

/* -----------------------------------------------------------------------------
   Spacing utilities
   -------------------------------------------------------------------------- */

/* Seven single-purpose classes, added under a COORDINATOR-OWNED TASK 10
   CORRECTION so workspace markup can express vertical rhythm, and one form
   width, without inline `style` attributes.

   WHY LITERAL PIXELS RATHER THAN TOKENS. There is no spacing scale to reuse.
   `tokens.css` defines colour, radius, shadow, focus-ring and font tokens and
   nothing else, and no `--space-*` custom property exists anywhere under
   `apps/web/src/styles`. The only 14px token in the repository is `--radius`,
   and spending a corner radius on a margin would be a false equivalence: it
   would couple two values that have no reason to move together, so the next
   person to change the radius would silently move a margin.

   Each class sets EXACTLY ONE property. None sets a colour, a layout mode, a
   position, or a dimension other than the single max-width, and none appears
   inside a media query. That is what makes them composable onto any element
   without changing how a primitive behaves — and it is asserted, not just
   intended, in `workspace-primitives.integration.spec.ts`. */

.ws-card-stack {
  margin-top: 24px;
}

/* Modification 19 (P1-23; R19-LC-10): the Admin controls panel, between the
   head and the tab panels, on every tab. Its status line answers its own acts;
   the workflow change folds away under its summary. */
.ws-admin-controls {
  margin: 16px 0 24px;
}

[data-admin-controls-status] {
  margin: 0 0 12px;
}

.ws-admin-workflow {
  margin-top: 16px;
}

.ws-field-gap {
  margin-top: 16px;
}

.ws-notice-gap {
  margin-top: 14px;
}

.ws-content-gap {
  margin-top: 12px;
}

.ws-control-gap {
  margin-top: 10px;
}

.ws-lead-gap {
  margin-bottom: 12px;
}

/* The only dimension here, and deliberately a MAXIMUM: it narrows a form on a
   wide screen and is inert below 560px, so it introduces no breakpoint and
   gives the responsive rules above nothing to disagree with. */
.ws-form-narrow {
  max-width: 560px;
}
