/* airescue.ca
 *
 * docs/design-direction.md is the spec. Every colour and type value here comes
 * from it. If the two disagree, one of them is a bug.
 *
 * Black, white, grey, and one red. The red points at something -- a flagged
 * token or the email address -- and never decorates. Machine text is IBM Plex
 * Mono and human text is IBM Plex Sans; the split is carried by typeface, not
 * by colour.
 */

/* ---------------------------------------------------------------- fonts -- */

/* One superfamily: IBM Plex Sans for everything human, IBM Plex Mono for
 * everything machine. They were drawn together, so the wordmark, the section
 * labels, the prose and the code all share proportions and terminals -- which
 * is why four files cover the whole site.
 *
 * Two weights of the sans, no more. 600 is the headline and the lead-ins; 400
 * is everything else. With font-synthesis off and no 700 face, `bold` resolves
 * to the 600, which is the intent. */

@font-face {
  font-family: "IBM Plex Sans";
  src: url(fonts/plexsans-400.woff2) format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url(fonts/plexsans-600.woff2) format("woff2");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url(fonts/plexmono-400-latin.woff2) format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url(fonts/plexmono-500-latin.woff2) format("woff2");
  font-weight: 500;
  font-display: swap;
}

/* --------------------------------------------------------------- tokens -- */

:root {
  /* Read by the theme toggle to find the *effective* theme, which is not the
   * same as the stored one: with nothing stored, the system preference wins.
   * Reading a computed custom property is the only way to ask that question
   * without duplicating the media query in JavaScript. */
  --is-dark: 0;

  --paper:   #FFFFFF;
  --surface: #F2F2F1;   /* code blocks, the hero card */
  --ink:     #111111;   /* neutral near-black, no colour cast */
  --muted:   #6B6B6B;
  --rule:    #E2E2E0;
  --mark:    #C8102E;   /* the only colour on the page */

  --sans:    "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --mono:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --measure: 38rem;     /* the widest a paragraph is allowed to be */
}

/* Measured: #C8102E is 5.88:1 on white and 5.25:1 on --surface; #EE4B5E is
 * 5.3:1 on the dark paper. --muted is 5.33:1 light and 6.76:1 dark. The
 * flagged token is the one thing on the page every visitor must be able to
 * read, so it never drops below AA. */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --is-dark: 1;
    --paper:   #101010;
    --surface: #1A1A1A;
    --ink:     #EDEDED;
    --muted:   #9A9A9A;
    --rule:    #2C2C2C;
    --mark:    #EE4B5E;
  }
}

:root[data-theme="dark"] {
  --is-dark: 1;
  --paper:   #101010;
  --surface: #1A1A1A;
  --ink:     #EDEDED;
  --muted:   #9A9A9A;
  --rule:    #2C2C2C;
  --mark:    #EE4B5E;
}

/* ------------------------------------------------------------- elements -- */

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 1.0625rem/1.65 var(--sans);
  font-synthesis: none;
}

b, strong { font-weight: 600; }

::selection { background: var(--mark); color: var(--paper); }

:focus-visible {
  outline: 2px solid var(--mark);
  outline-offset: 3px;
  border-radius: 1px;
}

/* Ordinary links are underlined in grey. Red is reserved for the two things
 * that mean "look here": a flagged token, and the email address. */
a { color: inherit; text-decoration-color: var(--muted); text-underline-offset: 3px; }
a:hover { text-decoration-thickness: 2px; }

/* --------------------------------------------------------------- layout -- */

.wrap {
  max-width: 62rem;
  margin-inline: auto;
  padding-inline: 1.5rem;
}

/* --------------------------------------------------------------- header -- */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: 1.5rem 2.25rem;
}

/* A span on the home page and a link back to it everywhere else, so the rule
 * has to cover both. `text-decoration: none` is the whole difference. */
.wordmark { font: 500 0.9375rem/1 var(--mono); letter-spacing: 0.02em; text-decoration: none; }

.theme {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: none;
  color: var(--muted);
  cursor: pointer;
}
.theme:hover { color: var(--ink); border-color: var(--muted); }

/* ----------------------------------------------------------------- type -- */

h1 {
  margin: 0 0 1.25rem;
  /* A grotesque carries more visual weight than the serif this replaced, so it
   * is set one step smaller and tracked tighter. Same headline, same measure. */
  font: 600 clamp(2rem, 5.6vw, 3.15rem)/1.06 var(--sans);
  letter-spacing: -0.026em;
  text-wrap: balance;
}

/* Section headings sit in the machine register on purpose: they are labels on
 * the document, not part of the argument. */
h2 {
  margin: 3.25rem 0 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  font: 500 0.75rem/1.4 var(--mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted);
}

p { margin: 0 0 1rem; max-width: var(--measure); }

.lede { font-size: 1.1875rem; margin-bottom: 0; }

.terms { color: var(--muted); font-size: 0.9375rem; }

/* ----------------------------------------------------------------- hero -- */

/* Two columns on wide screens so the fold carries the pitch AND the person AND
 * the way to start, instead of stacking them down three screens of scrolling. */
.hero { display: grid; gap: 2rem; align-items: start; }

@media (min-width: 56rem) {
  .hero { grid-template-columns: 1.45fr 1fr; gap: 3.5rem; }
  .pitch p { max-width: none; }
}

.card {
  padding: 1.5rem;
  background: var(--surface);
  border-radius: 3px;
}

.card p { margin: 0 0 1rem; max-width: none; font-size: 0.9375rem; }

.card img {
  display: block;
  width: 5.5rem;        /* the source is 281px square; never scale it up */
  height: auto;
  margin-bottom: 1rem;
  border-radius: 3px;
}

.contact { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }

.card .contact { margin-bottom: 0; }

.mail {
  font: 500 1.0625rem/1.4 var(--mono);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--mark);
}

.at { color: var(--muted); font-size: 0.875em; }

.said { color: var(--muted); font-size: 0.875rem; }

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

/* Both lists run two-up on wide screens. Seven short statements in one column
 * is a wall; in two it is a glance. */

.steps { counter-reset: step; margin: 0 0 1.25rem; padding: 0; list-style: none; }

.steps > li { position: relative; padding-left: 2.75rem; margin-bottom: 1.25rem; }

.steps > li::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0.3em;
  font: 500 0.75rem/1 var(--mono);
  letter-spacing: 0.08em;
  color: var(--muted);
}

/* "or" sits where a number would, because the fourth item is an alternative to
 * the sequence rather than the next step in it. The break in the numbering is
 * carrying that information, so the counter must not advance here. */
.steps > li.branch::before { counter-increment: none; content: "or"; text-transform: uppercase; }

.breaks { margin: 0; padding: 0; list-style: none; }

.breaks > li { position: relative; padding-left: 1.5rem; margin-bottom: 0.75rem; }

.breaks > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.75em;
  width: 0.75rem;
  height: 1px;
  background: var(--muted);
}

@media (min-width: 48rem) {
  .steps, .breaks { display: grid; grid-template-columns: 1fr 1fr; column-gap: 3rem; }
  .steps > li, .breaks > li { margin-bottom: 1rem; }
}

/* ------------------------------------------------------------ checklist -- */

/* /12-things/. Deliberately ONE column at every width, unlike .steps and
 * .breaks above: this is a list the reader works down and scores, and two
 * columns turn "twelve things" into an unreadable pair of columns where the
 * eye loses its place between item 6 and item 7. */
.check {
  counter-reset: item;
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: var(--measure);
}

.check > li {
  display: grid;
  grid-template-columns: 1.25rem 1fr;
  column-gap: 0.875rem;
  align-items: start;
  padding-bottom: 1.25rem;
  margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--rule);
}
.check > li:last-child { border-bottom: none; }

/* Native checkbox, tinted. A hand-drawn replacement would mean re-teaching the
 * browser focus, keyboard and touch-target behaviour that this already has for
 * free -- and this is the one control on the site that has to be obviously
 * operable to a non-technical reader. */
.check input {
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
  /* Optically centred on the first line of the label, which sits at 1.65
   * line-height. Not a magic number: (1.65em - 1.25rem) / 2 at the body size. */
  margin-top: 0.2rem;
  accent-color: var(--mark);
  cursor: pointer;
}

.check label {
  cursor: pointer;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--muted);
}

.check b {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 1.0625rem;
  line-height: 1.45;
  color: var(--ink);
}

/* The numbering is decorative here -- the count is what matters, not the
 * position -- so it rides on the lead-in rather than taking a column of its
 * own the way .steps does. */
.check b::before {
  counter-increment: item;
  content: counter(item) ". ";
  color: var(--muted);
  font: 500 0.8125rem/1 var(--mono);
}

/* Ticked items stay fully legible. Greying out or striking through what the
 * reader just admitted to would hide the only content they came for. The
 * marker alone carries the state. */
.check input:checked + label b { color: var(--mark); }

.score {
  margin: 0;
  padding: 1rem 1.25rem;
  max-width: var(--measure);
  background: var(--surface);
  border-left: 2px solid var(--mark);
  font-size: 0.9375rem;
  line-height: 1.6;
}
.score b { font: 500 1.0625rem/1 var(--mono); color: var(--mark); }

/* ----------------------------------------------------- the annotation -- */

.samples { margin-top: 1.5rem; }

.annot { margin: 0 0 1.75rem; }

.code {
  margin: 0;
  padding: 1rem 1.125rem;
  overflow-x: auto;
  background: var(--surface);
  border-left: 2px solid var(--rule);
  font: 400 0.8125rem/1.7 var(--mono);
  tab-size: 2;
}

/* Headroom on the narrowest phones. The fragments are written to fit 360px at
 * the size above, but a visitor with a larger default text size has none to
 * spare, and a horizontally scrolling code block reads as broken. */
@media (max-width: 26rem) {
  .code { font-size: 0.75rem; padding-inline: 0.875rem; }
}

/* The only coloured thing in the block, so the eye lands here before reading a
 * word. The underline is not decoration: WCAG 1.4.1 forbids colour as the only
 * means of conveying information, and without it a reader who cannot separate
 * red from black has no way to tell which token is flagged. */
.flag {
  background: none;
  color: var(--mark);
  font-weight: 500;
  box-shadow: inset 0 -2px 0 var(--mark);
}

.note {
  margin: 0.75rem 0 0;
  padding-left: 0.875rem;
  max-width: var(--measure);
  border-left: 2px solid var(--mark);
  font-size: 0.9375rem;
  line-height: 1.5;
}
.note code { font: 400 0.875em/1 var(--mono); }

@media (min-width: 56rem) {
  .annot { display: grid; grid-template-columns: minmax(0, 26rem) 1fr; column-gap: 2.5rem; align-items: start; }
  .note { margin-top: 0; padding-top: 0.125rem; }
}

/* The single motion moment on the page: the rule draws itself under the first
 * flagged token, once. Nothing else ever moves. Resist adding a second. */
.samples .annot:first-child .flag {
  box-shadow: none;
  background: linear-gradient(var(--mark), var(--mark)) no-repeat left bottom / 0% 2px;
  animation: draw 0.5s ease-out forwards;
}
@keyframes draw { to { background-size: 100% 2px; } }

@media (prefers-reduced-motion: reduce) {
  .samples .annot:first-child .flag { animation: none; background-size: 100% 2px; }
}

/* --------------------------------------------------------------- outro -- */

.outro p:last-child { color: var(--muted); font-size: 0.9375rem; }

/* ---------------------------------------------------------------- foot -- */

footer { padding-block: 0 2.5rem; margin-top: 3rem; }

footer p {
  margin: 0;
  max-width: none;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  font: 400 0.8125rem/1.5 var(--mono);
  color: var(--muted);
}
