/* System font stacks only — no webfont requests, which also keeps the CSP tight. */

:root {
  --bg: #fbfaf8;
  --surface: #ffffff;
  --ink: #16150f;
  --ink-soft: #57544a;
  --ink-faint: #86816f;
  --rule: #e3ded1;
  --accent: #8a5a00;
  --bad: #a3202b;
  --bad-bg: #fdf2f2;
  --good: #2c6a3f;
  --good-bg: #f2f8f3;
  --caution: #8a5a00;
  --caution-bg: #fdf8ef;

  --mono: ui-monospace, 'SF Mono', Monaco, 'Cascadia Mono', monospace;
  --sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14140f;
    --surface: #1c1c17;
    --ink: #f2efe6;
    --ink-soft: #b3ad9c;
    --ink-faint: #8a8474;
    --rule: #33322a;
    --accent: #e0a942;
    --bad: #f08b8b;
    --bad-bg: #2a1a1a;
    --good: #86c99a;
    --good-bg: #17241a;
    --caution: #e0a942;
    --caution-bg: #262013;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 2rem 1.25rem 4rem;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
}

main, .colophon { max-width: 46rem; margin: 0 auto; }

/* ------------------------------------------------------------- masthead */

.masthead { margin-bottom: 2rem; }

.masthead h1 {
  margin: 0;
  font-family: var(--mono);
  font-size: 1.75rem;
  letter-spacing: -0.02em;
}

.tagline {
  margin: 0.5rem 0 0;
  color: var(--ink-soft);
  max-width: 34rem;
  text-wrap: pretty;
}

/* ---------------------------------------------------------------- input */

textarea {
  width: 100%;
  padding: 0.9rem 1rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 0.8rem;
  line-height: 1.5;
  resize: vertical;
  tab-size: 2;
}

textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
textarea::placeholder { color: var(--ink-faint); }

.controls {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.75rem;
  flex-wrap: wrap;
}

button {
  padding: 0.45rem 1rem;
  border: 1px solid var(--rule);
  border-radius: 5px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
}

button:hover { border-color: var(--ink-faint); }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

button.primary {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
  font-weight: 500;
}

.status {
  color: var(--ink-faint);
  font-size: 0.85rem;
}

/* Once a report exists the raw header is no longer what the reader is looking
   at, and ten rows of it push the findings off a phone screen. Three rows keep
   the paste visible — proof it went in — without costing the report its place.
   4.5em is three of the textarea's own lines, so this survives the font-size
   bump under `pointer: coarse` below. */
.input-area--read textarea {
  height: calc(4.5em + 1.8rem);
  transition: height 0.18s ease;
}

/* A drop target has to say so before the file is let go, or the reader is
   guessing whether the page will take it or navigate away from it. */
.input-area--drop {
  outline: 2px dashed var(--accent);
  outline-offset: 6px;
  border-radius: 6px;
}

/* ---------------------------------------------------------- source guide */

.guide {
  margin-top: 0.9rem;
  color: var(--ink-soft);
  font-size: 0.85rem;
}

.guide > summary {
  color: var(--ink-faint);
  cursor: pointer;
}

.guide > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.guide h3 {
  margin: 0.9rem 0 0;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.guide p { margin: 0.4rem 0 0; text-wrap: pretty; }
.guide ul { margin: 0.35rem 0 0; padding-left: 1.1rem; }
.guide li { margin-top: 0.25rem; text-wrap: pretty; }

/* ---------------------------------------------------------- empty state */

.empty { margin-top: 2.5rem; }

.empty h2 {
  margin: 0 0 1rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.empty dl { margin: 0; }
.empty dt { font-weight: 600; margin-top: 1.1rem; }
.empty dt:first-child { margin-top: 0; }

.empty dd {
  margin: 0.15rem 0 0;
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* ------------------------------------------------------------- overview */

/* The report's table of contents. Eleven cards are a scroll with no shape on a
   phone; this says how many there are and what they are called before the
   reader has moved. It is also where the page puts focus after a run. */
.overview {
  margin-top: 1.5rem;
  padding: 0.85rem 1rem;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 6px;
}

.overview:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.overview__tally {
  margin: 0;
  color: var(--ink-soft);
  font-size: 0.85rem;
}

.overview__jumps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.6rem;
}

.overview__jump {
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  font-size: 0.78rem;
  line-height: 1.4;
  text-align: left;
  /* A card title can be longer than a phone is wide. */
  max-width: 100%;
  overflow-wrap: anywhere;
}

/* Tinted from the same tokens as the cards they point at, so the overview and
   the report cannot disagree about which finding is the alarming one. */
.overview__jump--alert {
  border-color: var(--bad);
  background: var(--bad-bg);
  color: var(--bad);
  font-weight: 600;
}

.overview__jump--info { border-color: var(--accent); background: var(--caution-bg); }
.overview__jump--neutral { color: var(--ink-soft); }

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

.card {
  margin-top: 1.5rem;
  padding: 1.25rem 1.35rem;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--rule);
  border-radius: 6px;
}

/* An alert card is tinted and titled like its bad rows, not just edged: the
   left border alone read as routine at the glance most cards get, and the
   terminal renderer already paints an alert title red. Same tokens as
   .item--bad, so light and dark are both covered by the existing palette. */
.card--alert { border-left-color: var(--bad); background: var(--bad-bg); }
.card--alert .card__title { color: var(--bad); }
.card--info { border-left-color: var(--accent); }

.card__title {
  margin: 0;
  font-size: 1.1rem;
  line-height: 1.35;
  text-wrap: balance;
}

/* A collapsible card must not look like a widget: the summary is the card
   title, with a marker small enough to read as punctuation. The default
   disclosure triangle sits outside the title and is styled by the platform, so
   it is removed in both spellings and drawn here instead — in `currentColor`,
   which is how it stays right in both colour schemes and on an alert. */
details.card > summary {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  cursor: pointer;
  list-style: none;
}

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

details.card > summary::before {
  /* The empty alternative text keeps the glyph out of the summary's
     accessible name, so a screen reader announces the title, not "▸ title".
     The plain form first: an engine that does not know the alt-text syntax
     (Firefox before 128, Safari before 17.4) drops that whole declaration and
     keeps this one, so the marker never disappears — it is merely announced. */
  content: "▸";
  content: "▸" / "";
  display: inline-block;
  flex: none;
  color: currentColor;
  opacity: 0.55;
  font-size: 0.9rem;
  transition: transform 0.15s ease;
}

details.card[open] > summary::before { transform: rotate(90deg); }

details.card > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Every card is focusable so a jump can land the reader inside it; the ring is
   how they see where they landed. */
.card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.card__lede {
  margin: 0.5rem 0 0;
  color: var(--ink-soft);
  font-size: 0.94rem;
  text-wrap: pretty;
}

.card__items { margin-top: 1.1rem; }

.item {
  padding: 0.7rem 0 0.7rem 0.85rem;
  border-top: 1px solid var(--rule);
  border-left: 2px solid transparent;
}

.item:first-child { border-top: none; }
.item--emphasis { border-left-color: var(--accent); background: var(--caution-bg); }
.item--bad { border-left-color: var(--bad); background: var(--bad-bg); }
.item--good { border-left-color: var(--good); background: var(--good-bg); }
.item--caution { border-left-color: var(--caution); background: var(--caution-bg); }

.item__label {
  font-weight: 600;
  font-size: 0.9rem;
}

.item--bad .item__label { color: var(--bad); }
.item--good .item__label { color: var(--good); }

/* A verdict is marked as well as coloured. Colour alone fails for anyone who
   cannot tell red from green, and it is the one distinction on this page that
   changes what a reader should do. Same three marks the terminal build uses. */
.item--good .item__label::before,
.item--bad .item__label::before,
.item--caution .item__label::before,
.item--fault .item__label::before,
.item--absent .item__label::before {
  display: inline-block;
  width: 1.1em;
  font-weight: 700;
}

.item--good .item__label::before { content: "✓"; color: var(--good); }
.item--bad .item__label::before { content: "✗"; color: var(--bad); }
.item--caution .item__label::before { content: "!"; color: var(--caution); }
/* Fault is the one mark that is not about the message: a section of this tool
   threw while it ran. Coloured like a failure because it is one — ours. */
.item--fault .item__label::before { content: "‡"; color: var(--bad); }
/* Absent is not a failure: a missing field is something the analysis could not
   do, not a fault in the message. Marked, but never coloured like a forgery. */
.item--absent .item__label::before { content: "○"; color: var(--ink-faint); }
.item--absent .item__label { color: var(--ink-soft); }

.item__value {
  margin-top: 0.15rem;
  color: var(--ink-soft);
  font-size: 0.9rem;
  overflow-wrap: anywhere;
}

.item__value--mono {
  font-family: var(--mono);
  font-size: 0.78rem;
  white-space: pre-wrap;
  color: var(--ink);
}

/* A payload that spans lines is the sender's own text, reproduced with their
   line breaks. Left unmarked it can be written to look like this tool's own
   rows — a tick, a verdict, a reassuring sentence, none of it computed here.
   Quoted like a mail client quotes, for the same reason. */
.item__value--quoted {
  border-left: 2px solid var(--rule);
  padding-left: 0.6rem;
}

/* Chips carry the short structural facts — where a value was found, how it was
   decoded, which platform issued it. Keeping them out of the prose is what lets
   a card be scanned instead of read. */
.item__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.4rem;
}

.chip {
  padding: 0.1rem 0.45rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--bg);
  color: var(--ink-soft);
  font-family: var(--mono);
  font-size: 0.7rem;
  line-height: 1.5;
  /* A chip carrying a header name and a decode method can be longer than a
     phone is wide, so it has to be allowed to break rather than overflow. */
  max-width: 100%;
  overflow-wrap: anywhere;
}

/* On a highlighted row the chips sit on a tinted background, so they need a
   surface of their own to stay legible. */
.item--emphasis .chip,
.item--bad .chip,
.item--good .chip,
.item--caution .chip { background: var(--surface); }

.item__note {
  margin-top: 0.35rem;
  color: var(--ink-faint);
  font-size: 0.82rem;
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------ colophon */

.colophon {
  margin-top: 3.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  color: var(--ink-faint);
  font-size: 0.84rem;
}

.colophon p { margin: 0 0 0.7rem; text-wrap: pretty; }
.colophon strong { color: var(--ink-soft); }
.colophon a { color: inherit; }

code {
  font-family: var(--mono);
  font-size: 0.86em;
}

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

/* ---------------------------------------------------------------- touch */

/* A finger, not a mouse. Two of these are corrections rather than taste:
   iOS Safari zooms into any field whose text is under 16 px and does not zoom
   back out afterwards, leaving the page wider than the screen for the rest of
   the visit; and 44 px is the smallest control Apple's own guidance says a
   thumb hits reliably. The mono type grows with the same reasoning the
   textarea does — 0.7rem is 11 px, which is not a size you read a hostname at
   when the hostname is the finding. */
@media (pointer: coarse) {
  textarea { font-size: 1rem; }

  button {
    min-height: 44px;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
  }

  .chip { font-size: 0.78rem; }
  .item__value--mono { font-size: 0.85rem; }
}

/* A phone held upright. The card padding was 1.35rem a side, which on a 320 px
   screen spends a sixth of the width on margins. */
@media (max-width: 26rem) {
  body { padding: 2rem 1rem 4rem; }
  .card { padding: 0.9rem 0.85rem; }
}
