/* bumpwarden design system. Derived from design/ART-DIRECTION.md.
   THE COLOUR LAW: colour means risk. Nothing else in this product is coloured, so the only
   saturated pixels on any screen belong to a score, a band, or a factor's contribution. */

/* Both faces are OFL and served from this origin, so reading a page reaches no third party and a
   container with no outbound network still renders correctly. The files are the latin and latin-ext
   subsets of
   fonts.googleapis.com/css2?family=Mona+Sans:ital,wdth,wght@0,75..125,200..900&family=JetBrains+Mono:wght@100..800
   and the licence of each sits beside them in fonts/. */
@font-face {
  font-family: 'Mona Sans';
  font-style: normal;
  font-weight: 200 900;
  font-stretch: 75% 125%;
  font-display: swap;
  src: url(fonts/mona-sans-latin.woff2) format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Mona Sans';
  font-style: normal;
  font-weight: 200 900;
  font-stretch: 75% 125%;
  font-display: swap;
  src: url(fonts/mona-sans-latin-ext.woff2) format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url(fonts/jetbrains-mono-latin.woff2) format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url(fonts/jetbrains-mono-latin-ext.woff2) format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

:root {
  --bg: #fafaf9;
  --panel: #ffffff;
  --panel-2: #f7f8f8;
  --ink: #14181b;
  --ink-2: #5a6469;
  /* Labels and axis annotations are small text, so this has to clear 4.5:1 rather than sit at the
     3:1 a graphic gets away with. Measured 4.77:1 on panel. */
  --ink-3: #6b747a;
  --rule: #e6e8e7;
  --rule-2: #f0f2f1;
  --tick: #cdd3d1;

  --r0: #0f766e;
  --r1: #4d7c3f;
  --r2: #b7791f;
  --r3: #c2410c;
  --r4: #b91c1c;

  /* One family across the whole range, which is what every measured product does. Headlines take
     the tight width and the heavy weight, rows take normal width. */
  --display: 'Mona Sans', sans-serif;
  --sans: 'Mona Sans', sans-serif;
  --mono: 'JetBrains Mono', monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0e1113;
    --panel: #161a1d;
    --panel-2: #1b2023;
    --ink: #e8edf0;
    --ink-2: #9aa5ab;
    --ink-3: #8b959a; /* 5.72:1 on the dark panel */
    --rule: #262c30;
    --rule-2: #1d2225;
    --tick: #394247;

    /* The ramp lifts on a dark ground so every step still clears contrast. The meaning of each
       step does not change, only its luminance. */
    --r0: #2dd4a7;
    --r1: #8fca6a;
    --r2: #e0a83a;
    --r3: #f2884a;
    --r4: #f2706e;
  }
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

/* ---------- chrome ---------- */

.bar {
  display: flex;
  align-items: center;
  gap: 26px;
  padding: 15px 34px;
  background: var(--panel);
  border-bottom: 1px solid var(--rule);
}
.logo {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 88%;
  font-size: 20px;
  letter-spacing: -0.02em;
  color: inherit;
  text-decoration: none;
}
.bar nav {
  display: flex;
  gap: 20px;
}
.bar nav a {
  color: var(--ink-2);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
}
.bar nav a:hover {
  color: var(--ink);
}
.bar nav a[aria-current] {
  color: var(--ink);
  font-weight: 700;
}
.bar .right {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-3);
}

.band {
  padding: 40px 34px 26px;
}
h1 {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 92%;
  font-size: clamp(29px, 4vw, 46px);
  letter-spacing: -0.028em;
  line-height: 1.06;
  margin: 0;
  max-width: 21ch;
}
.lede {
  margin: 14px 0 0;
  color: var(--ink-2);
  font-size: 16.5px;
  max-width: 62ch;
}
.crumb {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-3);
  margin: 0 0 12px;
}

/* Monochrome on purpose. A coloured button would teach the eye that colour is decoration, and in
   this product colour only ever means risk. */
.btn {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 14px;
  background: var(--ink);
  color: var(--bg);
  border: 1px solid var(--ink);
  border-radius: 8px;
  padding: 9px 18px;
  cursor: pointer;
  transition: opacity 120ms cubic-bezier(0.2, 0, 0, 1);
}
.btn:hover {
  opacity: 0.86;
}
.btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* ---------- the spread: the whole run on one shared axis ---------- */

.spread {
  margin: 26px 34px 0;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 22px 30px 12px;
}
.spread h2,
.panel-h {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin: 0 0 8px;
  color: var(--ink-3);
  font-weight: 700;
}
.spread .note {
  font-size: 13.5px;
  color: var(--ink-2);
  margin: 0 0 26px;
}
.axis-scroll {
  overflow-x: auto;
  /* A pin at 0 centres its label on the axis start, so the axis is inset far enough for the
     shortest label to sit under it without being clipped. */
  padding: 0 30px;
  margin: 0 -30px;
}
.axis {
  position: relative;
  /* Tall enough for four rows that must never overlap: the upper lane, the pins, the lower lane's
     labels, and the threshold numbers under them. A bump scoring 62 sits a whisker from the 61
     mark, so sharing a row with it is a collision waiting for real data. */
  height: 116px;
}
.axis .track {
  position: absolute;
  left: 0;
  right: 0;
  top: 44px;
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(
    90deg,
    var(--r0),
    var(--r1) 30%,
    var(--r2) 48%,
    var(--r3) 64%,
    var(--r4)
  );
  opacity: 0.22;
}
.thr {
  position: absolute;
  top: 34px;
  height: 26px;
  width: 1px;
  background: var(--ink-3);
}
.thr span {
  position: absolute;
  top: 48px;
  left: 0;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  white-space: nowrap;
}
.pin {
  position: absolute;
  transform: translateX(-50%);
  text-align: center;
}
.pin i {
  display: block;
  width: 11px;
  height: 20px;
  border-radius: 3px;
  margin: 0 auto;
}
.pin b {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  color: var(--ink-2);
  margin-top: 5px;
  white-space: nowrap;
}
.lane-a {
  top: 36px;
}
.lane-b {
  top: 0;
}

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

.list {
  margin: 22px 34px 52px;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
}
.lh,
.r {
  display: grid;
  grid-template-columns: 156px 168px 1fr 250px;
  gap: 20px;
  align-items: center;
  padding: 11px 30px;
}
/* Package names, version strings and file paths cannot be hyphenated, and a grid column sized to
   min-content would rather push the page sideways than wrap one. min-width lets the column narrow;
   break-word rather than anywhere so a path moves to its own line before it is ever cut in half,
   which is the difference between src/routes/files.ts:18 and src/routes/files.ts:1 8. */
.lh > *,
.r > *,
.reg > *,
.rub > * {
  min-width: 0;
  overflow-wrap: break-word;
}
.lh {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  font-weight: 700;
  border-bottom: 1px solid var(--rule);
}
.r {
  border-bottom: 1px solid var(--rule-2);
  text-decoration: none;
  color: inherit;
  transition: background 120ms cubic-bezier(0.2, 0, 0, 1);
}
.r:last-child {
  border-bottom: none;
}
.r:hover {
  background: var(--panel-2);
}
.nm {
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.01em;
}
.mv {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
}
.mv b {
  color: var(--ink-2);
  font-weight: 500;
}
.wy {
  font-size: 14px;
  color: var(--ink-2);
}

/* the same measurement as the spread, one row at a time */
.g {
  display: flex;
  align-items: center;
  gap: 11px;
}
.g .n {
  font-family: var(--mono);
  font-size: 16px;
  width: 26px;
  text-align: right;
}
.g .t {
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: var(--rule);
  position: relative;
}
.g .t i {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: 3px;
}
.g .t u {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 1px;
  background: var(--tick);
}
.g .w {
  font-size: 12px;
  font-weight: 700;
  width: 52px;
}

/* ---------- panels ---------- */

.foot {
  margin: 0 34px 64px;
  display: grid;
  /* The arithmetic column carries sixteen factor rows, each a label, a number and a bar. Pinned at
     330px every long evidence string wrapped to five lines while the wide screen it was on had room
     to spare, so the column takes a share of a large viewport and keeps 330px as its floor. */
  grid-template-columns: minmax(0, 1fr) minmax(330px, 0.42fr);
  gap: 26px;
  align-items: start;
}
.wrap {
  margin: 26px 34px 64px;
}
.card {
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 24px 28px;
}
.kick {
  font-size: 10.5px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--ink-3);
  margin: 0 0 10px;
}
.card h3 {
  font-family: var(--display);
  font-size: 24px;
  letter-spacing: -0.03em;
  margin: 0 0 10px;
  font-weight: 700;
}
.card p {
  margin: 0 0 14px;
  color: var(--ink-2);
  font-size: 14.5px;
}
.card p:last-child {
  margin-bottom: 0;
}
.claim {
  border-left: 2px solid var(--rule);
  padding: 2px 0 2px 16px;
  margin: 14px 0;
}
.claim .c1 {
  color: var(--ink);
  font-size: 14.5px;
  margin: 0 0 4px;
}
.claim .c2 {
  font-size: 13.5px;
  color: var(--ink-3);
  margin: 0;
}
code {
  font-family: var(--mono);
  font-size: 12.5px;
  background: var(--bg);
  padding: 1px 5px;
  border-radius: 3px;
}
a.src,
a.plain {
  color: var(--ink);
  text-underline-offset: 2px;
}

/* the arithmetic, shown so a reader can add it up */
.fall .f {
  display: grid;
  grid-template-columns: 1fr 34px 96px;
  gap: 12px;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px solid var(--rule-2);
  font-size: 13.5px;
}
/* A grid column defaults to min-content, so one long url in a cell pushes the points and the bar
   off the card entirely. These two lines are what stop any evidence string from breaking the row. */
.fall .f span {
  color: var(--ink-2);
  min-width: 0;
  overflow-wrap: break-word;
}
.fall .f b {
  font-family: var(--mono);
  font-weight: 500;
  text-align: right;
  font-size: 13px;
}
.fall .f i {
  display: block;
  height: 7px;
  border-radius: 3px;
}
/* The bump is what a reader scans this list for, so it leads the line and the reason follows it. */
.fall .f .lead {
  color: var(--ink);
  font-weight: 600;
}
.fall .z span,
.fall .z b {
  color: var(--ink-3);
}
.fall .z .lead {
  color: var(--ink-2);
}
/* A repository with nothing pending has no worst reading to place, and a zero drawn on the ramp
   would read as a score rather than as the absence of one. */
.g.idle {
  font-size: 12px;
  color: var(--ink-3);
  justify-content: flex-end;
}
.total {
  display: flex;
  justify-content: space-between;
  padding-top: 12px;
  margin-top: 8px;
  border-top: 2px solid var(--ink);
  font-family: var(--display);
  font-weight: 700;
  font-size: 19px;
}

/* ---------- audit register ---------- */

.reg {
  display: grid;
  grid-template-columns: 172px 190px 1fr 132px;
  gap: 20px;
  align-items: baseline;
  padding: 12px 30px;
  border-bottom: 1px solid var(--rule-2);
  font-size: 14px;
}
.reg:last-child {
  border-bottom: none;
}
.reg .t {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
}
.reg .who {
  color: var(--ink-2);
}
.chip {
  font-family: var(--mono);
  font-size: 11px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 2px 7px;
  color: var(--ink-2);
  white-space: nowrap;
}

/* ---------- rubric ---------- */

.rub {
  display: grid;
  grid-template-columns: 1fr 190px 66px;
  gap: 20px;
  align-items: baseline;
  padding: 11px 30px;
  border-bottom: 1px solid var(--rule-2);
  font-size: 14px;
}
.rub:last-child {
  border-bottom: none;
}
.rub .s {
  font-size: 13px;
  color: var(--ink-3);
}
.rub .p {
  font-family: var(--mono);
  text-align: right;
  font-size: 14px;
}
.rub .p.zero {
  color: var(--ink-3);
}

.bands {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-top: 22px;
}
.bandcard {
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 18px 20px;
  background: var(--panel);
}
.bandcard .rng {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
}
.bandcard h2 {
  font-family: var(--display);
  font-size: 19px;
  margin: 6px 0 8px;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.bandcard p {
  margin: 0;
  font-size: 13.5px;
  color: var(--ink-2);
}
.bandcard .rule-id {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  margin-top: 10px;
  display: block;
}

/* ---------- architecture schematic ---------- */

.schematic {
  width: 100%;
  height: auto;
  margin-top: 6px;
}
.schematic text {
  font-family: var(--sans);
  fill: var(--ink);
}
.schematic .cap {
  font-size: 12px;
  font-weight: 600;
}
.schematic .sub {
  font-size: 10.5px;
  fill: var(--ink-3);
  font-family: var(--mono);
}
.schematic .box {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 1.5;
  rx: 6;
}
.schematic .line {
  stroke: var(--ink-2);
  stroke-width: 1.5;
  fill: none;
}
.schematic .zone {
  fill: none;
  stroke: var(--rule);
  stroke-width: 1.5;
  stroke-dasharray: 6 5;
  rx: 10;
}
/* The one coloured mark in the diagram, because it IS a risk statement: the model branch ends. */
.schematic .stopmark {
  stroke: var(--r4);
  stroke-width: 3.5;
}

.spinup {
  font-family: var(--mono);
  font-size: 12.5px;
  background: var(--panel-2);
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 16px 18px;
  overflow-x: auto;
  color: var(--ink-2);
  line-height: 1.9;
}
.spinup b {
  color: var(--ink);
  font-weight: 600;
}

.two {
  display: grid;
  grid-template-columns: 1fr 340px;
  gap: 26px;
  align-items: start;
}

/* Same automatic-minimum-size trap as the dense rows: without this a panel refuses to go narrower
   than its longest unbreakable string, and the whole page scrolls sideways instead. */
.foot > *,
.two > *,
.bands > * {
  min-width: 0;
}

/* ---------- keyboard and assistive ---------- */

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

.skip {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 10;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 8px;
  padding: 9px 16px;
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
  transition: top 120ms cubic-bezier(0.2, 0, 0, 1);
}
.skip:focus {
  top: 12px;
}

:where(a, button, summary):focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ---------- rows that carry a second link ---------- */

/* The row leads to the bump, and the action inside it leads to GitHub. Nesting one anchor in
   another is invalid, so the row's own link covers the row from underneath and the action link
   sits above it. Both are reachable by keyboard, in reading order. */
.r {
  position: relative;
}
.stretch {
  color: inherit;
  text-decoration: none;
}
.stretch::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.stretch:focus-visible {
  outline: none;
}
.stretch:focus-visible::after {
  outline: 2px solid var(--ink);
  outline-offset: -2px;
}
.out {
  position: relative;
  z-index: 1;
  color: var(--ink-2);
  font-size: 13px;
  text-underline-offset: 2px;
}
.out:hover {
  color: var(--ink);
}
.none {
  color: var(--ink-3);
  font-size: 13px;
}

/* ---------- verdict filter ---------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 22px;
  align-items: baseline;
  margin: 22px 34px -6px;
  font-size: 14px;
}
.filters a {
  color: var(--ink-2);
  text-decoration: none;
  padding-bottom: 3px;
  border-bottom: 2px solid transparent;
  transition: color 120ms cubic-bezier(0.2, 0, 0, 1);
}
.filters a:hover {
  color: var(--ink);
}
.filters a[aria-current] {
  color: var(--ink);
  font-weight: 700;
  border-bottom-color: var(--ink);
}
.filters a b {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12.5px;
  color: var(--ink-3);
  margin-left: 5px;
}
.filters a[aria-current] b {
  color: var(--ink-2);
}

/* ---------- run control ---------- */

.run {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin-top: 20px;
}
.btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}
.run .status {
  font-size: 13.5px;
  color: var(--ink-2);
  max-width: 52ch;
}
.run .status b {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12.5px;
  color: var(--ink-3);
}

/* ---------- empty, error and missing-source states ---------- */

.state {
  margin: 26px 34px 64px;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 34px 30px;
  max-width: 68ch;
}
.state h1,
.state h2 {
  font-family: var(--display);
  font-size: 24px;
  letter-spacing: -0.03em;
  font-weight: 700;
  margin: 0 0 10px;
}
.state p {
  margin: 0 0 12px;
  color: var(--ink-2);
  font-size: 14.5px;
}
.state p:last-child {
  margin-bottom: 0;
}

.missing {
  margin: 0;
  font-size: 13.5px;
}
.missing div {
  padding: 7px 0;
  border-bottom: 1px solid var(--rule-2);
  color: var(--ink-2);
}
.missing div:last-child {
  border-bottom: none;
}
.missing b {
  color: var(--ink);
  font-weight: 600;
}

/* ---------- key/value facts ---------- */

.facts {
  margin: 0;
  display: grid;
  grid-template-columns: 132px 1fr;
  gap: 7px 16px;
  font-size: 13.5px;
}
.facts dt {
  color: var(--ink-3);
}
.facts dd {
  margin: 0;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}

.flag {
  font-size: 12px;
  color: var(--ink-3);
}

/* ---------- lists inside a reading card ---------- */

.steps {
  margin: 12px 0 14px;
  padding-left: 20px;
  color: var(--ink-2);
  font-size: 14.5px;
}
.steps li {
  margin-bottom: 6px;
}
.steps li::marker {
  color: var(--ink-3);
}

/* ---------- responsive ---------- */

@media (max-width: 900px) {
  /* The run metadata repeats on the Rubric page, so it goes rather than forcing a scrolling bar. */
  .bar {
    flex-wrap: wrap;
    gap: 14px 18px;
    padding: 12px 16px;
  }
  .bar .right {
    display: none;
  }
  .bar nav {
    gap: 16px;
  }

  .band,
  .spread,
  .list,
  .foot,
  .wrap,
  .filters,
  .state {
    margin-left: 16px;
    margin-right: 16px;
  }
  .band {
    padding: 28px 16px 20px;
  }
  .spread {
    padding: 18px 16px 10px;
  }
  .foot,
  .two,
  .bands {
    grid-template-columns: 1fr;
  }
  .lh {
    display: none;
  }

  /* The axis keeps its meaning at any width, so it scrolls sideways inside its own panel rather
     than being squashed until the labels collide. 620px was not enough room: a full queue puts ten
     package names on one axis, and two of them landed on top of each other. */
  .axis {
    min-width: 900px;
  }

  .r {
    grid-template-columns: 1fr auto;
    grid-template-areas: 'nm sc' 'mv sc' 'wy wy';
    row-gap: 4px;
    padding: 14px 16px;
  }
  .nm {
    grid-area: nm;
  }
  .mv {
    grid-area: mv;
  }
  .wy {
    grid-area: wy;
  }
  .g {
    grid-area: sc;
    flex-direction: column;
    align-items: flex-end;
    gap: 5px;
  }
  .g .t {
    width: 96px;
    flex: none;
  }
  .g .n,
  .g .w {
    width: auto;
  }

  .reg,
  .rub {
    grid-template-columns: 1fr;
    gap: 4px;
    padding: 14px 16px;
  }
  .rub .p {
    text-align: left;
  }
  .card {
    padding: 20px 18px;
  }

  /* File paths and symbol names cannot be shortened, so they wrap rather than push the page. */
  code {
    overflow-wrap: anywhere;
  }
  .fall .f {
    grid-template-columns: 1fr 30px 56px;
    gap: 8px;
  }

  .facts {
    grid-template-columns: 1fr;
    gap: 2px;
  }
  .facts dd {
    margin-bottom: 8px;
  }
  .state {
    padding: 26px 18px;
  }
}

/* ---------- motion ---------- */

/* A measurement arriving is worth seeing once. Marks are drawn from nothing to their value on
   first paint and never again, and nothing on any page animates because it scrolled into view.
   Transform rather than width, so the value a reader can measure is never mid-animation in the
   layout, only in the paint. */
@keyframes bw-draw {
  from {
    transform: scaleX(0);
  }
}
@keyframes bw-plant {
  from {
    transform: scaleY(0);
    opacity: 0;
  }
}

.g .t i,
.fall .f i {
  transform-origin: left center;
  animation: bw-draw 420ms cubic-bezier(0.2, 0, 0, 1) both;
}
.pin i {
  transform-origin: center bottom;
  animation: bw-plant 420ms cubic-bezier(0.2, 0, 0, 1) both;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    /* Without this a staggered mark would still wait its turn before appearing, which is the
       delay the reader asked not to have. */
    animation-delay: 0ms !important;
  }
}
