/* Groundsense commercial surfaces.
 *
 * Tokens are Aidan's, lifted verbatim from DESIGN.md. Nothing here invents a
 * colour, a type step or a spacing value. Where this file departs from the
 * product it is because a document is not an app, and each departure is
 * commented with why.
 *
 * Departure 1: the product is a fixed 100dvh shell that never page-scrolls,
 * because a map has to hold its ground. A plan is read end to end, printed and
 * sent to a partner, so this scrolls at the document.
 */

:root {
  /* Colour, DESIGN.md */
  --paper: #e9e6e1;
  --inset: #edeae5;
  --card: #ffffff;
  --recess: #f7f5f2;
  --board: #f1efeb;

  --ink: #1a1814;
  --ink-strong: #12100e;
  --ink-body: #3a362f;
  --ink-muted: #4a463e;
  --ink-faint: #615c54; /* The Faint Floor. Nothing lighter carries text. */

  --rule: #e3e0db;
  --rule-strong: #ddd8d0;
  --rule-edge: #d8d4cd;
  --rule-hair: #edeae5;

  --navy: #0f1c2e; /* The One Navy Rule: where you live now, and nothing else. */
  --navy-card: #14243a;
  --navy-rule: #26384e;
  --navy-pill: #2c4058;
  --on-navy: #ffffff;
  --on-navy-1: #c9d4e0;
  --on-navy-2: #9fb0c2;
  --on-navy-3: #8fa6be;

  --better: #1f7a54;
  --worse: #b4483a;
  --better-tint: #e9f3ee;
  --worse-tint: #fbeeeb;
  --better-ink: #145c3e;
  --worse-ink: #8d3629;

  --caution-bg: #fbf6ec;
  --caution-rule: #eaddc4;
  --caution-label: #8a6a2e;
  --caution-text: #5c4a22;

  /* Spacing, the nine-step 4px scale */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 20px;
  --s-6: 24px; --s-7: 32px; --s-8: 40px; --s-9: 56px;

  /* Rounded */
  --r-hair: 1px; --r-bar: 3px; --r-xs: 6px; --r-s: 8px;
  --r-m: 12px; --r-l: 16px; --r-pill: 999px;

  --tap: 44px;

  /* Type. Four figure steps, four interface steps, three mono steps. */
  --serif: 'Source Serif 4', 'Iowan Old Style', Georgia, serif;
  --sans: Archivo, system-ui, -apple-system, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --fig-xl: 3rem;     --fig-l: 2.125rem;  --fig-m: 1.625rem;  --fig-s: 1.25rem;
  --ui-prose: 1.0625rem; --ui-control: .9375rem; --ui-row: .875rem; --ui-meta: .8125rem;
  --mono-label: .75rem; --mono-prov: .6875rem; --mono-val: .8125rem;

  /* Shadow. Exactly two in the system, both with an offset as well as a blur. */
  --lift: 0 1px 2px rgba(26, 24, 20, .06);

  /* Motion. Ease-out only, no bounce. */
  --ease: cubic-bezier(.22, 1, .36, 1);
}

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 var(--ui-prose)/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* Playfair's old-style figures cost this portfolio three fix attempts on a
   different product. Source Serif 4 defaults to lining figures, but it is
   pinned here so a font update cannot quietly move a number off the baseline. */
.fig, table td, table th, .val {
  font-variant-numeric: lining-nums tabular-nums;
}

h1, h2, h3 { margin: 0; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }

/* The 68ch Rule. Capped on the text element, never on its container, because a
   paragraph inside a wide grid row otherwise takes the whole track. */
p, li, blockquote, .measure { max-width: 62ch; }

a { color: var(--ink-strong); text-underline-offset: 2px; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 2px solid var(--ink-strong);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* --- shared type classes ------------------------------------------------- */

.fig      { font-family: var(--serif); font-weight: 400; line-height: 1; }
.fig--xl  { font-size: var(--fig-xl); }
.fig--l   { font-size: var(--fig-l); line-height: 1.05; }
.fig--m   { font-size: var(--fig-m); }
.fig--s   { font-size: var(--fig-s); }

/* Tracked caps means "this describes the data, it is not the data". */
.label {
  font: 500 var(--mono-label)/1 var(--mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.prov {
  font: 500 var(--mono-prov)/1.4 var(--mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.val {
  font: 500 var(--mono-val)/1 var(--mono);
  letter-spacing: .04em;
}
.meta { font-size: var(--ui-meta); line-height: 1.45; color: var(--ink-muted); }
.row-label { font-size: var(--ui-row); line-height: 1.5; color: var(--ink-muted); }

/* --- visually hidden -------------------------------------------------------
 * For a table header that a screen reader needs and a sighted reader does
 * not, such as the label column of a comparison whose caption already names
 * it. Clip rather than display:none, so it stays in the accessibility tree.
 */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- caution band -------------------------------------------------------- */
/* The exclusion register. Warm rather than red: it reports a limit, not an
   error. Not dismissible here, unlike the product's, because the thing it
   discloses stays true for the life of the document. */

.caution {
  background: var(--caution-bg);
  border: 1px solid var(--caution-rule);
  border-radius: var(--r-m);
  padding: var(--s-4) var(--s-5);
  color: var(--caution-text);
}
.caution__label { color: var(--caution-label); display: block; margin-bottom: var(--s-2); }
.caution p + p { margin-top: var(--s-3); }
.caution strong { color: var(--caution-text); }

/* --- verdict chips ------------------------------------------------------- */
/* The Never Colour Alone Rule: every one of these carries a word as well as a
   hue, and the word is visible, not sr-only. */

.chip {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-2);
  padding: var(--s-1) var(--s-2);
  border-radius: var(--r-xs);
  font: 500 var(--ui-meta)/1.2 var(--sans);
  /* Measured at 375: nowrap pushed three chips past their own cell, because a
     two-column table cell there is about 150px and "Less deprived +49.4pp" is
     not. The word wraps under the figure rather than the chip spilling. */
  max-width: 100%;
  flex-wrap: wrap;
  row-gap: var(--s-1);
}
/* nowrap keeps a two-word label on one line, which is right until the cell is
   narrower than the label. At 320px a half-cell is about 99px and a tracked
   caps label can exceed it, so nowrap is lifted at the narrowest widths rather
   than letting the chip spill. */
.chip__word { white-space: nowrap; }
@media (max-width: 360px) { .chip__word { white-space: normal; } }
.chip__word {
  font: 500 var(--mono-prov)/1 var(--mono);
  letter-spacing: .08em;
  text-transform: uppercase;
}
.chip--better { background: var(--better-tint); color: var(--better-ink); }
.chip--worse  { background: var(--worse-tint);  color: var(--worse-ink); }
.chip--flat   { background: var(--board);       color: var(--ink-muted); }

/* --- a value's trailing annotation ---------------------------------------
   The chip that hangs under a figure in a comparison cell. This lived in
   plan.html alone, which left the same markup on index.html with an inline
   chip and no spacing. Both pages use it, so it lives here. */

.after { display: block; margin-top: var(--s-1); max-width: 100%; }
/* A chip used as a block-level .after must not be wider than the cell. */
.after.chip { display: flex; width: fit-content; }

/* --- standalone links -----------------------------------------------------
 * DESIGN.md sets a 24px floor under a fine pointer and 44px under a coarse
 * one, and it applies to controls. WCAG 2.2 AA 2.5.8 carves out targets that
 * sit inline in a sentence, and that exemption is real: a link inside a
 * paragraph cannot be padded without wrecking the line box, and the spec says
 * so. So inline prose links are left alone deliberately.
 *
 * A masthead "Back" and a row of footer links are NOT inline in a sentence.
 * They are navigation, the exemption does not reach them, and they measured
 * 14 to 20px tall. The hit area grows on negative block margins so the row
 * around them does not, which is the technique the product uses on
 * .rail__reset and .slider__clear.
 */
.mast a, .foot a, .foot__row a {
  display: inline-block;
  padding-block: 6px;
  margin-block: -6px;
}
@media (pointer: coarse) {
  /* Both dimensions, not just height. "Privacy" measured 43x46, which is the
     floor half-kept, the same fault DESIGN.md records against .slider__clear
     at 39x14. min-width rather than side padding so the row does not stretch. */
  .mast a, .foot a, .foot__row a {
    padding-block: 13px; margin-block: -13px;
    min-width: var(--tap); text-align: center;
  }
}

/* --- the mark -------------------------------------------------------------
   Ground in cross section, with a bore sunk into it.

   The obvious marks for anything about moving house are a roof outline and a
   map pin, and the obvious escapes from those are a compass rose, contour
   lines or a letter in a circle. All six are things you could guess from the
   category alone, which means they say nothing about this product.

   What is actually true here is that Groundsense drills a narrow column
   through one place and reads its layers: the money, the schools, the
   doctors, the flood history, the neighbourhood. That is a core sample, which
   is literally how anybody finds out what ground is made of.

   It is drawn in the same five quantile colours the maps are shaded with, so
   the mark and the evidence are the same object rather than two designs
   sharing a page.

   The bore is a real gap between two halves of each band rather than a drawn
   line, which is what makes it work anywhere: it shows whatever is behind the
   mark, so it stays legible on the dark header and on the paper footer with
   no colour rule at all. It stops on the deepest band, because a bore goes
   down to a depth rather than cutting the ground in two, and because a full
   width band at the bottom is what holds the tile together as one object.

   The first attempt drew this as a core sample: a rounded column of segments
   with a tick on its side. At every size from 16 to 96 it was a battery.

   No ids anywhere, because the same markup is inlined twice and a duplicated
   id would break the second copy. */
.brand { display: inline-flex; align-items: baseline; gap: var(--s-2); }
.brand__core { width: 20px; height: 20px; flex: none; position: relative; top: 3px; }

/* --- rules --------------------------------------------------------------- */

hr.rule { border: 0; border-top: 1px solid var(--rule); margin: var(--s-8) 0; }
hr.hair { border: 0; border-top: 1px solid var(--rule-hair); margin: var(--s-4) 0; }

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding: 0 var(--s-5);
  border-radius: var(--r-m);
  font: 500 var(--ui-control)/1.2 var(--sans);
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background-color .18s var(--ease), border-color .18s var(--ease);
}
.btn--primary { background: var(--ink-strong); color: var(--card); }
.btn--primary:hover { background: #2a2622; }
.btn--secondary { background: var(--card); color: var(--ink); border-color: var(--rule-strong); }
.btn--secondary:hover { border-color: var(--ink-faint); }

@media (prefers-reduced-motion: reduce) {
  .btn { transition: none; }
}
