/* ---- Shared layout and components ----------------------------------------
   The palette and the type/space scale live in `tokens.css`, which every
   template linking this file links first. Nothing here may introduce a colour
   literal: if a component needs a colour that no token names, the token block
   is where that argument gets settled.
   -------------------------------------------------------------------------- */

/* ---- Layout --------------------------------------------------------------- */

body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 1.5rem 1rem 4rem;
}

/* The full-bleed body: `body` sets no measure of its own, bands run edge to
   edge and each one centres its own `.page-width`.

   Two shells take it, and they are exactly the two that render
   `partials/site_header.html`. That is the point: the header centres itself,
   and a body that also caps itself would inset it twice and stop its rule
   short of the window. The pre-login surface
   (`public/base.html`) is one; the organization picker is the other, signed
   in but with no tenant chosen and so no application shell. */
body.page-public,
body.page-picker {
  --gutter: 1.25rem;
  max-width: none;
  padding: 0;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.page-width {
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  background: var(--accent);
  color: var(--on-accent);
  padding: var(--space-2) var(--space-4);
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus { left: 0; }

.site-header {
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.5rem;
}
.site-header__inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  flex-wrap: wrap;
  padding-block: 0.6rem;
}
.site-header a { color: inherit; text-decoration: none; }
/* ...except the one that is a filled button. `.site-header a` outranks `.btn`,
   so "Create a workspace" was ink-on-accent: roughly 2.7:1, unreadable. */
.site-header a.btn { color: var(--on-accent); }
.site-header nav {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  font-size: var(--fs-small);
}

/* Wordmark: the site icon plus its name, one target. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.wordmark img { width: 1.4rem; height: 1.4rem; display: block; }

/* The language switcher was an unstyled OS dropdown on every page (UX-001). */
.lang-switch select {
  font: inherit;
  font-size: var(--fs-small);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.25rem 0.4rem;
}

:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

.inline-form { display: inline; }
.linklike {
  background: none; border: none; padding: 0;
  color: var(--accent); cursor: pointer; font: inherit;
}

h1 { font-size: 1.4rem; }
h2 { font-size: 1.1rem; margin: 1.5rem 0 0.5rem; }

a { color: var(--accent); }

/* ---- Assessment workspace ------------------------------------------------- */

.summary-bar {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  margin: 1rem 0;
}

.assessment-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border);
  font-size: 0.9rem;
}
.assessment-table th, .assessment-table td {
  padding: 0.45rem 0.6rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
}
.assessment-table th {
  background: var(--neutral-soft);
  font-weight: 600;
}
.req-id { font-family: ui-monospace, monospace; white-space: nowrap; }
.statement-cell { max-width: 34rem; }

.detail-slot > td { background: var(--bg); }
.detail-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  padding: 0.9rem 1rem;
  margin: 0.4rem 0;
  display: grid;
  gap: 0.7rem;
}
.detail-panel .zh { color: var(--muted); }
.detail-panel .note { color: var(--muted); font-size: 0.85rem; }
.guidance {
  background: var(--accent-soft);
  border-radius: 4px;
  padding: 0.5rem 0.7rem;
  font-size: 0.88rem;
  /* Harvested guidance is one labelled line per checklist column
     (`load_guidance`); without this the four lines run together. */
  white-space: pre-line;
}

.fields-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 0.5rem 1rem;
  font-size: 0.88rem;
}
.fields-grid dt { color: var(--muted); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; }
.fields-grid dd { margin: 0; }

/* ---- Chips ---------------------------------------------------------------- */

.chip {
  display: inline-block;
  padding: 0.1rem 0.55rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
}
.chip-satisfied { background: var(--ok-soft); color: var(--ok); }
.chip-in_progress { background: var(--warn-soft); color: var(--warn); }
.chip-not_started { background: var(--crit-soft); color: var(--crit); }
.chip-not_applicable { background: var(--neutral-soft); color: var(--slate); }
.chip-waived { background: var(--waived-soft); color: var(--waived); }
.chip-kind { background: var(--neutral-soft); color: var(--slate); font-weight: 500; }
.chip-gap { background: var(--crit); color: var(--on-crit); }
/* Expired evidence and unreviewed self-attestation are the two states a
   compliance dashboard is tempted to hide; they get their own loud chips. */
.chip-expired { background: var(--crit); color: var(--on-crit); }
.chip-unreviewed { background: var(--warn-soft); color: var(--warn); }

/* Tone-named chips, for a component that shows records from several planes at
   once (the dashboard's record cards, `tenancy/records.py`). A case state, an
   advisory state and a source's last check are three vocabularies with the
   same handful of colour roles, so a record row names the ROLE and each plane
   decides which one its value takes. `--waived` keeps the status name it
   already had above; there is no accent tone at all, because blue is chrome
   and never a status (tokens.css, rule 2). */
.chip-ok { background: var(--ok-soft); color: var(--ok); }
.chip-warn { background: var(--warn-soft); color: var(--warn); }
.chip-crit { background: var(--crit-soft); color: var(--crit); }
.chip-quiet { background: var(--neutral-soft); color: var(--slate); }

/* ---- Forms & buttons ------------------------------------------------------ */

.detail-panel form { display: grid; gap: 0.5rem; }
.detail-panel label { font-size: 0.8rem; color: var(--muted); display: block; }
.detail-panel input[type="text"], .detail-panel input[type="url"],
.detail-panel input[type="date"], .detail-panel textarea, .detail-panel select {
  width: 100%; box-sizing: border-box;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border); border-radius: 4px;
  font: inherit; background: var(--surface); color: var(--text);
}
.btn {
  display: inline-block;
  background: var(--accent); color: var(--on-accent);
  border: none; border-radius: 4px;
  padding: 0.35rem 0.9rem;
  font: inherit; cursor: pointer;
}
.btn-quiet {
  background: var(--surface); color: var(--accent);
  border: 1px solid var(--border);
}
.btn-small {
  font-size: var(--fs-small);
  padding: 0.3rem 0.7rem;
  text-decoration: none;
}
.btn-row { display: flex; gap: 0.5rem; }

/* Present to a screen reader, absent from the page. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.error-box {
  background: var(--crit-soft); color: var(--crit);
  border-radius: 4px; padding: 0.5rem 0.7rem; font-size: 0.88rem;
}

/* `hidden` must win over any layout rule a component sets on the same
   element — static/js/field-switch.js relies on it to hide the input the
   chosen evidence kind does not use. */
[hidden] { display: none !important; }

.evidence-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.3rem; }
.evidence-list li {
  display: flex; justify-content: space-between; gap: 0.6rem;
  border: 1px solid var(--border); border-radius: 4px;
  padding: 0.35rem 0.6rem; font-size: 0.88rem; background: var(--surface);
}
.evidence-expired { color: var(--crit); }

/* One stored artifact: the link that hands the bytes back, and the digest a
   reader checks them against (templates/partials/evidence_file.html and
   evidence_digest.html). Both break anywhere, because a filename is
   user-supplied and a SHA-256 is 64 unbreakable characters. */
.evidence-file { overflow-wrap: anywhere; }
.evidence-digest {
  display: block;
  font-family: ui-monospace, monospace;
  font-size: 0.72rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* ---- Coverage dashboard (M3) ---------------------------------------------- */

.coverage-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: 0.8rem;
}
.coverage-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.8rem 1rem 1rem;
}
.coverage-card h3 { font-size: 1rem; margin: 0; }
.coverage-card .summary-bar { margin: 0.6rem 0; }

.report-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  font-size: 0.88rem;
}
.audit-pack-form {
  margin-top: 0.7rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.article-section { margin-top: 1.8rem; }
.article-section .assessment-table { margin-top: 0.5rem; }

.note { color: var(--muted); font-size: 0.85rem; }
.zh { color: var(--muted); }

/* ---- Case plane (M4) ------------------------------------------------------ */

.case-workspace { display: grid; gap: 1rem; margin-top: 1rem; }

.case-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.8rem 1rem 1rem;
}
.case-panel h2 { margin-top: 0; }

.chip-case-open { background: var(--crit-soft); color: var(--crit); }
.chip-case-waiting { background: var(--warn-soft); color: var(--warn); }
.chip-case-working { background: var(--accent-soft); color: var(--accent); }
.chip-case-closed { background: var(--neutral-soft); color: var(--slate); }

.panel-form { display: grid; gap: 0.5rem; margin-top: 0.7rem; }
.panel-form label { font-size: 0.8rem; color: var(--muted); display: block; }
.panel-form input[type="text"], .panel-form input[type="email"],
.panel-form input[type="date"], .panel-form input[type="file"],
.panel-form textarea, .panel-form select {
  width: 100%; box-sizing: border-box;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border); border-radius: 4px;
  font: inherit; background: var(--surface); color: var(--text);
}
.field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.5rem 0.8rem;
  align-items: end;
}
.checkbox-label { display: flex; align-items: center; gap: 0.4rem; }
.checkbox-label input { width: auto; }

.impact-dimensions {
  border: 1px solid var(--border); border-radius: 4px;
  padding: 0.5rem 0.7rem;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0.4rem 0.8rem;
}
.impact-dimensions legend { font-size: 0.8rem; color: var(--muted); }

.transition-list {
  display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: flex-start;
}
.transition-form {
  border: 1px solid var(--border); border-radius: 4px;
  padding: 0.5rem 0.7rem;
  display: grid; gap: 0.4rem;
  min-width: 14rem; max-width: 22rem;
}
.transition-blocked { background: var(--bg); }
.guard-list {
  margin: 0.2rem 0 0; padding-left: 1.1rem;
  color: var(--warn); font-size: 0.82rem;
}

.case-timeline { margin: 0; padding-left: 1.1rem; font-size: 0.88rem; }
.case-timeline li { margin-bottom: 0.25rem; }

/* ---- Release & advisory panels (M5) --------------------------------------- */

.release-facts {
  list-style: none; margin: 0.4rem 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.4rem;
  font-size: 0.82rem;
}
.release-facts li {
  border: 1px solid var(--border); border-radius: 4px;
  padding: 0.2rem 0.5rem;
}
.release-facts .req-id { margin-left: 0.3rem; }
.fact-ok { background: var(--ok-soft); color: var(--ok); }
.fact-missing { background: var(--crit-soft); color: var(--crit); }

/* English and its zh-Hant counterpart edit side by side (decision #9). */
.bilingual {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0.4rem 0.8rem;
}

.advisory-banner {
  border-left: 3px solid var(--accent);
  padding: 0.3rem 0 0.3rem 0.8rem;
}

/* The Markdown hint above the advisory's long fields is a grid item in
   `.panel-form`, so its own paragraph margins would stack on the grid gap. */
.advisory-format-hint { margin: 0; }

/* ---- Public report form --------------------------------------------------- */

.public-body { max-width: 46rem; }
.public-form { max-width: 40rem; }
.honeypot-field { display: none; }
.field-error { color: var(--crit); font-size: 0.82rem; }
.report-notice {
  border-left: 3px solid var(--accent);
  padding: 0.2rem 0 0.2rem 0.8rem;
  margin-top: 1.5rem;
}

/* ---- Product cards on workspace home -------------------------------------- */

.card-list { list-style: none; padding: 0; display: grid; gap: 0.6rem; }
.card-list li {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 6px; padding: 0.8rem 1rem;
}

/* ---- Flash messages (self-service signup, M7b) ----------------------------- */

.site-messages { list-style: none; margin: 0.8rem 1.2rem 0; padding: 0; display: grid; gap: 0.4rem; }
.site-messages li {
  border-radius: 4px; padding: 0.5rem 0.7rem; font-size: 0.9rem;
  background: var(--neutral-soft); color: var(--slate);
}
.site-messages li.success { background: var(--ok-soft); color: var(--ok); }
.site-messages li.error { background: var(--crit-soft); color: var(--crit); }
.site-messages li.warning { background: var(--warn-soft); color: var(--warn); }
/* Both full-bleed shells pad through `.page-width`; a second inset double-counts. */
.page-public .site-messages,
.page-picker .site-messages { margin-inline: 0; }

/* ---- Narrowed section notice ---------------------------------------------- */
/* Drawn by every page a dashboard count hands a reader to (the case list, the
   assessment workspace, the monitoring board, the test and review plan), so it
   belongs with the shared components rather than in four page stylesheets.
   It reads as chrome and never as a status: a filter is not a verdict, so the
   accent is right here and a status colour would not be (tokens.css, rule 2).
   The way out sits at the far end of the row, where a reader looking for it
   finds it in the same place on all four pages. */

.filter-notice {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.8rem;
  margin: 0.9rem 0;
  padding: 0.55rem 0.8rem;
  background: var(--panel-sunk);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
}
.filter-notice p { margin: 0; }
.filter-notice__label { color: var(--text); }
.filter-notice__n { color: var(--muted); font-size: var(--fs-small); }
.filter-notice__clear { margin-left: auto; }
