/* Breakpoints. A custom property cannot go in a media query, so these are written out where they are used, and a test
   fails on a width that is not on this list. Phone is below 768, tablet is 768 to 1023, desktop is from 1024.
   767   phone: the masthead's theme switch shares the title's row; ledger rows stack; the footer's columns pair up;
         folds, portraits, About's frames and case cards take their compact look; tabs tighten; the Handed over
         card's foot goes by with the rest of it; the island's hour chart says its figures and its key in fewer words
   768   tablet: the masthead puts the switch in its own column; paired boxes go side by side; ledger rows and the
         footer go to a row; day charts go three across; the island's hour chart is taller
   1024  desktop: the island panels sit in two columns and the just-landed tiles go nine across (below it they are a sideways-scrolling row of 124px tiles); the footer brand sits
         beside its columns; the masthead shows the site note beside the title (below it every page, the island
         included, keeps the note in the "i" hint); the Handed over card widens and sets its two ledgers side by side
   The island canvas is sized by its own frame (container queries at 611px and 844px of frame width, from the
   script's geometry). Sized by their own content, with no named width: the species cards (150px), the guest list, the case members, the
   reader chips, the fluid wordmark, title, chart height and portrait clamps, the leaderboard's filter row, and the
   key under the Passport Control strip (columns of 15rem). */
/* Fonts are self-hosted (SIL OFL), latin subset: Instrument Serif, Instrument Sans, JetBrains Mono. */
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/instrument-serif-latin-400-normal.5eb09b5ac0.woff2) format("woff2");
}
@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/instrument-serif-latin-400-italic.5a51946dff.woff2) format("woff2");
}
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(fonts/instrument-sans-latin-wght-normal.2ee17598a9.woff2) format("woff2");
}
@font-face {
  font-family: "Instrument Sans";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url(fonts/instrument-sans-latin-wght-italic.77210cdde0.woff2) format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url(fonts/jetbrains-mono-latin-wght-normal.18be452724.woff2) format("woff2");
}
@font-face {
  font-family: "Instrument Serif Fallback";
  src: local("Georgia"), local("Iowan Old Style"), local("Palatino Linotype");
  size-adjust: 76.4%;
}

/* Each colour that changes with the theme is written once, light value then dark value, as
   `var(--if-light, LIGHT) var(--if-dark, DARK)`. In the light theme --if-dark is an empty value (so its half drops
   out) and --if-light is unset (so its fallback shows); the dark theme, forced or from the system, swaps the two.
   That is all the two dark blocks below say. light-dark() would do it in one function, but it needs Chrome 123, Safari
   17.5 or Firefox 120, and this stylesheet already works back to Chrome 111 and Safari 16.2. */
:root {
  --if-dark: ;
  --paper: var(--if-light, #ffffff) var(--if-dark, #0b0f19);
  --ink: var(--if-light, #111827) var(--if-dark, #f3f4f6);
  --panel: var(--if-light, #f1f3f6) var(--if-dark, #161c2a);
  --muted: var(--if-light, #5b6472) var(--if-dark, #9aa4b5);
  --alert: var(--if-light, #c81e4a) var(--if-dark, #ff7d96);
  --ok: var(--if-light, #0f766e) var(--if-dark, #5fd3c4);
  --soft: var(--if-light, rgba(17, 24, 39, 0.16)) var(--if-dark, rgba(243, 244, 246, 0.18));
  --water: var(--if-light, #86c5d0) var(--if-dark, #16233f);
  --shadow: rgba(20, 24, 20, 0.22);
  --card-paper: #f3f4f6;
  --card-soft: #c5cad3;
  --display: "Instrument Serif", "Instrument Serif Fallback", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia,
    serif;
  --body: "Instrument Sans", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --data: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Courier New", monospace;
  box-sizing: border-box;
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --if-light: ;
    --if-dark: initial;
  }
}
:root[data-theme="dark"] {
  --if-light: ;
  --if-dark: initial;
}
/* Sizes, layers and timings already in use, named by their value. Only values that repeat on a scale are here: the
   odd ones (13.5px and 14.5px type, 7px and 18px spacing and the like) stay literal until they are folded onto it. */
:root {
  --space-2: 2px;
  --space-4: 4px;
  --space-6: 6px;
  --space-8: 8px;
  --space-10: 10px;
  --space-12: 12px;
  --space-14: 14px;
  --space-16: 16px;
  --space-20: 20px;
  --space-24: 24px;
  --space-32: 32px;
  --space-40: 40px;
  --space-48: 48px;
  --space-64: 64px;
  --text-10: 10px;
  --text-11: 11px;
  --text-12: 12px;
  --text-13: 13px;
  --text-14: 14px;
  --text-15: 15px;
  --text-16: 16px;
  --text-17: 17px;
  --text-18: 18px;
  --text-19: 19px;
  --text-20: 20px;
  --text-22: 22px;
  --text-24: 24px;
  --text-26: 26px;
  --text-28: 28px;
  --text-30: 30px;
  --text-32: 32px;
  --text-34: 34px;
  --z-2: 2;
  --z-5: 5;
  --z-10: 10;
  --z-20: 20;
  --z-50: 50;
  --z-100: 100;
  --z-200: 200;
  --dur-120: 120ms;
  --dur-150: 0.15s;
  --dur-180: 0.18s;
  --dur-400: 0.4s;
  --dur-800: 0.8s;
  /* Names by role, for the layout notes: each is defined on a number from the scale above, so changing one moves every
     place that plays the role. Spacing first: under the tabs, the title, a section, a subsection, a lead, a heading, a label,
     a block, columns, and a pair of boxes. */
  --gap-under-tabs: var(--space-14);
  --title-gap: var(--space-10);
  --title-icon-gap: var(--space-8);
  --gap-section: var(--space-32);
  --gap-subsection: var(--space-20);
  --gap-lead: var(--space-20);
  --gap-heading: var(--space-10);
  --gap-label: var(--space-8);
  --gap-block: var(--space-10);
  --gap-columns: var(--space-40);
  --gap-pair: var(--space-24);
  /* Boxes: the border every box and control wears (full, thin and dashed), the rule between rows, the padding inside a card, the gap between
     cards, the padding of a row, the padding of a table cell, and the least height of anything you can press. */
  --line: 2px solid var(--ink);
  --line-soft: 1px solid var(--soft);
  --line-thin: 1px solid var(--ink);
  --line-dashed: 2px dashed var(--ink);
  --card-pad: var(--space-12) var(--space-14);
  --card-gap: var(--space-12);
  --row-pad: var(--space-10) var(--space-14);
  --cell-pad: var(--space-6) var(--space-10);
  --tap: 44px;
  --hud-button: 36px;
  /* Portraits are 22 by 16 frame pixels. These are the widths inside the 2px border, so each frame pixel is a whole
     number of CSS pixels: 2, 3 and 4 to a pixel (48, 70 and 92px outside), 5 for a feature (114px outside), 8 for the
     species page (180px outside), and 1 for a dot in the Alignment chart on a phone (26px outside). */
  --mug-xs: 22px;
  --mug-s: 44px;
  --mug-m: 66px;
  --mug-l: 88px;
  --mug-xl: 110px;
  --mug-xxl: 176px;
  /* Type by role. Each is defined on a size from the scale above: titles, card titles, body, compact and small text, captions, labels, caps, data and figures (and the figure row). */
  --text-title: clamp(32px, 8vw, 38px);
  --text-heading: var(--text-28);
  --text-subheading: var(--text-24);
  --text-card-title: var(--text-22);
  --text-body: var(--text-16);
  --text-small: var(--text-14);
  --text-compact: var(--text-15);
  --text-caption: var(--text-13);
  --text-label: var(--text-12);
  --text-caps: var(--text-11);
  --text-data: var(--text-13);
  --text-figure-row: var(--text-28);
  --text-wordmark: 76px;
  --text-wordmark-small: clamp(30px, 11.5vw, 60px);
  --text-tagline: clamp(16px, 4.9vw, 26px);
  /* The page frame and how wide running text goes. The masthead, tab row and footer are the page width less a gutter
     each side. */
  --page-width: 1204px;
  --page-gutter: var(--space-16);
  --measure: 34em;
}
@media (min-width: 768px) {
  :root {
    --page-gutter: var(--space-24);
  }
}
html {
  scroll-padding-top: calc(env(safe-area-inset-top, 0px) + 56px);
  scrollbar-gutter: stable;
}
html:has(body.full) {
  scrollbar-gutter: auto;
}
*,
*::before,
*::after {
  box-sizing: border-box;
}
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 var(--text-body) / 1.45 var(--body);
}
body.full {
  overflow: hidden;
}
/* The frame every page shares: the masthead, the tab row, the page and the footer sit in one 1180px column. */
header.mast,
.navbar .tabs {
  width: min(calc(var(--page-width) - 2 * var(--page-gutter)), calc(100% - 2 * var(--page-gutter)));
  margin-left: auto;
  margin-right: auto;
}
body > main {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 0 var(--page-gutter) var(--space-24);
}

/* The masthead scrolls away. Only the tab row under it sticks. */
.mast {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-4) var(--space-12);
  margin-top: var(--space-16);
  margin-bottom: var(--space-6);
  padding-bottom: var(--space-10);
  border-bottom: var(--line);
}
.mast .title {
  grid-area: title;
}
/* The theme switch is its picture alone, the sun, the moon or the two together: no box round it. It is still 40px
   square to a finger, and the keyboard's ring (button:focus-visible) is drawn round that square. */
.mast .theme-toggle {
  grid-area: theme;
  justify-self: end;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
}
.theme-toggle .theme-icon {
  display: none;
  grid-area: 1 / 1;
}
:root[data-theme-choice="light"] .theme-icon[data-icon="light"],
:root[data-theme-choice="dark"] .theme-icon[data-icon="dark"],
:root:not([data-theme-choice="light"]):not([data-theme-choice="dark"]) .theme-icon[data-icon="system"] {
  display: block;
}
@media (min-width: 768px) {
  .mast {
    grid-template-areas: "title sim theme";
    align-items: start;
  }
  .mast .sim {
    align-self: start;
    white-space: nowrap;
  }
}
.mast .wordmark {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--text-wordmark);
  line-height: 0.95;
  letter-spacing: -0.01em;
}
.mast .wordmark a {
  color: var(--ink);
  text-decoration: none;
}
.mast .sub {
  margin: var(--space-6) 0 0;
  font-family: var(--display);
  font-style: italic;
  font-size: var(--text-tagline);
  line-height: 1.2;
  position: relative;
}
.mast .mast-note {
  display: none;
  color: var(--muted);
}
.mast .sim {
  grid-area: sim;
  justify-self: end;
  margin: 0;
  font-size: var(--text-caption);
  line-height: 1.35;
  color: var(--alert);
  font-weight: 600;
}
.mast .sim[hidden] {
  display: none;
}
/* Phone widths: the switch shares the title's row, right-aligned, and the wordmark shrinks to fit beside it. */
@media (max-width: 767px) {
  .mast {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "sim" "title";
    row-gap: 0;
  }
  .mast .sim {
    margin-bottom: var(--space-4);
  }
  .mast .theme-toggle {
    grid-area: title;
    align-self: start;
    position: relative;
    /* Above the title, which shares this cell and comes later in the page. */
    z-index: var(--z-2);
  }
  .mast .theme-toggle::after {
    content: "";
    position: absolute;
    inset: -2px;
  }
  .mast .wordmark {
    display: flex;
    align-items: center;
    min-height: 40px;
    padding-right: 52px;
    font-size: var(--text-wordmark-small);
  }
}
/* Full desktop width: the title, the site note as plain text, and the switch in one row. The note takes what the title
   and the switch leave, and the "i" hint is hidden (display: none) so the note is read out once. The simulated marker
   drops to a second row under the note and the switch, and only takes room when it is shown. */
@media (min-width: 1024px) {
  .mast {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "title note theme";
    column-gap: var(--gap-columns);
  }
  .mast .mast-note {
    display: block;
    grid-area: note;
    max-width: var(--measure);
    margin: var(--space-8) 0 0;
    font-size: var(--text-compact);
    font-weight: 400;
    line-height: 1.5;
    text-align: left;
  }
  .mast .sub .hint {
    display: none;
  }
  .mast .sim {
    grid-area: auto;
    grid-column: 2 / -1;
    grid-row: 2;
  }
}
.mast a:focus-visible,
.navbar a:focus-visible {
  outline: 3px solid var(--alert);
  outline-offset: 2px;
}

.navbar {
  position: sticky;
  top: env(safe-area-inset-top, 0px);
  z-index: var(--z-5);
  margin: 0 0 var(--gap-under-tabs);
  padding: var(--space-6) 0;
  background: var(--paper);
}
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
}
.tabs a {
  display: inline-flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding: 0 var(--space-4);
  border: var(--line);
  background: var(--paper);
  color: var(--ink);
  font-weight: 500;
  text-decoration: none;
}
.tabs a[aria-current="page"] {
  background: var(--ink);
  color: var(--paper);
}
@media (max-width: 767px) {
  .tabs {
    gap: var(--space-4);
  }
}

.stage {
  margin: 0;
}
.glass {
  container-type: inline-size;
  position: relative;
  overflow: hidden;
  border: var(--line);
  box-shadow: 4px 4px 0 var(--ink);
  background: var(--water);
  line-height: 0;
}
canvas {
  display: block;
  width: 100%;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
#island {
  /* The height the script sets, so the canvas has it at first paint: 336 under 611 island pixels, 355 from there, and
     twice both from 844px of frame, where the script draws two device pixels to each island pixel. In a window too short
     for that the frame is as tall as the window allows, down to 336px, and the script crops the scene from the top.
     The 150px is the tab row, the gap and the ticker. */
  height: 336px;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
  outline: none;
}
#island:focus-visible {
  outline: 3px solid var(--alert);
  outline-offset: -5px;
}
@container (min-width: 611px) {
  #island {
    height: 355px;
  }
}
@container (min-width: 844px) {
  #island {
    height: clamp(336px, 100dvh - 150px, 672px);
  }
}

/* Controls and windows that float over the island. */
.hud {
  position: absolute;
  top: 8px;
  display: flex;
  gap: var(--space-8);
  flex-wrap: wrap;
  line-height: 1.4;
}
.hud-tools {
  left: 8px;
}
.hud-feed {
  right: 8px;
  justify-content: flex-end;
}
.hud button {
  height: var(--hud-button);
  min-height: var(--hud-button);
}
.hud button.sq {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--hud-button);
  min-width: var(--hud-button);
  padding: 0;
}
.hud button.sq svg {
  display: block;
}
.hud button:disabled {
  opacity: 0.45;
  cursor: default;
}
.hud button,
.card,
.feed {
  box-shadow: 3px 3px 0 var(--ink);
}
@media (max-width: 767px) {
  .glass.has-card .hud-tools,
  .glass.has-card .hud-feed {
    display: none;
  }
}
/* The locator: a picture of the whole scene in the island's corner, with a box for the part in view. The script puts
   it over the canvas when the island has isles, so nothing moves to make room for it. Tapping it opens the map. Its
   picture is 64px by 38px inside the line. */
.locator {
  position: absolute;
  right: 8px;
  bottom: 8px;
  width: 68px;
  height: 42px;
  min-height: 0;
  padding: 0;
  line-height: 0;
  box-shadow: 3px 3px 0 var(--ink);
}
.locator canvas {
  height: 100%;
}
.locator:disabled {
  opacity: 0.45;
  cursor: default;
}
@media (max-width: 767px) {
  .glass.has-card .locator {
    display: none;
  }
}
.badge {
  display: inline-block;
  min-width: 24px;
  margin-left: var(--space-6);
  padding: 0 5px;
  background: var(--alert);
  color: var(--paper);
  text-align: center;
  font-family: var(--data);
  font-size: var(--text-data);
  font-weight: 600;
}
.badge[hidden] {
  display: none;
}
.feed {
  position: absolute;
  top: 54px;
  right: 8px;
  width: min(350px, calc(100% - 16px));
  max-height: calc(100% - 62px);
  overflow: auto;
  line-height: 1.4;
  background: var(--panel);
  border: var(--line);
  padding: var(--space-10) var(--space-12);
}
.feed[hidden],
.card[hidden] {
  display: none;
}
.feed:focus-visible,
.card:focus-visible {
  outline: 3px solid var(--alert);
  outline-offset: -5px;
}
.feed .head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-12);
  margin-bottom: var(--space-8);
}
.feed h2 {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--text-heading);
  line-height: 1.1;
}
.feed ol {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: var(--line);
}
.feed li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 0 var(--space-10);
  align-items: start;
  padding: var(--space-6) 0;
  border-bottom: var(--line-soft);
}
.feed time {
  font-family: var(--data);
  font-size: var(--text-13);
  line-height: 1.7;
  color: var(--muted);
}
.feed .who {
  overflow-wrap: anywhere;
  font-weight: 600;
}
.feed .req {
  display: block;
  color: var(--muted);
  font-family: var(--data);
  font-size: var(--text-13);
  font-weight: 400;
}
.tag {
  border: 1px solid currentColor;
  padding: 1px var(--space-6);
  font-family: var(--data);
  font-size: var(--text-label);
  font-weight: 600;
  line-height: 1.5;
  text-transform: uppercase;
  white-space: nowrap;
}
.tag.bad {
  color: var(--alert);
}
.tag.good {
  color: var(--ok);
}

/* Expanded: the island takes the whole window. */
body.full .stage {
  position: fixed;
  inset: 0;
  z-index: var(--z-20);
  display: flex;
  flex-direction: column;
  margin: 0;
  background: var(--paper);
  padding: calc(var(--space-8) + env(safe-area-inset-top, 0px)) var(--space-8)
    calc(var(--space-8) + env(safe-area-inset-bottom, 0px));
}
body.full .glass {
  flex: 1;
  min-height: 0;
  box-shadow: none;
}
body.full #island {
  height: 100%;
  aspect-ratio: auto;
}
body.full .ticker {
  margin-top: var(--space-8);
}

/* Night watch: the island and nothing else. The one control left is the contract button, which shows on touch or
   movement and goes after a few seconds. It is not clickable while hidden, so a tap there reaches the island. */
.hud button[hidden] {
  display: none;
}
body.watch .stage {
  padding: 0;
}
body.watch .glass {
  border: 0;
}
body.watch .ticker,
body.watch #bell,
body.watch #watch,
body.watch .locator {
  display: none;
}
body.watch .hud-tools:not(.awake):not(:focus-within) {
  opacity: 0;
  pointer-events: none;
}
body.watch .hud-tools {
  transition: opacity var(--dur-400);
}
@media (prefers-reduced-motion: reduce) {
  body.watch .hud-tools {
    transition: none;
  }
}

.ticker {
  display: flex;
  align-items: center;
  gap: var(--space-10);
  margin-top: var(--space-14);
  background: var(--ink);
  color: var(--paper);
  padding: var(--space-4) var(--space-4) var(--space-4) var(--space-12);
  min-height: 52px;
}
.ticker p {
  margin: 0;
  flex: 1;
  min-width: 0;
  /* One line: a long line is cut with an ellipsis and never makes the bar taller. */
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* On a phone the line has room for 14 to 27 characters of one line, so it takes two. The two lines are held whether or
   not the second is used, so the bar does not change height as the sentence does. */
@media (max-width: 767px) {
  .ticker p {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    min-height: 2.9em;
    white-space: normal;
  }
}
button {
  font-family: var(--body);
  font-size: var(--text-body);
  font-weight: 500;
  color: var(--ink);
  background: var(--paper);
  border: var(--line);
  min-height: var(--tap);
  padding: 0 var(--space-14);
  cursor: pointer;
}
.ticker button {
  border-color: var(--paper);
}
button:focus-visible {
  outline: 3px solid var(--alert);
  outline-offset: 2px;
}

/* Sections below the island. */
.home {
  display: grid;
  gap: var(--gap-section) var(--space-16);
  grid-template-columns: minmax(0, 1fr);
  margin-top: var(--gap-section);
}
@media (min-width: 1024px) {
  /* Two equal columns that end level: the hour chart at the left, Today at the port at the right, and the specimen
     band across the full width under them. */
  .home {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "hours port" "day day" "landed landed";
    column-gap: var(--gap-columns);
  }
  .home > section {
    min-width: 0;
  }
  .port {
    grid-area: port;
  }
  .hoursbox {
    grid-area: hours;
  }
  .daybox {
    grid-area: day;
  }
  .landedbox {
    grid-area: landed;
  }
  .hoursbox,
  .hoursbox .chart {
    display: flex;
    flex-direction: column;
  }
  .hoursbox .chart,
  .hoursbox .hplot {
    flex: 1;
  }
  /* The plot takes what the port block beside it is taller by, between 180 and 320px, so the two columns end level. */
  .hoursbox .hplot {
    height: auto;
    min-height: 180px;
    max-height: 320px;
  }
}
/* One section heading for the island page: the display serif, as before the panels were redrawn. */
.home h2 {
  font-size: var(--text-heading);
  line-height: 1.1;
}
.fine {
  max-width: var(--measure);
  margin: var(--space-6) 0 var(--gap-block);
  color: var(--muted);
  font-size: var(--text-small);
}
/* A heading with something at its right: the heading, then a link or a figure, on one baseline. */
.headrow {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4) var(--space-12);
  margin: var(--gap-section) 0 var(--gap-heading);
}
.headrow h2 {
  margin: 0;
}
.home .headrow {
  margin-top: 0;
}
main :is(h2, .headrow):has(+ .fine) {
  margin-bottom: var(--space-4);
}
main :is(h2, .headrow) + .fine {
  margin: 0 0 var(--space-12);
  font-size: var(--text-compact);
}
.aside {
  font-family: var(--data);
  font-size: var(--text-label);
  color: var(--muted);
}
/* The read-out above a chart: the bar it reads, and its figures. Today, or the busiest hour, is the red one. */
.readout {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  height: 20px;
  max-width: none;
  margin: var(--space-4) 0 var(--space-6);
  overflow: hidden;
  font-family: var(--data);
  font-size: var(--text-data);
  white-space: nowrap;
}
.readout .sw {
  flex: none;
  width: 10px;
  height: 10px;
  background: var(--muted);
  opacity: 0.4;
}
.readout .sw.now {
  background: var(--alert);
  opacity: 1;
}
.readout .at {
  color: var(--muted);
}
.readout .what {
  font-weight: 600;
}
.headrow .readout {
  margin: 0;
}
/* The hour chart's read-out stands under its axis, left with the plot, in a line of its own that is there empty. */
.hoursbox .readout {
  flex: none;
  margin: var(--space-4) 0 0 var(--space-32);
}
/* One row at every width: nine equal tiles across on desktop; narrower, the row scrolls sideways. */
.landed {
  list-style: none;
  margin: 0;
  padding: 0 0 var(--space-6);
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 124px;
  gap: var(--card-gap);
  overflow-x: auto;
}
@media (min-width: 1024px) {
  .landed {
    grid-auto-columns: calc((100% - 8 * var(--card-gap)) / 9);
  }
}
.landed li {
  container-type: inline-size;
  border: var(--line);
  background: var(--panel);
}
.landed li.support {
  border-style: dashed;
}
.landed li.support a {
  display: flex;
  flex-direction: column;
  height: 100%;
  color: inherit;
  text-decoration: none;
}
.landed li.support .mug {
  border-bottom-style: dashed;
}
.landed button {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  width: 100%;
  height: 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  text-align: left;
  background: var(--panel);
}
.landed canvas {
  /* The drawing is a whole number of CSS pixels to a frame pixel, centred on its colour, which fills the tile. */
  box-sizing: content-box;
  width: var(--mug-l);
  aspect-ratio: 22 / 16;
  padding-inline: calc((100% - var(--mug-l)) / 2);
  border-bottom: var(--line);
}
@container (min-width: 110px) {
  .landed canvas {
    width: var(--mug-xl);
    padding-inline: calc((100% - var(--mug-xl)) / 2);
  }
  .landed .mug {
    --m: var(--mug-xl);
  }
}
/* The Little Server's tile, drawn by the server as two pictures: the same box, tint and whole-number scale as the canvases above. */
.landed .mug {
  --m: var(--mug-l);
  position: relative;
  display: block;
  box-sizing: content-box;
  height: calc(var(--m) * 16 / 22);
  overflow: hidden;
  border-bottom: var(--line);
}
.landed .mug img {
  position: absolute;
  left: calc((100% - var(--m)) / 2 + var(--m) * var(--x) / 100);
  bottom: calc(var(--m) * 16 / 22 * var(--y) / 100);
  width: calc(var(--m) * var(--w) / 100);
  height: auto;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
.landed .mug .alt,
.landed li.b .mug img:not(.alt) {
  opacity: 0;
}
.landed li.b .mug .alt {
  opacity: 1;
}
.landed .nm {
  display: block;
  padding: var(--space-6) var(--space-8) 0;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.landed .net {
  display: block;
  padding: 1px var(--space-8) 0;
  color: var(--muted);
  font-size: var(--text-caption);
  font-weight: 400;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The order line holds its one line at every width; a label too long for the tile ends in an ellipsis (its title has it whole). */
.landed .ord {
  display: block;
  padding: 1px var(--space-8) 0;
  color: var(--muted);
  font-size: var(--text-caption);
  font-weight: 400;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.landed time,
.landed li.support a::after {
  display: block;
  margin-top: auto;
  padding: var(--space-4) var(--space-8) var(--space-8);
  font-family: var(--data);
  font-size: var(--text-label);
  font-weight: 400;
  color: var(--muted);
}
.landed li.support a::after {
  content: "\00a0";
}

/* Specimen of the day: the species with the most landings so far today. */
.dayband {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-12) var(--gap-columns);
  padding: var(--space-12) 0;
  border-top: var(--line-soft);
  border-bottom: var(--line-soft);
}
@media (min-width: 1024px) {
  .dayband {
    grid-template-columns: minmax(0, 1fr) minmax(16rem, 24rem);
  }
}
/* The facts at the side of the band, right-aligned, and the courier link at the end of them. */
.dayside {
  min-width: 0;
}
.dayside .plainlines {
  margin-top: 0;
}
.dayside .aside {
  margin: var(--space-6) 0 0;
  text-align: right;
}
.day {
  display: grid;
  grid-template-columns: calc(var(--mug-xl) + 4px) minmax(0, 1fr);
  gap: var(--space-12);
  align-items: start;
  line-height: 1.45;
  /* Name, Latin name, order line, the joke on that many lines, the count line: the content only, the band has its own padding. */
  --day-lines: 2;
  min-height: calc(
    1.2 *
    var(--text-18) +
    1.15 *
    var(--text-22) +
    3 *
    var(--space-6) +
    (1 + var(--day-lines)) *
    1.45 *
    var(--text-compact) +
    1.45 *
    var(--text-13)
  );
}
@media (max-width: 767px) {
  .day {
    --day-lines: 4;
  }
  .headrow .readout {
    flex-basis: 100%;
  }
}
.day.empty::before {
  content: "";
  box-sizing: content-box;
  width: var(--mug-xl);
  aspect-ratio: 22 / 16;
  border: var(--line-dashed);
}
.day .none {
  margin: 0;
  color: var(--muted);
}
.day canvas {
  box-sizing: content-box;
  width: var(--mug-xl);
  aspect-ratio: 22 / 16;
  border: var(--line);
}
/* Yesterday's specimen, drawn by the server when nothing has landed today: the same portrait as the canvas the script draws. */
.day .mug {
  position: relative;
  display: block;
  box-sizing: content-box;
  width: var(--mug-xl);
  aspect-ratio: 22 / 16;
  overflow: hidden;
  border: var(--line);
  background: var(--panel);
}
.day .mug img {
  position: absolute;
  left: calc(var(--x) * 1%);
  bottom: calc(var(--y) * 1%);
  width: calc(var(--w) * 1%);
  height: auto;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
.day h3 {
  margin: 0;
  font-family: var(--body);
  font-size: var(--text-18);
  font-weight: 600;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.day .latin {
  margin: 0;
  font-family: var(--display);
  font-style: italic;
  font-size: var(--text-22);
  line-height: 1.15;
  overflow-wrap: anywhere;
}
.day p {
  margin: var(--space-6) 0 0;
  font-size: var(--text-compact);
}
.day .ord {
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.day .meta {
  font-family: var(--data);
  font-size: var(--text-data);
}
.more {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  min-height: var(--tap);
  color: var(--ink);
  font-weight: 500;
}
.headrow .more {
  margin: calc(-1 * var(--space-6)) 0;
}
.headrow .more[hidden] {
  visibility: hidden;
}

/* The card over the island: a place's panel, a creature's or a flock's card, the bouncer's and the figure creator.
   Under 768px it is a sheet across the foot of the island; from 768px a panel at its left, under the buttons.

     .band   what kind of thing it is, its name, Close        .body   the lede, then the sections (.sec)
     .figs   a ledger: a label, dots, and what it comes to     .faces  who is at a place now, in one row
     .late   the latest sightings, in five kept rows           .trail  a creature's route, in a kept box
     .marks  a creature's tags, each whole, in kept room       .foot   the actions, ruled off and always in sight

   Whatever arrives later has its room kept. A list holds its rows before they are filled, a row that can outgrow its
   room scrolls or cuts its text short, a section that says "Nobody yet today" keeps the rows its figures take, and a
   creature's tags have the room of the most it can carry. A tag is never cut short. */
.card {
  /* One row of a list, and the route's number at the size the island draws it. */
  --row: calc(var(--space-24) + var(--space-4));
  --badge: calc(var(--space-20) + var(--space-2));
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 8px;
  max-height: 64%;
  overflow: auto;
  /* What is scrolled to by the keyboard stops clear of the foot, which stays over the end of the card. */
  scroll-padding-bottom: calc(var(--tap) + var(--space-20));
  line-height: 1.35;
  border: var(--line);
  background: var(--panel);
}
@media (min-width: 768px) {
  /* Clear of the island's buttons, which stand 8px from the top of the frame: 8px above them and 8px under. */
  .card {
    right: auto;
    bottom: auto;
    top: calc(var(--hud-button) + 16px);
    width: 330px;
    max-height: calc(100% - var(--hud-button) - 24px);
  }
}
/* A link that sits among the card's buttons and looks like one. */
.btn {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 var(--space-14);
  border: var(--line);
  background: var(--paper);
  color: var(--ink);
  font-weight: 500;
  text-decoration: none;
}
.btn:focus-visible {
  outline: 3px solid var(--alert);
  outline-offset: 2px;
}
button.primary,
.btn.primary {
  padding: 0 var(--space-24);
  background: var(--ink);
  color: var(--paper);
  font-weight: 600;
}
button.primary:hover,
.btn.primary:hover {
  background: var(--paper);
  color: var(--ink);
}

/* The band, on the ink as the ticker is. Close and the portrait's border take the paper's colour there, and so does
   the ring round Close when the keyboard is on it, which the alert colour would not show against the ink. */
.card .band {
  display: flex;
  align-items: flex-start;
  gap: var(--space-10);
  padding: var(--space-8) var(--space-10);
  background: var(--ink);
  color: var(--paper);
}
.card .band button {
  flex: none;
}
.card .band .mug,
.card .band button {
  border-color: var(--paper);
}
.card .band button:focus-visible {
  outline-color: var(--paper);
}
.card .mug {
  box-sizing: content-box;
  flex: none;
  width: var(--mug-s);
  aspect-ratio: 22 / 16;
  border: var(--line);
}
.card .who {
  flex: 1;
  min-width: 0;
}
/* The small capitals: what kind of thing the card is about, and the name of each section. */
.card .kind,
.card h3 {
  margin: 0;
  font: 600 var(--text-caps) / 1.5 var(--data);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.card h3 {
  color: var(--muted);
}
.card h2 {
  margin: 0;
  font: 400 var(--text-card-title) / 1.1 var(--display);
  overflow-wrap: anywhere;
}
.card .latin {
  margin: var(--space-2) 0 0;
  font: italic var(--text-20) / 1.15 var(--display);
}
/* On a phone the name's column is what the portrait and Close leave: a hundred pixels in the narrowest sheet, where a
   Latin name set in it took two lines for nearly every species. So there the band is a grid. The portrait, the kind
   over the name, and Close stand as they do from 768px, and under them the Latin name has a row of its own, from
   under the name to the band's edge, under Close. Close is where it was and the size it was. What it stands taller
   than the kind and a one-line name goes under the name (the 1fr row), so the name stays close under the kind. */
@media (max-width: 767px) {
  .card .band {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: auto 1fr;
    gap: 0;
  }
  .card .who {
    display: contents;
  }
  .card .band .mug {
    grid-area: 1 / 1 / 3 / 2;
    margin-right: var(--space-10);
  }
  .card .kind {
    grid-area: 1 / 2;
  }
  .card h2 {
    grid-area: 2 / 2;
  }
  .card .band button {
    grid-area: 1 / 3 / 3 / 4;
    margin-left: var(--space-10);
  }
  .card .latin {
    grid-area: 3 / 2 / 4 / 4;
  }
}
.card .body {
  padding: var(--space-10) var(--space-10) var(--space-12);
}
.card .lede {
  margin: 0;
  font-size: var(--text-compact);
  line-height: 1.4;
}
/* More and Less, at the end of the lede: a word in the line, with room round it for a finger. */
.card .lede button {
  min-height: 0;
  margin: calc(-1 * var(--space-6)) 0;
  padding: var(--space-6) var(--space-4);
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}
/* What is known of a creature, as tags. Every one is whole: they go on to a second line and a third before one is cut
   short, and none ever is. Under them, unseen, is the room the most a creature can carry at once would take at this
   width (.room: an empty box for each kind of tag, as wide as the longest of its kind is long). The two lie in one
   place, so the tags are as tall with one of them as with four, and a hold or an invitation that arrives later moves
   nothing. A tag is set in one width of letter, so a box is so many letters wide, and its padding and its border. */
.card .marks {
  display: grid;
  /* As wide as the card's column and no wider, so the tags turn on to the next line at its edge. */
  grid-template-columns: minmax(0, 1fr);
  margin: var(--space-8) 0 0;
}
.card .marks p {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: var(--space-4) var(--space-6);
  grid-area: 1 / 1;
  margin: 0;
}
.card .marks .tag {
  flex: none;
}
.card .marks .room {
  visibility: hidden;
}
.card .marks .room .tag {
  width: calc(var(--n) * 1ch + var(--space-12) + 2px);
  height: calc(1.5em + 4px);
}
@media (max-width: 767px) {
  /* The sheet is short, so on a phone a creature's tags come before the line about its order: straight under its
     name, where they are in sight without scrolling. */
  .card .body:has(> .marks) {
    display: flex;
    flex-direction: column;
  }
  .card .marks {
    order: -1;
    margin: 0 0 var(--space-8);
  }
}
.card .sec {
  margin-top: var(--space-12);
}
.card .sec > h3 {
  margin-bottom: var(--space-4);
}
.card .none {
  color: var(--muted);
}

/* A ledger row: the label, dots to what it comes to, and that at the right edge. The dots are an empty box whose foot
   stands on the text's baseline. */
.card .figs {
  position: relative;
  margin: 0;
}
.card .figs div {
  display: flex;
  align-items: baseline;
  gap: var(--space-6);
  min-height: var(--row);
}
.card .figs div::before,
.card .late li::before,
.card .stop::before {
  content: "";
  flex: 1 1 var(--space-12);
  order: 1;
  min-width: var(--space-12);
  border-bottom: 2px dotted currentColor;
}
.card .figs dt {
  flex: 0 1 auto;
}
.card .figs dd {
  flex: 0 1 auto;
  order: 2;
  max-width: 60%;
  margin: 0;
  overflow-wrap: anywhere;
  text-align: right;
}
/* A figure has the room of six characters whatever it comes to, so a label beside it breaks in the same place at 3
   as at 99,999, and a row kept for a figure is the height the figure's row will be. */
.card .figs .n {
  min-width: 6ch;
  font-family: var(--data);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
/* A value that takes two lines once it has come keeps them before. The last request keeps three, the most it takes,
   so the next one moves nothing. */
.card .figs .two {
  min-height: 2.7em;
}
.card .figs .req {
  min-height: 4.05em;
  font-family: var(--data);
  font-size: var(--text-13);
}
/* A row kept for a figure that has not come: the room its label and its figure will take, and a line of dots where
   the text's baseline would be. The label gives up the room the dots and their gap take in a row that is filled, so
   that it breaks where it will then. */
.card .figs .blank {
  position: relative;
}
.card .figs .blank > * {
  visibility: hidden;
}
.card .figs .blank dt {
  margin-right: calc(var(--space-12) + var(--space-6));
}
.card .figs .blank::before {
  position: absolute;
  inset: 0 0 auto;
  height: 1.05em;
}
/* "Nobody yet today" lies over the first of the kept rows and takes no room of its own. Its dots are the ink's, as
   every row's are. */
.card .figs .none {
  position: absolute;
  inset: 0 0 auto;
  background: var(--panel);
}
.card .figs .none::before,
.card .late .none::before {
  border-color: var(--ink);
}
/* Where rows are kept for labels that are not known yet, every label is held to one line and cut short if it is long. */
.card .tight dt {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Who is here now: one row. It scrolls sideways when it is full and its track is always there, so one more arrival
   adds no height. */
.card .faces {
  display: flex;
  gap: var(--space-6);
  margin: 0;
  padding: 0 0 var(--space-2);
  overflow-x: scroll;
  list-style: none;
  scrollbar-width: thin;
}
.card .faces li {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--space-6);
  min-height: var(--tap);
}
.card .faces button {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-2) var(--space-10) var(--space-2) var(--space-2);
  white-space: nowrap;
}
.card .faces canvas {
  width: var(--mug-s);
  aspect-ratio: 22 / 16;
}

/* Lately: five rows of one line each, filled or not. The request behind a row is in its title. */
.card .late {
  margin: 0;
  padding: 0;
  list-style: none;
}
.card .late li {
  display: flex;
  align-items: baseline;
  gap: var(--space-8);
  height: var(--row);
  padding-top: var(--space-2);
}
.card .late time {
  flex: none;
  color: var(--muted);
  font-family: var(--data);
  font-size: var(--text-13);
}
.card .late .nm {
  min-width: 0;
  overflow: hidden;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.card .late .tag,
.card .stop .tag {
  flex: none;
  order: 2;
}
/* A row nothing has filled yet is its dots alone, where the text's baseline would be. */
.card .late .blank {
  align-items: flex-end;
  padding-bottom: var(--space-8);
}

/* The weather: the sea's sentence and the sky's. Each lies over the room of its longest form (.room: that sentence
   with the letters of each word put in order, unseen, so it says nothing and turns where the sentence does), in one
   place. So each is as tall as its longest sentence is at that width, before a reading has come as after, and no
   taller, and a longer sentence moves nothing under it. Under them is the way to the chart of the sea
   (.wxto), which is under the island and not in the panel: a chart stands outside a card. How the readings are
   judged (.wxnote) is there only once More is asked for. */
.card .wx {
  display: grid;
  /* As wide as the card's column and no wider, so a sentence and its room turn at the same edge. */
  grid-template-columns: minmax(0, 1fr);
  font-size: var(--text-small);
}
.card .wx + .wx {
  margin-top: var(--space-6);
}
.card .wx p {
  grid-area: 1 / 1;
  margin: 0;
}
.card .wx .room {
  visibility: hidden;
}
.card .wxto {
  margin: var(--space-8) 0 0;
  font-size: var(--text-caption);
}
/* The expanded island covers the page, and the chart with it, so the way to the chart is not offered there. */
body.full .card .wxto {
  display: none;
}
.card .wxnote {
  margin: var(--space-8) 0 0;
  color: var(--muted);
  font-size: var(--text-caption);
}
/* The sea's last six hours, in a block of its own under the island (.seabox): the landings each reading counted as a
   stepped line, over the band of what was usual and the two marks above it, and under the plot a strip of the sea
   that was drawn. It stands on the page, as wide as the page, and in no card or panel. The server writes it into the
   page where the island has weather, so its room is there from the first paint; with no weather the block is empty
   and hidden.

   The plot is one drawing stretched to its box (see the hour chart), and every word is HTML beside it or under it:
   the figures of its scale in the margin at its left, the names of its lines in the margin at its right, each placed
   by a share of the box, and the hours under the strip. Nothing is written over the plot, so no word can lie on
   the line or on a figure whatever the readings are. The box is the same size with no reading as with six hours of
   them.

   Ink is the line and the hatching. A sea is told by its hatching and its name in the key. The island's water goes
   with it as a wash that deepens as the sea roughens, and the band of what is usual is the same wash as a ripple,
   which is the sea within reach of it. None of it is told by the wash alone. */
:root {
  --wash-chop: var(--if-light, color-mix(in srgb, var(--water) 80%, var(--paper)))
    var(--if-dark, color-mix(in srgb, var(--water) 54%, var(--muted)));
  --wash-swell: var(--if-light, color-mix(in srgb, var(--water) 88%, var(--ink)))
    var(--if-dark, color-mix(in srgb, var(--water) 38%, var(--muted)));
}
.seabox {
  margin-top: var(--gap-section);
}
.seabox[hidden] {
  display: none;
}
.seabox .headrow {
  margin-top: 0;
}
.wxchart {
  position: relative;
  font: var(--text-caps) / 1.3 var(--data);
}
.wxplot {
  position: relative;
  height: 120px;
  margin: 0 var(--space-40);
  border-bottom: var(--line);
}
.wxplot svg {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  shape-rendering: crispEdges;
}
.wxgrid,
.wxband,
.wxmark,
.wxline {
  fill: none;
  vector-effect: non-scaling-stroke;
}
.wxgrid {
  stroke: var(--soft);
  stroke-width: 1;
}
.wxband {
  fill: var(--wash-usual);
  stroke: var(--muted);
  stroke-width: 1;
}
.wxmark {
  stroke: var(--ink);
  stroke-width: 1;
  stroke-dasharray: 4 3;
}
.wxline {
  stroke: var(--ink);
  stroke-width: 2;
  stroke-linejoin: miter;
}
/* A figure of the scale and the name of a line, each level with what it stands for, outside the plot. */
.wxside,
.wxlab {
  position: absolute;
  transform: translateY(50%);
  line-height: 1;
  white-space: nowrap;
}
.wxside {
  right: 100%;
  margin-right: var(--space-6);
  color: var(--muted);
}
.wxlab {
  left: 100%;
  margin-left: var(--space-6);
}
/* A stretch for each run of one sea, under the plot and as wide. Each is a pixel wider than its place, so two that
   touch share one line. No reading is a dashed line and no box. */
.wxstrip {
  position: relative;
  height: 16px;
  margin: var(--space-6) calc(var(--space-40) + 1px) 0 var(--space-40);
}
.wxstrip span {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--x);
  width: calc(var(--w) + 1px);
  border: var(--line-thin);
}
.wxstrip .sea-none {
  top: 50%;
  bottom: auto;
  height: 0;
  border: 0;
  border-top: 1px dashed var(--ink);
}
.wxhours {
  position: relative;
  height: calc(1.3 * var(--text-caps));
  margin: var(--space-4) var(--space-40) 0;
  color: var(--muted);
  white-space: nowrap;
}
/* Each hour is centred under its line. The first and the last may stand half in the margins beside the plot. */
.wxhours span {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
}
.wxkey {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-12);
  margin: var(--space-8) 0 0;
  padding: 0;
  list-style: none;
}
.wxkey li {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.wxsw {
  flex: none;
  width: 14px;
  height: 9px;
  border: var(--line-thin);
}
.wxsw.sea-none {
  height: 0;
  border: 0;
  border-top: 1px dashed var(--ink);
}
/* The seas: a ripple is dots on the wash of what is usual, chop one hatch on a deeper one, swell two on the deepest.
   Flat calm is left empty. */
.sea-ripple {
  background-color: var(--wash-usual);
}
.sea-chop {
  background-color: var(--wash-chop);
  background-image: repeating-linear-gradient(45deg, transparent 0 3px, var(--ink) 3px 4px);
}
.sea-swell {
  background-color: var(--wash-swell);
}

/* The route. Its heading row is as tall as one of the island's buttons whether or not Follow it and Watch it climb
   are in it, and its box shows four stops whether it has none or forty: the rest scroll. */
.card .rhead {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  min-height: var(--hud-button);
}
.card .rhead h3 {
  margin-right: auto;
}
.card .rhead button,
.card .rhead .btn {
  min-height: var(--hud-button);
  padding: 0 var(--space-10);
  font-size: var(--text-small);
}
.card .trail {
  height: calc(4 * var(--hud-button));
  margin: 0;
  padding: 0;
  overflow-y: scroll;
  list-style: none;
  scrollbar-width: thin;
}
.card .trail li {
  min-height: var(--hud-button);
}
.card .trail .none {
  display: flex;
  align-items: center;
  font-family: var(--data);
  font-size: var(--text-13);
}
/* A stop not made yet: a line of dots where its text would stand. */
.card .trail .blank::before {
  content: "";
  display: block;
  height: calc(var(--hud-button) - var(--space-12));
  margin: 0 var(--space-4);
  border-bottom: 2px dotted var(--ink);
}
/* One stop: its number, when, where, dots, and what came of it. A place's name is not cut short here: a long one takes
   a second line, and the box scrolls. */
.card .stop {
  --stop-dim: var(--muted);
  --stop-chip: var(--ink);
  --stop-chip-ink: var(--paper);
  display: flex;
  align-items: baseline;
  gap: var(--space-8);
  width: 100%;
  min-height: var(--hud-button);
  padding: var(--space-6) var(--space-4) var(--space-4);
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
}
.card .stop .n {
  display: grid;
  flex: none;
  place-items: center;
  width: var(--badge);
  height: var(--badge);
  background: var(--stop-chip);
  color: var(--stop-chip-ink);
  font: 700 var(--text-12) / 1 var(--data);
}
.card .stop time {
  flex: none;
  color: var(--stop-dim);
  font-family: var(--data);
  font-size: var(--text-13);
}
.card .stop .nm {
  min-width: 0;
  font-weight: 600;
}
.card .stop .tag.good {
  color: var(--stop-good, var(--ok));
}
.card .stop .tag.bad {
  color: var(--stop-bad, var(--alert));
}
/* A stop with nothing to say of what came of it (the landing) has no dots leading nowhere. */
.card .stop:not(:has(.tag))::before {
  visibility: hidden;
}
/* These sit in boxes that scroll, which would cut off a ring drawn outside them. A stop's ring is the paper's colour
   while the stop is filled with ink. */
.card .stop:focus-visible,
.card .faces button:focus-visible {
  outline-offset: -3px;
}
.card .stop:focus-visible {
  outline-color: var(--stop-ring, var(--alert));
}
/* A picker shows one highlight, the ink fill, and it follows the pointer: the stop the camera is on is filled, and
   gives its fill up while another is pointed at. The pointer's rules are inside (hover: hover), since a phone leaves
   :hover on the last thing tapped. */
.card .stop[aria-pressed="true"] {
  --stop-dim: var(--paper);
  --stop-chip: var(--paper);
  --stop-chip-ink: var(--ink);
  --stop-good: var(--paper);
  --stop-bad: var(--paper);
  --stop-ring: var(--paper);
  background: var(--ink);
  color: var(--paper);
}
@media (hover: hover) {
  .card .stop:hover {
    --stop-dim: var(--paper);
    --stop-chip: var(--paper);
    --stop-chip-ink: var(--ink);
    --stop-good: var(--paper);
    --stop-bad: var(--paper);
    --stop-ring: var(--paper);
    background: var(--ink);
    color: var(--paper);
  }
  .card .trail:has(.stop:hover) .stop:not(:hover) {
    --stop-dim: var(--muted);
    --stop-chip: var(--ink);
    --stop-chip-ink: var(--paper);
    --stop-good: initial;
    --stop-bad: initial;
    --stop-ring: initial;
    background: none;
    color: inherit;
  }
  .card .faces button:hover {
    background: var(--ink);
    color: var(--paper);
  }
}

/* You, on the Visitors panel: a ledger row whose figure is the viewer's own where this browser holds one, and a
   dashed frame the same size where it does not, with the button that makes or changes it. The dots stand where the
   small capitals' baseline is in a row this tall. */
.card .you {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  min-height: var(--tap);
}
.card .you::before {
  content: "";
  flex: 1 1 var(--space-12);
  order: 1;
  align-self: flex-end;
  margin-bottom: calc(var(--space-16) + var(--space-2));
  border-bottom: 2px dotted var(--ink);
}
.card .you h3 {
  margin: 0;
}
.card .you .mug {
  order: 2;
}
.card .you span.mug {
  border-style: dashed;
}
.card .you button {
  order: 3;
}
/* Under You, on a row of its own that is always there: the way to Handed over, at the row's right edge under the
   button above it. */
.card .yours {
  display: flex;
  justify-content: flex-end;
  margin: var(--space-6) 0 0;
}

/* Handed over: what the island has of the last bot to land, and what this browser handed the page, a ledger each.
   One stands over the other in the sheet and in the 330px panel. From 1024px the card is up to 620px wide and they
   stand side by side. It stops short of where the Sightings panel opens (its 350px, and 8px in from each edge), and
   it is under seven tenths of the frame at every width from there, so the island's view still takes the card as
   standing at its left and keeps what it is looking at clear of it. Everything in the card is known when it is
   painted and it is painted once, so nothing in it arrives later; an island nobody has landed on keeps the bot's
   rows. */
.card .handed {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: var(--space-20);
}
@media (min-width: 1024px) {
  .card:has(> .body > .handed) {
    width: min(620px, calc(100% - 366px));
  }
  .card:has(> .body > .handed) .handed {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 767px) {
  /* The sheet is short and this card is for reading. So its foot goes by with the rest of it and is not held in
     sight, and the rows have the room the foot would take. */
  .card:has(> .body > .handed) .foot {
    position: static;
  }
}
/* A visitor's own user-agent line, word for word: under its label and as wide as its ledger, in the data face. It
   breaks anywhere, as every value in a ledger does, so no line of it is too long for a phone. Under it is the room a
   row has under its one line. */
.card .figs .agent {
  display: block;
  padding-bottom: var(--space-6);
}
.card .figs .agent::before {
  content: none;
}
.card .figs .agent dd {
  max-width: none;
  font-family: var(--data);
  font-size: var(--text-13);
  text-align: left;
}

/* A flock's sessions, one line each. */
.card .sessions {
  margin: var(--space-8) 0 0;
  padding: 0;
  border-top: 2px dotted var(--ink);
  list-style: none;
}
.card .sessions li {
  padding: var(--space-4) 0;
  font-family: var(--data);
  font-size: var(--text-13);
  overflow-wrap: anywhere;
}
/* The guest list: a box of one height before the list has come and after, which scrolls. */
.card pre {
  height: 150px;
  margin: 0;
  padding: var(--space-8) var(--space-10);
  overflow: auto;
  border: var(--line);
  background: var(--paper);
  font: var(--text-12) / 1.5 var(--data);
}

/* The actions: ruled off, and in sight however far the card is scrolled. They are one row, and a label takes a second
   line before the row would take a second. A card with no action has no foot. */
.card .foot {
  position: sticky;
  bottom: 0;
  display: flex;
  gap: var(--space-6);
  padding: var(--space-8) var(--space-10);
  border-top: var(--line);
  background: var(--panel);
}
.card .foot:empty {
  display: none;
}
.card .foot button,
.card .foot .btn {
  flex: 0 1 auto;
  justify-content: center;
  padding: 0 var(--space-8);
  font-size: var(--text-small);
  line-height: 1.15;
  text-align: center;
}
@media (min-width: 768px) {
  .card .band {
    padding: var(--space-10) var(--space-12);
  }
  .card .band .mug {
    width: var(--mug-m);
  }
  .card h2 {
    font-size: var(--text-26);
  }
  .card .body {
    padding: var(--space-10) var(--space-12) var(--space-12);
  }
  .card .foot {
    padding: var(--space-8) var(--space-12);
  }
}

/* Server-rendered pages (species, method, editions) share this sheet. */
main h1,
main h2,
main h3 {
  font-family: var(--display);
  font-weight: 400;
}
main strong,
main b {
  font-weight: 600;
}
main i,
main em {
  font-family: var(--display);
  font-size: 1.1em;
  /* The serif has one weight, so a bold or italic around it would be drawn by the browser and smear its thin strokes. */
  font-synthesis: none;
}
/* The serif is a display face: its thin stroke needs 20px or more. In small text an italic word is the sans italic. */
:is(.fine, .notes, .data, .tip-body, .split) :is(i, em) {
  font-family: inherit;
  font-size: inherit;
}
main code,
main pre,
main time {
  font-family: var(--data);
  font-size: var(--text-data);
}

/* The footer, the same on the island page as on the server pages. It sits in the masthead's column, under a 2px ink rule. */
body > footer {
  width: min(calc(var(--page-width) - 2 * var(--page-gutter)), calc(100% - 2 * var(--page-gutter)));
  margin: var(--space-16) auto 0;
  padding: var(--space-48) 0 calc(var(--space-48) + env(safe-area-inset-bottom, 0px));
  border-top: var(--line);
  font-size: var(--text-small);
}
body > footer p,
body > footer ul,
body > footer h2 {
  margin: 0;
  padding: 0;
}
body > footer ul {
  list-style: none;
}
body > footer .foot-top a {
  color: var(--ink);
  text-decoration: none;
}
body > footer .foot-top a:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}
body > footer .foot-top a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 2px;
  outline: 3px solid var(--alert);
  outline-offset: 2px;
}
.foot-top {
  display: flex;
  flex-direction: column;
  gap: var(--space-40);
}
.foot-brand {
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
  max-width: 20rem;
}
.foot-name {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  font-family: var(--display);
  font-size: var(--text-20);
  line-height: 1.2;
  color: var(--ink);
}
.foot-name img {
  width: 24px;
  height: 24px;
}
.foot-blurb {
  color: var(--muted);
  line-height: 1.625;
}
.foot-cols {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.foot-cols nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}
.foot-cols ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}
body > footer h2 {
  font: 600 var(--text-label) / 1.33 var(--body);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.foot-note {
  max-width: var(--measure);
  font-size: var(--text-caption);
  color: var(--muted);
}
.foot-legal {
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
  margin-top: var(--space-48);
  padding-top: var(--space-24);
  border-top: var(--line-soft);
}
.foot-legal p {
  max-width: var(--measure);
  font-size: var(--text-caption);
  color: var(--muted);
}
body > footer a.codeswhat-pill {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: var(--space-10);
  padding: var(--space-6) var(--space-14) var(--space-6) var(--space-6);
  border: var(--line-soft);
  border-radius: 9999px;
  background: color-mix(in srgb, var(--paper) 50%, transparent);
  color: var(--muted);
  text-decoration: none;
  transition: border-color var(--dur-150), background-color var(--dur-150);
}
body > footer a.codeswhat-pill:hover {
  border-color: var(--muted);
  background: color-mix(in srgb, var(--paper) 80%, transparent);
}
body > footer a.codeswhat-pill:focus-visible {
  outline: 3px solid var(--alert);
  outline-offset: 2px;
}
.codeswhat-pill .coin {
  width: 26px;
  height: 26px;
  border-radius: 9999px;
  box-shadow: 0 0 0 1px var(--soft);
}
:root[data-theme="dark"] .codeswhat-pill .coin {
  filter: invert(1);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .codeswhat-pill .coin {
    filter: invert(1);
  }
}
.codeswhat-pill .pill-text {
  font-size: var(--text-label);
  line-height: 1.33;
}
.codeswhat-pill .pill-name {
  font-weight: 600;
  color: var(--ink);
}
.codeswhat-pill .pill-arrow {
  flex: none;
  transition: transform var(--dur-150);
}
.codeswhat-pill:hover .pill-arrow {
  transform: translate(2px, -2px);
}
@media (prefers-reduced-motion: reduce) {
  .codeswhat-pill .pill-arrow {
    transition: none;
  }
}
@media (min-width: 768px) {
  .foot-legal {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}
@media (min-width: 768px) {
  .foot-cols {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-40) var(--space-64);
  }
}
@media (min-width: 1024px) {
  .foot-top {
    flex-direction: row;
    justify-content: space-between;
  }
  .foot-cols {
    justify-content: flex-end;
  }
}

/* The one link a script adds to every page. It sits in the footer, so it reads as one of its links. */
a.grown {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  margin-top: var(--space-6);
  color: var(--ink);
  font-family: var(--body);
  font-size: var(--text-small);
  line-height: 1.45;
  font-weight: 400;
  text-underline-offset: 2px;
}
a.grown:focus-visible {
  outline: 3px solid var(--alert);
  outline-offset: 2px;
}

/* Moving between pages: a browser that can do cross-document view transitions holds the masthead title, the
   tab row and a page's sub-tab row still and cross-fades only what is below them. Others navigate as before. */
@view-transition {
  /* biome-ignore lint/correctness/noUnknownProperty: biome 1.9 does not know the @view-transition descriptor */
  navigation: auto;
}
.mast .title {
  view-transition-name: mast-title;
}
.navbar {
  view-transition-name: main-nav;
}
.subnav {
  view-transition-name: sub-nav;
}
/* The mark of where you are slides to its new tab: on the tab row, a section's sub-tab row and the Census period
   switch. */
.navbar a[aria-current] {
  view-transition-name: nav-current;
}
.subnav a[aria-current] {
  view-transition-name: sub-current;
}
.seg a[aria-current] {
  view-transition-name: seg-current;
}
/* The part of a page its own controls change (src/shared/swap.ts) is one piece of the transition, so its old and
   new rows travel together and are not drawn in two places at once. Each part has its own name: two pages that do
   not share a part cross-fade in place. */
#period[data-swap] {
  view-transition-name: part-period;
}
#cases[data-swap] {
  view-transition-name: part-cases;
}
/* A control of a page lands on its own part when the page is loaded whole, a little under the tab row that sticks.
   The room for the tab row itself is the scroll-padding on html. */
[data-swap] {
  scroll-margin-top: var(--space-12);
}
/* A part takes the keyboard when its pager has turned the page. It is not a control and gets no ring. */
[data-swap]:focus {
  outline: none;
}
/* The part being fetched dims if the answer is slow. */
main[aria-busy="true"],
[data-swap][aria-busy="true"] {
  opacity: 0.55;
  transition: opacity var(--dur-120) linear var(--dur-150);
}
::view-transition-group(*) {
  animation-duration: var(--dur-120);
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--dur-120);
}
@media (prefers-reduced-motion: reduce) {
  @view-transition {
    /* biome-ignore lint/correctness/noUnknownProperty: biome 1.9 does not know the @view-transition descriptor */
    navigation: none;
  }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none;
  }
  main[aria-busy="true"],
  [data-swap][aria-busy="true"] {
    transition: none;
  }
}

/* The i hint lives here, not in pages.css, because the island page loads only this sheet and its masthead has one. */
/* A hint: a small round "i" that shows a short panel on hover, focus and tap, without moving anything. */
.hint {
  display: inline-block;
  vertical-align: middle;
  font-family: var(--body);
  font-size: var(--text-small);
  font-weight: 400;
  line-height: 1.35;
}
main .hint summary,
.mast .hint summary {
  min-height: 0;
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  list-style: none;
  cursor: pointer;
}
main .hint summary::-webkit-details-marker,
.mast .hint summary::-webkit-details-marker {
  display: none;
}
main .hint summary:focus-visible,
.mast .hint summary:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}
/* A hint wears the pixel circled i in place of the lettered circle: the icon alone, no CSS ring. */
.hint .info-icon {
  display: block;
}
.hint::details-content {
  content-visibility: visible;
  display: contents;
}
.hint .tip {
  display: none;
  position: absolute;
  z-index: var(--z-5);
  top: 100%;
  left: 0;
  width: max-content;
  max-width: min(34ch, calc(100vw - 32px));
  padding-top: var(--space-6);
}
.hint[open] .tip,
.hint:hover .tip,
.hint:focus-within .tip {
  display: block;
}
/* With the site script running (it sets data-hints on the root) a panel is fixed under its icon, centred, and kept
   12px inside the viewport; the script writes --hx, --hy and --hn (the notch's x). Without it the rules above hold. */
:root[data-hints] details.hint.hint .tip {
  position: fixed;
  z-index: var(--z-50);
  top: var(--hy, 0);
  right: auto;
  bottom: auto;
  left: var(--hx, 0);
  max-width: min(34ch, calc(100vw - 24px));
  padding-top: var(--space-8);
}
:root[data-hints] .mast .sub .hint .tip {
  max-width: min(40em, calc(100vw - 24px));
}
:root[data-hints] .tip-body {
  position: relative;
}
:root[data-hints] .tip-body::before {
  content: "";
  position: absolute;
  top: -5px;
  left: calc(var(--hn, 50%) - 5px);
  width: 8px;
  height: 8px;
  border: solid var(--ink);
  border-width: 1px 0 0 1px;
  background: var(--paper);
  transform: rotate(45deg);
}
/* An open panel is painted above its neighbours: its icon's box and the masthead (which holds its own stacking
   context for the view transition and sits before the sticky tab row) rise while it is open. */
.hint:is(:hover, :focus-within, [open]) {
  z-index: var(--z-50);
}
.mast:has(.hint:is(:hover, :focus-within, [open])) {
  position: relative;
  z-index: var(--z-50);
}
.tip-body {
  padding: var(--space-8) var(--space-10);
  border: var(--line-thin);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--text-small);
  font-style: normal;
  font-weight: 400;
  text-align: left;
}
.tip-body p {
  max-width: var(--measure);
  margin: 0 0 var(--space-6);
}
.tip-body p:last-child {
  margin-bottom: 0;
}

/* The intro hint after the masthead tagline: upright, centred on the text's x-height, panel under the tagline. */
.mast .sub .hint {
  position: static;
  margin-left: var(--space-8);
  font-style: normal;
  vertical-align: 0.05em;
}
.mast .sub .hint .tip {
  z-index: var(--z-10);
  max-width: min(40em, 100%);
  padding-top: var(--space-8);
}
.mast .sub .hint .tip-body {
  font-family: var(--body);
  font-size: var(--text-small);
  line-height: 1.4;
}

/* Phone: the footer's link columns pair up two by two. The two long lists, the first and the last, share the top row,
   so the short pair under them sets the height of the second and neither row is padded out by a long neighbour. */
@media (max-width: 767px) {
  .foot-cols {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-40) var(--space-16);
  }
  .foot-cols nav:first-child,
  .foot-cols nav:last-child {
    order: -1;
  }
}

/* The Rules ledger rows and share bar live in this sheet because the island page loads only this one. */
.rules {
  margin: 0 0 var(--gap-block);
  padding: 0;
  list-style: none;
  border: var(--line);
  background: var(--panel);
}
.rules > li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0 var(--space-12);
  padding: var(--card-pad);
  border-top: var(--line-soft);
}
.rules > li:first-child {
  border-top: 0;
}
.rules .where {
  color: var(--muted);
  font-size: var(--text-small);
}
.bar {
  display: flex;
  width: 100%;
  height: 8px;
  overflow: hidden;
  border: var(--line);
  background: var(--paper);
}
.bar .k {
  flex: 0 1 auto;
  background: var(--ok);
}
.bar .k.plain {
  background: var(--muted);
}
.bar .b {
  flex: 0 0 auto;
  min-width: 2px;
  background: var(--alert);
}
.rules > li.led {
  grid-template-columns: minmax(0, 1fr) 16rem;
  align-items: start;
}
.rules .rulecol {
  min-width: 0;
}
.rules .rulecol code {
  display: block;
}
.rules .big {
  display: grid;
  justify-items: end;
  gap: var(--space-4);
  align-self: center;
  width: 16rem;
  max-width: 100%;
  justify-self: end;
}
.rules .big .n {
  font-family: var(--data);
  font-size: var(--text-figure-row);
  font-weight: 600;
  line-height: 1;
}
.cap {
  margin: 0;
  color: var(--muted);
  font-family: var(--data);
  font-size: var(--text-label);
  font-weight: 400;
}
.rules .big .cap {
  text-align: right;
}
/* "18 of 578" on one line: today's figure, then the all-time total small and muted beside it. */
.rules .big .n .of {
  color: var(--muted);
  font-size: var(--text-caption);
  font-weight: 400;
}
.rules .big.plain .n {
  color: var(--muted);
}
@media (max-width: 767px) {
  .rules > li.led {
    grid-template-columns: minmax(0, 1fr);
  }
  /* On a phone the figure drops under the rule and stays on the right, as it is beside the rule on a wider screen. */
  .rules .big {
    justify-self: stretch;
    width: auto;
    margin-top: var(--space-4);
  }
}

/* The bar chart of the server's pages (96px chart, red current bar, mono axis), with the rest of what every page shares. */
.chart {
  margin: 0 0 var(--gap-block);
}
.bars {
  display: block;
  width: 100%;
  height: 96px;
  border-bottom: var(--line);
}
.bar-now {
  fill: var(--alert);
}
.bar-now-b {
  fill: var(--alert);
  fill-opacity: 0.55;
}
.bar-a {
  fill: var(--ink);
}
.bar-b {
  fill: var(--muted);
}
.chart .axis {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-4);
  color: var(--muted);
  font-family: var(--data);
  font-size: var(--text-label);
}
.hoursbox .chart {
  margin-bottom: 0;
}
/* The island's hour chart: today's landings in each UTC hour as a stepped line, the hour in progress dashed, over a
   band of what is usual at each hour. The plot (.harea) is one SVG stretched to its box, so its strokes keep their
   thickness by non-scaling-stroke, and what is written on it is HTML over it, placed by percentage. Over the plot is
   a strip for the mark that says where now is, and at its left is room for the figures of its scale. The box is the
   same size before anything is drawn as after.

   Nothing is written over the line. The one figure on the plot (.hpeak) stands over the highest step under it, in
   room the scale always leaves, and is held inside the plot at either edge. The mark for now (.hnow) is in the strip
   over the plot, so the two never meet. 
   Ink is the line. What is usual is a wash of the island's water with a hairline round it, and the read-out says it
   in figures: no colour here says anything that words do not. */
:root {
  --wash-usual: var(--if-light, color-mix(in srgb, var(--water) 45%, var(--paper)))
    var(--if-dark, color-mix(in srgb, var(--water) 70%, var(--muted)));
  --wash-failed: color-mix(in srgb, var(--alert) 28%, var(--paper));
}
.hplot {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 124px;
  padding: var(--space-20) 0 0 var(--space-32);
  cursor: crosshair;
  touch-action: pan-y;
}
@media (min-width: 768px) {
  .hplot {
    height: 180px;
  }
}
.harea svg:focus-visible {
  outline: 3px solid var(--alert);
  outline-offset: 2px;
}
.harea {
  position: relative;
  flex: 1;
  min-height: 0;
  border-bottom: var(--line);
}
.harea svg {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  shape-rendering: crispEdges;
}
.hgrid,
.hband,
.hline,
.hsofar {
  fill: none;
  vector-effect: non-scaling-stroke;
}
.hgrid {
  stroke: var(--soft);
  stroke-width: 1;
}
.hband {
  fill: var(--wash-usual);
  stroke: var(--muted);
  stroke-width: 1;
}
.hline,
.hsofar {
  stroke: var(--ink);
  stroke-width: 2;
  stroke-linejoin: miter;
}
.hsofar {
  stroke-dasharray: 3 3;
}
/* The picked hour: a grey column the full height of the plot, behind the line. */
.hpick {
  fill: var(--muted);
  fill-opacity: 0.3;
}
/* The figures of the scale: nought on the base line, the top, and half of it. */
.htick {
  position: absolute;
  bottom: 2px;
  left: 0;
  width: calc(var(--space-32) - var(--space-6));
  transform: translateY(50%);
  color: var(--muted);
  font: var(--text-caps) / 1 var(--data);
  text-align: right;
  white-space: nowrap;
}
.htick.htop {
  bottom: calc(100% - var(--space-20));
}
.htick.hmid {
  bottom: calc((100% - var(--space-20)) / 2 + 1px);
}
/* The mark for now: a shape and words, in the strip over the plot. Late in the day the words go to its left. */
.hnow {
  position: absolute;
  bottom: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  height: var(--space-20);
  transform: translateX(-4px);
  font: var(--text-caps) / 1 var(--data);
  white-space: nowrap;
  pointer-events: none;
}
.hnow::before {
  content: "";
  align-self: flex-end;
  border: 4px solid transparent;
  border-top: 6px solid var(--ink);
  border-bottom: 0;
}
.hnow.flip {
  flex-direction: row-reverse;
  transform: translateX(calc(4px - 100%));
}
.hnow[hidden],
.hpeak[hidden] {
  display: none;
}
/* The one figure on the plot: its foot just over the highest step under it (--at), and moved back by the share of
   its own width that its hour is across the plot (--x), so it is inside the plot at either edge. */
.hpeak {
  position: absolute;
  bottom: min(calc(var(--at) + var(--space-2)), calc(100% - 1.3em));
  transform: translateX(var(--x));
  padding: 0 var(--space-2);
  background: color-mix(in srgb, var(--paper) 80%, transparent);
  font: 700 var(--text-caps) / 1.3 var(--data);
  white-space: nowrap;
  pointer-events: none;
}
.haxis {
  position: relative;
  height: calc(1.45 * var(--text-label));
  margin: var(--space-4) 0 0 var(--space-32);
  color: var(--muted);
  font: var(--text-label) / 1.45 var(--data);
}
.haxis span {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
}
.haxis span:nth-child(2) {
  left: 25%;
}
.haxis span:nth-child(4) {
  left: 75%;
}
.haxis span:first-child {
  left: 0;
  transform: none;
}
.haxis span:last-child {
  right: 0;
  left: auto;
  transform: none;
}
/* Two wordings of one line, the long from 768px and the short below it. */
.at-phone {
  display: none;
}
@media (max-width: 767px) {
  .hoursbox .at-wide {
    display: none;
  }
  .hoursbox .at-phone {
    display: inline;
  }
}

/* Today's landings as Passport Control left them: one strip in four parts that add up to all of them, each as wide
   as its share. A part is told by its texture and by its name, in a box inside it where that fits and always in the
   key under it, with its figure. The green of a claim that passed and the red wash under one that failed go with
   those two textures and are never the only thing that tells them. The strip is there, empty, before anything has
   landed, and the key is in columns of a fixed least width, so a figure that grows moves nothing.

   It is a figure of its own on the page, above the bar list that shares its scale. */
.pc {
  min-width: 0;
  margin: 0 0 var(--gap-block);
}
.pc figcaption {
  margin-bottom: var(--space-8);
  line-height: 1.3;
}
.pcstrip {
  display: flex;
  height: 22px;
  overflow: hidden;
  border: var(--line-thin);
  background: var(--paper);
}
/* A part's name is a second line when it does not fit beside the strut, and the part is one line tall, so a name is
   shown whole or not at all. */
.pcseg {
  display: flex;
  flex: 0 1 0;
  flex-wrap: wrap;
  align-content: flex-start;
  justify-content: center;
  min-width: 3px;
  overflow: hidden;
  box-shadow: -1px 0 0 var(--ink);
}
.pcseg[hidden] {
  display: none;
}
.pcseg::before {
  content: "";
  width: 0;
  height: 20px;
}
.pcseg b {
  flex: none;
  align-self: center;
  margin: 0 var(--space-6);
  padding: 0 var(--space-4);
  border: var(--line-thin);
  background: var(--paper);
  font: 600 var(--text-10) / 1.2 var(--data);
  white-space: nowrap;
}
.pc-ok {
  background-color: var(--ok);
}
.pc-bad {
  background-color: var(--wash-failed);
}
.pc-none,
.pc-rest {
  background-color: var(--paper);
}
/* The textures, which this strip and the strip of the sea share: sparse dots, and two hatches crossed. */
.pc-rest,
.sea-ripple {
  background-image: radial-gradient(circle, var(--ink) 0 1px, transparent 1.3px);
  background-size: 6px 6px;
}
.pc-bad,
.sea-swell {
  background-image: repeating-linear-gradient(45deg, transparent 0 3px, var(--ink) 3px 4px),
    repeating-linear-gradient(135deg, transparent 0 3px, var(--ink) 3px 4px);
}
/* Read by a screen reader and not seen: the figures of a chart as a table, and a word for a mark. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.pcaxis {
  display: flex;
  justify-content: space-between;
  margin: var(--space-4) 0 0;
  color: var(--muted);
  font: var(--text-label) / 1.45 var(--data);
}
.pckey {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: var(--space-4) var(--space-16);
  margin: var(--space-6) 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-caption);
}
.pcsw {
  display: inline-block;
  width: 22px;
  height: 12px;
  margin-right: var(--space-6);
  border: var(--line-thin);
  vertical-align: -2px;
}
/* The bar list, on the island and on every page: unboxed rows, the name at the left in the body face, a bar from one
   common left edge, and its figure at the right edge in the figure face. Every bar in a list is measured on the list's
   one scale. A part of a whole is the ok tint, a count of a broken rule the alert tint under a hatch, and a plain count
   is ink at low strength, so the colour never stands alone. A zero is an empty track with a tick at its start. */
:root {
  --bl-ok: color-mix(in srgb, var(--ok) 24%, var(--paper));
  --bl-bad: color-mix(in srgb, var(--alert) 24%, var(--paper));
  --bl-plain: color-mix(in srgb, var(--ink) 22%, var(--paper));
}
.bl {
  min-width: 0;
  margin: 0 0 var(--gap-block);
}
.bl-rows {
  margin: 0;
  padding: 0;
  list-style: none;
}
.bl {
  container-type: inline-size;
}
/* Wide: the name, the bar and the figure on one line. The columns are the list's own, so every bar starts at one
   left edge and ends at one right edge, and the bar fills what is between the name and the figure. */
.bl-rows {
  display: grid;
  grid-template-columns: fit-content(40%) minmax(0, 1fr) max-content;
  column-gap: var(--space-12);
}
.bl-row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: center;
  padding: var(--space-4) 0;
}
.bl-name {
  min-width: 0;
  line-height: 1.3;
}
.bl-aside {
  color: var(--muted);
  font-size: var(--text-small);
}
.bl-sub .bl-name {
  padding-left: var(--space-16);
  color: var(--muted);
}
.bl-bar {
  display: flex;
  height: 10px;
  min-width: 0;
  border: var(--line-thin);
  background: var(--paper);
}
.bl-fill {
  display: flex;
  flex: none;
  min-width: 3px;
  height: 100%;
  border-right: var(--line-thin);
  background-color: var(--bl-plain);
}
.bl-fill.bl-part {
  background-color: var(--bl-ok);
}
.bl-fill.bl-broke {
  background-color: var(--bl-bad);
  background-image: repeating-linear-gradient(135deg, transparent 0 3px, var(--ink) 3px 4.2px);
}
.bl-fill.bl-strip {
  background: none;
}
.bl-seg {
  flex: 1 1 0;
  min-width: 2px;
  border-left: var(--line-thin);
  background-color: var(--paper);
}
.bl-seg:first-child {
  border-left: 0;
}
.bl-zero .bl-fill {
  width: 0;
  min-width: 0;
  border-right-width: 3px;
}
.bl-n {
  font-family: var(--data);
  font-size: var(--text-data);
  text-align: right;
  white-space: nowrap;
}
.bl .legend {
  margin-bottom: var(--space-6);
}
/* Narrow (a list in a column under about 520px: the island's, a phone's): the name at the left and the figure at the
   right on one line, and the bar full width under them. */
@container (max-width: 519px) {
  .bl-rows {
    display: block;
  }
  .bl-row {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--space-12);
    row-gap: var(--space-2);
  }
  .bl-name {
    grid-column: 1;
    grid-row: 1;
  }
  .bl-n {
    grid-column: 2;
    grid-row: 1;
  }
  .bl-bar {
    grid-column: 1 / -1;
    grid-row: 2;
  }
}
/* Stacked at every width (Today at the port): the bars share the Passport strip's full-width scale, so each row is the
   name and the figure on one line and the bar the whole column under them. */
.bl-stack .bl-rows {
  display: block;
}
.bl-stack .bl-row {
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--space-12);
  row-gap: var(--space-2);
}
.bl-stack .bl-name {
  grid-column: 1;
  grid-row: 1;
}
.bl-stack .bl-n {
  grid-column: 2;
  grid-row: 1;
}
.bl-stack .bl-bar {
  grid-column: 1 / -1;
  grid-row: 2;
}
@media (prefers-reduced-motion: no-preference) {
  .bl-fill {
    transition: width var(--dur-400);
  }
}
/* Two plain lines, a muted name at the left and its value at the right: no box around them. */
.plainlines {
  margin: var(--gap-block) 0 0;
  padding: 0;
  list-style: none;
}
.plainlines > li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-12);
  padding: var(--space-4) 0;
}
.plainlines .pl-name {
  flex: none;
  color: var(--muted);
  font-size: var(--text-small);
  white-space: nowrap;
}
.plainlines .pl-value {
  min-width: 0;
  overflow: hidden;
  font-family: var(--data);
  font-size: var(--text-data);
  line-height: 1.3;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (prefers-reduced-motion: no-preference) {
  .bar .k,
  .bar .b {
    transition: width var(--dur-400);
  }
}
/* Numbered steps as a strip of cards (one column on a phone, two on a tablet, one row on a desktop), and the one button
   with its note beside it: Send your bot, Send a courier and the island's courier strip. */
:is(.sendpage, .courier) .steps {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--card-gap);
  margin: 0 0 var(--gap-block);
  padding: 0;
  list-style: none;
  counter-reset: step;
}
@media (min-width: 768px) {
  :is(.sendpage, .courier) .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 1024px) {
  :is(.sendpage, .courier) .steps {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
  }
}
:is(.sendpage, .courier) .steps li {
  display: grid;
  align-content: start;
  gap: var(--gap-label);
  min-width: 0;
  padding: var(--card-pad);
  border: var(--line);
  background: var(--panel);
  counter-increment: step;
  overflow-wrap: anywhere;
}
:is(.sendpage, .courier) .getrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-10) var(--space-16);
  margin: var(--space-20) 0 0;
}
:is(.sendpage, .courier) .getrow form,
:is(.sendpage, .courier) .getrow .fine {
  margin: 0;
}
:is(.sendpage, .courier) .steps li::before {
  content: counter(step);
  display: grid;
  flex: none;
  place-items: center;
  width: 26px;
  height: 26px;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--data);
  font-size: var(--text-data);
  font-weight: 600;
}
/* The courier strip under the island's ticker: the link in a field with its Copy button, then the steps and the line. */
.courier {
  margin: 0 0 var(--gap-block);
}
.courier .headrow {
  margin-top: var(--gap-block);
}
.courier .getrow label {
  flex: 1 0 100%;
  font-weight: 600;
}
.courier .getrow input {
  flex: 1 1 16rem;
  min-width: 0;
  font-family: var(--data);
  font-size: var(--text-16);
}
.courier #courierStatus {
  margin: 0 0 var(--space-6);
  font-weight: 600;
}
.landed li {
  position: relative;
}
.landed .tag {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  background: var(--panel);
}

.me-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  margin: var(--space-12) 0;
  border: 0;
  padding: 0;
}
.me-row legend {
  margin-bottom: var(--space-6);
  font-weight: 600;
}
.me-row button {
  padding: 0 var(--space-8);
  font-size: var(--text-12);
}
.me-row button::before {
  content: "";
  display: inline-block;
  width: var(--space-12);
  height: var(--space-12);
  margin-right: var(--space-6);
  background: var(--swatch);
  border: var(--line-soft);
}
.me-row button[aria-checked="true"] {
  outline: var(--line);
  outline-offset: var(--space-2);
}
