/*
 * JWT Workbench — original stylesheet.
 *
 * No external fonts, images or imports. Colours are defined once as custom
 * properties and re-declared for the dark theme, so both themes are checked
 * against the same contrast targets (WCAG 2.2 AA: 4.5:1 for body text,
 * 3:1 for large text, UI component boundaries and focus indicators).
 */

:root {
  color-scheme: light dark;

  --ink:            #16191f;
  --ink-soft:       #4a5160;
  --ink-faint:      #646c7d;
  --surface:        #f4f5f8;
  --surface-raised: #ffffff;
  --surface-sunken: #e9ebf1;
  --line:           #c7ccd8;
  --line-strong:    #9aa2b4;

  --accent:         #2b4c8c;
  --accent-ink:     #ffffff;
  --accent-soft:    #dde5f5;

  --ok:             #1f6b3c;
  --ok-soft:        #dff0e4;
  --bad:            #a01f2b;
  --bad-soft:       #fbe0e2;
  --warn:           #7a4a05;
  --warn-soft:      #fcefd6;
  --info:           #1f5a6b;
  --info-soft:      #dceff4;

  --seg-header:     #5b2f8f;
  --seg-payload:    #0f5a4a;
  --seg-signature:  #8a4212;

  --focus:          #0b57d0;
  --select:         rgba(43, 76, 140, 0.26);

  --radius:  8px;
  --radius-s: 5px;
  --gap:     16px;
  --gap-s:   8px;

  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", "Cascadia Mono", "Liberation Mono", Menlo, Consolas, monospace;
}

/* Dark theme values. Applied when the user chooses dark, or when they leave
   the control on "Match system" and the system prefers dark. */
:root[data-theme="dark"],
:root[data-theme="system"]:where(.prefers-dark) {
  --ink:            #e7eaf1;
  --ink-soft:       #b3bbcb;
  --ink-faint:      #949db1;
  --surface:        #14161c;
  --surface-raised: #1d2029;
  --surface-sunken: #0f1116;
  --line:           #39404f;
  --line-strong:    #5b6478;

  --accent:         #9db8ee;
  --accent-ink:     #10131a;
  --accent-soft:    #26314a;

  --ok:             #7ed9a3;
  --ok-soft:        #16301f;
  --bad:            #ff9ba4;
  --bad-soft:       #3a1519;
  --warn:           #f0c274;
  --warn-soft:      #362610;
  --info:           #8fd2e6;
  --info-soft:      #102c34;

  --seg-header:     #c9a6f5;
  --seg-payload:    #74d9c1;
  --seg-signature:  #f2b183;

  --focus:          #8ab4f8;
  --select:         rgba(157, 184, 238, 0.30);
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.55;
}

h1, h2, h3 { line-height: 1.25; margin: 0; font-weight: 650; }
h1 { font-size: 1.15rem; }
h2 { font-size: 1.02rem; }
h3 { font-size: 0.95rem; }
p  { margin: 0 0 0.6em; }
p:last-child { margin-bottom: 0; }
code { font-family: var(--font-mono); font-size: 0.92em; }

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

/* ---------------------------------------------------------------- a11y -- */

.visually-hidden, .sr-heading {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: 8px; top: -60px;
  z-index: 20;
  padding: 10px 16px;
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--radius-s);
  text-decoration: none;
  transition: top 120ms ease-out;
}
.skip-link:focus { top: 8px; }

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: 3px;
}

main:focus { outline: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------- app bar -- */

.app-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap);
  padding: 12px clamp(12px, 3vw, 28px);
  background: var(--surface-raised);
  border-bottom: 1px solid var(--line);
}

.brand { display: flex; align-items: center; gap: 12px; }
.brand-mark { width: 30px; height: 30px; flex: none; }
.mark-a { fill: var(--seg-header); }
.mark-b { fill: var(--seg-payload); }
.mark-c { fill: var(--seg-signature); }
.brand-text { display: flex; flex-direction: column; }
.brand-name { font-weight: 700; font-size: 1.05rem; letter-spacing: -0.01em; }
.brand-sub { font-size: 0.78rem; color: var(--ink-faint); }

.app-bar-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.offline-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  padding: 4px 10px;
  font-size: 0.8rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-sunken);
  color: var(--ink-soft);
}
.offline-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ok);
  flex: none;
}

/* --------------------------------------------------------------- forms -- */

.field { display: flex; flex-direction: column; gap: 5px; margin-bottom: var(--gap-s); }
.field-label { font-size: 0.82rem; font-weight: 600; color: var(--ink-soft); }
.field-help { font-size: 0.82rem; color: var(--ink-soft); margin: 6px 0 0; max-width: 78ch; }

.field-inline { display: inline-flex; align-items: center; gap: 6px; font-size: 0.82rem; color: var(--ink-soft); }

.field-check {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 4px 0;
  font-size: 0.88rem;
}
.field-check input { margin-top: 3px; flex: none; width: 16px; height: 16px; accent-color: var(--accent); }

input[type="text"], input[type="number"], input[type="datetime-local"], select, textarea {
  font-family: inherit;
  font-size: 0.9rem;
  color: var(--ink);
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  padding: 7px 9px;
  width: 100%;
  min-width: 0;
}
textarea { resize: vertical; }
textarea.mono, .mono { font-family: var(--font-mono); font-size: 0.86rem; line-height: 1.5; }

select { appearance: auto; }

.control-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--gap-s) var(--gap);
  margin-bottom: var(--gap-s);
}

fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 10px 14px 12px;
  margin: var(--gap-s) 0;
}
legend { font-size: 0.82rem; font-weight: 650; color: var(--ink-soft); padding: 0 5px; }

/* ------------------------------------------------------------- buttons -- */

.btn {
  font: inherit;
  font-size: 0.86rem;
  font-weight: 550;
  color: var(--ink);
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-s);
  padding: 7px 13px;
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover:not(:disabled) { background: var(--surface-sunken); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-small { font-size: 0.79rem; padding: 4px 9px; }

.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.btn-primary:hover:not(:disabled) { filter: brightness(1.1); background: var(--accent); }

.btn-danger { border-color: var(--bad); color: var(--bad); }
.btn-danger:hover:not(:disabled) { background: var(--bad-soft); }

.btn-file { display: inline-flex; align-items: center; }
.btn-file:focus-within { outline: 3px solid var(--focus); outline-offset: 2px; }

.toggle[aria-pressed="true"], .toggle.is-active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--ink);
}

.row-actions, .card-actions, .strip-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-s);
}
.row-actions { margin-top: var(--gap-s); }

/* --------------------------------------------------------- token strip -- */

main {
  max-width: 1240px;
  margin: 0 auto;
  padding: clamp(12px, 2.4vw, 24px);
}

.token-strip {
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap);
  margin-bottom: var(--gap);
}

.strip-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-s);
  margin-bottom: 10px;
}
.strip-status { display: flex; flex-wrap: wrap; gap: 6px; }
.strip-note { font-size: 0.82rem; color: var(--ink-soft); }

.pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  border: 1px solid transparent;
  white-space: nowrap;
}
.pill-neutral { background: var(--surface-sunken); color: var(--ink-soft); border-color: var(--line); }
.pill-ok      { background: var(--ok-soft);   color: var(--ok);   border-color: var(--ok); }
.pill-bad     { background: var(--bad-soft);  color: var(--bad);  border-color: var(--bad); }
.pill-warn    { background: var(--warn-soft); color: var(--warn); border-color: var(--warn); }
.pill-info    { background: var(--info-soft); color: var(--info); border-color: var(--info); }

.seg-header    { color: var(--seg-header); font-weight: 600; }
.seg-payload   { color: var(--seg-payload); font-weight: 600; }
.seg-signature { color: var(--seg-signature); font-weight: 600; }
.seg-extra     { color: var(--ink-faint); }
.seg-dot       { color: var(--ink-faint); font-weight: 700; }
.seg-tilde      { color: var(--ink-faint); font-weight: 700; }
.seg-disclosure { color: var(--info); font-weight: 600; }

.segment-legend {
  display: flex; flex-wrap: wrap; gap: 14px;
  list-style: none; margin: 7px 0 0; padding: 0;
  font-size: 0.79rem; color: var(--ink-soft);
}
.segment-legend li { display: flex; align-items: center; gap: 6px; }
.swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.swatch-header    { background: var(--seg-header); }
.swatch-payload   { background: var(--seg-payload); }
.swatch-signature { background: var(--seg-signature); }

/* ---------------------------------------------------------------- tabs -- */

.tabs { margin-bottom: var(--gap); }
.tablist {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  border-bottom: 2px solid var(--line);
}
.tab {
  font: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: var(--radius-s) var(--radius-s) 0 0;
  padding: 9px 16px;
  cursor: pointer;
  margin-bottom: -2px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.tab:hover { color: var(--ink); background: var(--surface-raised); }
.tab[aria-selected="true"] {
  color: var(--ink);
  background: var(--surface-raised);
  border-color: var(--line);
  border-bottom: 2px solid var(--surface-raised);
}
.tab-count {
  min-width: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--warn-soft);
  color: var(--warn);
  border: 1px solid var(--warn);
  font-size: 0.72rem;
  font-weight: 700;
  text-align: center;
}

.panel { display: flex; flex-direction: column; gap: var(--gap); }
.panel:focus { outline: none; }
/* A `display` declaration outranks the user-agent rule for [hidden], so the
   hidden state has to be restated for anything given an explicit display. */
.panel[hidden], .card[hidden], .result-box[hidden], .jwks-box[hidden],
.verdict[hidden], [hidden] { display: none; }

/* --------------------------------------------------------------- cards -- */

.card {
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--gap);
}
.card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-s);
  margin-bottom: 10px;
}

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
}
@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------------- editors -- */

/*
 * A syntax-highlighted JSON editor.
 *
 * The coloured `<pre>` mirror is the element in normal flow, so it alone
 * decides the height of the box: the editor grows with its content and never
 * clips it. The `<textarea>` is laid over the mirror with transparent text and
 * a visible caret, so what the user sees is the mirror and what they type into
 * is the textarea. Both boxes therefore have to agree on every property that
 * affects where a glyph lands — font, line height, padding, border width,
 * wrapping and tab size — which is why those are declared together below.
 *
 * Highlighting is built from text nodes by `highlightJson`, never from markup,
 * so a claim containing HTML is still only ever text.
 */

.editor-wrap {
  position: relative;
  display: block;
}

.editor,
.editor-mirror {
  font-family: var(--font-mono);
  font-size: 0.86rem;
  line-height: 1.5;
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: normal;
  tab-size: 2;
  margin: 0;
}

.editor-mirror {
  background: var(--surface-sunken);
  color: var(--ink);
  /* Six lines when empty; beyond that the content decides the height. */
  min-height: 9em;
  overflow: hidden;
}

.editor {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  resize: none;
  overflow: hidden;
  background: transparent;
  color: transparent;
  caret-color: var(--ink);
  border-color: transparent;
}
.editor:focus-visible { border-color: var(--focus); }

/* With transparent text the placeholder would inherit transparency too. */
.editor::placeholder { color: var(--ink-faint); }

/* A compact token is a single unbroken word, so it must break anywhere, and
   four lines is enough to start from. */
.token-mirror, .token-mirror + .editor {
  word-break: break-all;
  overflow-wrap: anywhere;
}
.token-mirror { min-height: 4.6em; }

/* The mirror shows through the selection, so it must stay translucent. */
.editor::selection { background: var(--select); }

.editor-status {
  font-size: 0.82rem;
  margin: 6px 0 0;
  min-height: 1.4em;
  color: var(--ink-soft);
}
.editor-status[data-state="error"] { color: var(--bad); font-weight: 600; }
.editor-status[data-state="ok"] { color: var(--ok); }

/* ------------------------------------------------------- selective disc. -- */

.sd-disclosures { display: flex; flex-direction: column; gap: var(--gap-s); }
.sd-disclosure {
  border: 1px solid var(--line);
  border-left-width: 4px;
  border-radius: var(--radius-s);
  padding: 10px 13px;
  background: var(--surface-sunken);
}
.sd-disclosure.sd-ok  { border-left-color: var(--ok); }
.sd-disclosure.sd-warn { border-left-color: var(--warn); }
.sd-disclosure.sd-bad { border-left-color: var(--bad); }

.sd-row-head { display: flex; align-items: center; gap: var(--gap-s); flex-wrap: wrap; }
.sd-claim { font-family: var(--font-mono); font-weight: 650; }
.sd-detail { margin: 6px 0 0; font-size: 0.85rem; color: var(--ink-soft); }

.sd-fields {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 2px var(--gap-s);
  margin-top: 8px;
  font-size: 0.84rem;
}
.sd-field-label { font-family: var(--font-mono); color: var(--ink-faint); }
.sd-field-value { font-family: var(--font-mono); overflow-wrap: anywhere; }
.sd-muted { color: var(--ink-faint); }

.sd-hidden, .sd-kb { margin-top: var(--gap); }
.sd-hidden h3, .sd-kb h3 { font-size: 0.9rem; margin-bottom: 4px; }

/* ---------------------------------------------------------- secret test -- */

.crack-box {
  margin-top: var(--gap);
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface-sunken);
}
.crack-box h3 { font-size: 0.95rem; margin-bottom: 6px; }
#crack-progress { align-self: center; }

/* ------------------------------------------------------------- encoder -- */

.encoder-sign { margin-top: var(--gap); }
.encoder-sign-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--gap-s);
  margin-bottom: 6px;
}
.encoder-alg-note { font-size: 0.8rem; color: var(--ink-faint); }

.encoder-key-row {
  display: flex;
  align-items: flex-start;
  gap: var(--gap);
  flex-wrap: wrap;
}
.encoder-key-row textarea { flex: 1 1 320px; }
.encoder-key-row .field-inline { flex: none; padding-top: 6px; }
.encoder-key-row .field-inline > span { white-space: nowrap; }

.encoder-status {
  font-size: 0.82rem;
  margin: var(--gap-s) 0 0;
  min-height: 1.4em;
  color: var(--ink-soft);
}
.encoder-status[data-state="ok"]   { color: var(--ok); font-weight: 600; }
.encoder-status[data-state="bad"]  { color: var(--bad); font-weight: 600; }
.encoder-status[data-state="warn"] { color: var(--warn); font-weight: 600; }

.raw-json {
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 11px 13px;
  overflow-x: auto;
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.report-preview { max-height: 380px; overflow-y: auto; }

.tok-key     { color: var(--seg-header); }
.tok-string  { color: var(--seg-payload); }
.tok-number  { color: var(--seg-signature); }
.tok-literal { color: var(--info); font-weight: 600; }

.wrap-anywhere { overflow-wrap: anywhere; word-break: break-all; }

/* --------------------------------------------------------------- lists -- */

.meta-list { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 0.83rem;
  padding: 6px 9px;
  background: var(--surface-sunken);
  border-radius: var(--radius-s);
  border: 1px solid var(--line);
}
.meta-name { font-weight: 650; font-family: var(--font-mono); }
.meta-value { color: var(--ink-soft); overflow-wrap: anywhere; }

.issue-list, .check-list, .finding-list, .support-list {
  list-style: none;
  margin: var(--gap-s) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.issue-list:empty, .check-list:empty, .finding-list:empty { margin: 0; }

.issue {
  border: 1px solid var(--line);
  border-left-width: 4px;
  border-radius: var(--radius-s);
  padding: 9px 12px;
  font-size: 0.87rem;
  background: var(--surface-sunken);
}
.issue-bad  { border-left-color: var(--bad);  background: var(--bad-soft);  color: var(--ink); }
.issue-warn { border-left-color: var(--warn); background: var(--warn-soft); color: var(--ink); }
.issue-info { border-left-color: var(--info); background: var(--info-soft); color: var(--ink); }
.issue-ok   { border-left-color: var(--ok);   background: var(--ok-soft);   color: var(--ink); }

.finding {
  border: 1px solid var(--line);
  border-left-width: 4px;
  border-radius: var(--radius-s);
  padding: 11px 13px;
  background: var(--surface-sunken);
}
.finding-validation-failure { border-left-color: var(--bad); }
.finding-warning            { border-left-color: var(--warn); }
.finding-informational      { border-left-color: var(--info); }

.finding-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 9px; margin-bottom: 5px; }
.finding-title { font-weight: 650; font-size: 0.92rem; }
.finding-detail { font-size: 0.87rem; color: var(--ink-soft); margin: 0; }
.finding-ref {
  display: inline-block;
  margin-top: 6px;
  font-size: 0.77rem;
  color: var(--ink-faint);
  font-family: var(--font-mono);
}

.check {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  align-items: baseline;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 9px 12px;
  background: var(--surface-sunken);
}
.check-label { font-weight: 650; font-size: 0.88rem; min-width: 12rem; }
.check-detail { font-size: 0.85rem; color: var(--ink-soft); flex: 1 1 20rem; }

.support-list { flex-direction: row; flex-wrap: wrap; }
.support-item {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 5px 10px;
  font-size: 0.83rem;
  font-family: var(--font-mono);
  background: var(--surface-sunken);
}
.support-yes { border-color: var(--ok); color: var(--ok); }
.support-no  { border-color: var(--bad); color: var(--bad); }

/* -------------------------------------------------------------- tables -- */

/* The table keeps its own horizontal scroll on narrow viewports so the page
   itself never scrolls sideways. */
#claims-table-wrap { overflow-x: auto; max-width: 100%; }
.claims-table { width: 100%; border-collapse: collapse; font-size: 0.87rem; min-width: 0; }
.claims-table th, .claims-table td {
  text-align: left;
  vertical-align: top;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
}
.claims-table thead th {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  border-bottom: 2px solid var(--line);
}
.claims-table td.claim-name { white-space: nowrap; }
/* Wide enough for an ordinary issuer URL to sit on one line; `anywhere` still
   keeps a pathological value from forcing the table to scroll. */
.claims-table td.claim-value { font-family: var(--font-mono); overflow-wrap: anywhere; max-width: 46ch; }
.claims-table td.claim-value .value-item { display: block; }
.claims-table td.claim-value .value-item + .value-item { margin-top: 2px; }
.claims-table td.claim-type { color: var(--ink-faint); white-space: nowrap; }
.claims-table td.claim-note { color: var(--ink-soft); }
.claims-table tbody tr:last-child td { border-bottom: none; }

/* A left rail and a small chip mark each claim's provenance: a registered RFC
   7519 claim, a claim standardised elsewhere, a common convention, or an
   application-specific name with no rail at all. */
.claim-row { border-left: 3px solid transparent; }
.claim-registered { border-left-color: var(--accent); }
.claim-standard   { border-left-color: var(--info); }
.claim-convention { border-left-color: var(--line-strong); }

.claim-name-text { font-family: var(--font-mono); font-weight: 650; }
.claim-tag {
  display: inline-block;
  margin-left: 7px;
  padding: 1px 6px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  border-radius: 999px;
  vertical-align: 1px;
  white-space: nowrap;
}
.claim-tag-registered { background: var(--accent-soft); color: var(--accent); }
.claim-tag-standard   { background: var(--info-soft); color: var(--info); }
.claim-tag-convention { background: var(--surface-sunken); color: var(--ink-faint); }

/* ------------------------------------------------------------ verdicts -- */

.verdict {
  margin-top: var(--gap);
  border: 1px solid var(--line);
  border-left-width: 5px;
  border-radius: var(--radius-s);
  padding: 13px 15px;
  background: var(--surface-sunken);
}
.verdict[data-state="signature-valid"]   { border-left-color: var(--ok);   background: var(--ok-soft); }
.verdict[data-state="signature-invalid"] { border-left-color: var(--bad);  background: var(--bad-soft); }
.verdict[data-state="verification-error"]{ border-left-color: var(--bad);  background: var(--bad-soft); }
.verdict[data-state="refused"]           { border-left-color: var(--warn); background: var(--warn-soft); }
.verdict[data-state="unverified"]        { border-left-color: var(--info); background: var(--info-soft); }

.verdict-headline { font-weight: 700; font-size: 1rem; margin: 0 0 5px; }
.verdict-detail { font-size: 0.88rem; margin: 0; color: var(--ink-soft); }

.notice {
  margin-top: var(--gap);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 11px 14px;
  font-size: 0.86rem;
}
.notice h3 { margin-bottom: 5px; }
.notice-info { background: var(--info-soft); border-color: var(--info); }

.unsecured-box {
  margin-top: var(--gap);
  border: 1px dashed var(--warn);
  background: var(--warn-soft);
  border-radius: var(--radius-s);
  padding: 11px 14px;
}

.result-box, .jwks-box {
  margin-top: var(--gap);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  padding: 13px 15px;
  background: var(--surface-sunken);
}
.result-box h3, .jwks-box h3 { margin-bottom: 7px; }

.empty-state {
  color: var(--ink-faint);
  font-size: 0.87rem;
  font-style: italic;
  padding: 10px 0 2px;
  margin: 0;
}

/* ------------------------------------------------------------ timeline -- */

/* The viewBox grows with the number of label rows, so the rendered height
   must follow it rather than being pinned. Below the minimum width the labels
   shrink past legibility, so the graphic scrolls instead — the same treatment
   the claims table gets, and the instants list beneath carries the same
   values as text either way. */
#timeline-host { overflow-x: auto; }
.timeline-svg { width: 100%; min-width: 560px; height: auto; display: block; }
.tl-track   { fill: var(--surface-sunken); stroke: var(--line); }
.tl-window  { fill: var(--accent-soft); }
.tl-expired { fill: var(--bad-soft); }
.tl-tick    { stroke: var(--line-strong); stroke-width: 1; }
.tl-marker  { stroke-width: 2; }
.tl-marker-iat { stroke: var(--seg-header); fill: var(--seg-header); }
.tl-marker-nbf { stroke: var(--seg-payload); fill: var(--seg-payload); }
.tl-marker-exp { stroke: var(--seg-signature); fill: var(--seg-signature); }
.tl-marker-now { stroke: var(--bad); fill: var(--bad); }
/* Painting the stroke first knocks the card background out around each glyph,
   so a leader line running past an inner row does not strike through it. */
.tl-label   {
  font-family: var(--font-mono);
  font-size: 11px;
  fill: var(--ink-soft);
  paint-order: stroke fill;
  stroke: var(--surface-raised);
  stroke-width: 3px;
  stroke-linejoin: round;
}
/* Each label carries its mark's colour, which is what tells a stacked column
   apart now that only its innermost label draws a leader. */
.tl-label-iat { fill: var(--seg-header); }
.tl-label-nbf { fill: var(--seg-payload); }
.tl-label-exp { fill: var(--seg-signature); }
.tl-label-now { fill: var(--bad); }
.tl-caption { font-family: var(--font-ui); font-size: 12px; fill: var(--ink-faint); }

/* Exact instants behind the graphic, as label/value rows rather than prose. */
.instants {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 2px var(--gap);
  margin: var(--gap-s) 0 0;
  font-size: 0.82rem;
}
.instants dt {
  font-family: var(--font-mono);
  font-weight: 650;
  color: var(--ink-soft);
}
.instants dd {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px var(--gap-s);
  color: var(--ink-soft);
}
.instant-epoch { font-family: var(--font-mono); color: var(--ink-faint); }
.instant-time  { color: var(--ink); }
.instant-utc   { color: var(--ink-faint); }

.noscript-note {
  margin: var(--gap);
  padding: 13px 15px;
  border: 1px solid var(--warn);
  background: var(--warn-soft);
  border-radius: var(--radius-s);
}

@media (max-width: 620px) {
  .app-bar { flex-direction: column; align-items: stretch; }
  .app-bar-actions { justify-content: space-between; }
  .tab { flex: 1 1 auto; justify-content: center; padding: 9px 8px; }
  .claims-table { font-size: 0.8rem; }
  .claims-table th, .claims-table td { padding: 6px 6px; }
  .claims-table td.claim-value { max-width: 12ch; }
  .claims-table td.claim-note, .claims-table th:nth-child(4) { display: none; }
  .claims-table td.claim-type, .claims-table th:nth-child(3) { display: none; }
}

@media (forced-colors: active) {
  .pill, .btn, .card, .issue, .finding, .check, .verdict { border: 1px solid CanvasText; }
  .tab[aria-selected="true"] { border: 1px solid CanvasText; }
}
