/* SPDX-License-Identifier: Apache-2.0 */

/* Design tokens ported verbatim from the seal family docs site build
   (velvetmonkey/seal, docs/src/styles/custom.css) so seal-check matches the
   rest of the family. Same values, same `[data-theme]` switching mechanism
   (an attribute on <html>, not prefers-color-scheme and not a class) — see
   theme.js, which is this repo's equivalent of Starlight's ThemeSelect.
   Every foreground/background pair below is audited by scripts/contrast.mjs;
   change a token there and the audit follows. The three "-soft" tokens per
   theme (success-soft/warning-soft/danger-soft) are NOT in the ported file —
   they are this repo's own literal tints (status colour mixed into the
   theme's surface colour), computed once and pinned as plain hex so the
   audit script can still read them directly. */
:root {
  --seal-radius: 0.375rem;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

:root[data-theme='light'] {
  color-scheme: light;
  --seal-bg: #f8f5ef;
  --seal-surface: #fffdf8;
  --seal-text: #182826;
  --seal-muted: #53615e;
  --seal-border: #d5dbd0;
  --seal-accent: #a33d20;
  --seal-accent-text: #fffaf4;
  --seal-accent-soft: #f3e3d4;
  --seal-success: #266344;
  --seal-warning: #765000;
  --seal-danger: #a62d30;

  --seal-success-soft: #e1e7df;
  --seal-warning-soft: #e9e1d0;
  --seal-danger-soft: #f3e2de;
}

:root[data-theme='dark'] {
  color-scheme: dark;
  --seal-bg: #171b1b;
  --seal-surface: #242a29;
  --seal-text: #ecf1e9;
  --seal-muted: #b6c3ba;
  --seal-border: #414b45;
  --seal-accent: #ffad88;
  --seal-accent-text: #281910;
  --seal-accent-soft: #43372c;
  --seal-success: #a5d2aa;
  --seal-warning: #e5c474;
  --seal-danger: #ffadb0;

  --seal-success-soft: #3b4840;
  --seal-warning-soft: #474637;
  --seal-danger-soft: #4b4241;
}

* { box-sizing: border-box; }
body {
  margin: 0; background: var(--seal-bg); color: var(--seal-text);
  font: 16.5px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
}
.wrap { max-width: 1240px; margin: 0 auto; padding: 0 16px; }

:where(a) { color: var(--seal-accent); }
:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--seal-accent) 45%, transparent);
  outline-offset: 2px;
}

/* compact header: title, kernel identity, theme toggle and the privacy
   disclosure share one row, so the paste box owns the top of the first
   screen rather than a paragraph of branding/legal text. */
header {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px;
  padding: 10px 16px; border-bottom: 1px solid var(--seal-border);
  background: var(--seal-surface);
}
h1 { margin: 0; font-size: 18px; letter-spacing: -0.4px; }
header .header-actions { margin: 0 0 0 auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.muted { color: var(--seal-muted); }
code, .mono { font-family: var(--mono); }
code { background: var(--seal-accent-soft); padding: 1px 5px; border-radius: 4px; font-size: max(13px, 0.88em); }

.theme-toggle {
  font: inherit; font-size: 13px; cursor: pointer;
  background: var(--seal-surface); color: var(--seal-text);
  border: 1px solid var(--seal-muted); border-radius: var(--seal-radius);
  padding: 4px 10px;
}
.theme-toggle:hover { border-color: var(--seal-accent); }

/* Component boundaries a visitor must actually perceive (form field, toggle,
   disclosure) use --seal-muted, not the lighter --seal-border: the ported
   family --seal-border is a subtle content-divider colour (~1.3:1-1.9:1
   against --seal-bg) meant for section rules, not a 3:1 UI-component
   boundary. scripts/contrast.mjs audits this split. */
.pill { display: inline-block; font-family: var(--mono); font-size: 13px; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--seal-muted); }
.pill-wait { color: var(--seal-muted); }
.pill-ok { color: var(--seal-success); border-color: var(--seal-success); background: var(--seal-success-soft); }
.pill-bad { color: var(--seal-danger); border-color: var(--seal-danger); background: var(--seal-danger-soft); }

/* The one surviving disclosure: the technical log. Native <details>/<summary>
   — keyboard-operable (the summary is a default focusable, Enter/Space-
   toggled control) and screen-reader-sensible without any custom ARIA.
   Closed by default; nothing it contains is ever deleted. Every other
   explanatory disclosure from the previous design moved to a ⓘ tooltip
   (below) instead — jwtms redesign, round 2. */
#rv-tech {
  border: 1px solid var(--seal-muted); border-radius: var(--seal-radius);
  background: var(--seal-surface); padding: 0;
}
#rv-tech > summary {
  cursor: pointer; list-style: none; user-select: none;
  padding: 8px 12px; font-size: 14px; font-weight: 600; color: var(--seal-muted);
  display: flex; align-items: center; gap: 6px;
}
#rv-tech > summary::-webkit-details-marker { display: none; }
#rv-tech > summary::before {
  content: "\25B8"; /* ▸ */ display: inline-block; transition: transform 0.1s ease;
}
#rv-tech[open] > summary::before { transform: rotate(90deg); }
#rv-tech > summary:hover { color: var(--seal-text); }

/* Shared tooltip pattern (tooltip.js): a focusable ⓘ button plus a hoverable
   plain-text body, connected by aria-describedby. Replaces every disclosure
   this design cuts — nothing it held is deleted, only reached via hover,
   focus, or a tap instead of an inline paragraph. */
.tip { position: relative; display: inline-flex; align-items: center; }
.tip-btn {
  font: inherit; font-size: 11px; line-height: 1; cursor: pointer;
  width: 16px; height: 16px; padding: 0; margin-left: 4px;
  border-radius: 999px; border: 1px solid var(--seal-muted);
  background: transparent; color: var(--seal-muted);
  display: inline-flex; align-items: center; justify-content: center;
  font-style: italic; font-family: Georgia, serif;
}
.tip-btn:hover, .tip-btn:focus-visible { border-color: var(--seal-accent); color: var(--seal-accent); }
.tip-btn-text {
  width: auto; height: auto; border-radius: var(--seal-radius);
  padding: 4px 10px; font: inherit; font-size: 13px; gap: 4px;
}
.tip-body {
  position: absolute; top: 100%; right: 0; margin-top: 4px;
  width: max-content; max-width: 36ch; z-index: 20;
  background: var(--seal-surface); color: var(--seal-text);
  border: 1px solid var(--seal-muted); border-radius: var(--seal-radius);
  padding: 8px 10px; font-size: 13px; font-weight: 400; line-height: 1.4;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
  text-align: left;
}
.tip-body.left { right: auto; left: 0; }
header .tip { font-size: 13px; }

section { padding: 16px 0; border-bottom: 1px solid var(--seal-border); }
h2 { font-size: 21px; margin: 0 0 4px; }
h3 { font-size: 16.5px; margin: 0 0 4px; }
p { margin: 8px 0; }

textarea {
  width: 100%; margin: 8px 0; padding: 10px; resize: vertical;
  background: var(--seal-surface); color: var(--seal-text); border: 1px solid var(--seal-muted);
  border-radius: var(--seal-radius); font-family: var(--mono); font-size: 13.5px;
}
.error { color: var(--seal-danger); font-size: 13.5px; font-family: var(--mono); }

.result { margin-top: 14px; }
.hidden { display: none; }
/* Verdict never rests on colour: the word itself is the signal, and the box
   around it differs in fill and border weight per state as well as hue. */
.verdict { font-family: var(--mono); font-weight: 700; font-size: 18px; letter-spacing: 1px; padding: 2px 9px; border-radius: 5px; border: 1px solid var(--seal-border); }
.v-block { color: var(--seal-danger); background: var(--seal-danger-soft); border: 2px solid var(--seal-danger); }
.v-allow { color: var(--seal-success); background: var(--seal-success-soft); border-color: var(--seal-success); }
.v-error { color: var(--seal-warning); background: var(--seal-warning-soft); border-color: var(--seal-warning); }
.verdict:empty { display: none; }
.deny-kernel { color: var(--seal-muted); font-family: var(--mono); font-size: 13.5px; }
.reason { margin: 6px 0 10px; }
.reason.warn { color: var(--seal-warning); font-weight: 600; }
.reason.ok { color: var(--seal-success); font-weight: 600; }
.reason.bad { color: var(--seal-danger); font-weight: 600; }

details summary { cursor: pointer; color: var(--seal-muted); font-size: 14px; margin-bottom: 6px; }
table { width: 100%; border-collapse: collapse; font-size: 13.5px; margin-bottom: 8px; }
th, td { text-align: left; padding: 5px 8px; border-bottom: 1px solid var(--seal-border); vertical-align: top; }
th { color: var(--seal-muted); font-weight: 600; }
td.mono { word-break: break-all; }

/* the two claim panels: equal weight, side by side, neither a footnote.
   CLAIM DISCIPLINE (unchanged from the previous design): always visible,
   never folded behind a disclosure — this section states what the check
   proves and does not prove and must not require an extra click to read. */
.claim-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 10px; align-items: start; }
.claim { border: 1px solid var(--seal-border); border-radius: var(--seal-radius); padding: 12px 14px; background: var(--seal-surface); }
.claim p { font-size: 15px; line-height: 1.5; margin: 0; }
.claim h3 { margin: 0 0 4px; }
.claim.proves { border-color: var(--seal-success); }
.claim.notproves { border-color: var(--seal-warning); }
.claim.proves h3 { color: var(--seal-success); }
.claim.notproves h3 { color: var(--seal-warning); }

footer { padding: 16px 16px 40px; color: var(--seal-muted); }
footer h3 { margin-bottom: 6px; }
.ident { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px 20px; margin: 6px 0 10px; }
.ident dt { grid-row: 1; color: var(--seal-text); font-size: 14px; }
.ident dd { grid-row: 2; margin: 0; color: var(--seal-muted); word-break: break-all; font-size: 13.5px; }
.lab { font-family: var(--mono); font-size: 13px; padding: 0 6px; border-radius: 4px; margin-left: 6px; white-space: nowrap; }
.lab-ok { color: var(--seal-success); background: var(--seal-success-soft); border: 1px solid var(--seal-success); }
.lab-asserted { color: var(--seal-warning); background: var(--seal-warning-soft); border: 1px solid var(--seal-warning); }

@media (max-width: 860px) {
  .ident { grid-template-columns: 1fr; }
  .ident dt, .ident dd { grid-row: auto; }
  .ident dt { margin-top: 8px; }
}
@media (max-width: 700px) {
  .claim-grid { grid-template-columns: 1fr; }
}

/* deep-linked receipt verification */
.rv-checks { list-style: none; padding: 0; margin: .5rem 0; }

.legacy-fragment-notice {
  border: 2px solid var(--seal-danger);
  border-radius: 8px;
  background: var(--seal-danger-soft);
  color: var(--seal-danger);
  padding: .9rem 1rem;
  margin-bottom: 1.5rem;
}
/* Second finding from the round-2 read: this alert rendered on every page
   load because nothing ever hid it. It is legacy-anchor navigation feedback
   (see legacy-tools-redirect.js) — only relevant while its own fragment is
   the current target. */
#legacy-receipt-summary:not(:target) { display: none; }

.rv-checks li { padding: .15rem 0; font-size: 14px; overflow-wrap: anywhere; }
#receipt-verify .reason, .rv-subline { overflow-wrap: anywhere; }
.rv-ok { color: var(--seal-success); }
.rv-bad { color: var(--seal-danger); font-weight: 600; }
.rv-skip { color: var(--seal-muted); }

/* One full-width flow at every viewport: receipt, verdict, then details.
   Keep the visual order identical to the existing DOM order. */
.rv-panes { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; align-items: start; }
.input-pane textarea#paste-input { min-height: 180px; }
@media (min-width: 900px) {
  .input-pane textarea#paste-input { min-height: 420px; }
}
.output-pane { min-width: 0; }
.safety-note { font-size: 13.5px; margin-top: 6px; }

/* Match the docs callout shape and spacing, with the existing verdict palette. */
.rv-banner { border-left: 3px solid var(--seal-border); border-radius: 0 var(--seal-radius) var(--seal-radius) 0; padding: 0.85rem 1.1rem; margin: 0 0 8px; background: var(--seal-surface); }
.rv-banner.ok { background: var(--seal-success-soft); border-color: var(--seal-success); }
.rv-banner.bad { background: var(--seal-danger-soft); border-color: var(--seal-danger); }
.rv-banner.warn { background: var(--seal-warning-soft); border-color: var(--seal-warning); }
.rv-banner-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.rv-headline { font-size: 20px; font-weight: 600; line-height: 1.5; }
.rv-banner.ok .rv-headline { color: var(--seal-success); }
.rv-banner.bad .rv-headline { color: var(--seal-danger); }
.rv-banner.warn .rv-headline { color: var(--seal-warning); }
.rv-outcome-tag { font-family: var(--mono); font-size: 12px; color: var(--seal-muted); white-space: nowrap; }
.rv-outcome-tag:empty { display: none; }
.rv-subline { margin: 6px 0 0; font-size: 16px; line-height: 1.75; color: var(--seal-text); max-width: 76ch; display: flex; align-items: flex-start; gap: 4px; }
.rv-fails { margin: 8px 0 0; padding-left: 1.3em; color: var(--seal-danger); }
.rv-fails li { padding: 1px 0; font-size: 15px; }

/* The receipt input leads the full-width result flow. */
#receipt-verify { padding-top: 12px; }
.paste-label { display: block; font-size: 17px; font-weight: 600; margin: 0 0 6px; }
#paste-input {
  margin: 0;
  /* Local faces from Starlight’s code stack, ahead of the generic fallback. */
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 15px; font-weight: 400; line-height: 1.6;
}
#paste-error:empty { display: none; }

/* One table, two groups (Receipt / Checks). Field · Value · Re-check · ⓘ.
   Compact by default; the full sentence for every row lives in that row's ⓘ
   tooltip, never deleted, reached by hover, focus, or a tap. Nothing here
   ever renders as a single pass/fail badge — each dimension is its own row,
   and Signer authority / Decision occurred / Targets authorised can never
   render a green checkmark. */
.rv-table-wrap { overflow-x: auto; margin: 10px 0; background: var(--seal-surface); border: 1px solid var(--seal-border); border-radius: var(--seal-radius); }
.rv-table { font-size: 13.5px; table-layout: fixed; margin-bottom: 0; }
.rv-table th, .rv-table td { padding: 6px 8px; }
.rvt-col-field { width: 11em; }
.rvt-col-state { width: 9em; }
.rvt-col-tip { width: 2em; }
.rv-table th[scope="row"] { font-weight: 600; }
/* The Value column (2nd cell of every row) can carry an unbroken hash or
   JSON blob whether or not the row's markup gave it the .rvt-value class —
   the Decision row, appendSummaryRow's signed-family rows, and
   renderReceiptSummary's rows all build a bare <td> here. Without a wrap
   rule that bare <td> lets a 64-char hex string overflow its fixed column
   at every width, not just below the ~560px card breakpoint, silently
   pushing .rv-table-wrap's scrollable width past its container. Wrapping
   the column itself (not just the .rvt-value-classed Checks rows) fixes
   that at every width, matching the card layout's own wrap rule below. */
.rv-table td:nth-child(2) { overflow-wrap: anywhere; }
.rv-table .rvt-value { font-family: var(--mono); word-break: break-all; }
.rv-table .rvt-state { white-space: nowrap; font-family: var(--mono); font-size: 13px; }
.rv-table .rvt-pass { color: var(--seal-success); }
.rv-table .rvt-fail { color: var(--seal-danger); font-weight: 700; }
.rv-table .rvt-skip { color: var(--seal-warning); }
/* a failed row is tinted AND rule-marked, so the failure survives grayscale */
.rv-table tr.rvt-row-fail td, .rv-table tr.rvt-row-fail th { background: var(--seal-danger-soft); }
.rv-table tr.rvt-row-fail th { box-shadow: inset 3px 0 0 var(--seal-danger); }

/* Below ~560px the fixed 11em/9em/2em columns leave Value a few characters
   wide, wrapping hashes and JSON one syllable per line. Below that width the
   table becomes one card per row instead: Field (already a <th scope="row">)
   as the card's heading, then Value and Re-check each on their own full-width
   line, so long hashes read as continuous wrapped text, not fragments. No
   content changes — every field, tooltip and detail is still here, just
   stacked instead of squeezed into fixed columns. */
@media (max-width: 560px) {
  .rv-table, .rv-table thead, .rv-table tbody, .rv-table tr, .rv-table th, .rv-table td {
    display: block;
  }
  .rv-table colgroup { display: none; }
  .rv-table thead { display: none; }
  .rv-table tbody:not(.rvt-group) tr {
    padding: 8px 8px 10px;
    border-bottom: 1px solid var(--seal-border);
  }
  .rv-table tbody:not(.rvt-group) tr:last-child { border-bottom: 0; }
  .rv-table th[scope="row"] { padding: 0 0 2px; }
  .rv-table td { padding: 2px 0; }
  /* Whichever module built this row (app.js's row(), receipt-summary.js,
     appendSummaryRow), the Value cell is always the second cell — force it
     to wrap as continuous text at its own full card width, regardless of
     which per-class mono/word-break rule (or none) it carries above. */
  .rv-table td:nth-child(2) { word-break: break-word; overflow-wrap: anywhere; }
  .rv-table .rvt-state::before { content: "Re-check: "; color: var(--seal-muted); font-weight: 600; }
  .rv-table td:empty { display: none; }
}
/* group heading rows: their own single-row tbody so #receipt-summary keeps
   exactly six <tr> children (receipt-summary.test.mjs). */
.rvt-group th { background: var(--seal-bg); color: var(--seal-muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.4px; padding: 6px 8px; }

#rv-tech { margin-top: 12px; padding-bottom: 0; }
#rv-tech > *:not(summary) { padding-left: 12px; padding-right: 12px; }
#rv-tech > :last-child { padding-bottom: 12px; }

/* Local receipt/key file controls share the existing page palette. */
#signer-controls { margin: 12px 0; }
#signer-controls label { display: block; margin-top: 8px; }
#signer-key { width: 100%; box-sizing: border-box; font: inherit; }
#receipt-file, #signer-file { max-width: 100%; margin: 8px 0; }
