/* app.css — the whole custom-property system, section 1a of the design.
 *
 * Linked from every document this application serves. The
 * Content-Security-Policy allows no inline style of either kind, so a
 * value that is not in this file cannot be applied to anything.
 *
 * Three theme states, and the order below is what resolves them:
 *   1. :root                              light, the default
 *   2. @media (prefers-color-scheme:dark) unstamped, system says dark
 *   3. [data-theme="light"|"dark"]        stamped, wins over the system
 * Nothing stamps data-theme today. The stamped sets exist because the
 * design resolves light and dark as complete sets, and because a theme
 * control added later must not have to re-derive them.
 */

:root {
  /* Three type roles, and each one is a system stack. NO woff2 file is
   * in this repository, so there is no @font-face rule here. A CDN link
   * is not an option either: default-src 'self' blocks every external
   * host and the failure is silent.
   *
   *   --font-sans   what a person taps — a button, a label, a heading
   *   --font-serif  what a person reads as a sentence
   *   --font-mono   a time, a cell, a code
   *
   * A reader who cannot tell an instruction from a sentence is the
   * fault the three roles answer. */
  --font-sans: "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
  --font-serif: Charter, "Bitstream Charter", "Iowan Old Style", Georgia, serif;
  --font-mono: ui-monospace, Menlo, "SF Mono", Consolas, monospace;

  /* Type scale. Fluid clamp per step; the lower bound of each is the
   * number in the design's specimen, the upper bound is that step at a
   * desktop width. --fs-5's upper bound is 44px, the landing headline. */
  --fs-1: clamp(0.75rem, 0.72rem + 0.15vw, 0.8125rem);
  --fs-2: clamp(0.9375rem, 0.90rem + 0.19vw, 1rem);
  --fs-3: clamp(1.0625rem, 1.01rem + 0.28vw, 1.1875rem);
  --fs-4: clamp(1.3125rem, 1.19rem + 0.61vw, 1.625rem);
  --fs-5: clamp(1.875rem, 1.55rem + 1.6vw, 2.75rem);
  --fs-mono: clamp(0.8125rem, 0.79rem + 0.12vw, 0.875rem);

  --lh-1: 1.34;
  --lh-2: 1.5;
  --lh-3: 1.35;
  --lh-4: 1.2;
  --lh-5: 1.1;

  --tracking-tight: -0.02em;
  --tracking-snug: -0.01em;
  --tracking-wide: 0.09em;

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-bold: 600;

  /* Space. Seven steps, 4 8 12 16 24 32 48. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;

  /* Radii. --r-hex is the brand shape and the privacy promise: a
   * pointy-top hexagon, the same figure the H3 cell is drawn as. */
  --r-1: 6px;
  --r-2: 10px;
  --r-3: 18px;
  --r-hex: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);

  /* Targets. One-handed, outdoors, hurrying. */
  --tap-min: 48px;
  --tap-primary: 56px;

  --measure: 46rem;

  /* Color — ours, light. */
  --paper: #F1F4F7;
  --surface: #FFFFFF;
  --ink: #101620;
  --ink-2: #55606F;
  --ink-3: #66707F;
  --line: #D7DDE4;
  --focus: #1B4DB8;
  --caution: #8A6600;
  --caution-bg: #F7EFD8;

  /* Report status — five, each with a shape as well as a color. The
   * glyph is decoration: the status word is in the markup and is what a
   * screen reader announces. */
  --status-pending-bg: #E9ECF0;
  --status-pending-line: #C6CDD5;
  --status-pending-ink: #4C5563;
  --status-pending-glyph: "\25F7";

  --status-pooled-bg: #E1E9F4;
  --status-pooled-line: #1B4DB8;
  --status-pooled-ink: #1B4DB8;
  --status-pooled-glyph: "\2B21";

  --status-withheld-bg: #F7EFD8;
  --status-withheld-line: #8A6600;
  --status-withheld-ink: #8A6600;
  --status-withheld-glyph: "\25B2";

  --status-verified-bg: #DCEBE2;
  --status-verified-line: #1B7A4C;
  --status-verified-ink: #14603C;
  --status-verified-glyph: "\2713";

  --status-rejected-bg: #F7E6E4;
  --status-rejected-line: #A32118;
  --status-rejected-ink: #A32118;
  --status-rejected-glyph: "\2715";

  /* Theirs — the two colors an operator picks, and the derived ones.
   * The per-pack sheet overrides these at request time; the values here
   * are the neutral fallback so an unresolved pack renders legibly
   * rather than transparently.
   *
   * A pack picks ONE BRIGHT and ONE DEEP, and each has its own job.
   * --pack-hivis marks state: a ticked promise, a chosen subject, a
   * received report. --pack-accent acts: the wordmark mark, the primary
   * action, the located hex. Neither lands on body text, on a focus
   * ring or on a status color. Both -ink pairs are derived server-side
   * to clear 4.5:1, so either is safe under a label. */
  --pack-accent: #101620;
  --pack-accent-ink: #FFFFFF;
  --pack-accent-quiet: #E9ECF0;
  --pack-accent-quiet-ink: #101620;
  --pack-accent-firm: #101620;
  --pack-bg: #F1F4F7;
  --pack-hivis: #C2DA16;
  --pack-hivis-ink: #101620;

  color-scheme: light dark;
}

/* Unstamped, and the system asks for dark. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper: #131510;
    --surface: #1D1F19;
    --ink: #EFEDE4;
    --ink-2: #B3B5A8;
    --ink-3: #8C9082;
    --line: #33362C;
    --focus: #89A9FF;
    --caution: #E0B25C;
    --caution-bg: #3A2E14;

    --status-pending-bg: #262922;
    --status-pending-line: #4A4E42;
    --status-pending-ink: #C6C8BB;

    --status-pooled-bg: #1B2A38;
    --status-pooled-line: #4C7396;
    --status-pooled-ink: #A9CBE8;

    --status-withheld-bg: #3A2E14;
    --status-withheld-line: #8A6A22;
    --status-withheld-ink: #E7C480;

    --status-verified-bg: #1D2C1E;
    --status-verified-line: #4A6B4C;
    --status-verified-ink: #A8CFA6;

    --status-rejected-bg: #2E1D1B;
    --status-rejected-line: #7A4A44;
    --status-rejected-ink: #E2A9A2;

    --pack-accent: #EFEDE4;
    --pack-accent-ink: #131510;
    --pack-accent-quiet: #262922;
    --pack-accent-quiet-ink: #efede4;
    --pack-accent-firm: #EFEDE4;
    --pack-bg: #131510;
    --pack-hivis: #C2DA16;
    --pack-hivis-ink: #101620;
  }
}

/* Stamped light. Repeated in full rather than reset, because the media
 * query above may have already fired and a partial set would leave half
 * a theme behind. */
[data-theme="light"] {
  --paper: #F1F4F7;
  --surface: #FFFFFF;
  --ink: #101620;
  --ink-2: #55606F;
  --ink-3: #66707F;
  --line: #D7DDE4;
  --focus: #1B4DB8;
  --caution: #8A6600;
  --caution-bg: #F7EFD8;

  --status-pending-bg: #E9ECF0;
  --status-pending-line: #C6CDD5;
  --status-pending-ink: #4C5563;

  --status-pooled-bg: #E1E9F4;
  --status-pooled-line: #1B4DB8;
  --status-pooled-ink: #1B4DB8;

  --status-withheld-bg: #F7EFD8;
  --status-withheld-line: #8A6600;
  --status-withheld-ink: #8A6600;

  --status-verified-bg: #DCEBE2;
  --status-verified-line: #1B7A4C;
  --status-verified-ink: #14603C;

  --status-rejected-bg: #F7E6E4;
  --status-rejected-line: #A32118;
  --status-rejected-ink: #A32118;

  --pack-accent: #101620;
  --pack-accent-ink: #FFFFFF;
  --pack-accent-quiet: #E9ECF0;
  --pack-accent-quiet-ink: #101620;
  --pack-accent-firm: #101620;
  --pack-bg: #F1F4F7;
  --pack-hivis: #C2DA16;
  --pack-hivis-ink: #101620;

  color-scheme: light;
}

[data-theme="dark"] {
  --paper: #131510;
  --surface: #1D1F19;
  --ink: #EFEDE4;
  --ink-2: #B3B5A8;
  --ink-3: #8C9082;
  --line: #33362C;
  --focus: #89A9FF;
  --caution: #E0B25C;
  --caution-bg: #3A2E14;

  --status-pending-bg: #262922;
  --status-pending-line: #4A4E42;
  --status-pending-ink: #C6C8BB;

  --status-pooled-bg: #1B2A38;
  --status-pooled-line: #4C7396;
  --status-pooled-ink: #A9CBE8;

  --status-withheld-bg: #3A2E14;
  --status-withheld-line: #8A6A22;
  --status-withheld-ink: #E7C480;

  --status-verified-bg: #1D2C1E;
  --status-verified-line: #4A6B4C;
  --status-verified-ink: #A8CFA6;

  --status-rejected-bg: #2E1D1B;
  --status-rejected-line: #7A4A44;
  --status-rejected-ink: #E2A9A2;

  --pack-accent: #EFEDE4;
  --pack-accent-ink: #131510;
  --pack-accent-quiet: #262922;
  --pack-accent-quiet-ink: #efede4;
  --pack-accent-firm: #EFEDE4;
  --pack-bg: #131510;
  --pack-hivis: #C2DA16;
  --pack-hivis-ink: #101620;

  color-scheme: dark;
}

/* ---------------------------------------------------------------- base
 * Element defaults only. Every page in this application is bare
 * server-rendered HTML, so the elements below are the whole of what it
 * currently draws; a page's own components belong in that page's plan.
 */

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

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

body {
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-4) var(--sp-7);
  max-width: var(--measure);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-2);
  font-weight: var(--weight-regular);
  line-height: var(--lh-2);
  text-wrap: pretty;
}

/* Full-bleed escape for the one element that must not obey --measure. */
.bleed {
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  max-width: 100vw;
}

h1,
h2,
h3 {
  margin: 0 0 var(--sp-3);
  font-weight: var(--weight-bold);
  text-wrap: balance;
}

h1 {
  font-size: var(--fs-5);
  line-height: var(--lh-5);
  letter-spacing: var(--tracking-tight);
}

h2 {
  margin-top: var(--sp-6);
  font-size: var(--fs-4);
  line-height: var(--lh-4);
  letter-spacing: var(--tracking-snug);
}

h3 {
  margin-top: var(--sp-5);
  font-size: var(--fs-3);
  line-height: var(--lh-3);
}

p {
  margin: 0 0 var(--sp-4);
}

small,
.overline {
  font-size: var(--fs-1);
  line-height: var(--lh-1);
}

.overline {
  display: block;
  margin-bottom: var(--sp-2);
  color: var(--ink-3);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

code,
kbd,
samp,
pre,
.mono {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
}

a {
  color: var(--focus);
  text-underline-offset: 0.18em;
}

a:hover {
  color: var(--ink);
}

/* Ours only. Focus never comes from pack color, so an operator's hex
 * can never break it. */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--r-1);
}

hr {
  height: 1px;
  margin: var(--sp-5) 0;
  border: 0;
  background: var(--line);
}

header,
footer {
  color: var(--ink-3);
  font-size: var(--fs-1);
  line-height: var(--lh-1);
}

header {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
}

header p,
footer p {
  margin: 0;
}

/* The navigation, drawn in the header of every layout page that carries
 * one. Every color here is a token already defined above; nothing new
 * is introduced and nothing is measured against white.
 *
 * The list rules restate margin, padding and list-style at 0,1,1 because
 * the ul and li defaults further down this file would otherwise indent
 * the row and stack it. */
.wayfinding {
  margin-left: auto;
}

.wayfinding ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.wayfinding li {
  margin: 0;
}

/* Padding gives the foundation :focus-visible outline room to draw
 * clear of the letters. */
.wayfinding a {
  display: inline-block;
  padding: var(--sp-1) 0;
  color: var(--focus);
  font-weight: var(--weight-medium);
  text-decoration: none;
}

.wayfinding a:hover {
  color: var(--ink);
  text-decoration: underline;
}

/* The page a person is on. Weight and ink carry it, so the mark is not
 * the only signal; the hi-vis rule beneath is the same highlighter
 * .mark draws with. */
.wayfinding a[aria-current="page"] {
  color: var(--ink);
  font-weight: var(--weight-bold);
  box-shadow: inset 0 -0.2em 0 var(--pack-hivis);
}

main {
  display: block;
}

ul,
ol {
  margin: 0 0 var(--sp-4);
  padding-left: var(--sp-5);
}

li {
  margin-bottom: var(--sp-2);
}

/* PROVISIONAL, and the only rule in this file that names one page's
 * element. The sightings list is records rather than prose, and without
 * these two rules `/` — the document an installed application opens to —
 * renders as disc bullets. Whichever plan takes / and /map owns this and
 * should replace it; it is here so that foundations landing on its own
 * leaves nothing looking unfinished. */
#sightings {
  margin: 0 0 var(--sp-5);
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

#sightings li {
  margin: 0;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
  color: var(--ink-2);
}

fieldset {
  margin: 0 0 var(--sp-5);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--surface);
}

legend {
  padding: 0 var(--sp-2);
  color: var(--ink-3);
  font-size: var(--fs-1);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

label {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: var(--fs-2);
  font-weight: var(--weight-medium);
}

input,
select,
textarea {
  width: 100%;
  min-height: var(--tap-min);
  margin-bottom: var(--sp-4);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
}

input[type="checkbox"],
input[type="radio"] {
  width: auto;
  min-height: 0;
  margin-bottom: 0;
  accent-color: var(--pack-accent-firm);
}

/* A hidden input is not a control. Without this it keeps the margin the
 * rule above gives every input and adds a gap nothing occupies — and
 * /submit emits three of them, unconditionally, before the photo part. */
input[type="hidden"] {
  display: none;
  margin: 0;
}

[aria-invalid="true"] {
  border-color: var(--caution);
  background: var(--caution-bg);
}

button,
input[type="submit"] {
  min-height: var(--tap-primary);
  padding: var(--sp-3) var(--sp-5);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-weight: var(--weight-bold);
  cursor: pointer;
}

/* One of pack color's three jobs. --pack-accent-ink is derived
 * server-side to clear 4.5:1 against it, so this pairing is safe for any
 * hex an operator picks. */
button[type="submit"],
input[type="submit"] {
  border-color: transparent;
  background: var(--pack-accent-firm);
  color: var(--pack-accent-ink);
}

button[aria-pressed="true"] {
  border-color: var(--pack-accent-firm);
  background: var(--pack-accent-quiet);
  /* The fill is a tint of the pack's paper and it stays light in every
     theme. Its label comes from the same derivation, so the pair is
     measured. var(--ink) here would be light on light in dark mode. */
  color: var(--pack-accent-quiet-ink);
}

button:disabled {
  color: var(--ink-3);
  cursor: not-allowed;
}

form {
  margin: 0 0 var(--sp-5);
}

[role="status"] {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--surface);
  font-size: var(--fs-2);
}

/* /submit emits two of these empty and fills them from script. An empty
 * live region drawn as a box is a box that says nothing. */
[role="status"]:empty {
  display: none;
}

.caution {
  border: 1px solid var(--caution);
  border-radius: var(--r-2);
  padding: var(--sp-3) var(--sp-4);
  background: var(--caution-bg);
  color: var(--caution);
}

/* Report status. Shape and text, never color alone — the word is in the
 * markup, the glyph is drawn here, and the pack's hex reaches neither. */
.status {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: var(--fs-1);
  font-weight: var(--weight-bold);
  line-height: var(--lh-1);
  white-space: nowrap;
}

.status::before {
  content: var(--status-glyph, "");
  font-family: var(--font-mono);
}

.status-pending {
  --status-glyph: var(--status-pending-glyph);
  border-color: var(--status-pending-line);
  background: var(--status-pending-bg);
  color: var(--status-pending-ink);
}

.status-pooled {
  --status-glyph: var(--status-pooled-glyph);
  border-color: var(--status-pooled-line);
  background: var(--status-pooled-bg);
  color: var(--status-pooled-ink);
}

.status-withheld {
  --status-glyph: var(--status-withheld-glyph);
  border-color: var(--status-withheld-line);
  background: var(--status-withheld-bg);
  color: var(--status-withheld-ink);
}

.status-verified {
  --status-glyph: var(--status-verified-glyph);
  border-color: var(--status-verified-line);
  background: var(--status-verified-bg);
  color: var(--status-verified-ink);
}

.status-rejected {
  --status-glyph: var(--status-rejected-glyph);
  border-color: var(--status-rejected-line);
  background: var(--status-rejected-bg);
  color: var(--status-rejected-ink);
}

/* The brand shape, and the privacy promise. */
.hex {
  clip-path: var(--r-hex);
  background: var(--pack-accent);
}

/* HI-VIS MARKS STATE. THE PACK COLOUR ACTS. The two never swap jobs: a
 * ticked promise, a chosen subject and a received report are already
 * true, so they are hi-vis; a button is the pack's color because it is
 * the thing that does something. Hi-vis carries a label only through
 * --pack-hivis-ink, which is derived to clear 4.5:1 against whatever
 * bright the pack picked. */
.hivis {
  background: var(--pack-hivis);
  color: var(--pack-hivis-ink);
}

.hex-hivis {
  background: var(--pack-hivis);
}

/* One word in a heading, marked the way a highlighter marks one. An
 * inset shadow rather than a background, so the mark sits under the
 * letters and the descenders stay readable. */
.mark {
  box-shadow: inset 0 -0.3em 0 var(--pack-hivis);
}
