:root {
  /* JMS Metaltec brand palette — swap these to re-skin the app without touching markup */
  --brand-navy: #122445;
  --brand-light-blue: #2f86d6;
  --brand-orange: #fc702e;
  /* The brand orange as a *number* on white is 2.80:1, just under the 3:1 that large text
     needs. This is the same hue a shade deeper, for the KPI tile counts that would
     otherwise fall short. Not for badges - their 12px text needs 4.5:1, which is a bigger
     change to the palette than a shade. */
  --brand-orange-deep: #ee6a1e;
  --brand-bg: #f5f5f5;
  --brand-surface: #ffffff;
  --brand-text: #181818;
  --brand-text-muted: #606e87;
  --brand-border: #e5e7eb;
  --brand-radius: 10px;
  --brand-font: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* Chart fills, named for what they mean rather than for the colour they are - the API sends
     'critical' or 'ok' per series and charts.js resolves it here, so the dashboard's colours
     are these seven and nothing is picked in JavaScript. They are the same seven the badges
     and KPI tiles ramp through, so a Major NC finding is the same red wherever it appears. */
  --chart-critical: #c81e2c;
  --chart-high: #e63946;
  --chart-warning: var(--brand-orange-deep);
  --chart-ok: #1e8a5f;
  --chart-info: var(--brand-light-blue);
  --chart-navy: var(--brand-navy);
  --chart-neutral: var(--brand-text-muted);
}

* {
  box-sizing: border-box;
}

/* The hidden attribute has to win. The browser's own rule for it is display:none, but that is a
   UA-stylesheet rule and any author rule with a display beats it - so `.btn { display: inline-flex }`
   silently un-hides a button that JavaScript set hidden on, which is how an "Authorise resumption"
   button once showed to somebody with no authority to press it. !important because the whole point
   is to outrank whatever the element's own class says about display.

   This supersedes the per-class guards this file used to carry one at a time. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--brand-bg);
  font-family: var(--brand-font);
  color: var(--brand-text);
}

/* Centers a single card in the viewport — used by standalone pages like login */
.center-viewport {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}

.auth-card {
  width: 100%;
  max-width: 380px;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  overflow: hidden;
}

.auth-card__header {
  background: var(--brand-navy);
  padding: 2rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.auth-card__header img {
  max-width: 160px;
  height: auto;
  display: block;
}

.auth-card__body {
  padding: 2rem;
  text-align: center;
}

.card-title {
  margin: 0 0 1.75rem;
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--brand-text);
}

.card-subtitle {
  margin: 0 0 1.75rem;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--brand-text-muted);
}

/* What the sign-in card says about the build. Added by alpha.js, which also closes the gap the
   subtitle would otherwise leave above it. */
.card-subtitle:has(+ .auth-card__alpha) {
  margin-bottom: 0.6rem;
}

.auth-card__alpha {
  margin: 0 0 1.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid rgba(191, 122, 8, 0.35);
  border-radius: var(--brand-radius);
  background: rgba(245, 176, 65, 0.14);
  font-size: 0.8rem;
  line-height: 1.45;
  color: #8a5a06;
}

.auth-button {
  width: 100%;
  padding: 0.7rem 1rem;
  background: var(--brand-light-blue);
  color: #fff;
  border: none;
  border-radius: var(--brand-radius);
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  transition: filter 0.15s ease;
}

.auth-button:hover {
  filter: brightness(0.92);
}

.auth-button:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 2px;
}

/* Full-width top banner — used by app pages like welcome, logo left / title center / actions right */
.topbar {
  background: var(--brand-navy);
  padding: 0.85rem 1.5rem;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: 1rem;
}

.topbar__logo {
  height: 32px;
  width: auto;
  display: block;
  justify-self: start;
}

.topbar__title {
  grid-column: 2;
  justify-self: center;
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
}

.topbar__logout {
  grid-column: 3;
  justify-self: end;
  width: auto;
  padding: 0.5rem 1.25rem;
  font-size: 0.85rem;
}

/* The topbar's third column, holding the user flag and the logout button side by side. Built by
   user-flag.js rather than written into each page's markup - see the note in that file. Both of
   the button's own placement rules above are ignored once it is a flex item here. */
.topbar__actions {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
}

/* The access level the portal is treating the signed-in user as. Display only - it reports what
   the directory says, it doesn't control anything. */
.topbar__flag {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.3rem 0.75rem;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  font-size: 0.75rem;
  line-height: 1.3;
  color: #fff;
  white-space: nowrap;
}

.topbar__flag-role {
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* One accent per access level. The tint carries the colour and the text stays white: the badges
   elsewhere put a brand colour on 12% of itself, which works on the white surfaces they sit on
   but not against the navy up here. */
.topbar__flag--dev {
  border-color: rgba(47, 134, 214, 0.7);
  background: rgba(47, 134, 214, 0.32);
}

.topbar__flag--admin {
  border-color: rgba(252, 112, 46, 0.7);
  background: rgba(252, 112, 46, 0.32);
}

.topbar__flag--manager {
  border-color: rgba(255, 255, 255, 0.4);
  background: rgba(255, 255, 255, 0.16);
}

/* Standard User: signed in with no access level on the directory, which is what most people who
   sign in are. Reached on the bar by a Dev masking down to it. */
.topbar__flag--none {
  border-color: rgba(255, 255, 255, 0.25);
  background: transparent;
  color: rgba(255, 255, 255, 0.75);
}

/* A masked flag is temporary and has to look it, or a Dev forgets they are wearing one and reads
   the portal's behaviour as a bug. Dashed for "not really you", with the word said out loud. */
.topbar__flag--masked {
  border-style: dashed;
}

.topbar__flag-masked {
  font-size: 0.68rem;
  font-style: italic;
  color: rgba(255, 255, 255, 0.75);
}

/* The topbar's first column, holding the logo and the admin-view link side by side. Built by
   user-flag.js rather than written into each page's markup - see the note in that file. The logo's
   own justify-self is ignored once it is a flex item here. */
.topbar__lead {
  grid-column: 1;
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}

/* A little more air between the logo and the first link than between the links themselves, so they
   read as a group rather than as part of the mark. */
.topbar__lead .topbar__logo {
  margin-right: 0.4rem;
}

/* Route to user administration, for the access levels that can use it. Sized as a topbar control
   rather than a button: it is navigation, and it sits beside the logo, not among the actions. */
.topbar__admin-link {
  padding: 0.3rem 0.7rem;
  text-transform: uppercase;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: var(--brand-radius);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.15s ease;
}

.topbar__admin-link:hover {
  background: rgba(255, 255, 255, 0.14);
}

.topbar__admin-link:focus-visible {
  outline: 2px solid var(--brand-light-blue);
  outline-offset: 2px;
}

/* Already there - shown as the current place rather than as somewhere to go. */
.topbar__admin-link[aria-current="page"] {
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.5);
  cursor: default;
}

/* The Dev's level switch, beside the flag. Kept quiet: it is a testing control, not part of the
   QMS, and it only exists for one person on the directory. */
.topbar__mask {
  max-width: 12rem;
  padding: 0.3rem 0.5rem;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: var(--brand-radius);
  background: rgba(255, 255, 255, 0.08);
  font-family: inherit;
  font-size: 0.72rem;
  color: #fff;
  cursor: pointer;
}

/* The list itself drops out of the topbar onto the page, where navy-on-navy would be unreadable -
   so the options carry the page's own colours rather than the bar's. */
.topbar__mask option {
  background: var(--brand-surface);
  color: var(--brand-text);
}

.topbar__mask:disabled {
  opacity: 0.6;
  cursor: progress;
}

.topbar__mask:focus-visible {
  outline: 2px solid var(--brand-light-blue);
  outline-offset: 2px;
}

/* Narrow screens keep the flag and drop the Dev's switch - the topbar is three columns of fixed
   content, and a testing control is the first thing that can give. */
@media (max-width: 700px) {
  .topbar__mask {
    display: none;
  }
}

.page-content {
  padding: 3rem 1.5rem;
  text-align: center;
}

.page-heading {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--brand-text);
}

/* The alpha marker, sat under the page heading by alpha.js. A block of its own so it keeps its
   line and follows whatever alignment the heading has. */
.page-alpha {
  margin: 0.75rem 0 0;
}

.page-alpha__pill {
  display: inline-flex;
  align-items: center;
  padding: 0.25rem 0.7rem;
  border: 1px solid rgba(191, 122, 8, 0.4);
  border-radius: 999px;
  background: rgba(245, 176, 65, 0.16);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  line-height: 1.3;
  color: #8a5a06;
  white-space: nowrap;
}

.page-intro {
  max-width: 1280px;
  margin: 0.5rem auto 0;
  font-size: 0.9rem;
  color: var(--brand-text-muted);
  text-align: left;
}

.page-subheading {
  margin: 2.5rem 0 0;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--brand-text);
}

.page-subheading + .nav-card-grid {
  margin-top: 1rem;
}

/* A small way through to something off-page, sitting under the heading without taking a tile or
   moving the cards below it. */
.page-heading__action {
  margin-top: 0.9rem;
  padding: 0.4rem 0.9rem;
  font-size: 0.8rem;
}

/* Card grid of links to other areas of the site */
.nav-card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(270px, 1fr));
  gap: 1.25rem;
  max-width: 760px;
  margin: 2.5rem auto 0;
  text-align: center;
}

@media (max-width: 620px) {
  .nav-card-grid {
    grid-template-columns: 1fr;
  }
}

.nav-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  padding: 1.5rem;
  text-decoration: none;
  color: inherit;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.nav-card:hover {
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
  transform: translateY(-2px);
}

.nav-card:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 2px;
}

.nav-card__icon {
  width: 65px;
  height: 65px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.nav-card__icon svg {
  width: 40px;
  height: 40px;
}

/* The admin cards carry line glyphs in the text colour rather than an illustration from the QMS
   icon set - running the portal is a different kind of task from running a QMS workflow, and the
   tiles should not look interchangeable. */
.nav-card__icon--admin {
  background: rgba(24, 24, 24, 0.06);
  color: var(--brand-text);
}

.nav-card__icon img {
  width: 40px;
  height: 40px;
  object-fit: contain;
}

.nav-card__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--brand-text);
  white-space: nowrap;
}

.nav-card__desc {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--brand-text-muted);
}

/* Top-of-page row of highlighted feature cards (Audit Pack, Dashboard, Document Library, Work Instructions) */
.nav-card-grid--top {
  grid-template-columns: repeat(4, minmax(180px, 1fr));
  max-width: 1100px;
}

@media (max-width: 860px) {
  .nav-card-grid--top {
    grid-template-columns: repeat(2, minmax(180px, 1fr));
  }
}

@media (max-width: 620px) {
  .nav-card-grid--top {
    grid-template-columns: 1fr;
  }
}

.nav-card-grid--top .nav-card__title {
  white-space: normal;
}

/* Wider grid for hub pages (e.g. Actions) that list many cards with descriptions */
.nav-card-grid--wide {
  grid-template-columns: repeat(4, minmax(200px, 1fr));
  max-width: 1180px;
}

@media (max-width: 980px) {
  .nav-card-grid--wide {
    grid-template-columns: repeat(2, minmax(200px, 1fr));
  }
}

@media (max-width: 620px) {
  .nav-card-grid--wide {
    grid-template-columns: 1fr;
  }
}

.nav-card-grid--wide .nav-card__title {
  white-space: normal;
}

/* Reserved for the small number of cards that should visually stand out */
.nav-card--highlight {
  border-width: 2px;
  border-color: var(--brand-orange);
  padding: 1.75rem;
  box-shadow: 0 6px 20px rgba(252, 112, 46, 0.15);
}

.nav-card--highlight:hover {
  box-shadow: 0 10px 28px rgba(252, 112, 46, 0.22);
}

.nav-card--highlight .nav-card__icon {
  width: 65px;
  height: 65px;
  background: rgba(252, 112, 46, 0.14);
  color: var(--brand-orange);
}

.nav-card--highlight .nav-card__icon svg,
.nav-card--highlight .nav-card__icon img {
  width: 40px;
  height: 40px;
}

.nav-card--highlight .nav-card__title {
  font-size: 1.1rem;
}

/* --- Document Library tree --- */

.doc-search {
  position: relative;
  max-width: 760px;
  margin: 2rem auto 0;
  text-align: left;
}

.doc-search input {
  width: 100%;
  font-family: inherit;
  font-size: 0.9rem;
  padding: 0.65rem 0.9rem 0.65rem 2.5rem;
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  color: var(--brand-text);
  background: #fff;
  box-sizing: border-box;
}

.doc-search input:focus {
  outline: none;
  border-color: var(--brand-light-blue);
  box-shadow: 0 0 0 3px rgba(47, 134, 214, 0.15);
}

.doc-search__icon {
  position: absolute;
  left: 0.8rem;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  color: var(--brand-text-muted);
  pointer-events: none;
}

.doc-tree__panel {
  max-width: 760px;
  margin: 2rem auto 0;
  padding: 1.5rem;
  text-align: left;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

.doc-tree__status {
  padding: 1rem 0.25rem;
  font-size: 0.9rem;
  color: var(--brand-text-muted);
}

.doc-tree__status a {
  color: var(--brand-light-blue);
  font-weight: 600;
  text-decoration: none;
}

.doc-tree__status a:hover {
  text-decoration: underline;
}

.doc-tree__list,
.doc-tree__list ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.doc-tree__list ul {
  margin-left: 10px;
  padding-left: 18px;
  border-left: 1px solid var(--brand-border);
}

.doc-tree__list li {
  margin: 2px 0;
}

.doc-tree__folder > summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0.55rem 0.5rem;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 500;
  font-size: 0.9rem;
  color: var(--brand-text);
  user-select: none;
}

.doc-tree__folder > summary::-webkit-details-marker {
  display: none;
}

.doc-tree__folder > summary:hover {
  background: rgba(47, 134, 214, 0.08);
}

.doc-tree__folder > summary:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 2px;
}

.doc-tree__chevron {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: var(--brand-light-blue);
  transition: transform 0.15s ease;
}

.doc-tree__folder[open] > summary .doc-tree__chevron {
  transform: rotate(90deg);
}

.doc-tree__folder-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--brand-light-blue);
}

.doc-tree__file-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 0.55rem 0.5rem;
  border-radius: 8px;
}

.doc-tree__file-row:hover {
  background: var(--brand-bg);
}

.doc-tree__file-info {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.doc-tree__file-icon {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--brand-text-muted);
}

.doc-tree__file-name {
  font-size: 0.88rem;
  color: var(--brand-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.doc-tree__file-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.doc-tree__file-path {
  font-size: 0.75rem;
  color: var(--brand-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.doc-tree__download {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--brand-light-blue);
  text-decoration: none;
  padding: 0.3rem 0.65rem;
  border-radius: 6px;
  border: 1px solid transparent;
}

.doc-tree__download:hover {
  border-color: var(--brand-light-blue);
  background: rgba(47, 134, 214, 0.08);
}

.doc-tree__download:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 2px;
}

.doc-tree__empty {
  padding: 1.25rem 0.5rem;
  text-align: center;
  color: var(--brand-text-muted);
  font-size: 0.85rem;
}

.back-link {
  display: inline-block;
  margin-bottom: 0.75rem;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--brand-text-muted);
  text-decoration: none;
}

.back-link:hover {
  color: var(--brand-light-blue);
}

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

/* --- Buttons (non full-width, used alongside data tables/toolbars) --- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 1.2rem;
  border: 1px solid transparent;
  border-radius: var(--brand-radius);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  transition: filter 0.15s ease, background 0.15s ease;
}

.btn--primary {
  background: var(--brand-light-blue);
  color: #fff;
}

.btn--primary:hover {
  filter: brightness(0.92);
}

.btn--ghost {
  background: transparent;
  color: var(--brand-text-muted);
  border-color: var(--brand-border);
}

.btn--ghost:hover {
  background: var(--brand-bg);
}

.btn:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 2px;
}

/* --- Data table (record logs like Customer Feedback) --- */

.data-table__toolbar {
  max-width: 1280px;
  margin: 1.5rem auto 0;
  display: flex;
  justify-content: flex-end;
}

/* A toolbar that filters rather than one that acts: the controls read left to right from the start
   of the table, and the buttons that go with them sit at the end. */
.data-table__toolbar--filters {
  justify-content: flex-start;
  align-items: flex-end;
  gap: 0.75rem;
  flex-wrap: wrap;
}

/* A label and its control on one line, for a filter in a toolbar rather than a field in a form. */
.form-field--inline {
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
}

.form-field--inline > span {
  white-space: nowrap;
}

.data-table__panel {
  max-width: 1280px;
  margin: 1rem auto 0;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  overflow-x: auto;
  text-align: left;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}

.data-table th,
.data-table td {
  padding: 0.75rem 1rem;
  text-align: left;
  border-bottom: 1px solid var(--brand-border);
  vertical-align: middle;
}

.data-table th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--brand-text-muted);
  font-weight: 600;
  background: var(--brand-bg);
  white-space: nowrap;
}

.data-table__sort-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  color: inherit;
  cursor: pointer;
}

.data-table__sort-btn:hover {
  color: var(--brand-light-blue);
}

.data-table__sort-btn:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 2px;
}

.data-table__sort-arrow {
  font-size: 0.85rem;
}

.data-table tbody tr {
  cursor: pointer;
}

.data-table tbody tr:hover {
  background: rgba(47, 134, 214, 0.04);
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

.data-table__id-cell {
  white-space: nowrap;
}

.data-table__desc-cell {
  max-width: 280px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Dates and short numerics that shouldn't wrap onto two lines and make the row
   twice as tall as it needs to be */
.data-table__compact-cell {
  white-space: nowrap;
}

/* The risk register has 10 columns (vs. 6-8 on the other logs) - its two
   description-style columns need to be narrower or the table overflows its
   panel and forces a horizontal scrollbar. */
#riskTableBody .data-table__desc-cell {
  max-width: 190px;
}

/* The calibration register runs 9 columns, two of them free-text equipment
   descriptions - same reasoning as the risk register above. */
#calibrationTableBody .data-table__desc-cell {
  max-width: 200px;
}

.data-table__empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--brand-text-muted);
  font-size: 0.9rem;
}

/* --- Two-table pages (internal audit: reports above, findings below) --- */

/* Names each table where a page carries more than one, so the second doesn't read
   as a continuation of the first. */
.table-section__heading {
  max-width: 1280px;
  margin: 2.5rem auto 0;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--brand-text);
  text-align: left;
}

/* The parent row whose children the table below is filtered to. The inset bar marks
   it without competing with the row-hover tint. */
.data-table tbody tr.is-selected {
  background: rgba(47, 134, 214, 0.08);
  box-shadow: inset 3px 0 0 var(--brand-light-blue);
}

/* A second click target inside a row, where the row click itself does something
   other than open the record (on the audit log it filters the findings table). */
.data-table__row-action {
  padding: 0.3rem 0.7rem;
  font-size: 0.78rem;
  white-space: nowrap;
}

/* A row that is still on the register but no longer live - a deactivated portal user. Dimmed
   rather than hidden: they are kept deliberately, because their name is on filed records, and the
   row has to stay readable enough to reactivate. */
.data-table tbody tr.is-inactive td {
  color: var(--brand-text-muted);
}

/* A row past the date the QMS gave it. The tint is the row's own warning rather than a badge, so a
   list of a dozen items shows at a glance which ones have run out of time. */
.data-table tbody tr.is-overdue td {
  background: rgba(230, 57, 70, 0.06);
}

/* A value with a short qualifier beneath it, for a fact that has to be visible on every
   row but doesn't earn a column of its own - the auditor's name over their independence
   route (GP05 §7). The qualifier sits on its own line, outside the truncation above it,
   so it stays readable however long the name is. */
.data-table__stacked-cell {
  max-width: 170px;
}

.data-table__stacked-cell > span {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.data-table__stacked-cell > small {
  display: block;
  margin-top: 1px;
  font-size: 0.72rem;
  color: var(--brand-text-muted);
}

/* The audit log runs 10 columns and the findings table 8 - the widest of the record
   tables. Tighter cells buy back the room they need to fit 1280px without a horizontal
   scrollbar, which beats truncating the procedure, auditor and auditee names harder
   than they already are. */
.data-table--dense th,
.data-table--dense td {
  padding-left: 0.6rem;
  padding-right: 0.6rem;
}

#auditTableBody .data-table__desc-cell {
  max-width: 170px;
}

/* The finding statement carries the free text and takes the width; the category beside
   it holds a short label, so it wraps to a second line rather than truncating - a
   truncated category name loses its meaning. */
#findingTableBody .data-table__desc-cell {
  max-width: 400px;
}

#findingTableBody .data-table__label-cell {
  max-width: 150px;
}

/* The Stop Work log runs 10 columns, and its longest free-text column is the production
   stage - a short label rather than a sentence. */
#swoTableBody .data-table__label-cell {
  max-width: 130px;
}

#swoTableBody .data-table__stacked-cell {
  max-width: 150px;
}

/* --- Risk matrix heatmap (5x5, Likelihood x Severity) --- */

#risk-matrix {
  max-width: 1280px;
  margin: 1.5rem auto 0;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  padding: 1.25rem 1.5rem 1.5rem;
}

#risk-matrix h2 {
  /* left margin offsets the L5-L1 label column (80px cell + 8px border-spacing either
     side of it), which only exists on the left, so text-align: center below lines the
     title up over the 5x5 grid of squares rather than the table's full geometric
     center. Re-tune this if the matrix's cell width/border-spacing change. */
  margin: 0 0 1rem 88px;
  font-size: 1rem;
  font-weight: 600;
  color: var(--brand-navy);
  text-align: center;
}

#risk-matrix-table {
  border-collapse: separate;
  border-spacing: 8px;
  margin: 0 auto;
}

#risk-matrix-table th,
#risk-matrix-table td {
  width: 80px;
  height: 60px;
  text-align: center;
  vertical-align: middle;
}

#risk-matrix-table th {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--brand-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

#risk-matrix-table tr th:first-child {
  text-align: right;
  padding-right: 6px;
}

#risk-matrix-table td {
  border-radius: 8px;
  background: var(--brand-bg);
  color: var(--brand-navy);
  font-weight: 700;
  font-size: 0.95rem;
  cursor: pointer;
  transition: box-shadow 0.1s ease;
}

#risk-matrix-table td:not([data-count="0"]):hover {
  box-shadow: 0 0 0 2px var(--brand-light-blue) inset;
}

#risk-matrix-table td[data-count="0"] {
  color: var(--brand-text-muted);
  font-weight: 400;
  cursor: default;
}

#risk-matrix-table td.risk-matrix__cell--low,
.risk-matrix__ref-table td.risk-matrix__cell--low {
  background: #d3f2df;
  color: #1e8a5f;
}

#risk-matrix-table td.risk-matrix__cell--medium,
.risk-matrix__ref-table td.risk-matrix__cell--medium {
  background: #ffe9a8;
  color: #8a6112;
}

#risk-matrix-table td.risk-matrix__cell--high,
.risk-matrix__ref-table td.risk-matrix__cell--high {
  background: #fbd0d5;
  color: #b3202e;
}

#risk-matrix-table td.risk-matrix__cell--critical,
.risk-matrix__ref-table td.risk-matrix__cell--critical {
  background: #c81e2c;
  color: #fff;
}

.risk-matrix__chart {
  margin-bottom: 1.5rem;
}

.risk-matrix__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}

/* Standalone panel of reference tables (no heatmap above them), e.g. the grade
   scale and outcome bands on the supplier evaluation page. */
.reference-grid {
  max-width: 1280px;
  margin: 1.5rem auto 0;
  padding: 1.25rem 1.5rem 1.5rem;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}

.risk-matrix__ref-table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid var(--brand-border);
  font-size: 0.82rem;
}

.risk-matrix__ref-table caption {
  caption-side: top;
  text-align: left;
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--brand-navy);
  margin-bottom: 0.5rem;
}

.risk-matrix__ref-table th {
  background: var(--brand-navy);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-align: center;
  padding: 0.5rem 0.75rem;
}

.risk-matrix__ref-table td {
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--brand-border);
  vertical-align: top;
  text-align: left;
  line-height: 1.4;
}

.risk-matrix__ref-table td:first-child {
  white-space: nowrap;
  font-weight: 600;
  text-align: center;
}

.risk-matrix__ref-table tbody tr:last-child td {
  border-bottom: none;
}

.risk-matrix__cell--active {
  outline: 3px solid var(--brand-navy);
  outline-offset: 2px;
}

.risk-matrix__filter-notice {
  margin: 0 auto 0 0;
  font-size: 0.85rem;
  color: var(--brand-text-muted);
}

.risk-matrix__filter-notice button {
  background: none;
  border: none;
  padding: 0;
  margin-left: 6px;
  font: inherit;
  color: var(--brand-light-blue);
  text-decoration: underline;
  cursor: pointer;
}

/* --- KPI strip (calibration register due-state counts, QP04 §13) --- */

.kpi-strip {
  max-width: 1280px;
  margin: 1.5rem auto 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}

@media (max-width: 860px) {
  .kpi-strip {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Every tile carries one colour, set once as --kpi-accent by its variant below. The
   left stripe, the count, and the whole frame when the tile is the active filter all
   read it from there, so a variant is a single declaration and its three appearances
   can't drift apart. */
.kpi-tile {
  --kpi-accent: var(--brand-navy);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  padding: 1rem 1.15rem;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-left: 4px solid var(--kpi-accent);
  border-radius: var(--brand-radius);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.kpi-tile:hover {
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
  transform: translateY(-2px);
}

.kpi-tile:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 2px;
}

/* A tile with nothing in it isn't a filter worth applying */
.kpi-tile[data-count="0"] {
  cursor: default;
  transform: none;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

/* Selected as the table's filter: the whole frame takes the tile's own colour, so the
   accent grows into the border rather than being painted over by a second one. */
.kpi-tile.is-active {
  border-color: var(--kpi-accent);
  box-shadow: 0 0 0 2px var(--kpi-accent) inset;
}

.kpi-tile__value {
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--kpi-accent);
}

.kpi-tile__label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-weight: 600;
  color: var(--brand-text-muted);
}

.kpi-tile__note {
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--brand-text-muted);
}

/* Calibration register due states (QP04 §7, §13) */
.kpi-tile--overdue {
  --kpi-accent: #e63946;
}

.kpi-tile--due-soon {
  --kpi-accent: var(--brand-orange-deep);
}

.kpi-tile--in-date {
  --kpi-accent: #1e8a5f;
}

.kpi-tile--not-applicable {
  --kpi-accent: var(--brand-text-muted);
}

/* A plain count with no state attached to it - a headcount rather than something going wrong. */
.kpi-tile--neutral {
  --kpi-accent: var(--brand-navy);
}

/* Open audit findings by GP05 §8 severity - the same three-step ramp as the severity
   badges, so the tiles and the table read as one scale. */
.kpi-tile--major-nc {
  --kpi-accent: #e63946;
}

.kpi-tile--minor-nc {
  --kpi-accent: var(--brand-orange-deep);
}

.kpi-tile--ofi {
  --kpi-accent: var(--brand-light-blue);
}

/* The alarm tile. Its neighbours count categories; this one counts the thing that ought
   to be zero - audit findings past their §10.2 window, open complaints, a review that has
   run out of time. Set apart by weight rather than by another shade of red, and filled
   only while the count is above zero. */
.kpi-tile--alarm {
  --kpi-accent: #c81e2c;
  background: var(--kpi-accent);
  border-color: var(--kpi-accent);
  border-left-color: #8f1520;
}

.kpi-tile--alarm .kpi-tile__value {
  color: #fff;
}

/* Held just off pure white so the count still leads, but no further - at 0.85 the
   label drops under 4.5:1 against the fill. */
.kpi-tile--alarm .kpi-tile__label,
.kpi-tile--alarm .kpi-tile__note {
  color: rgba(255, 255, 255, 0.93);
}

/* Its frame is already its own colour, so selecting it shows inside instead. */
.kpi-tile--alarm.is-active {
  border-color: #8f1520;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9) inset;
}

/* A count of zero here is good news and shouldn't look like an alarm, so the tile drops
   back to the same white-with-a-coloured-accent shape as the ones beside it. The fill is
   the escalation, not the tile's identity. */
.kpi-tile--alarm[data-count="0"] {
  background: var(--brand-surface);
  border-color: var(--brand-border);
  border-left-color: var(--kpi-accent);
}

.kpi-tile--alarm[data-count="0"] .kpi-tile__value {
  color: var(--kpi-accent);
}

.kpi-tile--alarm[data-count="0"] .kpi-tile__label,
.kpi-tile--alarm[data-count="0"] .kpi-tile__note {
  color: var(--brand-text-muted);
}

/* Stop Work Orders by the QP03 §16 authority tier that lifts them - the same
   blue / orange / red ramp as the audit severities, so a category reads the same way
   across the portal. */
.kpi-tile--swo-routine {
  --kpi-accent: var(--brand-light-blue);
}

.kpi-tile--swo-conformity {
  --kpi-accent: var(--brand-orange-deep);
}

.kpi-tile--swo-customer {
  --kpi-accent: #e63946;
}

/* Not a category but a check against §16 - kept neutral so it doesn't read as a fourth
   severity. */
.kpi-tile--swo-no-ncr {
  --kpi-accent: var(--brand-text-muted);
}

/* Customer feedback (GP04 §8). The two lifecycle tiles take orange then blue - waiting on
   us, then waiting on closure - and compliments take the green, being the good news. */
.kpi-tile--fb-open {
  --kpi-accent: var(--brand-orange-deep);
}

.kpi-tile--fb-actioned {
  --kpi-accent: var(--brand-light-blue);
}

.kpi-tile--fb-compliment {
  --kpi-accent: #1e8a5f;
}

/* Document change requests, along the GP01 §9 steps: raised, under review, approved and
   waiting to be drafted and issued. */
.kpi-tile--dcr-raised {
  --kpi-accent: var(--brand-orange-deep);
}

.kpi-tile--dcr-review {
  --kpi-accent: var(--brand-light-blue);
}

.kpi-tile--dcr-approved {
  --kpi-accent: #1e8a5f;
}

/* Supplier evaluations (QP02 §12). Critical is a supplier category so it takes a colour
   from the ramp; This Period is a convenience filter on the annual cycle rather than a
   category, so it stays neutral - the same distinction as the NCR-gap tile above. */
.kpi-tile--se-awaiting {
  --kpi-accent: var(--brand-orange-deep);
}

.kpi-tile--se-critical {
  --kpi-accent: var(--brand-light-blue);
}

.kpi-tile--se-period {
  --kpi-accent: var(--brand-text-muted);
}

/* The QP01 §8 treatment cycle: plan to agree, being treated, then watched. */
.kpi-tile--risk-open {
  --kpi-accent: var(--brand-orange-deep);
}

.kpi-tile--risk-treatment {
  --kpi-accent: var(--brand-light-blue);
}

.kpi-tile--risk-monitoring {
  --kpi-accent: #1e8a5f;
}

/* Status/severity pills */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.25rem 0.65rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

.badge--severity-minor {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--severity-moderate {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--severity-significant {
  background: rgba(230, 57, 70, 0.12);
  color: #e63946;
}

.badge--severity-critical {
  background: #e63946;
  color: #fff;
}

.badge--status-open {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--status-actioned {
  background: rgba(230, 57, 70, 0.12);
  color: #e63946;
}

.badge--status-closed {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--dcr-status-raised {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--dcr-status-under-review {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--dcr-status-approved {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--dcr-status-issued {
  background: #1e8a5f;
  color: #fff;
}

.badge--dcr-status-denied {
  background: rgba(230, 57, 70, 0.12);
  color: #e63946;
}

/* Supplier evaluation outcome, QPF02.01 total-grade bands */
.badge--grade-excellent {
  background: #1e8a5f;
  color: #fff;
}

.badge--grade-good {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--grade-average {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--grade-below-average {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--grade-unsatisfactory {
  background: #e63946;
  color: #fff;
}

/* Supplier category, QP02 §7 */
.badge--category-critical {
  background: rgba(230, 57, 70, 0.12);
  color: #e63946;
}

.badge--category-standard {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--category-minor {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
}

.badge--eval-status-draft {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
}

.badge--eval-status-awaiting {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--eval-status-signed-off {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

/* Calibration register: derived in-date / due-soon / overdue state (QP04 §7) */
.badge--cal-in-date {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--cal-due-soon {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--cal-overdue {
  background: #e63946;
  color: #fff;
}

.badge--cal-not-applicable {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
}

.badge--cal-source-internal {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--cal-source-external {
  background: rgba(18, 36, 69, 0.1);
  color: var(--brand-navy);
}

/* M&TE maintenance status, QP04 §6 lifecycle plus the §9 / §11 withdrawn states */
.badge--mte-status-in-service {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--mte-status-out-for-calibration {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--mte-status-suspect {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--mte-status-out-of-tolerance {
  background: #e63946;
  color: #fff;
}

.badge--mte-status-out-of-service {
  background: rgba(230, 57, 70, 0.12);
  color: #e63946;
}

.badge--mte-status-lost {
  background: rgba(18, 36, 69, 0.1);
  color: var(--brand-navy);
}

.badge--mte-status-retired {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
}

/* Audit finding severity, GP05 §8 - a three-step ramp of tints. Severity classifies a
   finding, it doesn't demand action today, so none of the three is filled: on this page
   the filled badge is reserved for Overdue below, which does. */
.badge--finding-major {
  background: rgba(230, 57, 70, 0.14);
  color: #c81e2c;
}

.badge--finding-minor {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--finding-ofi {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

/* Where a finding has reached in the GP05 §10.1 What-to-Validate flow, plus Overdue,
   which the API folds into the same status once the §10.2 window has run out. Overdue
   is the only filled badge on the page - it is the only one that means act now. */
.badge--finding-status-open {
  background: rgba(18, 36, 69, 0.1);
  color: var(--brand-navy);
}

.badge--finding-status-actioned {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--finding-status-verified {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--finding-status-closed {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--finding-status-overdue {
  background: #c81e2c;
  color: #fff;
}

/* Internal audit report sign-off state */
.badge--audit-status-draft {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
}

.badge--audit-status-awaiting {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--audit-status-signed-off {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--audit-status-closed {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

/* Stop Work Order category, which is the QP03 §16 tier that decides who can lift the
   stop. Tints, on the same blue / orange / red ramp as the audit severities. */
.badge--swo-routine {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--swo-conformity {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--swo-customer-impacting {
  background: rgba(230, 57, 70, 0.14);
  color: #c81e2c;
}

/* Auditor independence route, GP05 §7 */
.badge--auditor-internal {
  background: rgba(18, 36, 69, 0.1);
  color: var(--brand-navy);
}

.badge--auditor-external {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

/* --- Modal dialog (native <dialog>, e.g. "Log Feedback" form) --- */

dialog.modal {
  border: none;
  border-radius: var(--brand-radius);
  padding: 0;
  width: min(480px, 92vw);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
}

dialog.modal::backdrop {
  background: rgba(18, 36, 69, 0.45);
}

.modal__form {
  padding: 1.75rem;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

.modal__title {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--brand-text);
}

/* Wider variant for forms that carry a scoring table (supplier evaluation). The
   dialog also gets a height cap so a long form scrolls inside the modal rather
   than overflowing the viewport. */
dialog.modal--wide {
  width: min(680px, 94vw);
  max-height: 88vh;
}

/* Section divider inside a long modal form */
.form-section {
  margin: 0.75rem 0 0;
  padding-top: 0.9rem;
  border-top: 1px solid var(--brand-border);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--brand-text-muted);
  font-weight: 600;
  text-align: left;
}

.form-section__note {
  margin: -0.5rem 0 0;
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--brand-text-muted);
  text-align: left;
}

/* QPF02.01 weighted scoring grid, used in both the form and the detail card */
.criteria-table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid var(--brand-border);
  font-size: 0.82rem;
  text-align: left;
}

.criteria-table th {
  padding: 0.5rem 0.6rem;
  background: var(--brand-bg);
  border-bottom: 1px solid var(--brand-border);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--brand-text-muted);
  font-weight: 600;
}

.criteria-table td {
  padding: 0.4rem 0.6rem;
  border-bottom: 1px solid var(--brand-border);
  font-weight: 400;
  color: var(--brand-text);
}

.criteria-table th:first-child,
.criteria-table td:first-child {
  width: 3rem;
  font-weight: 600;
}

.criteria-table select {
  width: 100%;
  font-family: inherit;
  font-size: 0.82rem;
  padding: 0.3rem 0.4rem;
  border: 1px solid var(--brand-border);
  border-radius: 6px;
  color: var(--brand-text);
  background: #fff;
}

.criteria-table select:focus {
  outline: none;
  border-color: var(--brand-light-blue);
  box-shadow: 0 0 0 3px rgba(47, 134, 214, 0.15);
}

.criteria-table tfoot td {
  border-bottom: none;
  background: var(--brand-bg);
  font-weight: 700;
  color: var(--brand-navy);
}

/* GPF05.02's findings grid on the report card: one long statement alongside four short
   labels. Left to the auto layout, the statement ends up the narrowest of the five and
   wraps to a dozen lines - so it is given the width explicitly. Cells align to the top,
   since a row is as tall as its statement. */
.criteria-table--findings th:nth-child(2) {
  width: 52%;
}

.criteria-table--findings th:nth-child(3),
.criteria-table--findings th:nth-child(4),
.criteria-table--findings th:nth-child(5) {
  width: 14%;
}

.criteria-table--findings td {
  vertical-align: top;
}

/* Live outcome readout under the scoring grid */
.eval-outcome {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  padding: 0.7rem 0.85rem;
  border-radius: 8px;
  background: var(--brand-bg);
  font-size: 0.82rem;
  font-weight: 400;
  line-height: 1.45;
  color: var(--brand-text-muted);
  text-align: left;
}

.eval-outcome--resolved {
  color: var(--brand-text);
}

/* --- Repeating findings editor (GPF05.02 carries 0..n findings per report) --- */

.findings-editor {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.finding-block {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 0.9rem 1rem 1rem;
  background: var(--brand-bg);
  border: 1px solid var(--brand-border);
  border-left: 3px solid var(--brand-light-blue);
  border-radius: 8px;
}

.finding-block__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.finding-block__no {
  margin: 0;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-weight: 600;
  color: var(--brand-text-muted);
}

.finding-block__remove {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: 0.78rem;
  color: var(--brand-light-blue);
  text-decoration: underline;
  cursor: pointer;
}

/* Severity, category and NCR no. sit on one line at modal width. auto-fit rather than
   a fixed 3 so the row closes up instead of leaving a dead column when the NCR field
   is hidden - which it is for an OFI, and until a severity is chosen. */
.finding-block__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.75rem;
}

/* The GP05 §10.2 closure window implied by the severity chosen above */
.finding-block__due {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--brand-text-muted);
  text-align: left;
}

.finding-block__due:empty {
  display: none;
}

.findings-editor__empty {
  margin: 0;
  padding: 0.9rem 1rem;
  border: 1px dashed var(--brand-border);
  border-radius: 8px;
  font-size: 0.82rem;
  color: var(--brand-text-muted);
  text-align: left;
}

/* Adds a block to the editor above it - a finding, an invited attendee, a decision. Sits under
   the last block rather than in the modal's footer actions, which are Cancel/Save only.

   The site's ghost button in everything but its edge, which is dashed: this one grows the form
   rather than submitting anything, and the dash carries over from the empty-state note it appears
   under. Styled in full rather than leaning on .btn, because the class is used on its own - and
   the typography is set explicitly because a .form-section wrapper would otherwise pass its
   uppercase heading treatment down into the label. */
.findings-editor__add {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.9rem;
  padding: 0.6rem 1.2rem;
  background: transparent;
  border: 1px dashed var(--brand-border);
  border-radius: var(--brand-radius);
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: var(--brand-text-muted);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/* Directly inside the modal's own flex column, the container's gap already spaces it and the
   margin above would double up. */
.modal__form > .findings-editor__add {
  margin-top: 0;
}

.findings-editor__add:hover {
  background: var(--brand-bg);
  border-color: var(--brand-light-blue);
  color: var(--brand-navy);
}

.findings-editor__add:focus-visible {
  outline: 2px solid var(--brand-navy);
  outline-offset: 2px;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--brand-text);
  text-align: left;
}

.form-field__optional {
  font-weight: 400;
  color: var(--brand-text-muted);
}

.form-field__hint {
  font-weight: 400;
  font-size: 0.78rem;
  color: var(--brand-text-muted);
}

.form-field__hint:empty {
  display: none;
}

.combobox {
  position: relative;
}

.combobox__list {
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.25rem);
  left: 0;
  right: 0;
  max-height: 220px;
  overflow-y: auto;
  margin: 0;
  padding: 0.25rem;
  list-style: none;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(18, 36, 69, 0.12);
}

.combobox__option {
  padding: 0.5rem 0.6rem;
  border-radius: 6px;
  font-weight: 400;
  font-size: 0.9rem;
  cursor: pointer;
}

.combobox__option:hover,
.combobox__option.is-active {
  background: rgba(47, 134, 214, 0.1);
}

.combobox__empty {
  padding: 0.5rem 0.6rem;
  color: var(--brand-text-muted);
  font-size: 0.85rem;
  font-weight: 400;
}

.form-field input,
.form-field select,
.form-field textarea {
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 400;
  padding: 0.55rem 0.65rem;
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  color: var(--brand-text);
  background: #fff;
}

.form-field input:focus,
.form-field select:focus,
.form-field textarea:focus {
  outline: none;
  border-color: var(--brand-light-blue);
  box-shadow: 0 0 0 3px rgba(47, 134, 214, 0.15);
}

.form-field textarea {
  resize: vertical;
}

.form-field input:disabled {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
}

/* A field the form filled in from somewhere else rather than one to type in - an invited
   attendee's Role comes off the staff directory. Treated like a disabled field, because that is
   how it reads to whoever is looking at it, but its value still submits. */
.form-field input[readonly] {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
  cursor: default;
}

/* No focus ring either: the blue edge is the form's way of saying "type here". */
.form-field input[readonly]:focus {
  border-color: var(--brand-border);
  box-shadow: none;
}

.modal__actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-top: 0.25rem;
}

/* Read-only detail card, opened by clicking a data-table row */
dialog.modal--detail {
  width: min(560px, 92vw);
}

/* The internal audit report card is the densest read in the app - a dozen header fields,
   four prose sections and the GPF05.02 findings grid. Declared after modal--detail so it
   wins the equal-specificity contest for width, and capped in height so a long report
   scrolls inside the card. */
dialog.modal--report {
  width: min(880px, 94vw);
  max-height: 88vh;
}

.detail-card__grid {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem 1.5rem;
}

.detail-card__field dt {
  margin: 0;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--brand-text-muted);
  font-weight: 600;
}

.detail-card__field dd {
  margin: 0.3rem 0 0;
  font-size: 0.92rem;
  color: var(--brand-text);
}

.detail-card__description h3 {
  margin: 0 0 0.4rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--brand-text-muted);
  font-weight: 600;
}

.page-footer {
  margin-top: 2.5rem;
  padding: 1rem 0;
  text-align: center;
}

.icon-attribution {
  margin: 0;
  font-size: 0.72rem;
  color: var(--brand-text-muted);
}

.icon-attribution a {
  color: inherit;
  text-decoration: underline;
}

.detail-card__description p {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--brand-text);
  white-space: pre-wrap;
}

/* ===================================================================================
   Management Review (GPF06.01, per GP06)

   A review is the one workflow in the portal that runs as a process rather than a form:
   it is scheduled, its pack is built and circulated, the meeting is held, the minutes are
   signed, and its actions are chased between reviews. So the status badge below is a ramp
   rather than a set of categories - grey for a diary entry, blue once there is a pack,
   orange while something is owed, green once it is signed, navy once the cycle is shut.
   =================================================================================== */

.kpi-tile--mr-preparation {
  --kpi-accent: var(--brand-light-blue);
}

.kpi-tile--mr-minutes {
  --kpi-accent: var(--brand-orange);
}

.kpi-tile--mr-tracked {
  --kpi-accent: #1e8a5f;
}

/* Review status, in lifecycle order (GP06 sections 8-11) */
.badge--mr-status-scheduled {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
}

.badge--mr-status-pack-built {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

/* GP06 §11 gives the QAM ten working days to issue the minutes, so a completed meeting
   is a clock running, not a job finished. */
.badge--mr-status-meeting-complete {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--mr-status-minutes-approved {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--mr-status-actions-tracked {
  background: #1e8a5f;
  color: #fff;
}

/* Terminal: the next review has taken up this one's actions (GP06 §10). */
.badge--mr-status-cycle-closed {
  background: var(--brand-navy);
  color: #fff;
}

/* Action log status. Overdue is derived from the due date and replaces Open or In
   Progress, the same way a finding's §10.2 state replaces its recorded one. */
.badge--mr-action-open {
  background: rgba(47, 134, 214, 0.12);
  color: var(--brand-light-blue);
}

.badge--mr-action-in-progress {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--mr-action-complete {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--mr-action-cancelled {
  background: var(--brand-bg);
  color: var(--brand-text-muted);
}

.badge--mr-action-overdue {
  background: #e63946;
  color: #fff;
}

/* Whether the portal could assemble an input, or whether the QAM has to write it. Shown
   on every input in the pack so the meeting can see which figures came out of a register
   and which came off somebody's desk. */
/* One hue in three strengths - filled, tinted, outlined - rather than three colours. Coverage is
   how much of a clause the portal can see, which is a scale, and it sits inches from a Green /
   Amber / Red status: sharing those hues made the two read as the same judgement. The border is
   declared on all three so the outlined one is the same height as the others. */
.badge--assembly-automatic,
.badge--assembly-partial,
.badge--assembly-manual {
  border: 1px solid transparent;
}

.badge--assembly-automatic {
  background: var(--brand-navy);
  color: #fff;
}

.badge--assembly-partial {
  background: rgba(18, 36, 69, 0.14);
  color: var(--brand-navy);
}

.badge--assembly-manual {
  background: transparent;
  border-color: rgba(18, 36, 69, 0.45);
  color: var(--brand-navy);
}

.badge--attendance-present {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.badge--attendance-apologies {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.badge--attendance-absent {
  background: rgba(230, 57, 70, 0.12);
  color: #e63946;
}

/* --- The input pack ---------------------------------------------------------------
   Twelve inputs is too many to lay flat, so each is a disclosure: the reference, title
   and assembly badge always visible, the figures and tables inside. The chair walks
   down this list in order (GP06 §9), which is why they open independently rather than as
   an accordion that closes its neighbour. */
.mr-pack {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.mr-input {
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  background: var(--brand-surface);
  overflow: hidden;
}

.mr-input[open] {
  border-color: var(--brand-light-blue);
}

.mr-input__head {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding: 0.8rem 1rem;
  cursor: pointer;
  list-style: none;
}

.mr-input__head::-webkit-details-marker {
  display: none;
}

.mr-input__head::before {
  content: "\25B8";
  color: var(--brand-text-muted);
  font-size: 0.8rem;
}

.mr-input[open] > .mr-input__head::before {
  content: "\25BE";
}

/* The §9.3.2 reference, set as the form prints it - it is how the agenda, the minutes and
   the standard all refer to the same item. */
.mr-input__ref {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--brand-navy);
  min-width: 2.4rem;
}

.mr-input__title {
  font-weight: 600;
  font-size: 0.95rem;
}

.mr-input__flag {
  margin-left: auto;
  display: inline-flex;
  gap: 0.4rem;
  align-items: center;
}

.mr-input__body {
  padding: 0 1rem 1rem;
  border-top: 1px solid var(--brand-border);
}

.mr-input__source {
  margin: 0.8rem 0 0;
  font-size: 0.78rem;
  color: var(--brand-text-muted);
}

/* --- Figures, tables and gaps: shared by both packs ------------------------------
   The Management Review input pack and the Audit-Readiness Pack emit the same three JSON
   shapes and are drawn by the same functions (assets/pack.js), so they share the styling.
   Named pack- rather than mr- for that reason. */
.pack-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.6rem;
  margin: 0.9rem 0;
}

.pack-figure {
  padding: 0.6rem 0.75rem;
  background: var(--brand-bg);
  border-radius: 8px;
}

.pack-figure__value {
  display: block;
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--brand-navy);
  font-variant-numeric: tabular-nums;
}

.pack-figure__label {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
}

.pack-figure__note {
  display: block;
  font-size: 0.7rem;
  color: var(--brand-text-muted);
}

.pack-table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.75rem 0;
  font-size: 0.8rem;
}

.pack-table caption {
  text-align: left;
  font-weight: 600;
  font-size: 0.8rem;
  padding-bottom: 0.3rem;
  color: var(--brand-navy);
}

.pack-table th,
.pack-table td {
  border: 1px solid var(--brand-border);
  padding: 0.35rem 0.5rem;
  text-align: left;
  vertical-align: top;
}

.pack-table th {
  background: var(--brand-bg);
  font-weight: 600;
}

.pack-table__scroll {
  overflow-x: auto;
}

/* What the procedure or the clause needs and the portal cannot reach, stated on the item
   itself rather than in a footnote. */
.pack-gaps {
  margin: 0.75rem 0 0;
  padding: 0.6rem 0.8rem;
  background: rgba(252, 112, 46, 0.08);
  border-left: 3px solid var(--brand-orange);
  border-radius: 0 8px 8px 0;
}

.pack-gaps h4 {
  margin: 0 0 0.3rem;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-orange);
}

.pack-gaps ul {
  margin: 0;
  padding-left: 1.1rem;
}

.pack-gaps li {
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--brand-text);
}

.mr-input__capture {
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px dashed var(--brand-border);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.mr-input__saved {
  font-size: 0.75rem;
  font-weight: 600;
  color: #1e8a5f;
}

/* --- Attendance and signatures --------------------------------------------------- */
.mr-attendance {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

.mr-attendance th,
.mr-attendance td {
  border-bottom: 1px solid var(--brand-border);
  padding: 0.45rem 0.5rem;
  text-align: left;
}

.mr-attendance th {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-text-muted);
}

.mr-attendance select,
.mr-attendance input {
  width: 100%;
  padding: 0.35rem 0.4rem;
  border: 1px solid var(--brand-border);
  border-radius: 6px;
  font-family: inherit;
  font-size: 0.82rem;
}

.mr-attendance__role {
  font-size: 0.72rem;
  color: var(--brand-text-muted);
}

/* The derived answer to the GPF06.01 quorum box (GP06 §7), shown live as attendance is
   ticked so the chair is not asked to work it out. */
.mr-quorum {
  margin: 0.9rem 0 0;
  padding: 0.7rem 0.9rem;
  border-radius: 8px;
  font-size: 0.85rem;
  font-weight: 600;
}

.mr-quorum--met {
  background: rgba(30, 138, 95, 0.12);
  color: #1e8a5f;
}

.mr-quorum--short {
  background: rgba(230, 57, 70, 0.12);
  color: #e63946;
}

.mr-signatures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.9rem;
  margin-top: 0.5rem;
}

.mr-signature {
  padding: 0.8rem 0.9rem;
  border: 1px solid var(--brand-border);
  border-radius: 8px;
}

.mr-signature--signed {
  border-color: #1e8a5f;
  background: rgba(30, 138, 95, 0.06);
}

.mr-signature__role {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-text-muted);
}

.mr-signature__name {
  display: block;
  font-weight: 600;
  padding-top: 0.25rem;
}

.mr-signature__date {
  display: block;
  font-size: 0.75rem;
  color: var(--brand-text-muted);
}

/* The summary above the pack: which review, over what period, and what the calendar says
   about it. */
.mr-meeting-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.4rem;
  padding: 0.8rem 1rem;
  background: var(--brand-bg);
  border-radius: var(--brand-radius);
  margin-bottom: 1rem;
  font-size: 0.82rem;
}

.mr-meeting-strip dt {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-text-muted);
}

.mr-meeting-strip dd {
  margin: 0.1rem 0 0;
  font-weight: 600;
}

.mr-late {
  color: #e63946;
  font-weight: 600;
}

/* --- Charts (assets/charts.js) ---------------------------------------------------
   Everything about how a chart looks is here rather than in the SVG the module builds: font
   sizes, gridline weight, swatch shape. The module positions things and names colours; this
   decides what they look like, the same split as every other component in the file. */

/* Every chart is drawn to a fixed viewBox and scaled to its card, so one set of geometry
   constants in charts.js works at any card width. */
.chart__svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* Kept to the height of the bar charts it sits alongside, rather than filling the card. */
.chart__svg--doughnut {
  max-width: 240px;
  margin: 0 auto;
}

.chart__gridline {
  stroke: var(--brand-border);
  stroke-width: 1;
}

.chart__axis-label,
.chart__category {
  font-size: 9px;
  fill: var(--brand-text-muted);
}

.chart__value {
  font-size: 9px;
  font-weight: 600;
  fill: var(--brand-navy);
}

.chart__doughnut-total {
  font-size: 26px;
  font-weight: 700;
  fill: var(--brand-navy);
}

.chart__doughnut-label {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  fill: var(--brand-text-muted);
}

.chart__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1rem;
  margin: 0.6rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.75rem;
  color: var(--brand-text-muted);
}

.chart__legend-item {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.chart__legend-value {
  font-weight: 700;
  color: var(--brand-navy);
}

.chart__swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: none;
}

/* A register with nothing on it. Set where the chart would have been, so the card keeps its
   place in the grid and the sentence is read instead of a blank box. */
.chart__empty {
  margin: 0;
  padding: 2.5rem 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--brand-text-muted);
}

/* --- The Quality Dashboard (pages/dashboard.html) ---
   Nine chart cards, the risk matrix, and the audit-pack tile. Two columns at the same 1280px the
   registers use, so the dashboard and the pages it links to line up down the same edges. */

.dashboard-meta {
  max-width: 1280px;
  margin: 0.6rem auto 0;
  text-align: left;
  font-size: 0.78rem;
  color: var(--brand-text-muted);
}

.chart-grid {
  max-width: 1280px;
  margin: 1.5rem auto 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
}

/* One column below the width where two charts stop being readable side by side - twelve months
   of stacked bars in half of a narrow screen is a picture of nothing. */
@media (max-width: 980px) {
  .chart-grid {
    grid-template-columns: 1fr;
  }
}

.chart-card {
  display: flex;
  flex-direction: column;
  padding: 1.15rem 1.35rem 1rem;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  text-align: left;
}

/* A chart the API marks wide takes the whole grid row - for one whose categories are people, the
   room is the difference between eight readable names and eight truncated ones. */
.chart-card--wide {
  grid-column: 1 / -1;
}

.chart-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.chart-card__title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--brand-navy);
}

/* The procedure the register implements, on every card that has one. An audit asks which clause
   a figure comes from, and the answer belongs beside the figure. */
.chart-card__procedure {
  flex: none;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--brand-text-muted);
}

.chart-card__note {
  margin: 0.35rem 0 0;
  font-size: 0.76rem;
  line-height: 1.45;
  color: var(--brand-text-muted);
}

/* Takes the space between the note and the footer, with the drawing centred in it. Cards in a
   row are as tall as the tallest chart in it, and a five-bar chart pinned to the top of a card
   sized by a twelve-month one leaves a hole underneath it. */
.chart-card__chart {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin: 0.9rem 0 0;
}

/* Pushed to the bottom of the card, so the links line up across a row whose charts are
   different heights. */
.chart-card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: auto;
  padding-top: 0.85rem;
  font-size: 0.78rem;
  color: var(--brand-text-muted);
}

.chart-card__foot a {
  color: var(--brand-light-blue);
  font-weight: 500;
  text-decoration: none;
}

.chart-card__foot a:hover {
  text-decoration: underline;
}

/* The register's own copy of this grid is a filter on the table underneath it. Here there is no
   table to filter, so the cells are read rather than pressed - and they say so by not offering
   the pointer and hover the register's cells do. */
.risk-matrix--static #risk-matrix-table td {
  cursor: default;
}

.risk-matrix--static #risk-matrix-table td:hover {
  box-shadow: none;
}

.dashboard-matrix__note {
  max-width: 640px;
  margin: 1rem auto 0;
  font-size: 0.76rem;
  line-height: 1.5;
  color: var(--brand-text-muted);
  text-align: center;
}

/* The way through to the Audit-Readiness Pack. Dashed rather than solid, so it reads as a way out
   of the dashboard rather than as a tenth chart. */
.pack-card {
  max-width: 1280px;
  margin: 1.5rem auto 0;
  padding: 1.25rem 1.5rem;
  background: var(--brand-surface);
  border: 1px dashed var(--brand-border);
  border-radius: var(--brand-radius);
  text-align: left;
}

.pack-card__title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--brand-navy);
}

.pack-card__body {
  margin: 0.4rem 0 0;
  max-width: 70ch;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--brand-text-muted);
}

.pack-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.pack-card__link {
  flex: none;
  color: var(--brand-light-blue);
  font-size: 0.8rem;
  font-weight: 500;
  text-decoration: none;
}

.pack-card__link:hover {
  text-decoration: underline;
}

/* The pack's clause statuses, live. Filled in after the charts are drawn. */
.pack-card__status {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0.8rem 0 0;
}

.pack-card__loading {
  font-size: 0.78rem;
  color: var(--brand-text-muted);
}

.pack-status {
  min-width: 92px;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  border-left: 4px solid var(--brand-border);
  background: var(--brand-bg);
}

.pack-status__value {
  display: block;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--brand-navy);
  font-variant-numeric: tabular-nums;
}

.pack-status__label {
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--brand-text-muted);
}

.pack-status--green {
  border-left-color: var(--chart-ok);
}

.pack-status--amber {
  border-left-color: var(--chart-warning);
}

.pack-status--red {
  border-left-color: var(--chart-critical);
}

/* The clauses that are not Green, each a link into the pack. */
.pack-card__attention {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.7rem 0 0;
  font-size: 0.78rem;
  color: var(--brand-text-muted);
}

.pack-card__clause {
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

.pack-card__clause--amber {
  background: rgba(252, 112, 46, 0.12);
  color: var(--brand-orange);
}

.pack-card__clause--red {
  background: rgba(200, 30, 44, 0.12);
  color: var(--chart-critical);
}

.pack-card__clause:hover {
  text-decoration: underline;
}

.pack-card__note {
  color: var(--brand-text-muted);
  font-size: 0.72rem;
}

/* Off the page but not out of the accessibility tree - the numbers behind each chart, as a
   table, for a screen reader. Not [hidden] and not display:none, either of which would take it
   out of that tree as well. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- The ISO 9001:2015 Audit-Readiness Pack (pages/audit_readiness_pack.html) -----
   A clause card per clause with a sticky contents list beside them, under a summary
   carrying the status counts and the moment they were taken. The figures, tables and gaps
   inside a card use the shared pack- classes above. */

.arp-loading {
  max-width: 1280px;
  margin: 2rem auto;
  text-align: left;
  font-size: 0.85rem;
  color: var(--brand-text-muted);
}

/* When the pack was taken, what it covers, and the counts. */
.arp-summary {
  max-width: 1280px;
  margin: 1.5rem auto 0;
  padding: 1.25rem 1.5rem;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  text-align: left;
}

.arp-summary__meta {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--brand-navy);
}

.arp-summary__scope {
  margin: 0.3rem 0 0;
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--brand-text-muted);
}

.arp-summary__counts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 0.75rem;
  margin: 1.1rem 0 0;
}

.arp-count {
  padding: 0.7rem 0.85rem;
  border-radius: 8px;
  border-left: 4px solid var(--brand-border);
  background: var(--brand-bg);
}

.arp-count__value {
  display: block;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--brand-navy);
  font-variant-numeric: tabular-nums;
}

.arp-count__label {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
}


.arp-count--green {
  border-left-color: var(--chart-ok);
}

.arp-count--amber {
  border-left-color: var(--chart-warning);
}

.arp-count--red {
  border-left-color: var(--chart-critical);
}


/* The rule behind the overall verdict, under the counts. */
.arp-summary__rule {
  margin: 1rem 0 0;
  max-width: 90ch;
  font-size: 0.76rem;
  line-height: 1.6;
  color: var(--brand-text-muted);
}

.arp-summary__actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 1rem 0 0;
}

/* Building the PDF assembles the pack again, which takes a few seconds. */
.arp-summary__progress {
  font-size: 0.78rem;
  color: var(--brand-text-muted);
}

/* A source the pack could not reach, said once at the top and again in the clauses it
   affects. */
.arp-notice {
  max-width: 1280px;
  margin: 1rem auto 0;
  padding: 0.7rem 0.9rem;
  background: rgba(252, 112, 46, 0.08);
  border-left: 3px solid var(--brand-orange);
  border-radius: 0 8px 8px 0;
  text-align: left;
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--brand-text);
}

.arp-walk {
  max-width: 1280px;
  margin: 1.5rem auto 0;
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: 1.5rem;
  align-items: start;
}

/* Below two columns the contents list goes above the cards, and stops being sticky - a
   block that tall would cover what it links to. */
@media (max-width: 900px) {
  .arp-walk {
    grid-template-columns: 1fr;
  }
}

.arp-toc {
  position: sticky;
  top: 1rem;
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 0.9rem 0.75rem;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  border-radius: var(--brand-radius);
  text-align: left;
}

@media (max-width: 900px) {
  .arp-toc {
    position: static;
    max-height: none;
  }
}

.arp-toc__heading {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--brand-navy);
}

.arp-toc__section {
  margin: 0.8rem 0 0.25rem;
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--brand-text-muted);
}

.arp-toc__link {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.25rem 0.3rem;
  border-radius: 6px;
  font-size: 0.76rem;
  line-height: 1.35;
  color: var(--brand-text);
  text-decoration: none;
}

.arp-toc__link:hover {
  background: var(--brand-bg);
}

.arp-toc__link:focus-visible {
  outline: 2px solid var(--brand-light-blue);
  outline-offset: 1px;
}

.arp-toc__id {
  flex: none;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--brand-navy);
}

.arp-clauses {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.arp-clause {
  padding: 1.15rem 1.35rem 1.25rem;
  background: var(--brand-surface);
  border: 1px solid var(--brand-border);
  /* The status as an edge down the whole card, so it is readable while scrolling past rather
     than only when the header is in view. */
  border-left: 5px solid var(--brand-border);
  border-radius: var(--brand-radius);
  text-align: left;
  /* A card flush against the top of the viewport reads as cut off. */
  scroll-margin-top: 1rem;
}

.arp-clause--green {
  border-left-color: var(--chart-ok);
}

.arp-clause--amber {
  border-left-color: var(--chart-warning);
}

.arp-clause--red {
  border-left-color: var(--chart-critical);
}

/* The status in words on the card, not just as a colour: the colour is the quick read and the
   word is what somebody quotes. */
.arp-status-chip {
  flex: none;
  padding: 0.2rem 0.6rem;
  border-radius: 5px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #fff;
  background: var(--brand-text-muted);
}

.arp-status-chip--green {
  background: var(--chart-ok);
}

.arp-status-chip--amber {
  background: var(--chart-warning);
}

.arp-status-chip--red {
  background: var(--chart-critical);
}

.arp-clause__head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.arp-clause__title {
  flex: 1;
  min-width: 12rem;
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--brand-navy);
}

.arp-clause__id {
  font-variant-numeric: tabular-nums;
}

.arp-clause__id::after {
  content: " ";
}

/* The requirement in the standard's own terms, set apart from the figures below it. */
.arp-clause__iso {
  margin: 0.7rem 0 0;
  padding: 0.6rem 0.8rem;
  background: var(--brand-bg);
  border-radius: 8px;
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--brand-text-muted);
}

/* The conditions that set the status, one per row against the status it produces. A definition
   list rather than a sentence: the reader is checking a value against a condition, not reading
   an explanation of how the check works. */
.arp-thresholds__heading {
  margin: 0.9rem 0 0;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-text-muted);
}

.arp-thresholds {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0.3rem 0.7rem;
  margin: 0.35rem 0 0;
}

.arp-thresholds__status {
  padding: 0.1rem 0.5rem;
  border-radius: 4px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #fff;
  justify-self: start;
}

.arp-thresholds__status--red {
  background: var(--chart-critical);
}

.arp-thresholds__status--amber {
  background: var(--chart-warning);
}

.arp-thresholds__status--green {
  background: var(--chart-ok);
}

.arp-thresholds__condition {
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.45;
}

/* The status somebody set on a clause the portal holds no evidence for, and the control to
   change it. Bordered in navy rather than the clause card's grey: this is the one part of the
   pack that is typed in rather than measured. */
.arp-manual {
  margin: 0.9rem 0 0;
  padding: 0.7rem 0.85rem;
  background: var(--brand-bg);
  border-left: 3px solid var(--brand-navy);
  border-radius: 0 8px 8px 0;
}

.arp-manual h4 {
  margin: 0 0 0.2rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-text-muted);
}

.arp-manual__set {
  margin: 0;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--brand-navy);
}

.arp-manual__evidence-text {
  margin: 0.2rem 0 0;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--brand-text-muted);
}

.arp-manual__controls {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0.6rem 0 0;
}

.arp-manual__controls .form-field {
  margin: 0;
}

.arp-manual__evidence {
  flex: 1;
  min-width: 16rem;
}

.arp-manual__saved {
  font-size: 0.78rem;
  color: var(--brand-text-muted);
}

.arp-clause__narrative {
  margin: 0.7rem 0 0;
  font-size: 0.85rem;
  line-height: 1.65;
}

/* A dot rather than a coloured card: a card is mostly figures, and a wash of colour behind
   them makes them harder to read. */
.arp-status {
  flex: none;
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--brand-text-muted);
}

.arp-status--green {
  background: var(--chart-ok);
}

.arp-status--amber {
  background: var(--chart-warning);
}

.arp-status--red {
  background: var(--chart-critical);
}

/* What the clause resolved against the live SharePoint library: where the document is and
   when it last changed. Never a revision number the portal cannot see. */
.arp-documents {
  margin: 0.9rem 0 0;
  padding: 0.7rem 0.85rem;
  background: var(--brand-bg);
  border-radius: 8px;
}

.arp-documents h4 {
  margin: 0 0 0.4rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-text-muted);
}

.arp-documents ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.arp-doc {
  padding-left: 0.6rem;
  border-left: 3px solid var(--chart-ok);
}

.arp-doc__code {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--brand-navy);
}

.arp-doc__name {
  font-size: 0.78rem;
}

.arp-doc__meta {
  display: block;
  font-size: 0.68rem;
  line-height: 1.5;
  color: var(--brand-text-muted);
  word-break: break-word;
}

/* Missing, and present only as an archived or duplicated copy. Both are findings. */
.arp-doc--missing {
  border-left-color: var(--chart-critical);
}

.arp-doc--missing .arp-doc__name {
  color: var(--chart-critical);
  font-weight: 600;
}

.arp-doc--superseded {
  border-left-color: var(--chart-warning);
}

/* Screen: nothing. Print: the running header. See the print block below. */
.arp-print-header {
  display: none;
}

/* --- Print: the packs and the minutes --------------------------------------------
   The Management Review pack and its minutes (GP06 §11) print from an open dialog, so the
   page behind them is what gets hidden. The Audit-Readiness Pack is the page, so for it the
   chrome is what goes - and its filed copy is the PDF export, not this. */
@page {
  margin: 14mm 12mm 16mm;
}

@media print {
  .topbar,
  .page-footer,
  .back-link,
  .kpi-strip,
  .data-table__toolbar,
  .modal__actions,
  .mr-input__capture button,
  .risk-matrix__filter-notice,
  .arp-toc,
  .arp-summary__actions,
  .arp-loading,
  .arp-manual__controls,
  .arp-notice[hidden] {
    display: none !important;
  }

  body:has(dialog.modal[open]) main.page-content {
    display: none;
  }

  dialog.modal[open] {
    position: static;
    display: block;
    max-width: none;
    max-height: none;
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    box-shadow: none;
    overflow: visible;
  }

  dialog.modal::backdrop {
    display: none;
  }

  /* Every input open, whatever the chair had expanded on screen - a filed pack that omits
     the items nobody clicked is not the pack. */
  .mr-input__body {
    display: block !important;
  }

  .mr-input {
    break-inside: avoid;
    border-color: #ccc;
  }

  .pack-figure {
    border: 1px solid #ddd;
  }

  .pack-table th {
    background: #f0f0f0 !important;
  }

  /* --- The Audit-Readiness Pack in print ---
     Sized in rem throughout, so dropping the root size scales the whole pack down at once:
     screen sizes cost twice the sheets. Scoped to this page. */
  html:has(.arp-page) {
    font-size: 12px;
  }

  /* The two columns collapse to one: the contents list is a navigation aid and a printed page
     cannot be clicked. */
  .arp-walk {
    display: block;
    max-width: none;
  }

  /* Every edge but the left one, which carries the status. */
  .arp-clause {
    border-top-color: #ccc;
    border-right-color: #ccc;
    border-bottom-color: #ccc;
    margin-bottom: 0.9rem;
  }

  /* Cards split; only their opening is held together. Keeping whole cards off page breaks
     cost thirty-four pages of white space. */
  .arp-clause__head,
  .arp-clause__iso,
  .arp-thresholds {
    break-after: avoid;
  }

  .pack-table,
  .arp-documents,
  .pack-gaps {
    break-inside: avoid;
  }

  .arp-summary {
    break-inside: avoid;
    border-color: #ccc;
  }

  /* The generated-at line, at the head of the printed document. Page one only: no browser
     will repeat generated content per page from CSS. The per-page stamp is in the PDF
     export, which is the copy to file. */
  .arp-print-header {
    display: block;
    margin: 0 0 4mm;
    padding-bottom: 2mm;
    border-bottom: 1px solid #ccc;
    font-size: 7.5pt;
    line-height: 1.4;
    color: #444;
  }

  /* Ink: a page-wide grey wash behind a document. */
  body {
    background: #fff !important;
  }

  .arp-summary__counts {
    grid-template-columns: repeat(4, 1fr);
  }

  /* A traffic light that prints as a grey circle is not a traffic light. */
  .arp-status,
  .arp-status-chip,
  .arp-thresholds__status,
  .arp-clause,
  .arp-count,
  .arp-doc,
  .pack-gaps {
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
}
