/* ============================================================================
   THE BOOKING FLOW — THE TITLE BLOCK
   Loaded on /order-online only. Tokens come from site.css.

   THE PROBLEM THIS SOLVES, in the owner's words: "it's honestly just words down
   a page. doesn't even look like a form."

   So the governing requirement is that a field reads as a FIELD on first paint,
   before anybody types anything and before any focus state exists. On a page
   with no color that is harder than it sounds: the usual answers are a blue
   border and a blue focus ring, and this site's rule is that color lives only
   inside a photograph. The answer is TONE, not hue. An empty field is a gray
   slab sitting in white space, which reads as a hole to be filled from across
   the room. Filling it turns it white and strikes a tick in the margin, so the
   page gets visibly lighter as the form gets more complete.

   The rest inherits site.css's governing rule: nothing is enclosed. No cards,
   no radius, no shadow. Rank comes from weight, scale and rule-work. The one
   rectangle permitted is a drafting instrument, and the stamp on the
   confirmation screen is the one rotated thing anywhere on this site.
   ============================================================================ */

/* THE CHECKOUT USES THE SHEET'S WIDTH. At 720px the guide's two columns had to
   share a measure meant for one, so the fleet panel's dimension lines wrapped and
   the whole thing read cramped. The screens that are a table, a picker or a
   walkthrough want the room; only the ones that are a column of text inputs do
   not, and those cap themselves below. */
.shell--book { max-width: 1080px; margin: 0 auto; padding: 0 var(--gutter); }
/* A text input has a comfortable width and 1040px is not it. The steps that are
   genuinely a form keep a form's measure inside the wider sheet. */
.bookform { max-width: 620px; }
/* WHERE A STEP OPENS (#780). On a phone the step list sits just above the step, so the gap
   leaves it in view; on a wide screen the list is in the left column and needs no room. */
.book__step { scroll-margin-top: 56px; }
@media (min-width: 1024px) { .book__step { scroll-margin-top: 24px; } }
.band--book  { padding-block: 28px 64px; }

.book__h1 {
  font-stretch: 62%; font-weight: 900; text-transform: uppercase;
  font-size: clamp(38px, 11vw, 64px); line-height: .94; letter-spacing: -.01em;
  /* site.css sets word-spacing on display headings because the condensed axis
     eats the word space down to 0.07em. Two words here, so it matters. */
  word-spacing: .16em;
  margin: 0 0 14px;
}

/* The promise, above the first field rather than under the last one. Somebody
   deciding whether to start needs to know how it ends before they type. */
/* A NOTE ON A DRAWING SHEET IS RULED OFF AND LABELED, not bracketed by a thick bar
   down its left edge. Same change already made to .scale__note on the public sheet, so
   the two read as one annotation language rather than two. */
.book__promise {
  font-size: 15px; line-height: 1.5; color: var(--mid);
  border-top: 1px solid var(--rule); padding-top: 10px;
  margin: 0 0 26px; max-width: 54ch;
}
.book__promise::before, .book__note::before, .bookform__note::before,
.rec__hedge::before, .rec__up::before {
  content: 'Note'; display: block; margin-bottom: 4px;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--mid-dark);
}
.book__callout { display: block; margin-top: 6px; font-weight: 700; color: var(--ink); }

/* ------------------------------------------------------------ wayfinding -- */
/* Named steps, not a percentage. "Step 2 of 4" says how much is left and never
   what it is; "Size" says both, in the same space. */
.steps__list {
  display: flex; gap: 0; list-style: none; margin: 0 0 30px; padding: 0;
  border-top: 2px solid var(--ink); border-bottom: 1px solid var(--rule);
}
.steps__item {
  flex: 1 1 0; display: flex; align-items: baseline; gap: 6px;
  padding: 9px 8px 8px; font-family: var(--mono); font-size: var(--label);
  text-transform: uppercase; letter-spacing: .06em; color: var(--mid);
  border-right: 1px solid var(--rule);
}
.steps__item:last-child { border-right: 0; }
.steps__n { font-weight: 700; }
.steps__item.is-done { color: var(--ink); }
/* The current step is the only filled cell, so position is legible at a glance
   rather than by reading four labels and finding the bold one. */
.steps__item.is-now { background: var(--ink); color: var(--paper); font-weight: 700; }
.steps__label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ------------------------------------------------------------- the field -- */
.fld { margin: 0 0 22px; }
.fld__label {
  display: block; font-family: var(--mono); font-size: var(--label);
  text-transform: uppercase; letter-spacing: .07em; font-weight: 700;
  margin-bottom: 6px;
}
.fld__opt {
  margin-left: 8px; font-weight: 400; letter-spacing: .05em;
  text-transform: none; color: var(--mid);
}
/* The hint sits ABOVE the input, not below it. Below, it is read after the
   answer has already been typed, which is too late to be a hint. */
/* NO MEASURE ON A HINT. Under the field now, so the margin is above it rather than below,
   and it takes the width of the field it belongs to.

   THE 50-75 CHARACTER RULE IS FOR RUNNING PROSE, and I had been applying it to everything
   with words in it. Measured: this hint is 70 characters, rendered 413px wide in a column
   with 611px available, wrapping to two lines and throwing away 198px. A one-sentence
   note attached to a control is read once, in place, as part of that control. Its width
   is the control's width. A reading measure only earns its keep when someone has several
   lines to track back across. */
.fld__hint { margin: 8px 0 0; font-size: 15px; line-height: 1.45; color: var(--mid); }

/* The tick gutter is ALWAYS reserved, filled or not, so a field does not shift
   sideways the instant it is completed. */
.fld__box { position: relative; padding-right: 22px; }

.fld__input {
  width: 100%; min-height: 56px; padding: 12px 14px;
  font-family: var(--sans); font-size: 17px; font-weight: 500; color: var(--ink);
  /* 17px, not 16px. iOS Safari zooms the whole page on focus at anything under
     16px, and 16px exactly is close enough to the threshold to be worth not
     testing the edge of. */
  background: #efefef; border: 0; border-bottom: 2px solid var(--ink);
  border-radius: 0; appearance: none;
}
.fld__input--area { min-height: 96px; line-height: 1.5; resize: vertical; }

/* FILLED IS WHITE. The page lightens as it is completed, which is the progress
   indicator that costs no vertical space. */
.fld--filled .fld__input { background: var(--paper); border-bottom-color: var(--ink); }
/* NOT ON A FIELD THAT IS WRONG. `.fld--filled` means "has a value" and `.fld--bad` means "that
   value is not acceptable", and an invalid field is usually both — so the tick rendered 42px above
   "Please enter a valid email address." on the very field the page was rejecting. Measured on the
   deployed form, not reasoned about: the email input came back as `fld fld--bad fld--filled`. */
.fld--filled:not(.fld--bad) .fld__tick { opacity: 1; }

.fld__tick {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  font-size: 14px; line-height: 1; opacity: 0; transition: opacity 120ms linear;
}

/* Focus is a bar struck down the left edge, INSIDE the field, so it reads on
   the gray and on the white without a color and without a glow. The global
   :focus-visible outline still applies and is not fought. */
.fld__input:focus { outline: none; box-shadow: inset 4px 0 0 0 var(--ink); background: var(--paper); }
.fld__input:focus-visible { outline: 2.5px solid var(--ink); outline-offset: 2px; }

/* ERRORS WITHOUT RED. Red is not in this palette and inventing one for errors
   would break the rule that color comes only from photography — and red alone
   fails anyone who cannot see it anyway. A dashed rule is the answer because
   nothing else on this site is dashed, it survives grayscale, it survives
   forced-colors mode, and on a drawing a dashed line already means "not final". */
/* THE INVALID FIELD KEEPS ITS FILL. An input on this sheet is a gray block with a dark
   underline; forcing it white left an empty field with no border but the dashed one, so on a
   white page the one box the visitor has to go back and fix was the only one they could not
   see. The dashed underline is the error signal and it is enough on its own. */
.fld--bad .fld__input { border-bottom: 4px dashed var(--ink); }
/* NO SECOND MARKER. The field above is already carrying the error, as a 4px dashed
   underline, and the comment on that rule explains why dashed is this sheet's word for
   "not final". Repeating the message with an accent bar down the text says the same
   thing twice in two different visual languages, and the bar is the one that reads as
   generated UI. Bold ink under a dashed field is unambiguous on its own. */
.fld__err {
  margin: 7px 0 0; font-size: 15px; font-weight: 700; color: var(--ink);
}

/* The honeypot. Off-screen rather than display:none, because some bots skip
   what is hidden, and it must never be reachable by keyboard or announced. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --------------------------------------------------------------- errors --- */
/* NOT A BOX, AND NOT A 10px ACCENT RAIL. DESIGN.md's governing rule is that nothing on
   this site is enclosed, and the thick left edge was the clearest generated-UI tell in
   the checkout. The dashed rule is the same word the invalid fields below it use, at the
   summary's scale, so the error language is one language at two sizes. */
.book__errors {
  border-top: 4px dashed var(--ink);
  padding: 12px 0 0; margin: 0 0 26px;
}
.book__errors-t {
  margin: 0 0 6px; font-family: var(--mono); font-size: var(--label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em;
}
.book__errors ul { margin: 0; padding-left: 18px; font-size: 15px; }
.book__errors a  { font-weight: 700; }

.book__note, .bookform__note {
  border-top: 1px solid var(--rule); padding-top: 10px;
  margin: 0 0 22px; font-size: 15.5px; line-height: 1.5; color: var(--mid); max-width: 56ch;
}
.bookform__ok {
  margin: -12px 0 22px; font-family: var(--mono); font-size: var(--label);
  text-transform: uppercase; letter-spacing: .06em; font-weight: 700;
}
.bookform__ok::before { content: '\2713\00a0'; }

/* ----------------------------------------------------------------- forms -- */
.bookform__t {
  font-stretch: 70%; font-weight: 900; text-transform: uppercase;
  font-size: clamp(19px, 4.6vw, 24px); letter-spacing: .01em;
  margin: 34px 0 4px; padding-top: 12px; border-top: 2px solid var(--ink);
}
.bookform__t:first-of-type { margin-top: 0; }
/* Same reasoning: this line is a date and a ZIP code being read back, not a label. */
.bookform__for {
  font-family: var(--mono); font-size: var(--label); color: var(--mid);
  letter-spacing: .02em; margin: 0 0 22px;
}
.bookform__edit, .review__edit, .bookform__for a { margin-left: 10px; font-weight: 700; color: var(--ink); }

.bookform__go { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 30px; }
.btn--big { min-height: 60px; flex: 1 1 auto; font-size: 16px; }

/* ------------------------------------------------------------- the fork --- */
.fork { display: grid; gap: 0; border-top: 2px solid var(--ink); margin-bottom: 40px; }
.fork__card {
  display: block; padding: 20px 0; border-bottom: 1px solid var(--rule);
  text-decoration: none;
}
/* THE SHIFT IS A TRANSFORM ON THE TEXT, NOT A PADDING ON THE ROW. Animating padding
   relaid out the card on every frame of the hover. Translating the whole row instead
   would carry its bottom rule 10px right and break the ruled stack, so only the two
   spans move, and they move on the compositor. Same fix as .doors__d on the home page. */
.fork__k, .fork__d { transition: transform 120ms ease-out; }
.fork__card:hover :is(.fork__k, .fork__d) { transform: translateX(10px); }
.fork__k {
  display: flex; align-items: baseline; gap: 12px;
  font-stretch: 70%; font-weight: 900; text-transform: uppercase;
  font-size: clamp(21px, 5.4vw, 28px); line-height: 1.1;
}
/* The mark that says the row is a control. It leads the hover rather than following it,
   so the row reads as going somewhere before the text has finished moving. */
.fork__go {
  margin-left: auto; font-size: .8em; color: var(--mid);
  transition: transform 120ms ease-out;
}
.fork__card:hover .fork__go { transform: translateX(6px); color: var(--ink); }
.fork__card--go:hover .fork__go { color: var(--go); }
.fork__d { display: block; margin-top: 5px; font-size: 15px; color: var(--mid); }
/* The one colored mark on the screen, on the one action we want most. */
.fork__card--go .fork__k { color: var(--go); }

/* THE SPACING LIVES ON THE BLOCK, NOT ON THE GRID RULE THAT USED TO PLACE IT. It was a
   margin-top on the `grid-column: 1` exception, so moving the block into the aside took
   its separation with it and the heading butted straight into the phone line above. */
.fork__fleet { margin-top: 26px; padding-top: 10px; border-top: 1px solid var(--rule); }
.fork__fleet-t {
  font-family: var(--mono); font-size: var(--label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; margin: 0 0 10px;
  color: var(--mid-dark);
}
.fleetlist { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.fleetlist__i a {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 14px; align-items: baseline;
  padding: 13px 0; border-bottom: 1px solid var(--rule); text-decoration: none;
}
.fleetlist__i b { font-stretch: 76%; font-weight: 800; font-size: 17px; }
.fleetlist__p { font-family: var(--mono); font-weight: 700; font-size: 15px; text-align: right; }
.fleetlist__d, .fleetlist__s {
  grid-column: 1 / -1; font-size: 15px; color: var(--mid); line-height: 1.4;
}
.fleetlist__d { font-family: var(--mono); font-size: var(--label); }

/* ------------------------------------------------------------ questions --- */
/* THE GUIDE IS A WALKTHROUGH. Question on the left, the fleet standing beside it
   the whole way on the right, so the visitor learns what a 20 yard IS while they
   answer rather than being handed one at the end. */
.guide { display: grid; gap: 34px; }
.guide__count {
  margin: 0 0 4px; font-family: var(--mono); font-size: var(--label);
  text-transform: uppercase; letter-spacing: .1em; color: var(--mid);
}
.guide__form { min-width: 0; }

.qs { border: 0; padding: 0; margin: 0; min-width: 0; }
.qs__q {
  padding: 0; font-stretch: 64%; font-weight: 900; text-transform: uppercase;
  font-size: clamp(26px, 6.4vw, 40px); line-height: 1.02; word-spacing: .14em;
  margin-bottom: 8px;
}
.qs__note { margin: 0 0 20px; font-size: 15px; line-height: 1.5; color: var(--mid); }
.qs__grid { display: grid; gap: 0; border-top: 2px solid var(--ink); }
.qs__card {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 16px 40px 17px 0; font-family: var(--sans); color: var(--ink);
  background: var(--paper); border: 0; border-bottom: 1px solid var(--rule); position: relative;
}
.qs__card::after {
  content: '\2192'; position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  font-size: 20px; transition: transform 130ms ease-out;
}
.qs__card:hover { background: #efefef; }
.qs__card:hover::after { transform: translateY(-50%) translateX(5px); }
.qs__card--unsure .qs__label { color: var(--mid); }
.qs__label { display: block; font-size: 17px; font-weight: 700; font-stretch: 88%; line-height: 1.25; }
/* The guidance line. This is the difference between a quiz and a guide: every option
   says what it means before it is chosen. */
.qs__hint  { display: block; margin-top: 4px; font-size: 15px; line-height: 1.45; color: var(--mid); }
.qs__leads {
  display: block; margin-top: 5px;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .04em; color: var(--ink);
}
.qs__leads span { color: var(--mid); margin-left: .7em; }
.qs__back { margin: 16px 0 0; font-size: 15px; }
.qs__grid--two .qs__card { padding-right: 40px; }

/* ---- the fleet reference, present on every screen ---- */
.guide__fleet { min-width: 0; }

/* PICK A ROW, THEN ORDER ONLINE (#853). Each row is a label around a radio, so the whole row is
   the target; the picked row takes the ground the recommended row used to have. Without :has a
   browser still shows the radio, so the choice is never invisible. */
.gfleet__pick {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: 46px minmax(0, 1fr) auto; gap: 2px 14px; align-items: start;
  cursor: pointer;
}
.gfleet__radio {
  grid-column: 3; grid-row: 1; margin: 4px 0 0; width: 20px; height: 20px; accent-color: var(--ink);
}
.gfleet__pick .gfleet__n { grid-column: 1; grid-row: 1; }
.gfleet__pick .gfleet__d { grid-column: 2; grid-row: 1; }
/* EVEN ROOM ON BOTH SIDES OF EVERY PICKABLE ROW, so shading one moves nothing and the radio is
   never against the edge (#854: it was padding-left only, on the shaded row only). */
.gfleet__i:has(.gfleet__pick) { padding: 14px 12px; }
.gfleet__i:has(.gfleet__radio:checked) { background: #efefef; box-shadow: inset 3px 0 0 0 var(--ink); }
.gfleet__i:has(.gfleet__radio:focus-visible) { outline: 2px solid var(--ink); outline-offset: 2px; }
.gfleet__rec {
  display: block; margin-top: 6px; font-family: var(--mono); font-size: var(--label);
  font-weight: 700; letter-spacing: .04em; color: var(--ink);
}
.guide__fleet-go { margin: 22px 0 0; }
.guide__fleet-go .btn { width: 100%; }
.guide__fleet-t {
  margin: 0 0 10px; font-family: var(--mono); font-size: var(--label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .09em; color: var(--mid);
}
.gfleet { list-style: none; margin: 0; padding: 0; border-top: 2px solid var(--ink); }
.gfleet__i {
  display: grid; grid-template-columns: 46px minmax(0, 1fr); gap: 2px 14px; align-items: start;
  padding: 13px 0; border-bottom: 1px solid var(--rule);
}
.gfleet__top { display: flex; justify-content: space-between; gap: 14px; align-items: baseline; }
/* The size the answers point at, marked while they are still choosing, when the rows are not
   radios (no checkout template). With radios the picked row is marked instead, above. */
.gfleet__i.is-on:not(:has(.gfleet__radio)) { background: #efefef; box-shadow: inset 3px 0 0 0 var(--ink); padding-left: 10px; }
.gfleet__n {
  font-stretch: 62%; font-weight: 900; font-size: 26px; line-height: .9;
  font-variant-numeric: tabular-nums;
}
.gfleet__n span {
  display: block; margin-top: 3px; font-family: var(--mono); font-size: var(--label);
  font-weight: 400; color: var(--mid); letter-spacing: .06em;
}
.gfleet__dim { font-family: var(--mono); font-size: var(--label); letter-spacing: .03em; white-space: nowrap; }
.gfleet__cap { display: block; margin-top: 3px; font-family: var(--mono); font-size: var(--label); color: var(--mid); }
.gfleet__suits { display: block; margin-top: 4px; font-size: 15px; line-height: 1.4; color: var(--mid); }
.gfleet__p { font-family: var(--mono); font-size: 14px; font-weight: 600; white-space: nowrap; }

/* --------------------------------------------------------------- result --- */
.rec { border-top: 2px solid var(--ink); padding-top: 20px; }
.rec__k {
  font-family: var(--mono); font-size: var(--label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; color: var(--mid); margin: 0;
}
.rec__size {
  font-stretch: 62%; font-weight: 900; text-transform: uppercase;
  font-size: clamp(44px, 12vw, 72px); line-height: .92; margin: 2px 0 0; word-spacing: .1em;
}
.rec__price { font-family: var(--mono); font-size: 20px; font-weight: 700; margin: 4px 0 0; }
.rec__reason { margin: 14px 0 0; font-size: 16px; line-height: 1.5; }
/* The answer restates the facts it was chosen on, so it can be checked. */
.rec__facts { list-style: none; margin: 20px 0 0; padding: 0; border-top: 1px solid var(--rule); }
.rec__facts li {
  display: flex; justify-content: space-between; gap: 18px; align-items: baseline;
  padding: 9px 0; border-bottom: 1px solid var(--rule);
}
.rec__facts b { font-family: var(--sans); font-stretch: 84%; font-weight: 800; font-size: 15.5px; }
.rec__facts span {
  font-family: var(--mono); font-size: var(--label); color: var(--mid);
  text-transform: uppercase; letter-spacing: .07em; order: -1;
}
.rec__hedge, .rec__up {
  margin: 18px 0 0; padding-top: 10px; border-top: 1px solid var(--rule);
  font-size: 15.5px; line-height: 1.5; color: var(--mid); max-width: 50ch;
}
.rec__swap {
  display: inline; padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; font-weight: 700; color: var(--ink);
  text-decoration: underline; text-underline-offset: 3px;
}
.rec__actions { display: flex; gap: 12px; flex-wrap: wrap; margin: 26px 0 0; }
.guide__skip { margin: 20px 0 0; font-size: 15px; }

/* --------------------------------------------------------------- picker --- */
.picker { list-style: none; margin: 0; padding: 0; border-top: 2px solid var(--ink); }
/* The radio is not hidden with display:none, which removes it from the
   accessibility tree and from keyboard order. It is clipped, so it is still
   focusable and still announced, and the label is what is painted. */
.picker__radio {
  position: absolute; opacity: 0; width: 1px; height: 1px;
  margin: 0; pointer-events: none;
}
.picker__card {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 16px; align-items: start;
  padding: 18px 0 18px 30px; border-bottom: 1px solid var(--rule);
  cursor: pointer; position: relative;
}
/* The selection mark is a struck square in the left margin, drawn in rule-work
   rather than filled with a color. */
.picker__card::before {
  content: ''; position: absolute; left: 0; top: 22px;
  width: 16px; height: 16px; border: 2px solid var(--ink); background: var(--paper);
}
.picker__radio:checked + .picker__card { background: #efefef; }
.picker__radio:checked + .picker__card::before { background: var(--ink); box-shadow: inset 0 0 0 3px var(--paper); }
.picker__radio:focus-visible + .picker__card { outline: 2.5px solid var(--ink); outline-offset: 2px; }

.picker__head { grid-column: 1; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.picker__name { font-stretch: 68%; font-weight: 900; text-transform: uppercase; font-size: 24px; line-height: 1; }
.picker__flag {
  font-family: var(--mono); font-size: var(--label); font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; background: var(--ink); color: var(--paper); padding: 3px 6px;
}
.picker__price { grid-column: 2; grid-row: 1 / span 2; text-align: right; }
.picker__price b { display: block; font-family: var(--mono); font-size: 26px; font-weight: 700; line-height: 1; }
/* SENTENCE CASE, AND 12px, BOTH FOR THE SAME REASON. These were set uppercase at 10.5px to read
   as annotation, and both halves of that were wrong: 10.5px is under the legibility floor, and
   uppercasing a twenty-character phrase strips the word shapes people actually read by. Uppercase
   is for a label of a word or two. "estimated, incl. tax" is a sentence doing a caveat's job, and
   it is the caveat on a price, which is the last text on this page that should be hard to read. */
.picker__pn, .picker__nq {
  display: block; margin-top: 3px; font-family: var(--mono); font-size: var(--label);
  letter-spacing: .02em; color: var(--mid); font-weight: 400;
}
.picker__nq { font-size: 17px; color: var(--ink); }
/* NOT UPPERCASED. Two of the three items here are sentences, not labels: "About 10 pickup loads"
   and "7 days included". Uppercase strips the ascenders and descenders words are recognized by,
   which is a fair trade for a two-word label and a bad one for a phrase somebody is reading to
   decide what to buy. The mono face and the gray already mark these as annotation. */
.picker__spec { grid-column: 1; display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 4px;
                font-family: var(--mono); font-size: var(--label); color: var(--mid);
                letter-spacing: .02em; }
.picker__suits { grid-column: 1 / -1; margin-top: 6px; font-size: 15.5px; color: var(--mid); line-height: 1.45; }
.picker__low   { grid-column: 1 / -1; margin-top: 6px; font-family: var(--mono); font-size: var(--label);
                 font-weight: 700; letter-spacing: .02em; }
.picker__outmsg{ grid-column: 1 / -1; margin-top: 6px; font-size: 15px; }
/* ONE COLUMN ON A PHONE (#780). Beside a price column 230px wide the name column was 60px, so
   "8' W x 4' H x 14' L" broke into three lines and "7 days included" into two. Stacked, the
   price sits under the name and every line gets the card's full width. */
@media (max-width: 559px) {
  .picker__card  { grid-template-columns: 1fr; }
  .picker__price { grid-column: 1; grid-row: auto; text-align: left; margin-top: 8px; }
  .picker__price b { display: inline; margin-right: 8px; }
  .picker__pn    { display: inline; }
  .picker__from  { display: block; }
}
/* Sold out is drawn out of the page rather than dimmed to illegibility: the
   name stays readable so it can be recognized, and the row is struck. */
.picker__i--out .picker__card { cursor: not-allowed; }
.picker__i--out .picker__name { text-decoration: line-through; }
/* DIMMED WITH A COLOR, NOT WITH OPACITY. At .5 the price measured 1.3:1, which is
   not dim, it is gone. An opacity stack multiplies against whatever is behind it and
   cannot be reasoned about; --mid is tuned against paper at 7.0:1 and stays legible
   while still reading as unavailable. The site has made this mistake once before, in
   the footer on the black ground, and the fix was the same. */
.picker__i--out .picker__price, .picker__i--out .picker__suits { color: var(--mid); }
.picker__i--out .picker__price b { color: var(--mid); }

/* --------------------------------------------------------------- review --- */
.review__money { border-top: 2px solid var(--ink); padding-top: 16px; margin-bottom: 34px; }
.review__mk {
  margin: 0; font-family: var(--mono); font-size: var(--label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; color: var(--mid);
}
/* The most important number on the site, set at display scale. Not animated,
   not counted up: a price that moves is a price nobody trusts. */
.review__mv {
  margin: 0; font-stretch: 62%; font-weight: 900;
  font-size: clamp(52px, 15vw, 84px); line-height: .9; letter-spacing: -.02em;
}
.review__split { display: grid; gap: 0; margin: 14px 0 0; border-top: 1px solid var(--rule); }
.review__split > div {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 7px 0; border-bottom: 1px solid var(--rule);
  font-family: var(--mono); font-size: 15px;
}
.review__split dt, .review__split dd { margin: 0; }
.review__caveat { margin: 12px 0 0; font-size: 15px; line-height: 1.5; color: var(--mid); }

.review__rows { margin: 0 0 30px; }

/* THE ADDRESS DROPDOWN. Anchored to the field box rather than the page so it follows the input
   when a phone keyboard opens, and above the rest of the form because a suggestion list that
   renders behind the next label is a list nobody can click. */
/* THE ADDRESS DROPDOWN LIVES UNDER .acx, FURTHER DOWN THIS FILE, AND THERE IS ONLY ONE OF IT.

   There were two. This file carried a complete .addr component AND the .acx one it was ported
   beside, and the script wired .addr, so every argued decision in .acx was dead CSS: the ink
   border, the inverted active row, the maximum z-index, the measured height, the flip. The one
   that was live had a highlight of var(--paper, #eef1f4) over a list of var(--card, #fff), and on
   a site where --card is undefined and --paper is #ffffff that is white on white, for a mouse and
   for the arrow keys alike.

   Deleting .addr rather than fixing its colors is the point. Two components for one job is how
   the broken one stays wired while the good one is reviewed.

   .fld__box keeps position:relative because other things in the field wrapper rely on it; the
   list itself no longer does, being a child of <body>. */
.fld__box { position: relative; }

/* The number, under the line that names it, so the sentence stays short and the digits stay
   readable at a glance. */
.done__num { display: block; margin-top: 3px; font-weight: 600; font-variant-numeric: tabular-nums; }
.review__row {
  display: grid; grid-template-columns: 1fr; gap: 3px;
  padding: 14px 0; border-bottom: 1px solid var(--rule);
}
.review__row dt {
  font-family: var(--mono); font-size: var(--label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--mid);
}
.review__row dd { margin: 0; font-size: 16px; line-height: 1.5; }
.review__dim { display: block; font-family: var(--mono); font-size: var(--label); color: var(--mid); }
.review__heavy { display: block; margin-top: 6px; font-weight: 700; }
.review__last { margin: 0 0 14px; font-size: 15px; color: var(--mid); }
.review__submit { display: flex; gap: 12px; flex-wrap: wrap; align-items: stretch; }
.btn--send { flex: 1 1 240px; }

/* ------------------------------------------------------------ confirmed --- */
.done { border-top: 2px solid var(--ink); padding-top: 24px; }
/* THE SIGNATURE, and the only rotated element on this site. A stamp struck on
   the page: the mark a dispatcher makes when a job is real. It is spent here
   and nowhere else. */
.done__stamp {
  display: inline-block; transform: rotate(-4deg);
  border: 3px solid var(--ink); padding: 6px 16px 5px; margin: 0 0 20px;
  font-stretch: 70%; font-weight: 900; text-transform: uppercase;
  font-size: 30px; letter-spacing: .06em; line-height: 1;
}
@media (prefers-reduced-motion: no-preference) {
  /* A STAMP DOES NOT SPRING. The old curve overshot past 1 and wobbled back, which is
     what a rubber ball does; a stamp hits paper and stops dead. An exponential ease-out
     decelerates hard into the final position and never passes it. */
  .done__stamp { animation: strike 260ms cubic-bezier(.22, 1, .36, 1) both; }
  @keyframes strike {
    from { transform: rotate(-14deg) scale(1.35); opacity: 0; }
    to   { transform: rotate(-4deg)  scale(1);    opacity: 1; }
  }
}
.done__t {
  font-stretch: 64%; font-weight: 900; text-transform: uppercase;
  font-size: clamp(28px, 7.4vw, 44px); line-height: 1.02; margin: 0 0 14px; word-spacing: .14em;
}
.done__ref { margin: 0 0 22px; font-family: var(--mono); font-size: 15px; }
.done__next { margin: 0 0 28px; padding-left: 0; list-style: none; counter-reset: n; }
.done__next li {
  counter-increment: n; position: relative; padding: 14px 0 14px 38px;
  border-bottom: 1px solid var(--rule); font-size: 15.5px; line-height: 1.5;
}
.done__next li::before {
  content: counter(n); position: absolute; left: 0; top: 14px;
  font-family: var(--mono); font-size: var(--label); font-weight: 700;
  width: 22px; height: 22px; display: grid; place-items: center;
  border: 1.5px solid var(--ink);
}
.done__call { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; font-size: 15px; }

/* ----------------------------------------------------------------- 640+ --- */
@media (min-width: 640px) {
  .band--book { padding-block: 40px 80px; }
  /* The question and the fleet sit side by side from 640 up. Below that the fleet
     follows the question rather than pushing it off the screen. */
  .guide { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 48px; align-items: start; }
  .guide__count { grid-column: 1 / -1; }
  /* Two columns only where a pair of fields genuinely belongs on one line. Town
     and state are read as one answer, so they are set as one row. */
  .bookform .fld:has(#f-city), .bookform .fld:has(#f-state) { display: inline-block; width: calc(50% - 8px); vertical-align: top; }
  .bookform .fld:has(#f-city) { margin-right: 12px; }
  .qs__grid--two { grid-template-columns: 1fr 1fr; }
  .qs__grid--two .qs__card { border-right: 1px solid var(--rule); }
  .qs__grid--two .qs__card:last-child { border-right: 0; }
  .review__row { grid-template-columns: 200px 1fr; gap: 0 24px; align-items: baseline; }
  .fork__card { padding: 26px 0; }
}

/* ---------------------------------------------------------- forced colors -- */
/* Every state in this file is carried by a border, a background or a character,
   all of which forced-colors keeps. The one thing it drops is the gray slab, so
   an empty field would lose its only cue. Give it a real border there. */
@media (forced-colors: active) {
  .fld__input { border: 1px solid; border-bottom-width: 2px; }
  .fld--bad .fld__input { border-bottom: 4px dashed; }
  .picker__radio:checked + .picker__card { forced-color-adjust: none; }
}

/* ------------------------------------------------------------- call bar --- */
/* site.css reserves 58px at the foot of every phone page for the fixed .callbar.
   This page does not render one, so that reservation is dead space under the
   footer. Loaded after site.css, so the same selector wins on source order. */
body { padding-bottom: 0; }
.picker__from {
  display: block; margin-top: 2px; font-family: var(--mono); font-size: var(--label);
  color: var(--mid); letter-spacing: .02em;
}


/* ------------------------------------------------------ the enquiry form --
   /contact-us. Same field parts as the booking flow, which is why this sheet now
   loads on both routes: one set of inputs to style, one set of focus and error
   states to keep correct.

   The honeypot is positioned off-screen rather than display:none. Some bots skip
   hidden inputs, and some browsers skip them on autofill; moving it out of view
   keeps it in the document for a bot and out of the way for a person. */
.cform__hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.cform { margin-top: 26px; max-width: 720px; }
.cform__grid { display: grid; gap: 0 32px; }
/* Name and email share a row once there is room for two 260px columns and their
   gap. Below that they stack, which is where a phone is. */
@media (min-width: 680px) {
  .cform__grid { grid-template-columns: 1fr 1fr; }
  .cform__f--message { grid-column: 1 / -1; }
}
/* The note is the CSRF failure, which belongs to the form and not to a field. A
   dashed rule is the sheet's own way of marking something wrong; it matches
   .fld--bad rather than introducing a second error language. */
.formnote {
  margin: 22px 0 0; padding: 12px 0 0; border-top: 4px dashed var(--ink);
  font-size: 16px; line-height: 1.45; max-width: 54ch;
}
.band--form .actions { margin-top: 4px; }


/* ------------------------------------------------------------- the admin --
   THE MARKETING CHROME IS NOISE ON A SETTINGS SCREEN. The owner arriving here has
   already chosen this page; the sticky order bar, the service-area column and the
   forty-link footer are all asking them to convert on their own site. The masthead
   and its nav stay, because they are how the owner gets back to the pages they are
   configuring. Hidden rather than given a second layout: one template, one place
   where the admin differs, nothing for a future page to inherit by accident. */
.is-admin .callbar { display: none; }
.is-admin .foot__cols { display: none; }
.is-admin .cform { max-width: 640px; }
/* The label and its "optional" tag ran together as "Send fromoptional" with the sheet
   unloaded. It is styled in .fld__opt; this only makes the gap explicit so the two can
   never touch if that rule moves. */
.is-admin .fld__opt { margin-left: .5ch; }

/* ================================================== /contact-us, as a form page ==
   A contact page has one job and the page was not built around it. Measured before:
   the only image was logo.png at 514x514 — a solid black square, the exact file
   DESIGN.md names as unrenderable on a white sheet and the governing rule's one
   forbidden shape — sitting 600px under the identical masthead wordmark. The visitor
   travelled 1,053px to reach a phone number, met "Contact Us" and two buttons that
   duplicated the form 206px below them, and the desktop used 61% of its width with
   roughly 750,000px² of the content region carrying nothing.

   Nothing below moves a frozen word. Document order is untouched; this is composition
   only, the same contract the band-ordering block in site.css works under. */

/* THE BLACK SQUARE GOES. It is a logo, not a photograph, and it was wearing the crop
   marks that mark a photograph. The wordmark is already in the masthead 600px above. */
.is-contact .band--medialead > .shell > .prose.segment__media { display: none; }

/* THE PARAGRAPH RUNS FULL WIDTH. Asked for. With the address record moved down to the
   form there is nothing to sit beside it, and a lone column of prose with an empty half
   next to it reads as a layout that lost something. */
@media (min-width: 1024px) {
  .is-contact .band--medialead > .shell { display: block; }
  .is-contact .band--medialead > .shell > h1 { max-width: 20ch; }
  .is-contact .prose--lede,
  .is-contact .prose--lede > p { max-width: none; }
}

/* "CONTACT US" HEADS THE FORM. The client's own frozen heading sits in its own band with
   the form in the next one, so the two were 262px apart with a pair of buttons between
   them that only scrolled 206px to the form. The buttons are gone from the panel and the
   gap is closed, so the heading belongs to the thing it heads. */
.is-contact .band:has(+ .band--form) { padding-bottom: 0; border-bottom: 0; }
.is-contact .band:has(+ .band--form) + .band--form { padding-top: 14px; border-top: 0; }

/* The form uses the width instead of leaving 456px of it empty: the standfirst takes the
   narrow column, the fields take the wide one. */
@media (min-width: 1024px) {
  /* THREE ROWS, THE FIRST TWO SIZED TO THEIR CONTENT. The form spans the column, and a
     spanning item distributes its height across every row it covers — so with two rows the
     standfirst and the record were pushed to the top and bottom of a 500px column with a
     void between them. A third row absorbs the form's remaining height instead, and the two
     things in the left column sit together where they belong. */
  .is-contact .band--form > .shell {
    display: grid; grid-template-columns: minmax(230px, 1fr) 1.9fr; column-gap: 64px;
    grid-template-rows: min-content min-content 1fr; align-items: start;
  }
  .is-contact .band--form .deck        { grid-column: 1; grid-row: 1; margin: 0; }
  .is-contact .band--form .cform__card { grid-column: 1; grid-row: 2; margin-top: 26px; }
  .is-contact .band--form .cform       { grid-column: 2; grid-row: 1 / span 3; margin-top: 0; max-width: none; }
}

/* THE RECORD IS A TITLE BLOCK. Ruled off in the heavy weight, the business name in the
   display voice and the three lines under it tight, so the name, email, phone and address
   read as one stamped record rather than four loose paragraphs. */
.is-contact .cform__card { border-top: 2px solid var(--ink); padding-top: 14px; max-width: 34ch; }
.is-contact .cform__card h3 { margin: 0; font-size: 17px; }
.is-contact .cform__card p  { margin: 8px 0 0; font-size: 16px; line-height: 1.5; }
@media (max-width: 1023px) { .is-contact .cform__card { margin: 26px 0 0; } }
/* A gray standfirst was 24px against 19px black body copy above it — larger AND lighter,
   which inverts the rank it is meant to sit below. It is a caption for the form now. */
.is-contact .band--form .deck { font-size: 17px; line-height: 1.55; max-width: 34ch; }

/* THE FIXED BAR WAS EATING THE LAST LINE OF THE FOOTER. 63px tall over a body with no
   bottom padding, so 20px of the copyright line was unreachable at maximum scroll. */
@media (max-width: 719px) { body:has(.callbar) { padding-bottom: 66px; } }

/* ============================================== the booking page, two columns ==
   Asked for. It was one 1,080px column with the reassurance and the step nav
   scrolling away above the fields, so by the time someone was typing an address
   the thing telling them nothing is charged yet was off screen.

   The split is by JOB, not by halves: the left column is everything you consult
   (what happens at the end, where you are in the flow, what the fleet is) and the
   right column is the one thing you operate. The h1 spans both because it names
   the page, not a column.

   ONE CATCH-ALL, THEN THE EXCEPTIONS. Every child lands in the working column
   unless it is named below, so a step that grows a new element gets the right
   place by default instead of falling out of the grid. */
@media (min-width: 1024px) {
  .shell--book {
    display: grid;
    grid-template-columns: minmax(250px, 1fr) 1.75fr;
    column-gap: 56px;
    align-items: start;
  }
  .shell--book > *            { grid-column: 2; }
  .shell--book > .book__h1    { grid-column: 1 / -1; grid-row: 1; }
  /* THE REHEARSAL BAND SPANS BOTH COLUMNS, and it has to, because it sits between the h1 and the
     aside in the DOM. Left in the working column it took a grid row of its own, which pushed the
     aside down one row and left the two columns starting at different heights on every step. */
  .shell--book > .book__rehearsal { grid-column: 1 / -1; }
  /* ONE ITEM, so the working column beside it cannot stretch the rows it sits in.
     STICKY, because it is the column you consult: a total and a step list that scroll away are
     the two things this layout exists to keep in view. */
  .shell--book > .book__aside { grid-column: 1; position: sticky; top: 24px; }
  /* NO SECOND COLUMN WHEN THERE IS NOTHING TO PUT IN IT. The confirmation renders no aside, and
     without this the grid still reserved its column and squeezed the confirmation into the right
     two thirds of an otherwise empty page. */
  .shell--book-solo { display: block; }
  .shell--book-solo > * { max-width: 68ch; }
  /* The fleet list used to be teleported here with a grid-column override while remaining a
     sibling of the working column, which put it in the right column and the wrong row. It is
     inside the aside now, so it needs no exception at all. */
  .book__aside .book__promise { margin-bottom: 0; }
  .book__aside .steps         { margin-top: 26px; }

  /* The step nav stops being a horizontal bar when it is 250px wide: the four
     labels become a list, which is what a contents list looks like anyway. */
  .book__aside .steps__list { display: block; border: 0; }
  .book__aside .steps__item {
    display: flex; gap: 10px; align-items: baseline;
    padding: 9px 0; border: 0; border-bottom: 1px solid var(--rule); background: none;
  }
  .book__aside .steps__item:last-child { border-bottom: 0; }
  .book__aside .steps__item.is-now { background: none; color: var(--ink); font-weight: 700; }
  .book__aside .steps__item.is-now .steps__n,
  .book__aside .steps__item.is-done .steps__n { color: var(--ink); }

  /* The working column never needs its own cap now that it has a column. */
  .book__step > .bookform,
  .book__step > .fork,
  .book__step > .guide { max-width: none; margin-top: 0; }

  /* THE GUIDE STEP IS TWO COLUMNS, NOT THREE, and this is a jam rather than a preference.
     Measured by the TDG Mobile session at a 1060px viewport: with the page aside, the questions
     and the fleet all competing, the fleet column was 256px and reported scrollWidth past its own
     clientWidth, so it genuinely overflowed. One 996px track splits it 507 / 441 instead.

     THE SECOND RULE IS NOT DECORATION AND MUST NOT BE DROPPED. `.shell--book > *` above puts every
     child in column 2; with a single track that lands them in an IMPLICIT second column and
     collapses the first to zero. It happens to look right, which is exactly why it would survive
     a review that did not know to look.

     The aside gives up sticky here because it is no longer a column: it reads as an opening
     paragraph above the guide, and a sticky opening paragraph follows you down a page you are
     reading rather than consulting. */
  /* THROUGH .book__step SINCE #780. Every step sits in that wrapper now, and these rules still
     said `> .guide`, so they stopped matching and the guide went back to three columns. */
  .shell--book:has(> .book__step > .guide) { grid-template-columns: minmax(0, 1fr); }
  .shell--book:has(> .book__step > .guide) > *            { grid-column: 1; }
  .shell--book:has(> .book__step > .guide) > .book__aside { position: static; max-width: 62ch; }
  .shell--book:has(> .book__step > .guide) .guide         { margin-top: 40px; }
}

/* The booking-mode banner. Ruled in the heavy weight because it is the one line on the
   admin whose value changes what a customer's submission actually does; LIVE is set in
   the display voice so it cannot be skimmed past. */
.modeflag {
  margin: 0 0 26px; padding: 12px 0 0; border-top: 4px solid var(--ink);
  font-size: 16px; line-height: 1.45; max-width: 60ch;
}
.modeflag--live { font-family: var(--sans); font-stretch: 76%; font-weight: 900;
                  text-transform: uppercase; letter-spacing: .01em; font-size: 19px; }
.modeflag--test { color: var(--mid); border-top-color: var(--rule); }

/* --------------------------------------------------------------- the receipt --- */
/* Appended at TOP LEVEL, outside every media block. Checked, because the last time a
   block was added to the end of a stylesheet here it landed inside an open
   `@media (max-width: 759px)` and silently did nothing above 760px. */

/* The confirmation sits under the client's own frozen copy, so it needs a rule above
   it to read as a separate answer rather than as more of the same paragraph.
   scroll-margin because the redirect lands on #booked: without it the block's own top
   rule sits flush against the top of the viewport and reads as a cut-off page.
   :focus-visible is suppressed because the browser focuses this section on the hash
   jump, and a focus ring around the whole confirmation is a ring nobody asked for. */
.band--receipt { padding-block: 8px 56px; scroll-margin-top: 18px; }
.band--receipt:focus { outline: none; }

/* What they just booked, checkable at a glance. A definition list because that is what
   it is: four labeled facts, not a table and not a paragraph. */
.receipt { margin: 0 0 30px; border-top: 1px solid var(--rule); }
.receipt__row {
  display: flex; gap: 16px; justify-content: space-between; align-items: baseline;
  padding: 11px 0; border-bottom: 1px solid var(--rule);
}
.receipt dt {
  font-family: var(--mono); font-size: var(--label); text-transform: uppercase;
  letter-spacing: .06em; color: var(--mid); margin: 0;
}
/* Right-aligned and tabular, so the figures line up under each other and a total reads
   as a total rather than as the end of a sentence. */
.receipt dd {
  margin: 0; text-align: right; font-size: 16px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* The enquiry version. One sentence, so it is set as one, at reading size. */
.tyq { margin: 0 0 20px; font-size: 17px; line-height: 1.55; }

/* ------------------------------------------------------- conversions report --- */
.convsum {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px;
  margin: 0 0 24px; background: var(--rule); border: 1px solid var(--rule);
}
.convsum__cell { background: var(--paper); padding: 14px 16px; }
.convsum__k {
  display: block; font-family: var(--mono); font-size: var(--label);
  text-transform: uppercase; letter-spacing: .06em; color: var(--mid); margin-bottom: 6px;
}
/* The number is the content of this cell, so it is set at display size and in the
   display weight. A metric tile whose figure is body copy is a label with a number in it. */
.convsum__v {
  display: block; font-stretch: 70%; font-weight: 900; font-size: 30px; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.convsum__note { display: block; margin-top: 6px; font-size: 13px; color: var(--mid); }

/* A wide table on a phone scrolls INSIDE ITS OWN BOX. The page body never scrolls
   sideways; that is a layout bug wearing a scrollbar. */
.convwrap { overflow-x: auto; margin: 0 0 24px; }
.convtable { width: 100%; border-collapse: collapse; font-size: 14px; min-width: 620px; }
.convtable th, .convtable td {
  text-align: left; padding: 9px 14px 9px 0; border-bottom: 1px solid var(--rule);
  white-space: nowrap; vertical-align: baseline;
}
/* SOURCE AND REFERENCE ARE CAPPED, because their content is not ours. `source` and `gclid` are
   stored clipped to 190 characters, which is a perfectly reachable length for one ad URL with a
   long tracking parameter, and with nowrap and no cap a single such row stretched the table to
   2,206px and pushed the Amount column, the entire point of this screen, 1,030px off the right at
   1440. One row did that to every other row. Same treatment .steps__label already uses. */
.convtable td:nth-child(5), .convtable td:nth-child(6) {
  max-width: 22ch; overflow: hidden; text-overflow: ellipsis;
}
.convtable th {
  font-family: var(--mono); font-size: var(--label); text-transform: uppercase;
  letter-spacing: .06em; color: var(--mid); font-weight: 400;
  border-bottom-width: 2px; border-bottom-color: var(--ink);
}
.convtable td.is-num { text-align: right; font-variant-numeric: tabular-nums; padding-right: 0; }
/* State is carried by weight and a rule, not by color: this palette has no color to
   spend, and a red pill would be the only one on the site. */
.convtable .is-test { color: var(--mid); }
.convtable .conv-kind {
  font-family: var(--mono); font-size: var(--label); text-transform: uppercase;
  letter-spacing: .06em;
}
.convtable .conv-kind--purchase { font-weight: 700; color: var(--ink); }

.convempty { margin: 0 0 24px; font-size: 16px; line-height: 1.5; color: var(--mid); max-width: 60ch; }

@media (min-width: 640px) {
  .convsum { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* -------------------------------------------------------- receipt, 900+ --- */
/* MEASURED, NOT GUESSED. At 1280 the confirmation ran the full 1176px of the shell,
   which put "CONTAINER" and "20 Yard" 1100px apart on one line: a label and its value
   far enough apart that they stop reading as a pair. The numbered steps beside them
   were already capped at 586px, so the block was half empty on the right and
   unreadable on the left at the same time.

   Two columns fixes both, and it fixes them in DOM order: the facts on the left, what
   happens next on the right. Nothing is visually reordered, so what a screen reader
   reads and what the eye follows stay the same sequence. */
@media (min-width: 900px) {
  .done__facts {
    display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1fr);
    gap: 0 64px; align-items: start;
  }
  .done__facts .receipt    { margin-bottom: 0; }
  /* The list keeps its own reading-width cap. It is prose, and prose does not want a
     column boundary to be the thing that decides where a line breaks. */
  .done__facts .done__next { margin-bottom: 0; }
  /* SCOPED TO THE BLOCK IT WAS WRITTEN FOR. Unprefixed it also reached the enquiry confirmation
     and the no-database fallback, neither of which has a .done__facts to sit under, so both picked
     up 30px of spacing meant for a two-column receipt. The two rules above it were scoped; this
     one was not. */
  .done__facts + .done__call { margin-top: 30px; }
}

/* ------------------------------------------------- the itemised purchase --- */
/* The allowances are a different KIND of fact from the charge: not what you pay,
   but what would make you pay more. Set quieter and behind a labeled rule so it
   reads as terms rather than as extra costs already added. */
.review__split--terms {
  margin-top: 18px; padding-top: 12px; border-top: 1px solid var(--rule);
}
.review__split--terms::before {
  content: "Included, and what more would cost";
  display: block; margin-bottom: 8px;
  font-family: var(--mono); font-size: var(--label); text-transform: uppercase;
  letter-spacing: .06em; color: var(--mid);
}
.review__split--terms dd { font-variant-numeric: tabular-nums; }

/* The Box Tracker disconnect. A destructive option, so it is set apart from the fields it
   undoes rather than sitting in the grid with them as though it were another value to fill in. */
.adm__clear {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 4px 0 18px; padding-top: 14px; border-top: 1px solid var(--rule);
  font-size: 14.5px; line-height: 1.45; color: var(--mid); max-width: 60ch;
}
.adm__clear input { margin-top: 3px; flex: none; width: 18px; height: 18px; }

/* ------------------------------------------------------- taking a card --- */
/* THIS BLOCK HAD NO STYLES AT ALL. Six classes, zero matching rules, on the one
   screen that asks for a card number: the fieldset rendered on browser defaults
   with a 2px grooved 3D bevel that appears nowhere else on the site, the four
   fields stacked full width so a 3-character security code was 281px wide, and
   the whole box sat 49px short of the button beneath it because a fieldset's
   min-inline-size stops it stretching as a flex item. A payment form that looks
   unfinished is a payment form people abandon, and they are right to. */
.pay {
  flex: 1 1 100%;                 /* a fieldset will not stretch on its own */
  min-inline-size: 0;             /* ...and this is why */
  border: 1.5px solid var(--ink); border-radius: 0;
  margin: 0 0 18px; padding: 18px 16px 20px;
}
.pay__legend {
  padding: 0 8px; margin-left: -4px;
  font-family: var(--mono); font-size: var(--label); text-transform: uppercase;
  letter-spacing: .06em; font-weight: 700;
}
/* The card number wants the full width; expiry and security code are four
   characters each and are read as one line, so they sit on one. */
.pay__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 12px; }
.pay__f--ccardFName, .pay__f--ccardNumber { grid-column: 1 / -1; }
/* The card's billing address (#793). Ticked, it is one line naming the delivery
   address; unticked, its fields open under it. No script: an old browser without
   :has simply shows the fields, which the server ignores while the box is ticked. */
.bill { margin: 18px 0 0; padding-top: 14px; border-top: 1px solid var(--rule); }
.bill__same {
  display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
  font-size: 15.5px; line-height: 1.45; font-weight: 600; color: var(--ink);
}
.bill__check { margin: 2px 0 0; flex: none; width: 20px; height: 20px; accent-color: var(--ink); }
.bill__check:focus-visible { outline: 2.5px solid var(--ink); outline-offset: 2px; }
.bill__where { display: block; font-size: 14.5px; font-weight: 400; color: var(--mid); }
.bill__fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 12px; margin-top: 16px; }
.bill__f--bill_address, .bill__f--bill_city { grid-column: 1 / -1; }
.bill:has(.bill__check:checked) .bill__fields { display: none; }
/* The one warning that has to be read before anything is typed, so it is set in
   the sheet's own "pay attention" language rather than as body copy. */
.pay__test {
  margin: 0 0 16px; padding: 11px 13px;
  border: 1.5px dashed var(--ink); font-size: 14.5px; line-height: 1.5;
}

/* ------------------------------------------------- admin: saved, not failed --- */
/* .formnote is a 4px DASHED black rule, which this sheet elsewhere calls "the
   way of marking something wrong". .formnote--ok matched nothing, so the
   confirmation of a successful save wore the error mark. A solid rule and the
   ink voice: same family, opposite meaning. */
.formnote--ok { border-top-style: solid; color: var(--ink); }
/* The bare-button forms: a test button and a sign-out button were unstyled
   wrappers inheriting nothing, so they sat flush against whatever preceded them. */
.adminout { margin: 22px 0 0; padding-top: 18px; border-top: 1px solid var(--rule); }

@media (min-width: 640px) {
  .pay { padding: 22px 20px 24px; }
  .pay__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* The name and the number keep the full row; expiry and code take one quarter
     each, which is about as wide as four digits ever needs to be. */
  .pay__f--ccardExp, .pay__f--ccardCVV { grid-column: span 1; }
}

/* --------------------------------------------- admin: the three set editors --- */
/* APPENDED AT TOP LEVEL, verified rather than assumed. The brace count was even
   before this block and is checked again after it, because the last time something
   was added to the end of this sheet it landed inside an open media query and
   applied only above 640px, which looks like the styles simply not working. */

/* Collapsed by default. Cities, containers and services fully expanded is around
   200 inputs on one screen, and the owner arriving to change a phone number should
   not have to scroll past the fleet to reach it. The summary carries the counts, so
   the answer to "how many cities are live" is readable without opening anything. */
.setblk { margin: 0 0 14px; border-top: 1px solid var(--rule); }
.setblk[open] { padding-bottom: 22px; border-bottom: 1px solid var(--rule); }
.setblk__sum {
  display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: baseline;
  /* 44px of tappable height on a phone, met by padding rather than a fixed height
     so a wrapped count still grows the target instead of overflowing it. */
  padding: 13px 0; cursor: pointer; list-style: none;
}
.setblk__sum::-webkit-details-marker { display: none; }
/* The disclosure mark is drawn, not an image and not an emoji: it has to survive
   forced-colors mode, where a background image disappears without trace. */
.setblk__sum::before {
  content: "+"; flex: none; width: 18px;
  font-family: var(--mono); font-size: 17px; line-height: 1; color: var(--ink);
}
.setblk[open] > .setblk__sum::before { content: "\2212"; }
.setblk__name {
  font-family: var(--sans); font-stretch: 76%; font-weight: 800;
  text-transform: uppercase; letter-spacing: .02em; font-size: 16px;
}
.setblk__count {
  font-family: var(--mono); font-size: var(--label); color: var(--mid);
  font-variant-numeric: tabular-nums;
}
.setblk__note {
  margin: 14px 0 0; font-size: 14.5px; line-height: 1.5; color: var(--mid); max-width: 62ch;
}
/* `.is-admin .cform` caps every form on this screen at 640px, which is right for four
   labeled fields and wrong for a seven-column table: measured at 1280px the scroll box
   was 640px holding a 1048px table, so an owner scrolled sideways through a table that
   had 536px of empty page beside it. Written at the SAME specificity as the rule it
   overrides — a bare `.cform--set` is (0,1,0) against that rule's (0,2,0) and lost
   silently, which is how the cap survived being "removed" in the first place. */
.is-admin .cform--set { margin-top: 4px; max-width: none; }

/* SIX COLUMNS DO NOT FIT IN 375px AND ARE NOT MADE TO. The table keeps its real
   width and the wrapper scrolls, which is the honest answer for a dense editor on a
   phone; overflow: hidden here would cut the Listed checkbox off the right edge with
   nothing to say it was there. */
/* AND IT HAS TO SAY SO. Containers is thirteen columns and 1950px wide; at 375px all
   three are wider than the screen. A column an owner cannot see is a column they never
   fill in.

   THE GRADIENT TRICK WAS TRIED HERE AND DOES NOT WORK, which is why it is not here: the
   edge shadow is painted on the container's own background, and every cell in the row is
   an input with an opaque paper fill sitting on top of it. Measured at both 375px and
   1280px, the shading was invisible at exactly the edge it existed to mark. A reserved
   scrollbar gutter is drawn by the browser over nothing, so it survives that, and the
   deck above the sets says the tables scroll rather than leaving it to be discovered on
   the platforms that hide the bar until you already know to swipe. */
.setgrid__scroll {
  overflow-x: auto; margin: 6px 0 0; -webkit-overflow-scrolling: touch;
  scrollbar-width: thin; scrollbar-gutter: stable;
}
.setgrid { border-collapse: collapse; font-size: 14px; }
.setgrid th, .setgrid td { padding: 6px 10px 6px 0; text-align: left; vertical-align: middle; }
.setgrid thead th {
  padding-bottom: 8px; border-bottom: 1.5px solid var(--ink);
  font-family: var(--mono); font-size: var(--label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; white-space: nowrap;
}
.setgrid tbody tr { border-bottom: 1px solid var(--rule); }
/* The key is the row's identity and is not editable, so it is set as data rather
   than dressed up as a field somebody will try to type into. */
.setgrid__key { white-space: nowrap; }
.setgrid__key code { font-family: var(--mono); font-size: 13px; }
.setgrid__page {
  display: block; margin-top: 2px;
  font-family: var(--mono); font-size: 11.5px; color: var(--mid); letter-spacing: .02em;
}
.setgrid__in {
  /* 44px, not 40. Measured at 375px: the row inputs came out 40px tall, under the
     44px floor this project holds every tappable thing to. The checkbox cells were
     already over it because their padding does the work. */
  width: 100%; min-width: 108px; min-height: 44px; padding: 9px;
  border: 1px solid var(--rule); border-radius: 0; background: var(--paper);
  font: inherit; color: var(--ink);
}
.setgrid__in:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; border-color: var(--ink); }
.setgrid__in--bad { border: 1.5px dashed var(--ink); }
/* 18px is the box; the 44px target is the padded cell around it, which is why the
   checkbox cell keeps the same vertical padding as an input cell. */
.setgrid__chk { width: 18px; height: 18px; accent-color: var(--ink); }
.setgrid__row--bad > * { background: #f4f4f4; }
.setgrid__err td {
  padding: 0 0 10px; border-bottom: 1px solid var(--rule);
  font-size: 13.5px; line-height: 1.45; color: var(--ink);
}
/* The add row is the same shape as the rows above it and is marked as the end of
   the list rather than as another entry in it. */
.setgrid__new > * { padding-top: 14px; border-top: 1.5px solid var(--ink); }

@media (min-width: 760px) {
  .setgrid { font-size: 14.5px; }
  .setgrid__in { min-width: 130px; }
}

/* ------------------------------------------------------- the rehearsal band --- */
/* Appended at TOP LEVEL, outside every media block. Verified below, because this file
   has already had a block land inside an open @media once. */
.book__rehearsal {
  margin: 0 0 26px; padding: 12px 0 0;
  border-top: 4px solid var(--ink);
  font-size: 15px; line-height: 1.5; max-width: 72ch;
}
.book__rehearsal strong {
  font-family: var(--sans); font-stretch: 76%; font-weight: 900;
  text-transform: uppercase; letter-spacing: .01em;
}

/* ------------------------------------------------------- the running order --- */
/* The consulting column's job, once there is an order to consult. Drawn as the
   annotation voice the rest of that column already speaks in: hairlines, mono labels,
   one heavy figure. It must not compete with the working column, because the thing
   you press is over there. */
.rail {
  margin-top: 26px; padding-top: 10px;
  border-top: 1px solid var(--rule);
}
.rail__h {
  margin: 0 0 10px;
  font-family: var(--mono); font-size: var(--label); font-weight: 400;
  letter-spacing: .12em; text-transform: uppercase; color: var(--mid-dark);
}
.rail__rows { margin: 0; }
.rail__row {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 7px 0; border-bottom: 1px solid var(--rule);
  font-size: 15px; line-height: 1.4;
}
.rail__row dt { color: var(--mid); }
.rail__row dd { margin: 0; text-align: right; }
.rail__total {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  margin: 12px 0 0;
}
.rail__tk {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--mid-dark);
}
.rail__tv {
  font-family: var(--sans); font-stretch: 76%; font-weight: 900;
  font-size: 30px; line-height: 1; letter-spacing: -.01em;
}
.rail__note { margin: 6px 0 0; font-size: 13px; color: var(--mid); }

/* THE RAIL IS A DESKTOP IDEA. Below the two-column breakpoint the aside is stacked
   above the form, and a running total there would sit between the heading and the
   first field, pushing the fields down on the screen where they are hardest to reach.
   The working column shows the same figure on the step where it matters. */
@media (max-width: 1023px) { .rail { display: none; } }

/* WHICH STYLESHEET WINS, WHEN A HOST STILL SHIPS ITS OWN COPY OF THIS ONE.

   THIS FILE WINS. The module's <link> is emitted after the host's, and at equal specificity the
   LAST declaration applies. Verified on a live install rather than reasoned about: site.css, then
   the host's booking.css, then /order-online/booking.css on every step of the checkout.

   IT COSTS NOTHING WHILE THE TWO AGREE, which is why it is easy to get backwards, and both this
   session and the one maintaining that host stated it the wrong way round for a week without
   anything breaking. It starts costing the day a value differs: change a color or a padding
   here and the host's own edit to the same rule silently stops applying, and their file looks
   like it is being ignored for no reason anybody can see.

   A selector only one of the two defines is unopposed and cascade order is irrelevant to it. */

/* ------------------------------------------------- the address combobox --- */
/* Appended at TOP LEVEL, and checked below, because this file has had a block land
   inside an open @media before.
   THE LIST IS DRAWN BY THE SCRIPT and nothing here renders without it, so none of
   this affects the no-JavaScript form. */
.acx { position: relative; }
.acx__list {
  /* FIXED AND AT THE TOP OF THE STACK, because this is a child of <body> now rather than of the
     field. LastPass injects its own overlay at z-index 2147483647 !important, the largest 32-bit
     integer, so it cannot be beaten on the number. Equal values resolve by document order, and
     address.js re-appends this to the end of <body> every time it opens.
     !important because the whole point is to not lose to a declaration somebody else injects.
     Position and width are written by address.js from the field's own box; nothing here can know
     where the field ended up. */
  position: fixed; z-index: 2147483647 !important;
  margin: 0; padding: 0; list-style: none;
  background: var(--paper); border: 1.5px solid var(--ink);
  /* A starting cap only. address.js measures the room actually left under the field and
     overrides this, because 46vh is a guess about a viewport and the thing that matters is
     where this particular field ended up on this particular page. */
  max-height: 46vh; overflow-y: auto;
  /* The one shadow on this site. A list that overlaps the fields underneath has to
     read as being in front of them, and a border alone does not do it. */
  box-shadow: 0 10px 24px rgba(0, 0, 0, .16);
}
.acx__item {
  padding: 11px 12px; cursor: pointer;
  font-size: 15px; line-height: 1.35;
  border-bottom: 1px solid var(--rule);
}
.acx__item:last-child { border-bottom: 0; }

/* Opening upward, for a field sitting low on a short screen with the keyboard up. The offset
   itself is written by address.js; this only turns the shadow over. */
.acx__list--up { box-shadow: 0 -10px 24px rgba(0, 0, 0, .16); }
/* Hover and keyboard share one appearance, so the active row looks the same whichever
   way you got to it.

   THE ARIA STATE AND NOTHING ELSE. This also matched .is-on for a day, which is the state the
   site this ported from used. The script sets aria-selected, because that is the state a listbox
   option actually has, and a selector matching a class nobody emits is the dead-CSS shape that
   kept .addr wired while .acx was reviewed. One expression of one state. */
.acx__item:hover,
.acx__item[aria-selected="true"] { background: var(--ink); color: var(--paper); }

/* The announcement after a pick. Visible, not screen-reader-only: everybody benefits
   from being told three fields below just changed. */
.acx__said:empty { display: none; }
.acx__said {
  margin: 6px 0 0; font-size: 13px; line-height: 1.4; color: var(--mid);
}

/* The coverage answer keeps its slot whether or not it has anything in it, so filling
   a ZIP from the dropdown does not shove the date field down the page. */
.bookform__area:empty { display: none; }