/* Copyright (c) 2026 by Fly Compliant, LLC
 *
 * Page styles. Tokens live in tokens.css; a rebrand is that file, not this one.
 *
 * ALL sizing is in rem. One hard-coded px font-size silently opts that element
 * out of the A− / A / A+ control, which is an accessibility regression that
 * looks fine in every screenshot.
 */

html { font-size: 100%; }
body {
  margin: 0;
  font-family: var(--fc-font-sans);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--fc-ink);
  background: var(--fc-surface);
  /* Sticky footer. On a short page the footer sat directly beneath the content, so its
     top border read as a stray rule in the middle of the page rather than as the base
     of it. dvh, not vh, so mobile browser chrome does not push it below the fold. */
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
body > main { flex: 1 0 auto; }

/* The container. 60rem is a READABILITY cap, not a layout accident: a line of prose
   2,000px wide is hard to track back to the start of, so prose pages keep it.

   A six-column table is not prose. It was scrolling inside its own .table-scroll box
   while the window had hundreds of pixels spare. .page-wide (set from PageData.Wide on
   the admin and log pages) lifts the cap and lets the container follow the viewport,
   which is a max-width change and therefore reflows on resize with no JavaScript. */
.wrap { max-width: 60rem; margin: 0 auto; padding: 0 1rem; }
.narrow { max-width: 42rem; }
/* 120rem so a table stops growing on an ultrawide, where a row 3,000px wide makes the
   eye lose which record it is on between the first column and the last. */
.page-wide .wrap { max-width: min(120rem, 100%); }

/* Anything wide scrolls inside its own box; the page body never scrolls
 * sideways. */
.table-scroll { overflow-x: auto; }

h1 { font-size: 1.75rem; line-height: 1.3; margin: 1.5rem 0 0.5rem; }
h2 { font-size: 1.3rem; margin: 1.75rem 0 0.5rem; color: var(--fc-navy); }
h3 { font-size: 1.05rem; margin: 1rem 0 0.35rem; }
a { color: var(--fc-link); }
a:hover { color: var(--fc-link-hover); }

/* Inline code. Added for the dev-mode sign-in panel, which names a shell command; the
   element had no rule, so it rendered at the browser's default monospace size — usually
   a size smaller than the surrounding text, and in px, which would opt it out of the
   A− / A / A+ control. 0.9em rather than a rem value so it tracks its container. */
code {
  font-family: var(--fc-font-mono);
  font-size: 0.9em;
  background: var(--fc-surface-2);
  border: 1px solid var(--fc-line);
  border-radius: 0.25rem;
  padding: 0.075em 0.3em;
  word-break: break-word;
}

.skip-link {
  position: absolute; left: -9999rem; top: 0; z-index: 100;
  background: var(--fc-surface); padding: 0.5rem 1rem;
}
.skip-link:focus { left: 0; }

/* A visible focus ring everywhere. Removing it is the single most common
 * accessibility regression in a redesign. */
:focus-visible {
  outline: 3px solid var(--fc-link);
  outline-offset: 2px;
}

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

/* Header ------------------------------------------------------------------ */
.site-header { border-bottom: 1px solid var(--fc-line); background: var(--fc-surface); }
.header-row {
  display: flex; align-items: center; gap: 1rem;
  flex-wrap: wrap; padding-top: 0.75rem; padding-bottom: 0.75rem;
}
/* Brand lockup: glyph + two lines of live text.
   The wordmark <img> it replaces was traced type, so the name could not be changed in it.
   .wordmark's rule is gone with it rather than left behind as dead CSS. */
.brand {
  display: inline-flex; align-items: center; gap: 0.6rem;
  text-decoration: none; color: var(--fc-ink);
}
.brand:hover { color: var(--fc-ink); }
.brand:hover .brand-name { color: var(--fc-red-deep); }
.brand-mark { height: 2.25rem; width: auto; display: block; }
/* Two lines, tight: the product name leads and the company is subordinate to it, which is
   the relationship "FC135.ai by Fly Compliant, LLC" states. */
.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-name {
  font-size: 1.35rem; font-weight: 800; letter-spacing: -0.015em;
  color: var(--fc-ink);
}
/* The TLD in brand red so the name reads as a domain rather than a word. --fc-red is a
   gated text role, so it clears AA on this surface in both themes. */
.brand-tld { color: var(--fc-red); }
.brand-by { font-size: 0.7rem; font-weight: 600; color: var(--fc-muted); }
/* On a narrow screen the second line is the first thing worth dropping — the glyph and
   "FC135.ai" are enough to identify the site, and the footer carries the company name on
   every page anyway. */
@media (max-width: 26rem) {
  .brand-by { display: none; }
  .brand-name { font-size: 1.2rem; }
}
.dark-only { display: none; }
:root[data-theme="dark"] .light-only { display: none; }
:root[data-theme="dark"] .dark-only { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .light-only { display: none; }
  :root:not([data-theme="light"]) .dark-only { display: block; }
}

.site-nav { display: flex; gap: 1rem; align-items: center; margin-left: auto; flex-wrap: wrap; }
/* Sign out is a <button> inside a <form>, because signing out must be a POST. That form
   is a flex ITEM of the nav rather than a link like its neighbours, and a form carries a
   user-agent margin, which lifted its button clear of the line the links sit on. Zeroing
   the margin and making the form its own centred flex container puts the button on
   exactly the links' baseline. */
.site-nav .inline-form { display: flex; align-items: center; margin: 0; }
/* A divider before it, so a destructive-looking control is visibly separated from
   navigation rather than reading as a fifth place to go. */
.site-nav .inline-form::before {
  content: ""; align-self: stretch; width: 1px; margin-right: 1rem;
  background: var(--fc-line);
}
.controls { display: flex; gap: 0.5rem; align-items: center; }
.textsize { display: inline-flex; gap: 0.15rem; align-items: center; }

/* Every footer control button — A− A A+ and the theme icon — is one rule.
   They were two: this one set the style and a separate .icon-button rule gave the
   theme button its own size and no background, so it rendered taller than its
   neighbours and off their baseline. A button that is "nearly" the same as the ones
   beside it looks like a mistake, because it is one.
   inline-flex + center is what puts a glyph and an SVG on the same optical line;
   text-only buttons sit on the text baseline and an SVG does not.
   2.25rem square (36px) clears the 24x24 CSS-pixel WCAG 2.2 Target Size (Minimum)
   for all four, which the icon alone at 18px would not, and does it in rem so the
   text-size control scales its own buttons. */
.textsize button, #theme-toggle, #palette-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.25rem;
  min-height: 2.25rem;
  padding: 0.3rem 0.55rem;
  font-size: 0.875rem;
  line-height: 1;
  cursor: pointer;
  border: 1px solid var(--fc-control-line); border-radius: var(--fc-radius);
  background: var(--fc-surface-2); color: var(--fc-ink);
}

/* Banners ----------------------------------------------------------------- */
.banner {
  border-radius: var(--fc-radius); padding: 0.75rem 1rem; margin: 1rem auto;
  border-left: 0.25rem solid var(--fc-warn); background: var(--fc-surface-alt);
}
.banner-warn { border-left-color: var(--fc-warn); }
.banner-ok { border-left-color: var(--fc-ok); }
/* A retryable failure is our fault, not the user's. Distinct from a refusal so
 * "try again" and "we won't answer that" never look the same. */
.banner-retry { border-left-color: var(--fc-navy); }
.banner p { margin: 0 0 0.35rem; }
.banner p:last-child { margin-bottom: 0; }

.effort { margin-top: 1rem; }
.effort select {
  font: inherit; font-size: 1rem; padding: 0.45rem 0.6rem;
  border: 1px solid var(--fc-line); border-radius: var(--fc-radius);
  background: var(--fc-surface); color: var(--fc-ink);
}

/* The AI disclaimer is not dismissible. There is deliberately no close button
 * and no JS that can hide it. */
.ai-disclaimer {
  border: 1px solid var(--fc-warn);
  border-left-width: 0.25rem;
  border-radius: var(--fc-radius);
  padding: 0.75rem 1rem;
  margin: 1rem 0;
  color: var(--fc-warn);
  background: var(--fc-surface-alt);
  font-size: 0.95rem;
}

/* Forms ------------------------------------------------------------------- */
textarea, input[type="email"], input[type="text"], input[type="file"] {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 1rem;
  /* Control boundary, not a divider — WCAG 2.2 SC 1.4.11 wants 3:1 here. */
  padding: 0.6rem; border: 1px solid var(--fc-control-line);
  border-radius: var(--fc-radius);
  background: var(--fc-surface); color: var(--fc-ink);
}
label { display: block; font-weight: 600; margin-top: 1rem; }
label.checkbox, label.consent-check {
  font-weight: 400; display: flex; gap: 0.5rem; align-items: flex-start;
}
label.checkbox input, label.consent-check input { width: auto; margin-top: 0.3rem; }
.help { color: var(--fc-muted); font-size: 0.9rem; margin: 0.35rem 0 0; }

/* Lede — the one-line statement of what a page is for.
   Used on the ask page and the login page, and until now had no rule at all, so it
   rendered at body weight and the h1 had nothing following it that read as a subtitle. */
.lede { color: var(--fc-muted); font-size: 1.05rem; margin: 0.25rem 0 1.5rem; max-width: 34rem; }

/* Login page --------------------------------------------------------------
   Two columns on a wide screen: what the product is on the left, the sign-in card on
   the right. One column below 52rem with the hero first — on a phone the visitor
   should reach the email field by scrolling, not read a pitch twice the length of the
   form.

   Ordered product first, legal second. The data-capture disclosure sits inside the
   card above the checkbox that acknowledges it, so it cannot be skipped. */
.login-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  align-items: start;
  margin: 1.5rem 0 3rem;
}
@media (min-width: 52rem) {
  .login-grid { grid-template-columns: 1.05fr 1fr; gap: 3.5rem; }
  /* The hero holds less vertical content than the card, so nudging it down puts the
     h1 and the card heading on roughly the same optical line. */
  .login-hero { padding-top: 1.25rem; }
}

.login-hero h1 {
  font-size: 2.1rem;
  line-height: 1.15;
  /* Slightly negative tracking at display size only. At body size this would cost
     legibility; at 2.1rem the default spacing looks loose. */
  letter-spacing: -0.02em;
  margin: 0 0 0.75rem;
  text-wrap: balance;
}
.login-hero .lede { font-size: 1.075rem; margin-bottom: 2rem; }

/* Eyebrow above the h1. States the jurisdiction before the claim — AGENTS.md requires
   that never be left implicit — and gives the heading something to sit under. */
.eyebrow {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--fc-navy);
  margin: 0 0 0.75rem;
}
.eyebrow::before {
  content: ""; width: 1.5rem; height: 0.125rem;
  background: var(--fc-red); border-radius: 1rem;
}

.login-hero h2 {
  font-size: 0.8rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--fc-muted);
  margin: 0 0 0.75rem;
}

/* Example questions. Quoted sample input, so each gets its own surface — set as list
   bullets they read as a policy list, which is the opposite of what they are. */
.examples { list-style: none; padding-left: 0; margin: 0 0 1rem; display: grid; gap: 0.625rem; }
.examples li {
  border: 1px solid var(--fc-line);
  border-radius: var(--fc-radius-lg);
  background: var(--fc-surface-2);
  padding: 0.75rem 0.9rem;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.examples li:hover { border-color: var(--fc-navy); transform: translateY(-0.0625rem); }
.example-q { display: block; margin-top: 0.25rem; font-size: 0.975rem; }
/* Which of the two allowed kinds this is. A pill, so it reads as a label rather than
   as the first words of the question. Uses --fc-badge-fg because the fill is a
   mid-tone in light mode and a light tint in dark mode, so white text is correct in
   one theme and unreadable in the other. */
.example-kind {
  display: inline-block;
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 0.125rem 0.5rem; border-radius: 1rem;
  background: var(--fc-navy); color: var(--fc-badge-fg);
}
.example-kind.kind-manual { background: var(--fc-guidance); }

/* The sign-in card. */
.login-card {
  border: 1px solid var(--fc-line);
  border-radius: var(--fc-radius-lg);
  background: var(--fc-surface);
  box-shadow: var(--fc-shadow-lg);
  padding: 1.75rem;
}
.login-card h2 {
  font-size: 1.3rem; color: var(--fc-ink); margin: 0 0 0.25rem;
  letter-spacing: -0.01em;
}
.card-sub { color: var(--fc-muted); font-size: 0.925rem; margin: 0 0 1.25rem; }
.login-card label[for="email"] { margin-top: 0; }
.login-card .btn-primary {
  width: 100%; margin-top: 1.25rem;
  font-weight: 600; box-shadow: var(--fc-shadow);
}

/* The data-capture disclosure. Required reading, and it sits between the email field
   and the button, so it needs a visible boundary or it reads as the form's help text.
   Deliberately not a <details>: a disclosure someone has to open first is not one we
   stated plainly. */
.consent {
  border: 1px solid var(--fc-line);
  border-left: 0.1875rem solid var(--fc-slate);
  border-radius: var(--fc-radius);
  background: var(--fc-surface-2);
  padding: 0.875rem 1rem; margin: 1.5rem 0 1.25rem;
  font-size: 0.9rem;
}
.consent h3 { font-size: 0.9375rem; margin: 0 0 0.5rem; }
.consent ul { margin: 0 0 0.75rem; padding-left: 1.1rem; }
.consent li { margin-bottom: 0.125rem; }
.consent p { margin: 0 0 0.625rem; }
.consent p:last-child { margin-bottom: 0; }

.actions { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-top: 1rem; }
.btn {
  display: inline-block; font-size: 1rem; padding: 0.6rem 1.1rem;
  border-radius: var(--fc-radius); border: 1px solid transparent;
  cursor: pointer; text-decoration: none;
}
.btn-primary { background: var(--fc-red-solid); color: #fff; }
.btn-primary:hover { background: var(--fc-red-deep); color: #fff; }
.btn-secondary {
  background: var(--fc-surface-2); color: var(--fc-navy);
  border-color: var(--fc-control-line);
}
.btn-danger { background: var(--fc-danger); color: #fff; }
/* A disabled action has to LOOK unavailable, not merely be unavailable — a
 * button that ignores clicks while looking normal reads as a broken site. */
.btn:disabled,
.btn[aria-disabled="true"] {
  background: var(--fc-line);
  color: var(--fc-muted);
  cursor: not-allowed;
}
.linkish {
  background: none; border: none; padding: 0; font: inherit;
  color: var(--fc-link); text-decoration: underline; cursor: pointer;
}
.linkish.danger { color: var(--fc-danger); }
/* Sign out in red, at Kent's request. Worth knowing what it costs: --fc-danger is the
   semantic destructive colour, and tokens.css keeps it deliberately distinct from the
   brand red so "error" and "primary action" cannot be confused. Account erasure — which
   is genuinely irreversible and ends access permanently — is the same colour, so the two
   now read as equally serious when one is a single click to undo. */
.linkish.signout { color: var(--fc-danger); font-weight: 600; }
.linkish.signout:hover { color: var(--fc-danger); text-decoration-thickness: 0.125rem; }
.inline-form { display: inline; }

/* Answer ------------------------------------------------------------------ */
.answer {
  background: var(--fc-surface-alt); border: 1px solid var(--fc-line);
  border-radius: var(--fc-radius); padding: 1rem 1.25rem; margin: 1.5rem 0;
}
.direct-answer { font-size: 1.1rem; font-weight: 600; }
.answer-para { margin: 0.75rem 0; }
.cite-ref a { text-decoration: none; font-size: 0.75rem; }

.citations { padding-left: 1.25rem; }
.citation { margin: 0.85rem 0; }
.citation-label { display: flex; gap: 0.5rem; align-items: baseline; flex-wrap: wrap; }
.quote {
  margin: 0.35rem 0; padding: 0.5rem 0.75rem;
  border-left: 0.2rem solid var(--fc-navy);
  background: var(--fc-surface); font-family: var(--fc-font-mono);
  font-size: 0.9rem; overflow-x: auto;
}
/* A manual quotation is visually distinct from a regulation, because
 * conflating "what my manual says" with "what the law requires" is the whole
 * risk of the feature. */
.quote-manual, .citation-manual .quote { border-left-color: var(--fc-slate); }
.badge {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 0.1rem 0.4rem; border-radius: 0.2rem; font-weight: 700;
}
/* Badge text comes from a token, not a literal #fff.
 *
 * Badge backgrounds are mid-tone brand colours in light mode and LIGHT tints in
 * dark mode, so a hard-coded white foreground is correct in one theme and
 * illegible in the other. All three original badges measured 2.06-2.26:1 in dark
 * mode against WCAG AA's 4.5 floor. check-contrast.py now tests these pairs. */
.badge-corpus   { background: var(--fc-navy);     color: var(--fc-badge-fg); }
.badge-manual   { background: var(--fc-slate);    color: var(--fc-badge-fg); }
.badge-high     { background: var(--fc-danger);   color: var(--fc-badge-fg); }
.badge-medium   { background: var(--fc-warn);     color: var(--fc-badge-fg); }
.badge-low      { background: var(--fc-slate);    color: var(--fc-badge-fg); }
/* Guidance: how a rule may be met, not the rule. */
.badge-guidance { background: var(--fc-guidance); color: var(--fc-badge-fg); }

/* A non-binding source says so in words as well as colour — colour alone is not
 * an accessible signal, and this distinction is the point of the badge. */
.authority-note {
  color: var(--fc-muted); font-size: 0.85rem;
  margin: 0.25rem 0 0.5rem; font-style: italic;
}
.citation-meta {
  display: flex; gap: 1rem; flex-wrap: wrap; align-items: baseline;
  margin-top: 0.4rem;
}
.collected-at { color: var(--fc-muted); font-size: 0.85rem; }
.locator { color: var(--fc-muted); font-size: 0.9rem; }
.answer-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-top: 1rem; }

/* Lists and tables --------------------------------------------------------- */
.corpus-list { columns: 1; }
@media (min-width: 44rem) { .corpus-list { columns: 2; } }
.corpus-list li { break-inside: avoid; }

.history { list-style: none; padding: 0; }
.history-item { border-bottom: 1px solid var(--fc-line); padding: 0.9rem 0; }
.history-q { font-weight: 600; }
.history-a { color: var(--fc-muted); margin: 0.25rem 0; }
.meta { color: var(--fc-muted); font-size: 0.875rem; }

/* Tables ------------------------------------------------------------------
   ONE style for every table in the app. There were two near-identical rule sets keyed on
   table.usage and table.corpus-table, which is how two tables on the same page end up
   half a rule apart — and the log-links table was borrowing class="usage" to get styled
   at all, which is a class name lying about what the table holds.

   .data-table is the base. Behaviour that only some tables want (zebra, sortable
   headers, a wrapping prose column) is a modifier, so a new table gets the house style by
   default and opts in to the rest. */
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.95rem;
}
.data-table th, .data-table td {
  text-align: left;
  padding: 0.4rem 0.6rem;
  border-bottom: 1px solid var(--fc-line);
  white-space: nowrap;
}
/* Columns 1-2 wrap; every other column stays on one line.
   A tier badge and a date are short and read better unbroken, but a citation and a
   description are the two that get long — and Name being nowrap was forcing the column
   wide enough to push the date columns out of view. overflow-wrap: anywhere because a
   source id like "8900.1,Vol.2,Ch4,Sec8" contains no spaces to break at. */
.data-table td.wrap-col { white-space: normal; overflow-wrap: anywhere; }
/* .prose-col also takes the slack when the container is wider than the other columns
   need, so a wide window grows the description rather than the gaps. */
.data-table td.prose-col { width: 40%; min-width: 14rem; }

/* Right-align a numeric column, header AND cell. Aligning only the cells leaves each
   header floating over the left edge of its own column. */
.num, td.num, th.num { text-align: right; }
td.num { font-variant-numeric: tabular-nums; }
th.num .sort-link { justify-content: flex-end; }

/* Zebra striping. On the row, not the cell, so the stripe survives a colspan. */
.zebra tbody tr:nth-child(even) { background: var(--fc-surface-2); }
.zebra tbody tr:hover { background: var(--fc-surface-alt); }

/* Sortable headers are links, so a sort is a URL: bookmarkable, shareable, and working
   with JavaScript off. */
.sortable thead th {
  background: var(--fc-surface);
  border-bottom: 2px solid var(--fc-line);
  padding: 0;
}
.sort-link {
  display: flex; align-items: center; gap: 0.35rem;
  padding: 0.5rem 0.6rem;
  color: var(--fc-ink); font-weight: 600; text-decoration: none;
}
.sort-link:hover { color: var(--fc-link); background: var(--fc-surface-2); }
.sort-link.active { color: var(--fc-link); }
/* The inactive marker is dimmed rather than hidden: a column that only reveals it is
   sortable on hover is a column most people never discover is sortable. */
.sort-arrow { font-size: 0.7rem; opacity: 0.35; }
.sort-link.active .sort-arrow { opacity: 1; }

/* Filter row: an input, a button, sometimes a Clear link, and a count.
   Everything on the row is given the SAME box height explicitly. Left to themselves an
   <input> and a <button> compute their heights from different things — the input from its
   font's normal line-height, the button from the inherited 1.6 — so they came out a few
   pixels apart and nothing on the row shared a baseline. Exactly the footer-button
   problem again: a control that is "nearly" aligned with the one beside it reads as a
   mistake, because it is one. */
.table-filter {
  display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  margin: 0.75rem 0;
}
.table-filter input[type="text"],
.table-filter .btn,
.logview-bar > .btn {
  box-sizing: border-box;
  min-height: 2.5rem;
  padding: 0.45rem 0.75rem;
  font-size: 1rem;
  line-height: 1.4;
}
.table-filter input[type="text"] { width: auto; flex: 1 1 16rem; max-width: 24rem; }
/* inline-flex so the label is centred in the box rather than sitting on the text
   baseline, which is what put the button a shade low next to the input. */
.table-filter .btn,
.logview-bar > .btn {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  padding-left: 1.1rem; padding-right: 1.1rem;
}
/* The Clear link and the count are text, not boxes — centred on the row rather than given
   the control height, which would grow the row for nothing. */
.clear-filter, .table-filter .meta { align-self: center; line-height: 1.4; }
.clear-filter { font-size: 0.9rem; white-space: nowrap; }
.empty { color: var(--fc-muted); font-style: italic; text-align: center; padding: 1.5rem; }

.tier {
  display: inline-block; font-size: 0.75rem; white-space: nowrap;
  padding: 0.1rem 0.45rem; border-radius: 1rem;
  background: var(--fc-surface-2); border: 1px solid var(--fc-line);
  color: var(--fc-muted);
}
.doc-name { font-weight: 600; }

.pager {
  display: flex; align-items: center; justify-content: center; gap: 1.5rem;
  margin-top: 1rem; font-size: 0.95rem;
}
.pager .disabled { color: var(--fc-muted); }
.pager-where { font-variant-numeric: tabular-nums; }


.account-facts { display: grid; grid-template-columns: auto 1fr; gap: 0.35rem 1rem; }
.account-facts dt { font-weight: 600; color: var(--fc-muted); }
.account-facts dd { margin: 0; }

.danger-zone {
  border: 1px solid var(--fc-danger); border-radius: var(--fc-radius);
  padding: 1rem 1.25rem; margin-top: 2rem;
}
.warning-box {
  border: 1px solid var(--fc-warn); border-radius: var(--fc-radius);
  padding: 0.75rem 1rem; margin: 1rem 0; background: var(--fc-surface-alt);
}
/* The attached-manual row: file name, the use-it checkbox, and Remove.
   align-items: center on the row was not enough, because .checkbox is itself a flex
   container with align-items: flex-start and a 0.3rem nudge on its input — so the label
   sat high while the name and the button sat centred, and three things on one line each
   found a different baseline. The row overrides that nudge for its own children. */
.manual-attached > .checkbox { align-items: center; margin-top: 0; }
.manual-attached > .checkbox input { margin-top: 0; }
.manual-attached > .linkish { align-self: center; }
.manual-attached {
  display: flex; gap: 1rem; align-items: center; flex-wrap: wrap;
  background: var(--fc-surface-2); border: 1px solid var(--fc-line);
  border-radius: var(--fc-radius); padding: 0.6rem 0.9rem; margin: 1rem 0;
}
.findings { padding-left: 1.25rem; }
.finding { margin: 1.25rem 0; }

/* Footer ------------------------------------------------------------------ */
.site-footer {
  border-top: 1px solid var(--fc-line); margin-top: 3rem;
  padding: 1.25rem 0 2rem; font-size: 0.9rem;
}
.disclaimer-permanent { color: var(--fc-warn); }
.version { font-family: var(--fc-font-mono); font-size: 0.8rem; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* "What's loaded" — grouped disclosure.
   <details>/<summary> rather than a JS accordion, so keyboard and screen-reader
   behaviour is native. Only the marker rotation and spacing are ours. */
.loaded-group {
  border: 1px solid var(--fc-line);
  border-radius: var(--fc-radius);
  margin-bottom: 0.5rem;
  padding: 0.5rem 0.75rem;
}
.loaded-group > summary {
  cursor: pointer;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  /* No focus rule here on purpose: app.css already has a global
     :focus-visible { outline: 3px solid var(--fc-link) }, and a second weaker ring
     would quietly override the accessible one on exactly the element a keyboard
     user tabs to. */
}
.loaded-group[open] > summary {
  margin-bottom: 0.5rem;
}
.corpus-groups {
  list-style: none;
  padding-left: 0;
}
.corpus-groups li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.125rem 0;
}
.corpus-groups .count {
  font-variant-numeric: tabular-nums;
  color: var(--fc-muted);
}

/* Footer controls: text size and theme.
   Moved out of the header because on the top line they competed with the question
   box for first attention, and the question box is the page. */
/* One footer row: copyright left, controls right.
   Stacked on their own lines these read as content, with the same weight as the
   legal text above them. space-between makes the row a utility bar instead. */
.footer-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1rem;
  /* No border-top. .site-footer's rule spans the viewport while this one sat inside
     .wrap, so the two rendered as a long line, the disclaimer, then a short line —
     reading as two footers rather than one. Spacing separates the row instead. */
}
.footer-ident p { margin: 0; }
.footer-controls {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
/* On a narrow screen the row wraps, and the copyright should not then be stranded
   against one edge with the controls against the other. */
@media (max-width: 30rem) {
  .footer-bar {
    justify-content: center;
    text-align: center;
  }
}
/* No .icon-button rule: the theme button is styled by the shared footer-button rule
   above, with the text-size buttons, so the four cannot drift apart. */
#palette-toggle[aria-pressed="true"] {
  /* An active toggle must LOOK active, or a user cannot tell whether the click landed. */
  background: var(--fc-navy);
  color: var(--fc-badge-fg);
  border-color: var(--fc-navy);
}
/* pointer-events: none so a hover anywhere on the button resolves to the BUTTON, not to
   whichever path happens to be under the cursor. Without it the tooltip flickers between
   the button's title and the SVG's as the pointer crosses the artwork.
   
   NO display here. `#theme-toggle svg` is specificity 101 and
   `:root[data-theme="dark"] .light-only` is 30, so `display: block` beat the icon-swap
   rules and the theme button rendered the sun AND the moon at once, in both themes. The
   display:block was there to kill an inline descender gap that no longer exists — the
   button is an inline-flex container, so the icon is a flex item and never sat on a text
   baseline in the first place. Caught by screenshotting every page, which is exactly the
   kind of thing that is invisible when you only ever look at one theme. */
#theme-toggle svg, #palette-toggle svg { pointer-events: none; }
/* No `#theme-toggle svg { display: block }` here any more, and it must not come back.
   At specificity 101 it beat `.dark-only { display: none }` (10) and
   `:root[data-theme="dark"] .light-only` (30), so the theme button rendered the sun AND
   the moon simultaneously, in both themes. It was added to kill an inline descender gap
   that the button no longer has: #theme-toggle is an inline-flex container, so the icon is
   a flex item and never sits on a text baseline. */
.copyright {
  /* Inside .footer-bar, so the row owns the spacing. */
  margin: 0;
}

/* No theme rules for the icons: the existing .light-only/.dark-only pair already
   shows .dark-only in dark and .light-only in light, which is exactly what the
   button wants — the sun (class dark-only) appears while dark, and clicking it goes
   to light. A duplicate rule here would be dead CSS that looks load-bearing. */

/* ANSWER_FORMATTER=both — the two formatters side by side.
   A testing view, so it is plain: the job is comparing prose, and anything
   decorative here competes with the thing being judged. */
.formatter-compare {
  margin-top: 1.5rem;
  border-top: 1px solid var(--fc-line);
  padding-top: 1rem;
}
.compare-grid {
  display: grid;
  /* Side by side where there is room, stacked where there is not. minmax with a
     22rem floor rather than a media query, so it reflows with the text-size
     control too — at A+ two columns of 22rem stop fitting and it stacks. */
  grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
  gap: 1rem;
}
.compare-panel {
  border: 1px solid var(--fc-line);
  border-radius: var(--fc-radius);
  padding: 0.75rem 1rem;
}
.compare-panel h4 {
  margin: 0 0 0.25rem;
  text-transform: none;
}
.compare-rejected {
  /* Dimmed, not hidden: a discarded result is the most interesting one to read,
     because it shows what the formatter tried to do. */
  opacity: 0.75;
}
.compare-reason {
  font-weight: 600;
}
.answer-heading {
  margin: 1rem 0 0.25rem;
}

/* Log viewer ---------------------------------------------------------------
   Records as cards rather than table rows: a qa.jsonl entry holds a question and an
   answer, and prose in a table cell either stretches the row off the page or wraps into
   a column two words wide. */
.logview-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
}
.logview-bar .table-filter { margin: 0.75rem 0; }
.crumb { margin: 1rem 0 0; font-size: 0.9rem; }

.log-records { list-style: none; padding-left: 0; margin: 0.5rem 0 0; }
.log-record {
  border: 1px solid var(--fc-line);
  border-left: 0.1875rem solid var(--fc-navy);
  border-radius: var(--fc-radius);
  background: var(--fc-surface-2);
  padding: 0.7rem 0.9rem; margin-bottom: 0.625rem;
}
.log-head {
  display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap;
  margin-bottom: 0.4rem;
}
.log-time { font-family: var(--fc-font-mono); font-size: 0.8rem; color: var(--fc-muted); }
.log-email { font-weight: 600; }
.log-headline { flex: 1 1 12rem; }
.log-line { font-size: 0.75rem; color: var(--fc-muted); margin-left: auto; }

/* Short fields. auto/1fr rather than a fixed key column, so a long key name is not
   truncated and a short one does not leave a gutter. */
.log-fields {
  display: grid; grid-template-columns: auto 1fr; gap: 0.15rem 0.75rem;
  margin: 0; font-size: 0.9rem;
}
.log-fields dt { color: var(--fc-muted); font-family: var(--fc-font-mono); font-size: 0.8rem; }
.log-fields dd { margin: 0; overflow-wrap: anywhere; }

.log-long { margin-top: 0.5rem; }
.log-long-key {
  color: var(--fc-muted); font-family: var(--fc-font-mono); font-size: 0.8rem;
  margin-bottom: 0.15rem;
}
/* pre must scroll inside its own box; the page body never scrolls sideways. */
.log-long pre, .log-raw {
  margin: 0; padding: 0.5rem 0.65rem;
  background: var(--fc-surface); border: 1px solid var(--fc-line);
  border-radius: var(--fc-radius);
  font-family: var(--fc-font-mono); font-size: 0.825rem; line-height: 1.5;
  white-space: pre-wrap; overflow-wrap: anywhere; overflow-x: auto;
  max-height: 22rem; overflow-y: auto;
}
/* An unparseable line is a defect, not data — coloured as one. */
.log-raw { border-color: var(--fc-danger); }

.log-links-table .log-actions { display: flex; gap: 0.9rem; }

/* Narrow screens: rows become cards, and nothing scrolls sideways ---------
   A six-column table (eight on usage) cannot fit a 320px phone, so the choice is a
   horizontal scroll or a different layout. Scrolling a data table sideways on a phone
   means losing the column you were comparing against, so each row becomes a card and
   each cell carries its own label — the data-label attribute the markup sets.

   The header row is hidden rather than restyled: with one cell per line, the labels ARE
   the header, and keeping both would print every column name twice per card.

   60rem, not 30rem. The breakpoint has to be high enough that the table always fits
   above it — between "fits as a table" and "becomes cards" there must be no gap where it
   overflows, because the gap is where the horizontal scrollbar lives. */
@media (max-width: 60rem) {
  .data-table thead { display: none; }
  .data-table, .data-table tbody, .data-table tr, .data-table td { display: block; width: auto; }
  .data-table tr {
    border: 1px solid var(--fc-line);
    border-radius: var(--fc-radius);
    margin-bottom: 0.625rem;
    padding: 0.25rem 0.5rem;
  }
  /* The stripe is what distinguished adjacent rows in a dense table; as cards, the border
     does that job and the fill only muddies the contrast of the text inside. */
  .zebra tbody tr:nth-child(even) { background: none; }
  .data-table td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.3rem 0.1rem;
    border-bottom: 1px solid var(--fc-line);
    /* No nowrap on a phone: a long value must wrap rather than widen the card. */
    white-space: normal;
    overflow-wrap: anywhere;
    text-align: right;
  }
  .data-table tr td:last-child { border-bottom: none; }
  .data-table td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-weight: 600;
    color: var(--fc-muted);
    text-align: left;
    /* Not italic, not smaller: this is the column header, and shrinking it would make the
       card harder to scan than the table it replaced. */
  }
  /* A cell with no label would render an empty ::before box and an odd gap. */
  .data-table td:not([data-label])::before { content: none; }
  .data-table td.prose-col { width: auto; min-width: 0; }
  .data-table .log-actions { justify-content: flex-end; }

  /* The filter row on a 320px screen: the input must be allowed to shrink below its
     16rem basis, or it and the button together overflow the container. */
  .table-filter input[type="text"] { flex: 1 1 8rem; min-width: 0; max-width: none; }
  .table-filter { gap: 0.4rem; }
  /* Download stops sitting opposite the filter and goes under it, full width, rather
     than being squeezed to a few characters. */
  .logview-bar { display: block; }
  .logview-bar > .btn { width: 100%; margin-bottom: 0.5rem; }
  .pager { gap: 0.75rem; }
}

/* Very small phones (iPhone SE is 320px = 20rem). */
@media (max-width: 26rem) {
  .login-hero h1 { font-size: 1.75rem; }
  .login-card { padding: 1.1rem; }
  /* Card labels and values stack, because "Chief Counsel legal interpretations" opposite
     its label leaves each about eight characters wide. */
  .data-table td { display: block; text-align: left; }
  .data-table td::before { display: block; margin-bottom: 0.1rem; }
  .pager { flex-wrap: wrap; }
}

/* Corpus document review -------------------------------------------------- */
.doc-facts {
  display: grid; grid-template-columns: auto 1fr; gap: 0.2rem 1rem;
  margin: 1rem 0 1.5rem; font-size: 0.925rem;
}
.doc-facts dt { color: var(--fc-muted); font-weight: 600; }
.doc-facts dd { margin: 0; overflow-wrap: anywhere; }
.doc-facts .unknown { color: var(--fc-warn); }

/* One rule: its text, the verdicts on it, and the form. Bordered because a reviewer works
   one rule at a time and needs to see where each one ends. */
.rule {
  border: 1px solid var(--fc-line);
  border-radius: var(--fc-radius-lg);
  padding: 1rem 1.25rem;
  margin-bottom: 1.25rem;
  background: var(--fc-surface);
}
.rule h2, .rule h3 { margin-top: 0; }
.rule-number { font-family: var(--fc-font-mono); color: var(--fc-navy); margin-right: 0.4rem; }
/* Regulation text at a comfortable measure even inside a wide container: the container is
   wide for the TABLES, and a 1,600px line of statutory prose is unreadable. */
.rule-body { max-width: 46rem; }
.rule-body p { margin: 0 0 0.75rem; }

.verdicts { list-style: none; padding-left: 0; margin: 1rem 0; }
.verdict {
  border-left: 0.1875rem solid var(--fc-line);
  padding: 0.4rem 0 0.4rem 0.75rem; margin-bottom: 0.5rem;
  font-size: 0.925rem;
}
/* The three verdicts are colour-coded to the semantic tokens rather than the brand, so
   "an expert says this is wrong" cannot be mistaken for a primary action. */
.verdict-valid { border-left-color: var(--fc-ok); }
.verdict-invalid { border-left-color: var(--fc-danger); }
.verdict-unsure { border-left-color: var(--fc-warn); }
.verdict-kind {
  display: inline-block; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase; margin-right: 0.5rem;
}
.verdict-valid .verdict-kind { color: var(--fc-ok); }
.verdict-invalid .verdict-kind { color: var(--fc-danger); }
.verdict-unsure .verdict-kind { color: var(--fc-warn); }
.verdict-who { font-weight: 600; }
.verdict-when, .verdict-basis { color: var(--fc-muted); font-size: 0.85rem; }
.verdict-note { margin: 0.25rem 0 0; overflow-wrap: anywhere; }
.verdict-basis { margin: 0.15rem 0 0; }

.verdict-form { margin-top: 1rem; }
.verdict-form fieldset {
  border: 1px solid var(--fc-line); border-radius: var(--fc-radius);
  padding: 0.75rem 1rem; margin: 0;
  background: var(--fc-surface-2);
}
.verdict-form legend { font-weight: 600; padding: 0 0.35rem; }
.verdict-choices { display: flex; flex-direction: column; gap: 0.35rem; margin-bottom: 0.5rem; }
/* Radios inherit the checkbox layout so a click on the words selects the option, and the
   row does not depend on baseline luck. */
label.radio { font-weight: 400; display: flex; gap: 0.5rem; align-items: flex-start; margin-top: 0; }
label.radio input { width: auto; margin-top: 0.3rem; }
.verdict-form textarea { margin-top: 0.25rem; }
.verdict-form .btn { margin-top: 0.75rem; }

/* Processing panel -------------------------------------------------------
   Shown while a synchronous upload-and-check runs. */
.processing {
  border: 1px solid var(--fc-line);
  border-left: 0.1875rem solid var(--fc-navy);
  border-radius: var(--fc-radius-lg);
  background: var(--fc-surface-2);
  padding: 1rem 1.25rem;
  margin: 1.5rem 0;
}
.processing:focus-visible { outline: 3px solid var(--fc-link); outline-offset: 2px; }
.processing-head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.5rem; }
.processing-steps { margin: 0 0 0.75rem; padding-left: 1.25rem; color: var(--fc-muted); }
.processing-steps li { margin-bottom: 0.15rem; }
.processing-elapsed { margin: 0; }
.processing-elapsed [data-elapsed] { font-variant-numeric: tabular-nums; }

.spinner {
  flex: 0 0 auto;
  width: 1.1rem; height: 1.1rem;
  border: 0.1875rem solid var(--fc-line);
  border-top-color: var(--fc-navy);
  border-radius: 50%;
  animation: fc-spin 0.8s linear infinite;
}
@keyframes fc-spin { to { transform: rotate(360deg); } }
/* The global prefers-reduced-motion rule stops this animating, which is correct — and it
   is also why the elapsed counter matters: with the spinner frozen, the ticking number is
   the only thing telling the user the page is still alive. */

/* History entry kind. A pill, so a question and a manual check are distinguishable at a
   glance in a single timeline rather than by reading each row. */
.history-kind {
  display: inline-block; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  padding: 0.1rem 0.45rem; border-radius: 1rem; margin-bottom: 0.35rem;
  background: var(--fc-navy); color: var(--fc-badge-fg);
}
.history-kind.kind-check { background: var(--fc-guidance); }

/* Answer layout ----------------------------------------------------------
   One column by default. Above 72rem the answer and its Sources sit side by side, which
   is what makes a wide window useful here: stacked, the reader scrolls past the entire
   answer to reach the citation a superscript pointed at.

   The prose column is capped at 46rem regardless of how wide the window is. A wide screen
   is a reason to show MORE THINGS, not to set one line of statutory text across 2,000px —
   past about 75 characters the eye loses the line when it wraps. */
.answer-layout { display: block; }
.answer-main { max-width: 46rem; }
@media (min-width: 72rem) {
  .page-wide .answer-layout {
    display: grid;
    grid-template-columns: minmax(0, 46rem) minmax(18rem, 1fr);
    gap: 3rem;
    align-items: start;
  }
  /* Sticky, so the citation a superscript refers to is still on screen after scrolling
     into the middle of a long answer. */
  .page-wide .answer-sources {
    position: sticky;
    top: 1rem;
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
  }
}
.answer-sources h3 { margin-top: 0; }

/* User editor -------------------------------------------------------------
   The form element lives in the Roles cell and the other inputs join it with form="",
   which is how one row can be one form inside a table: a <form> cannot wrap <td>s. */
/* Every editable cell in the user table has the same shape: the control, then one hint
   line. They were a mix of input-only, input-plus-hint and checkbox-above-input, so each
   column resolved to its own height and no two cells in a row shared a baseline — and the
   Status checkbox sitting above its reason box pushed that column a whole row taller. */
.data-table td { vertical-align: top; }
.cap-cell {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 0.2rem;
}
.cap-cell-left { align-items: stretch; }
/* Reserve the hint line whether or not it has text, so a cell with no hint still occupies
   the same height as one that does. */
.cap-cell .meta { min-height: 1.1rem; line-height: 1.1rem; }
/* The Disabled checkbox is a CONTROL, at control size and colour. It was briefly styled
   as the hint line, which made the columns line up and demoted the only way to suspend an
   account to muted 12px text — alignment is not worth losing a control over. It keeps the
   reserved hint height so the column still matches its neighbours. */
.status-check {
  margin-top: 0; align-items: center;
  min-height: 1.1rem; line-height: 1.1rem;
  font-size: 0.9rem; color: var(--fc-ink); white-space: nowrap;
}
.status-check input { margin-top: 0; }

/* Closing an account is destructive and irreversible, so it is folded away behind its own
   disclosure rather than sitting one stray click from Save. */
.danger-details > summary {
  cursor: pointer; font-size: 0.8rem; color: var(--fc-danger);
  white-space: nowrap; margin-top: 0.25rem;
}
.erase-form {
  border: 1px solid var(--fc-danger); border-radius: var(--fc-radius);
  padding: 0.6rem 0.75rem; margin-top: 0.4rem;
  text-align: left; min-width: 16rem;
}
.erase-form .help { margin-bottom: 0.4rem; }
.erase-form .cap-input { max-width: none; text-align: left; }
.erase-form .btn { margin-top: 0.4rem; width: 100%; }

.policy-form { display: flex; flex-direction: column; gap: 0.2rem; }
.policy-form .checkbox { margin-top: 0; font-size: 0.9rem; }
.cap-input {
  width: 100%; max-width: 9rem; box-sizing: border-box;
  padding: 0.3rem 0.4rem; font-size: 0.9rem; text-align: right;
}
/* An efforts field holds "low,medium,high", which does not read right-aligned. */
input[name="efforts"], input[name="disabled_reason"] { text-align: left; max-width: 11rem; }
.data-table td .meta { display: block; font-size: 0.75rem; }

/* Admin sections as native disclosures --------------------------------------
   <details>/<summary>, not a JS accordion — the same choice the "What's loaded" panel
   makes. Keyboard operation, the expanded/collapsed state in the accessibility tree, and
   find-in-page all come free, and the sections still work with JavaScript off.

   Only the marker and the spacing are ours. */
.admin-section {
  border-top: 1px solid var(--fc-line);
  padding-top: 0.5rem;
  margin-bottom: 1.5rem;
}
/* The h2 stays a real heading inside the summary, so the document outline and heading
   navigation are unchanged — a screen-reader user still jumps between sections by
   heading, collapsed or not. */
.admin-section > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.admin-section > summary::-webkit-details-marker { display: none; }
.admin-section > summary h2 { margin: 0.5rem 0; }
/* Our own marker, so it can sit before the heading and rotate. aria-hidden is unnecessary
   because ::before content is not exposed to assistive tech, and <details> already
   announces its own expanded state. */
.admin-section > summary::before {
  content: "";
  flex: 0 0 auto;
  width: 0.5rem; height: 0.5rem;
  border-right: 0.125rem solid var(--fc-muted);
  border-bottom: 0.125rem solid var(--fc-muted);
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
}
.admin-section[open] > summary::before { transform: rotate(45deg); }
.admin-section > summary:hover h2 { color: var(--fc-link); }
