/* ------------------------------------------------------------------
 * Shipping Tools
 *
 * This site is a neutral public directory and the styling is
 * deliberately its own: nothing here is shared with, or derived from,
 * any freight company's brand. Warm paper, tangerine accent, rounded
 * everything, Inter. If a token below ever starts matching another
 * site's palette, that is a bug, not a convenience.
 *
 * Bright and friendly on purpose - the audience is somebody at a desk
 * at 6am trying to find one calculator, and the page should feel easy
 * rather than corporate.
 * ------------------------------------------------------------------ */

/* ---------------- theme ----------------
 *
 * DARK IS THE DEFAULT, for everyone, the way the Squarespace site was.
 * The grounds are lifted straight off it: #111118 masthead, #1e1e2a
 * page, white headings, #d0d0d0 body copy, and #253551 - the navy its
 * buttons used - kept as the tint behind badges and chips.
 *
 * The one thing added is a brighter blue for links and accents. The
 * original had no readable accent at all; #253551 on #1e1e2a is about
 * 1.4:1, which is invisible as text.
 *
 * Because dark is the base rather than a media query, the site does
 * NOT follow the reader's OS - it looks the same for everyone, which
 * is what the original did. To make it follow the OS instead, move the
 * light block below into @media (prefers-color-scheme: light).
 */

:root {
  color-scheme: dark;

  --header-bg: #111118;
  --paper: #272735;
  --cream: #1e1e2a;
  --cream-deep: #2b2b3a;
  --ink: #ffffff;
  --ink-soft: #d0d0d0;
  --muted: #9292a2;
  --line: #32323f;
  --line-firm: #434352;

  --invert-bg: #ffffff;
  --invert-fg: #16161f;

  --brand: #6f9bff;
  --brand-dark: #a3c0ff;
  --brand-wash: #253551;
  --sky: #9fbdf0;
  --sky-wash: #253551;
  --sun: #f5c451;
  --sun-wash: #3a3220;

  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 22px -12px rgba(0, 0, 0, .75);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, .45), 0 16px 34px -14px rgba(0, 0, 0, .85);

  --radius: 16px;
  --radius-sm: 10px;
  --shadow: 0 1px 2px rgba(38, 34, 32, .05), 0 8px 22px -12px rgba(38, 34, 32, .16);
  --shadow-lift: 0 2px 4px rgba(38, 34, 32, .06), 0 16px 34px -14px rgba(38, 34, 32, .24);

  /* Lifted from shipmotowebsite so the logo sits the same distance
     from the left edge on both, and the toggle the same from the
     right: --shell 1680 with a 26-40px fluid gutter. */
  --wrap: 1680px;
  /* The shell is the full width of the window; the content inside an
     interior page is a column. Same number the home page bands use,
     so every page has one content width. */
  --wrap-read: 1240px;
  --gutter: clamp(1.625rem, 1.2rem + 2.2vw, 2.5rem);
  --font: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
}

/* The light alternative, reached only by the header switch. Plain
   neutral slate with one blue - the ordinary, unobjectionable choice. */
:root[data-theme="light"] {
  color-scheme: light;

  --header-bg: #fffcf6;
  --paper: #fffcf6;
  --cream: #f6f1e8;
  --cream-deep: #ece5d8;
  --ink: #22201c;
  --ink-soft: #544e45;
  --muted: #7e7668;
  --line: #e4dcce;
  --line-firm: #cec4b2;

  --invert-bg: #22201c;
  --invert-fg: #fffcf6;

  /* The blues stay blue - a warm page wants a cool accent, not a
     second warm one - but pulled a shade deeper so they hold against
     cream rather than against white. */
  --brand: #2457d6;
  --brand-dark: #1b44ab;
  --brand-wash: #e8edfa;
  --sky: #0e6b64;
  --sky-wash: #e8f4f1;
  --sun: #a2500a;
  --sun-wash: #faf0dc;

  /* Shadows carry the paper's warmth too; a blue-grey shadow under a
     cream card is what makes it look dirty rather than lifted. */
  --shadow: 0 1px 2px rgba(60, 48, 30, .06), 0 8px 22px -12px rgba(60, 48, 30, .20);
  --shadow-lift: 0 2px 4px rgba(60, 48, 30, .07), 0 16px 34px -14px rgba(60, 48, 30, .28);
}

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

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

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 800;
  /* Inter is drawn to be tracked in at display sizes; left at its
     default it reads loose and a touch soft, which is the opposite of
     what the headings are for here. */
  letter-spacing: -.022em;
  line-height: 1.18;
  margin: 0;
  color: var(--ink);
}

a { color: inherit; }

.wrap { width: min(100% - var(--gutter) * 2, var(--wrap)); margin: 0 auto; }

/* Interior pages - anything with a .phead at the top - read as a
   column rather than spreading across the whole window. The masthead
   and the footer keep the full shell width; only what you read
   narrows. The home page has no .phead, so it is untouched. */
.phead .wrap,
.phead ~ section > .wrap { max-width: var(--wrap-read); }

section { padding: 46px 0; }
section.alt { background: var(--paper); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }

.h2 { font-size: clamp(22px, 2.4vw, 29px); }
.sub { color: var(--ink-soft); margin: 8px 0 26px; max-width: 62ch; font-size: 16px; }

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--invert-bg); color: var(--invert-fg); padding: 10px 16px; z-index: 50;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip:focus { left: 0; }

:where(a, button, input, textarea, [tabindex]):focus-visible {
  outline: 3px solid var(--sky);
  outline-offset: 2px;
  border-radius: 4px;
}

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

/* The masthead spans the window rather than the 1140px column the
   rest of the page uses - fourteen category names need the room, and
   a menu that stops short of the edges reads as a narrower site. */
.hdr {
  background: var(--header-bg);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 30;
}
/* Two bands: the name and the theme switch on one line, the menu
   centred on its own below. Right-aligning fourteen items against the
   logo left a ragged first row that started halfway across the page. */
/* Name left, toggle right, menu filling and centring the space
   between them. It wraps to two rows inside that middle column rather
   than dropping to a band of its own. */
.hdr__row {
  display: grid;
  grid-template-columns: minmax(150px, auto) minmax(0, 1fr) minmax(150px, auto);
  align-items: center;
  gap: 10px 24px;
  padding-top: 14px; padding-bottom: 14px;
}
.hdr__brand { grid-column: 1; justify-self: start; }
.hdr__links { grid-column: 2; }
.hdr__tools { grid-column: 3; justify-self: end; }

.hdr__logo { display: inline-flex; align-items: center; text-decoration: none; }
.hdr__word {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 21px;
  letter-spacing: -.025em;
  letter-spacing: -.025em;
  color: var(--ink);
  white-space: nowrap;
}
/* The one piece of brand left in the header. A thin space keeps the
   two words readable as two words without a gap wide enough to look
   like a mistake. */
.hdr__word2 { color: var(--brand); margin-left: .22em; }
.hdr__logo:hover .hdr__word2 { color: var(--brand-dark); }

/* Fourteen full names will not sit on one line and are not meant to -
   they wrap to two rows, right-aligned, as they did on the original. */
.hdr__links {
  display: flex; flex-direction: column; align-items: center;
  gap: 2px;
}
/* Each rank is its own centred line. They still wrap if the window is
   narrower than one rank, which is the right failure: more rows, never
   a horizontal scrollbar. */
.hdr__rank {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 2px 6px;
}
.hdr__links a {
  text-decoration: none;
  color: var(--ink-soft);
  font-weight: 600;
  font-size: 13.5px;
  padding: 5px 9px;
  border-radius: var(--radius);
  white-space: nowrap;
}
.hdr__links a:hover { background: var(--brand-wash); color: var(--brand-dark); }
.hdr__links a.is-all { color: var(--ink); font-weight: 700; }

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

/* The hero and the suggestion block both sit on the container photo,
   the way the foot of every page did on the Squarespace site. The
   image is a background rather than an <img> because it is decoration:
   nothing is lost if it never loads, and the overlay below guarantees
   the text stays readable whether it arrives or not. */
.shot {
  position: relative;
  background: var(--cream);
  isolation: isolate;
}
.shot::before {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background: url('/assets/images/band-suggest.jpg') center/cover no-repeat;
  opacity: .20;
}
.shot::after {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--cream) 55%, transparent),
    color-mix(in srgb, var(--cream) 88%, transparent));
}
:root[data-theme="light"] .shot::before { opacity: .11; }

/* Covers the hero so a click on empty space re-selects "none".
   Sits above the photo layers (-1) and below the content (1), so
   it never swallows a click meant for the search box or an
   option. Not focusable; the radio itself carries the label. */
.hero__clear { position: absolute; inset: 0; z-index: 0; cursor: default; }
.hero > .wrap { position: relative; z-index: 1; }
/* The wrap is a full-width block, so on its own it paints over the
   label and eats every click in the hero except the two gutters down
   the sides - the clear only appeared to work because that is where a
   stray click happened to land. Making the wrap transparent to the
   pointer and handing it back to each child means the words, the
   search box and the four options take their own clicks, and the empty
   space between and around them falls through to the label. */
.hero > .wrap { pointer-events: none; }
.hero > .wrap > * { pointer-events: auto; }
/* Same again one level down: the gaps between the four options are
   part of "not an option". */
.hero .pills { pointer-events: none; }
.hero .pills label { pointer-events: auto; }

.hero {
  padding: 66px 0 56px;
  text-align: center;
  border-bottom: 1px solid var(--line);
  /* Flat. The solid menu strip above it and the rule below it are
     the edges of this block; a gradient as well would be a third
     thing saying the same. */
  background: var(--cream);
  /* position for .hero__clear, which is inset:0 against this; z-index
     so the whole block sits above the sections that follow it in the
     DOM rather than being painted over by them. */
  position: relative;
  z-index: 20;
}
.hero h1 { font-size: clamp(30px, 5vw, 50px); max-width: 20ch; margin: 0 auto; }
.hero > .wrap > p {
  color: var(--ink-soft);
  font-size: clamp(15px, 1.4vw, 17px);
  max-width: 56ch;
  margin: 12px auto 24px;
}

/* Capped and centred. Without this it stretches the whole 1680
   shell, which reads as a page-wide bar rather than a search box. */
.search { position: relative; max-width: 760px; margin: 0 auto; }
.search svg {
  position: absolute; left: 20px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; color: var(--muted); pointer-events: none;
}
.search input {
  width: 100%;
  font: inherit;
  font-size: 17px;
  padding: 17px 20px 17px 52px;
  border: 2px solid var(--line-firm);
  border-radius: var(--radius);
  /* Solid, not a tint. Over a photograph a translucent field reads as
     decoration; this has to read as the thing to type in. */
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 2px 6px rgba(0,0,0,.22), 0 18px 40px -18px rgba(0,0,0,.55);
}
.search input::placeholder { color: var(--muted); }
.search input:focus { outline: none; border-color: var(--brand); box-shadow: var(--shadow-lift); }
.search__hint {
  color: var(--muted); font-size: 12.5px; margin: 18px 0 0;
  opacity: .8;
}

/* ---------------- search results ---------------- */

#results { display: none; padding-top: 32px; }
body.searching #results { display: block; }
body.searching #browse { display: none; }
/* The four pills and the prompt belong to the browse state, not the
   results state - leaving them up while results show is confusing. */
body.searching .pills, body.searching .hero__ask { display: none; }

.rescount { color: var(--ink-soft); font-weight: 700; margin: 0 0 16px; font-family: var(--font-display); }

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

.tools { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
@media (min-width: 720px) { .tools { grid-template-columns: 1fr 1fr; } }

.tool a {
  display: flex; align-items: center; gap: 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 13px 15px;
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(38, 34, 32, .04);
  transition: border-color .14s, box-shadow .14s, transform .14s;
}
.tool a:hover {
  border-color: var(--brand);
  box-shadow: var(--shadow-lift);
  transform: translateY(-1px);
}
.tool__txt { flex: 1; min-width: 0; display: block; }
.tool__cat {
  display: inline-block;
  font-size: 11px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  color: var(--brand-dark); background: var(--brand-wash);
  padding: 2px 8px; border-radius: var(--radius); margin-bottom: 5px;
}
.tool__name { display: block; font-weight: 700; color: var(--ink); line-height: 1.3; }
.tool__host {
  display: block; font-size: 13px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tool a svg { width: 18px; height: 18px; color: var(--muted); flex: none; }
.tool a:hover svg { color: var(--brand); }

.tool--broken a { border-style: dashed; border-color: var(--line-firm); background: var(--cream-deep); }
.tool__warn { display: block; font-size: 12.5px; color: var(--brand-dark); margin-top: 4px; line-height: 1.4; }

/* ---------------- category grid ---------------- */

.grid {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 14px;
}
.grid > .cat {
  flex: 0 1 calc((100% - 42px) / 4);  /* three 14px gaps between four */
}
/* The basis is a quarter of the row, and the tiles do not grow - that
   is what keeps a two-tile band the same size as a four-tile one. It
   also means they cannot fill a narrow screen on their own, so the
   basis steps down rather than being propped up by a min-width, which
   just left a 240px card sitting in a 320px column. */
@media (max-width: 980px) { .grid > .cat { flex-basis: calc((100% - 14px) / 2); } }
@media (max-width: 560px) { .grid > .cat { flex-basis: 100%; } }

/* One band per job. The heading is small and quiet on purpose: it is
   a label on a shelf, not a section title competing with the tiles
   underneath it. */
.band { max-width: var(--wrap-read); margin-inline: auto; }
/* Closed until a job is picked, and every tile inside it closed until
   that job claims it. .cat is a flex column, so revealing one is
   display:flex and not display:block. */
.band--start,
.band--start .cat { display: none; }
.band + .band { margin-top: 30px; }
.band__h {
  text-align: center;
  font-size: 12px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
  /* No rule under it. The space and the tiles starting is enough of a
     break; the only divider left on the page is the one closing the
     masthead. */
  margin: 0 0 13px;
}

.cat {
  /* A column so the count can be pushed to the foot of the card.
     Grid rows already stretch every card to the tallest in the row,
     so that puts a whole row of counts on one line however long the
     descriptions above them run. */
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
  transition: border-color .14s, box-shadow .14s, transform .14s;
}
.cat:hover { border-color: var(--brand); box-shadow: var(--shadow-lift); transform: translateY(-2px); }

/* The photograph, with the name over it. A 4:3 crop rather than the
   old square - squares stacked four across made the page very tall
   before a single tool was visible. */
.cat__shot {
  display: block; position: relative;
  aspect-ratio: 2.6 / 1;
  background: var(--cream-deep);
  overflow: hidden;
}
.cat__shot img {
  display: block; width: 100%; height: 100%;
  object-fit: cover;
  /* Faded hard, so fourteen photographs read as one calm grid instead
     of fourteen competing pictures. The name is the thing to see. */
  opacity: .42;
  transition: transform .4s ease, opacity .25s ease;
}
.cat:hover .cat__shot img { opacity: .6; }
.cat:hover .cat__shot img { transform: scale(1.04); }

/* A scrim, not a box. The old artwork drew a thin rectangle inset
   from the edges; this is a gradient from the bottom so the name sits
   on darkness without anything being outlined. */
/* Centred, on an even wash rather than a bottom-up gradient - with
   the photo this faded a directional scrim just looks like a smudge. */
.cat__label {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 10px;
  background: rgba(0, 0, 0, .32);
}
.cat__label span {
  font-family: var(--font-display); font-weight: 800;
  font-size: 15px; line-height: 1.25; text-align: center;
  letter-spacing: .02em; color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .65);
}

.cat__meta {
  display: flex; align-items: flex-start; gap: 10px; justify-content: space-between;
  padding: 10px 12px 11px;
  flex: 1;
}
.cat__blurb { color: var(--ink-soft); font-size: 13px; line-height: 1.42; }
.cat__n {
  flex: none;
  font-family: var(--font-display); font-weight: 800; font-size: 13px;
  color: var(--brand); background: var(--brand-wash);
  padding: 2px 9px; font-size: 12px; border-radius: var(--radius);
}

/* ---------------- chips ---------------- */

.chips { list-style: none; display: flex; flex-wrap: wrap; gap: 7px; margin: 0 0 26px; padding: 0; }
.chips a {
  display: block; text-decoration: none;
  font-size: 13.5px; font-weight: 700;
  padding: 7px 13px; border-radius: var(--radius);
  background: var(--paper); border: 1px solid var(--line); color: var(--ink-soft);
}
.chips a:hover { border-color: var(--brand); color: var(--brand-dark); }
.chips a[aria-current="page"] { background: var(--invert-bg); border-color: var(--invert-bg); color: var(--invert-fg); }

/* ---------------- page headers ---------------- */

.phead {
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  padding: 34px 0 30px;
}
.phead h1 { font-size: clamp(26px, 3.4vw, 38px); max-width: 24ch; }
.crumb { font-size: 13.5px; color: var(--muted); margin: 0 0 12px; font-weight: 600; }
.crumb a { color: var(--brand-dark); text-decoration: none; }
.crumb a:hover { text-decoration: underline; }

.phead--post h1 { font-size: clamp(23px, 2.5vw, 31px); line-height: 1.22; max-width: 860px; }

/* ---------------- article ---------------- */

.article { max-width: 72ch; }
.article p, .article ul, .article ol { color: var(--ink-soft); }
.article h4 { font-size: 18px; margin: 28px 0 8px; color: var(--ink); }
.article a { color: var(--brand-dark); }
.article blockquote {
  margin: 20px 0; padding: 2px 0 2px 18px;
  border-left: 3px solid var(--sun); color: var(--ink-soft);
}

.stale {
  background: var(--sun-wash);
  border: 1px solid var(--sun);
  border-radius: var(--radius);
  padding: 13px 16px;
  font-size: 14.5px;
  color: var(--ink);
  margin: 0 0 24px;
}

/* ---------------- form ---------------- */

/* The suggestion block is centred: it is the one place on the page
   asking the reader for something, and left-aligned in a 1480px
   column it drifted away from the eye. */
#suggest { text-align: center; }
#suggest .sub { margin-left: auto; margin-right: auto; }
#suggest .formsay { text-align: center; }

.form { max-width: 560px; margin: 0 auto; text-align: left; }
.form label { display: block; font-weight: 700; font-size: 14.5px; margin: 14px 0 6px; }
.form textarea, .form input {
  width: 100%; font: inherit; color: var(--ink);
  padding: 12px 14px;
  border: 2px solid var(--line-firm); border-radius: var(--radius);
  background: var(--paper);
}
.form textarea { min-height: 112px; resize: vertical; }
.form textarea:focus, .form input:focus { outline: none; border-color: var(--brand); }

.btn {
  display: inline-block; margin-top: 18px;
  font-family: var(--font-display); font-weight: 800; font-size: 16px;
  color: #fff; background: var(--brand);
  border: 0; border-radius: var(--radius); padding: 13px 26px; cursor: pointer;
  box-shadow: var(--shadow);
}
.btn:hover { background: var(--brand-dark); }
.btn[disabled] { opacity: .55; cursor: default; }

/* The honeypot. Positioned off-screen rather than display:none or
   hidden, because some bots skip those and fill anything else. Not
   .vh, which is for things a screen reader SHOULD read; this one is
   aria-hidden and tabindex -1, so nothing human meets it. */
.trap {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}

.formsay { margin: 14px 0 0; font-weight: 600; font-size: 15px; min-height: 1.4em; }
.formsay a { color: var(--brand-dark); }

/* The band at the foot of the page runs down the middle: heading, lede,
   labels and button all on the same centre line. The fields are the one
   exception - text typed into a centred textarea crawls out from the
   middle in both directions, which is horrible to read back. */
#suggest .form { text-align: center; }
#suggest .form textarea,
#suggest .form input { text-align: left; }


/* ---------------- footer ---------------- */

.ftr {
  background: var(--paper);
  border-top: 1px solid var(--line);
  padding: 20px 0 22px;
  font-size: 14px;
}
/* Links and small print share a row on anything wider than a phone,
   which halves the height of the foot of the page. */
.ftr .wrap {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 8px 28px; justify-content: space-between;
}
.ftr__links {
  display: flex; flex-wrap: wrap; gap: 6px 20px;
  flex: none;
  /* Last in the row, so a second line of links stays against the
     right edge instead of hanging off the left of its own column.
     space-between on the parent only separates items that SHARE a
     line - once the small print is long enough to push the links onto
     a line of their own they are the only item on it, and a lone item
     sits at the start. The auto margin is what holds them right in
     both cases. justify-content handles the links wrapping internally. */
  margin-left: auto;
  justify-content: flex-end;
}
.ftr__links a { color: var(--ink-soft); text-decoration: none; font-weight: 700; }
.ftr__links a:hover { color: var(--brand); text-decoration: underline; }

.ftr__fine p { margin: 0; }
.ftr__fine p + p { margin-top: 5px; }
.ftr__count { opacity: .8; }
/* The credit has to read as a link against small grey print. */
.ftr__count a { color: var(--ink-soft); text-decoration: underline; text-underline-offset: 2px; }
.ftr__count a:hover { color: var(--brand); }
.ftr__fine {
  margin: 0;
  color: var(--muted); font-size: 12.5px; line-height: 1.5;
  flex: 1 1 760px; min-width: 0;
  text-align: left;
}
@media (max-width: 700px) {
  /* Stacked, so the alignment that separated the two columns on a wide
     screen now just looks like a mistake. Both blocks go left and the
     rule between them moves to whichever one is underneath. */
  .ftr .wrap { display: block; }
  .ftr__links {
    margin-top: 14px; padding-top: 14px;
    border-top: 1px solid var(--line);
    justify-content: flex-start;
  }
}

/* ---------------- small screens ---------------- */

/* Only ever a phone control: on anything wider the fourteen names
   are the menu and there is nothing to open. */
.burger { display: none; }

@media (max-width: 760px) {
  .burger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; margin-left: 8px;
    border: 1px solid var(--line-firm); border-radius: var(--radius);
    color: var(--ink-soft); cursor: pointer;
  }
  .burger svg { width: 20px; height: 20px; }
  /* One button, two glyphs: whichever one is not the current state is
     hidden, so the control says what the next tap does. */
  .burger__x, #navtoggle:checked ~ .hdr__tools .burger svg { display: none; }
  #navtoggle:checked ~ .hdr__tools .burger .burger__x { display: block; }
  #navtoggle:checked ~ .hdr__links { display: flex; }

  /* Fourteen full category names stack to about 390px on a phone -
     half the viewport. Sticky would mean the menu permanently covering
     half the screen, so below this width the header scrolls away like
     anything else. Measured, not guessed. */
  .hdr { position: static; }
  /* The three-column header squeezes the menu into a middle column
     about 70px wide here, which wrapped it to 437px tall. Name and
     toggle share a row, menu gets the full width beneath. */
  .hdr__row { grid-template-columns: 1fr auto; }
  .hdr__brand { grid-column: 1; }
  .hdr__tools { grid-column: 2; }
  .hdr__links { grid-column: 1 / -1; grid-row: 2; display: none; }
  .hdr__row { flex-wrap: wrap; min-height: 0; padding-top: 12px; padding-bottom: 12px; gap: 8px; }
  .hdr__links { width: 100%; max-width: none; justify-content: flex-start; gap: 1px; }
  .hdr__links a { padding: 5px 7px; font-size: 12.5px; }
  section { padding: 34px 0; }
  .hero { padding: 40px 0 36px; }
}

@media (max-width: 430px) {
  body { font-size: 16px; }
  .hdr__word { font-size: 18px; }
  .search input { padding: 14px 16px 14px 46px; font-size: 16px; }
  .search svg { left: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .tool a:hover, .cat:hover { transform: none; }
}

/* ---------------- theme toggle ---------------- */

.themer {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  background: transparent;
  border: 1px solid var(--line-firm);
  border-radius: 999px;
  color: var(--ink-soft);
  cursor: pointer;
}
.themer:hover { border-color: var(--brand); color: var(--brand); }
.themer svg { width: 17px; height: 17px; }

/* Dark is the base, so the button shows a sun (press for light) by
   default, and a moon only once light has been chosen. */
.themer .i-sun { display: block; }
.themer .i-moon { display: none; }
:root[data-theme="light"] .themer .i-sun { display: none; }
:root[data-theme="light"] .themer .i-moon { display: block; }

/* The hero wash is built from accent tints and reads better screened
   over the dark ground; on light it stacks normally. */
.hero { background-blend-mode: screen; }
:root[data-theme="light"] .hero { background-blend-mode: normal; }

/* ---------------- pieces the rewrite dropped ----------------
   These classes are emitted by the generator and lost their rules when
   the stylesheet was rebuilt from scratch, so they were rendering
   unstyled - the prev/next pager in particular sat flush against the
   last tool with no gap at all. Found by diffing every class in the
   built HTML against the stylesheet. */

.seealso {
  margin: 30px 0 0; font-size: 14.5px; color: var(--ink-soft);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
}
.seealso a {
  color: var(--brand); text-decoration: none; font-weight: 700;
  padding: 4px 11px; border-radius: var(--radius);
  border: 1px solid var(--line-firm);
}
.seealso a:hover { border-color: var(--brand); }

.pager {
  display: flex; justify-content: space-between; gap: 16px;
  margin-top: 34px; padding-top: 22px;
  border-top: 1px solid var(--line);
  font-weight: 700; font-size: 15px;
}
.pager a { color: var(--brand); text-decoration: none; }
.pager a:hover { color: var(--brand-dark); text-decoration: underline; }
.pager span:last-child { text-align: right; }

.posts { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.post a {
  display: block;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 15px 17px;
  text-decoration: none;
  transition: border-color .14s, box-shadow .14s;
}
.post a:hover { border-color: var(--brand); box-shadow: var(--shadow-lift); }
.post time {
  display: block; font-size: 12.5px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--brand);
  margin-bottom: 5px;
}
.post h3 { font-size: 17px; line-height: 1.35; color: var(--ink); }

.search__ico {
  position: absolute; left: 20px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; color: var(--muted); pointer-events: none;
}
.tool__go { width: 18px; height: 18px; color: var(--muted); flex: none; }
.tool a:hover .tool__go { color: var(--brand); }

/* Visually hidden, but still focusable and still read aloud. Used by
   the radios behind the hero options and by the headings that sit
   under the category photographs. */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* ---------------- diary, grouped by year ---------------- */

.diary__year + .diary__year { margin-top: 34px; }
.diary__yh {
  display: flex; align-items: baseline; gap: 12px;
  font-size: 15px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-soft);
  padding-bottom: 10px; margin-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.diary__yh span {
  font-family: var(--font); font-size: 12.5px; font-weight: 600;
  letter-spacing: 0; text-transform: none; color: var(--muted);
}

/* ---------------- the four starting points, in the hero ---------------- */

/* Sits with the options it introduces, not with the search box
   above - it was reading as a caption on the wrong element. */
/* Needs to outrank `.hero > .wrap > p`, which also matches this
   paragraph and was overriding both its size and its spacing - the
   prompt was rendering at lede size and sitting with the search box. */
.hero > .wrap > p.hero__ask {
  color: var(--ink-soft); font-size: 16px; font-weight: 600;
  /* auto on the sides, not 0 - the rule this overrides centres the
     paragraph with margin:auto and a 56ch cap, so a bare 0 shunted it
     to the left edge. */
  margin: 30px auto 9px; letter-spacing: .02em;
}
/* Equal columns, not flex-wrap: four labels of different lengths left
   ragged widths that read as four unrelated buttons. */
.pills {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 9px; max-width: 920px; margin: 0 auto;
}
@media (max-width: 860px) { .pills { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 460px) { .pills { grid-template-columns: 1fr; } }
.pills label {
  cursor: pointer; display: block; text-align: center;
  background: var(--paper);
  border: 2px solid var(--line-firm);
  border-radius: var(--radius);
  padding: 13px 16px;
  box-shadow: 0 1px 3px rgba(0,0,0,.2);
  transition: border-color .14s, background .14s;
}
.pills label:hover { border-color: var(--brand); }
.pills strong {
  display: block; font-family: var(--font-display); font-weight: 800;
  font-size: 15px; color: var(--ink);
}

/* The selected pill, and the panel it reveals. The radios are the
   first children of <main>, so ~ reaches both the hero and #browse. */
#who-0:checked ~ .hero .pills label:nth-of-type(1),
#who-1:checked ~ .hero .pills label:nth-of-type(2),
#who-2:checked ~ .hero .pills label:nth-of-type(3),
#who-3:checked ~ .hero .pills label:nth-of-type(4) {
  border-color: var(--brand);
  background: var(--brand-wash);
}
#who-0:focus-visible ~ .hero .pills label:nth-of-type(1),
#who-1:focus-visible ~ .hero .pills label:nth-of-type(2),
#who-2:focus-visible ~ .hero .pills label:nth-of-type(3),
#who-3:focus-visible ~ .hero .pills label:nth-of-type(4) {
  outline: 3px solid var(--sky); outline-offset: 2px;
}

/* Every category stays on the page; the ones matching the chosen job
   are lit. --lit is set to 1 by the generated selectors in the page's
   own <style>, which are built from the same data as the roles, so a
   category moving between jobs needs no edit here. */
.cat { position: relative; }


