/* Booking app additions to the shared stylesheet. Same tokens, same layers. */
@layer base {
  /* The bunkhouse's own colour. The server sets --accent from Settings,
     for the light scheme and the dark one; everything the pages paint
     green reads it through these three. The fallbacks are the colours the
     site was built in, so a bunkhouse that has never set one is unchanged.
     --on-green falls back to the paper, which is what the pages used
     before there was a colour to choose: white on the green by day, the
     dark ground on the lifted green by night. */
  :root {
    --green: var(--accent, #00873f);
    --green-hover: var(--accent-hover, #00823d);
    --on-green: var(--accent-on, var(--paper));
  }
  /* The fallbacks need a dark half of their own. These rules come after
     the shared stylesheet's, so without this a bunkhouse that has cleared
     its colour would take the daytime green into the dark, where the
     shared sheet had lifted it. */
  @media (prefers-color-scheme: dark) {
    :root {
      --green: var(--accent, #35b56d);
      --green-hover: var(--accent-hover, #4cc98a);
    }
  }
}

@layer components {
  :root { --danger: #9f1d1d; --warn: #b45309;
    /* For the copy of an email, whose own spacing is part of what was sent. */
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; }
  /* After dark the two signal colours are lifted the way the green is. */
  @media (prefers-color-scheme: dark) { :root { --danger: #ff8f8f; --warn: #eaad55; } }
  /* Links on the grey surfaces use the pressed green: the plain green measures 4.3:1 on stone. */
  booking-summary a, notice-box a, site-footer a { color: var(--sea); }
  site-footer a, a.brand { display: inline-block; padding-block: 0.3em; }
  booking-form, booking-summary, option-list, notice-box { display: block; }

  form.stay {
    display: grid;
    gap: var(--space-m);
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    align-items: end;
    max-inline-size: 44rem;
    & label { display: grid; gap: 0.3rem; font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); }
    & input, & select { font: inherit; font-family: var(--font-body); font-size: var(--step-0); color: var(--ink); background: var(--paper); border: 1px solid color-mix(in oklab, var(--ink) 30%, var(--paper)); border-radius: 3px; padding: 0.55em 0.7em; inline-size: 100%; min-inline-size: 0; }
    &.change { grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); max-inline-size: 44rem; & button { grid-column: 1 / -1; justify-self: start; } }
    & input:focus-visible, & select:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-color: var(--green); }
    & button { grid-column: 1 / -1; justify-self: start; }
  }
  form.details {
    display: grid;
    gap: var(--space-m);
    max-inline-size: 36rem;
    & label { display: grid; gap: 0.3rem; font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); }
    & input, & textarea { font: inherit; font-family: var(--font-body); font-size: var(--step-0); color: var(--ink); background: var(--paper); border: 1px solid color-mix(in oklab, var(--ink) 30%, var(--paper)); border-radius: 3px; padding: 0.55em 0.7em; inline-size: 100%; }
    & textarea { min-block-size: 5rem; resize: vertical; }
    & input:focus-visible, & textarea:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-color: var(--green); }
  }
  /* The profile's fields that are shown and not changed: laid out like a
     field's label, with what it is as plain text beneath. */
  form.details :is(label, p.field) small { font-family: var(--font-body); color: var(--muted); }
  form.details p.field { display: grid; gap: 0.3rem; margin: 0; font-size: var(--step-0); color: var(--ink);
    & > span { font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); } }
  form.details.profile { margin-block-start: var(--space-m); & > button { justify-self: start; } }
  notice-box form { margin-block-start: 0.5rem; & button.link { padding: 0; font-family: var(--font-body); font-size: inherit; color: var(--sea); text-decoration: underline; } }
  button.primary, a.button {
    display: inline-block; font: inherit; font-family: var(--font-display); font-size: var(--step--1);
    background: var(--green); color: var(--on-green); border: 1px solid var(--green); border-radius: 3px; padding: 0.8em 1.6em; cursor: pointer; text-decoration: none;
    transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
    &:hover { background: var(--green-hover); border-color: var(--green-hover); color: var(--on-green); }
  }
  a.quiet { display: inline-block; font: inherit; font-family: var(--font-display); font-size: var(--step--1); background: none; color: var(--green); border: 1px solid var(--green); border-radius: 3px; padding: 0.8em 1.6em; text-decoration: none; }
  a.quiet:hover { color: var(--green-hover); border-color: var(--green-hover); }
  /* A button's own display would otherwise beat the browser's rule for
     hidden, and show what the page has hidden. */
  [hidden] { display: none !important; }
  /* A heading the page does not need to show: the breadcrumb says where
     the guest is, but the document still needs its outline. */
  .sr-only { position: absolute; inline-size: 1px; block-size: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
  /* What to do next, said once and plainly. Each step asks one thing, so
     this is one line, and it keeps its height as the wording changes so
     the calendar below it never moves. */
  notice-box.guide { font-size: var(--step-1); color: var(--ink); min-block-size: 1lh;
    & p { margin: 0; } }
  /* An action row ends where the reading does: the way on last and hard
     against the right-hand edge, the way back beside it rather than
     stranded at the other end of the page. */
  p.actions { display: flex; flex-wrap: wrap; gap: var(--space-s); align-items: center; justify-content: flex-end; }
  /* What the row says about the choice so far stays on the left and takes
     the slack, so the buttons keep their end of it. */
  p.actions .party { flex: 1; min-inline-size: 0; }
  /* A summary line with nothing in it yet says nothing at all. */
  booking-summary dd:empty, booking-summary dt:has(+ dd:empty) { display: none; }
  /* The papers a guest can keep: the statement, and a receipt per payment. */
  p.papers { margin-block-start: var(--space-s); font-size: var(--step--1); color: var(--muted); max-inline-size: 34rem; }
  table.prices td:last-child a, table.list td:last-child a { font-size: var(--step--1); }
  /* The app's words are in sentence case, set as they are written. These
     two come from the stylesheet shared with the website, which still
     capitalises them, so they are set back here rather than there. */
  a.skip, table.prices th { text-transform: none; letter-spacing: normal; }
  /* Payments: what was paid, then the receipt for it. */
  table.payments { & td:nth-child(2) { text-align: end; font-variant-numeric: tabular-nums; } & td:last-child { inline-size: 5rem; } }
  /* One room to a row: the choice, what it costs, and why. */
  form.options { display: grid; gap: 0; max-inline-size: 40rem;
    & label.option { display: grid; grid-template-columns: auto 1fr auto; gap: 0.4rem var(--space-m); align-items: baseline; padding: var(--space-s) var(--space-m); border-block-start: 1px solid var(--line); border-radius: 3px; cursor: pointer; }
    & label.option:last-of-type { border-block-end: 1px solid var(--line); }
    & input[type=radio] { inline-size: 1.1rem; block-size: 1.1rem; accent-color: var(--green); margin: 0; align-self: center; }
    & option-what { display: grid; gap: 0.15rem; }
    & option-what small, & option-price small { display: block; color: var(--muted); font-size: var(--step--1); }
    & option-price { font-family: var(--font-display); font-size: var(--step-1); text-align: end; font-variant-numeric: tabular-nums; }
    & label.option:hover { background: color-mix(in oklab, var(--green) 5%, var(--paper)); }
    & label.option:has(:checked) { background: color-mix(in oklab, var(--green) 8%, var(--paper)); } }
  button.quiet, a.quiet-link, button.link, booking-calendar .pages a { transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease; }
  form.search { max-inline-size: none; grid-template-columns: 1fr auto auto; & label { grid-column: 1; } & button { grid-column: 2; justify-self: start; } & a { grid-column: 3; align-self: end; } }
  p.wide { max-inline-size: none; }
  .tight > * + * { margin-block-start: var(--space-s); }
  p.lede { font-size: var(--step-1); color: var(--muted); }
  p.pager { display: flex; gap: var(--space-m); align-items: baseline; }
  a.quiet-link { display: inline-block; font-family: var(--font-display); font-size: var(--step--1); color: var(--sea); text-decoration: none; padding: 0.8em 1em; }
  button.quiet { display: inline-block; font: inherit; font-family: var(--font-display); font-size: var(--step--1); background: none; color: var(--green); border: 1px solid var(--green); border-radius: 3px; padding: 0.8em 1.6em; cursor: pointer; &:hover { color: var(--green-hover); border-color: var(--green-hover); } }

  /* The booking flow's progress line: five numbered squares, done ones
     solid green, the current one hollow green, the rest grey. */
  /* The line belongs to the steps, so it ends where they do. */
  booking-steps { display: block; inline-size: fit-content; max-inline-size: 100%; margin-block-end: var(--space-m);
    & ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-s) var(--space-m); font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); }
    & li { display: flex; align-items: center; gap: 0.5em; }
    & b { display: grid; place-items: center; inline-size: 1.6rem; block-size: 1.6rem; box-sizing: border-box; border-radius: 3px; font-weight: 400; background: color-mix(in oklab, var(--ink) 14%, var(--paper)); color: var(--muted); }
    & li.done b { background: var(--sea); color: var(--paper); }
    & li.done { color: var(--ink); }
    & li.current { color: var(--ink); font-weight: 600; letter-spacing: 0.08em; }
    & li.current b { background: var(--paper); border: 2px solid var(--sea); color: var(--ink); }
    /* A step behind the guest is a link back to it, so it carries the green. */
    & a { color: var(--sea); text-decoration: none; display: flex; align-items: center; gap: 0.5em; transition: color 120ms ease; }
    & a:hover, & a:focus-visible { color: var(--sea-hover); text-decoration: underline; }
    /* A line under the steps, filled as far as the guest has come. */
    & progress-line { display: block; block-size: 2px; background: var(--line); margin-block-start: var(--space-s); }
    & progress-fill { display: block; block-size: 100%; background: var(--sea); inline-size: calc(var(--step) / var(--steps) * 100%); view-transition-name: booking-progress; } }
  /* The calendar of nights: a square per night, hollow green when there is
     room, solid grey when full, grey with a green edge when partly booked. */
  booking-calendar { display: block; max-inline-size: 26rem;
    & .range { font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); margin: 0 0 var(--space-s); }
    & ol { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
    & .weekdays { font-family: var(--font-display); font-size: 0.875rem; color: var(--muted); text-align: center; margin-block-end: 4px; }
    & .week { margin-block-start: 4px; }
    & .week li > * { display: grid; place-items: center; aspect-ratio: 1; box-sizing: border-box; border-radius: 3px; font-family: var(--font-display); font-size: var(--step--1); line-height: 1; text-decoration: none;
      /* Every state is the same box; only its colours move, so a night
         lighting up or greying out reads as a change rather than a repaint. */
      transition: background-color 140ms ease, border-color 140ms ease, color 140ms ease; }
    & a time { display: contents; }
    & .past { border: 2px solid transparent; color: color-mix(in oklab, var(--ink) 30%, var(--paper)); }
    & .free { border: 2px solid var(--green); color: var(--ink); background: var(--paper); }
    & a.free[href]:hover, & a.free[href]:focus-visible { background: var(--green); color: var(--on-green); }
    & .full { border: 2px solid transparent; background: color-mix(in oklab, var(--ink) 14%, var(--paper)); color: var(--muted); }
    & a:not([href]) { cursor: default; }
    & .start, & .in, & .end { background: var(--green); border: 2px solid var(--green); color: var(--on-green); }
    & a.can-end:hover { background: var(--green); color: var(--on-green); }
    & .pages { display: flex; justify-content: space-between; margin-block-start: var(--space-s); font-family: var(--font-display); font-size: var(--step--1); & a { text-decoration: none; padding-block: 0.3em; } } }
  /* The brand band: the mark and the name on the left, the address of the
     website they came from on the right, and nothing else. It is a header
     that says whose booking this is, not one that offers anywhere to go. */
  body.booking site-header {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: var(--space-s) var(--space-m);
    & .brand {
      display: flex; align-items: center; gap: 0.6rem;
      font-family: var(--font-display); font-size: var(--step-1); letter-spacing: 0.02em;
      color: var(--ink); text-decoration: none; line-height: 1;
      & img { inline-size: 2rem; block-size: 2rem; }
      &:hover span { color: var(--sea); }
    }
    /* The way out, said as the address so it is plain where it goes. */
    & .away {
      font-family: var(--font-display);
      font-size: var(--step--1); color: var(--sea); text-decoration: none;
      padding-block: 0.4em;
      &:hover { color: var(--sea-hover); text-decoration: underline; }
    }
  }
  /* The marketing site's own button, borrowed by the prices page along
     with its markup: uppercase, in the display face, on the green. In the
     flow it wears the flow's shape and the bunkhouse's own accent, like
     every other button here. */
  body.booking call-to-action a {
    font-family: inherit;
    text-transform: none;
    letter-spacing: normal;
    font-size: 1rem;
    padding: 0.75rem 1.5rem;
    border-radius: 8px;
    background: var(--jb-accent);
    color: var(--jb-accent-text);
    &:hover { background: var(--jb-accent-hover); color: var(--jb-accent-text); }
  }
  form.stay.party { max-inline-size: 26rem; }
  .continue[hidden] { opacity: 0; display: none; }
  @starting-style { .continue:not([hidden]) { opacity: 0; } }
  /* Appears once the date is chosen: a fade, since it arrives in place
     rather than from anywhere. */
  .continue { opacity: 1; transition: opacity 220ms ease, display 220ms allow-discrete; }
  option-list {
    display: grid;
    gap: var(--space-m);
    max-inline-size: 44rem;
    & article { display: grid; grid-template-columns: 1fr auto; gap: var(--space-s) var(--space-m); align-items: center; padding-block: var(--space-m); border-block-start: 1px solid var(--line); }
    & article:last-child { border-block-end: 1px solid var(--line); }
    & h2 { font-size: var(--step-1); }
    & .price { font-family: var(--font-display); font-size: var(--step-2); line-height: 1; text-align: end; }
    & .price small { display: block; font-family: var(--font-body); font-size: var(--step--1); margin-block-start: 0.3rem; }
    & ul { list-style: none; grid-column: 1 / -1; color: var(--muted); font-size: var(--step--1); }
    & li { display: block; margin-block-start: 0.2rem; }
    & a.button { grid-column: 2; justify-self: end; }
  }

  booking-summary {
    background: var(--grey);
    border-radius: 3px;
    padding: var(--space-m);
    max-inline-size: 36rem;
    & dl { display: grid; grid-template-columns: max-content 1fr; gap: 0.4rem var(--space-m); align-items: baseline; }
    & dt { font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); }
    & dd { font-variant-numeric: tabular-nums; }
    & table { inline-size: 100%; margin-block-start: var(--space-m); }
    & td { padding: 0.3em 0; border-block-start: 1px solid var(--line); }
    & td:last-child { text-align: end; }
    /* The total is the same money as the figures above it, said once more,
       so it is set the same: same face, same size. Fjalla One is condensed,
       so it read a size smaller than the body face beside it even when the
       size matched. The 2px rule above is what marks the row out. */
    & tr.total td { border-block-start: 2px solid var(--line); }
  }

  notice-box {
    border-inline-start: 3px solid var(--green);
    padding: var(--space-s) var(--space-m);
    background: var(--grey);
    max-inline-size: 36rem;
    /* A staff page's main is a plain block, so a notice between the title
       and the booking would otherwise sit flush against both. */
    body.staff main > & { margin-block: var(--space-m); }
    &.warn { border-inline-start-color: var(--warn); }
    /* Work that is real but not settled — a room change the day's work will
       drop if a cancellation makes it unnecessary. A solid edge says
       "this stands"; a pencilled one says "this is pencilled in". It is a
       pattern rather than a third colour, the way a blocked bed is. */
    &.provisional { border-inline-start-color: transparent;
      background-image: repeating-linear-gradient(135deg, var(--muted) 0 3px, transparent 3px 6px);
      background-size: 3px 100%; background-repeat: no-repeat; background-position: 0 0; }
  }
  p.error { color: var(--danger); font-weight: 600; max-inline-size: 36rem; }
  .ref { font-family: var(--font-display); letter-spacing: 0.08em; }
  .muted { color: var(--muted); }
  .two-col { display: grid; gap: var(--space-l); align-items: start; grid-template-columns: minmax(0, 1fr); & > * { min-inline-size: 0; } }
  @container page (min-width: 46rem) { .two-col { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
}

/* Staff area */
@layer base {
  /* The staff admin's palette, as handed over: semantic names only, and the
     dark values are counterparts rather than an inversion — "booked" is the
     solid pip in both, so on a dark ground it becomes light-on-dark and an
     empty slot reads empty. Nothing below refers to a colour by its hex. */
  :root {
    --bh-canvas: #f3f4f6;
    --bh-surface: #ffffff;
    --bh-surface-sunken: #f3f4f6;
    --bh-surface-hover: #f8f8fc;
    --bh-surface-hover-alt: #f0f7ff;
    --bh-border: #d1d5db;
    --bh-border-strong: #9ca3af;
    --bh-border-subtle: #efefef;
    --bh-border-control: #dddddd;
    --bh-text: #111827;
    --bh-text-strong: #090909;
    --bh-text-secondary: #4b5563;
    --bh-text-muted: #6b7280;
    --bh-text-faint: #9ca3af;
    --bh-text-on-accent: var(--accent-on, #ffffff);
    --bh-accent: var(--accent, #047857);
    --bh-accent-hover: var(--accent-hover, #0f5132);
    --bh-accent-quiet: color-mix(in oklab, var(--bh-accent) 10%, var(--bh-canvas));
    --bh-link: var(--accent-ink, #0f5132);
    --bh-link-hover: color-mix(in oklab, var(--bh-link) 82%, var(--bh-text));
    --bh-focus-ring: var(--accent, #047857);
    --bh-pip-booked: #090909;
    --bh-pip-booked-label: #ffffff;
    --bh-pip-owing: #f59e0b;
    --bh-pip-owing-border: #b45309;
    --bh-pip-owing-label: #422006;
    --bh-pip-private: #e5e7eb;
    --bh-pip-private-label: #4b5563;
    --bh-pip-blocked-a: #e5e7eb;
    --bh-pip-blocked-b: #f9fafb;
    --bh-pip-free: #ffffff;
    --bh-owing-text: #b45309;
    --bh-test-mode: #f97316;
    --bh-chart-fill: var(--accent-chart, #86c69f);
    --bh-chart-track: #f3f4f6;
    --bh-chart-label: var(--bh-text);
    --bh-inset-control: inset 0 0 5px rgb(0 0 0 / 5%);
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --bh-canvas: #0d100f;
      --bh-surface: #15191a;
      --bh-surface-sunken: #1d2224;
      --bh-surface-hover: #1f2527;
      --bh-surface-hover-alt: #16242b;
      --bh-border: #2c3336;
      --bh-border-strong: #556065;
      --bh-border-subtle: #23292b;
      --bh-border-control: #333b3e;
      --bh-text: #eef1f2;
      --bh-text-strong: #ffffff;
      --bh-text-secondary: #b6bfc2;
      --bh-text-muted: #97a1a5;
      --bh-text-faint: #78848a;
      --bh-text-on-accent: var(--accent-on, #04120c);
      --bh-accent: var(--accent, #3ddc97);
      --bh-accent-hover: var(--accent-hover, #6ee7b0);
      --bh-accent-quiet: color-mix(in oklab, var(--bh-accent) 10%, var(--bh-canvas));
      --bh-link: var(--accent-ink, #5fe3a6);
      --bh-link-hover: color-mix(in oklab, var(--bh-link) 82%, var(--bh-text));
      --bh-focus-ring: var(--accent, #3ddc97);
      --bh-pip-booked: #e8ecee;
      --bh-pip-booked-label: #0d100f;
      --bh-pip-owing: #d98a0b;
      --bh-pip-owing-border: #f0b355;
      --bh-pip-owing-label: #1a0f00;
      --bh-pip-private: #394246;
      --bh-pip-private-label: #cfd6d9;
      --bh-pip-blocked-a: #2a3134;
      --bh-pip-blocked-b: #1a1f21;
      --bh-pip-free: #15191a;
      --bh-owing-text: #f0b355;
      --bh-test-mode: #fb923c;
      --bh-chart-fill: var(--accent-chart, #2f7d5b);
      --bh-chart-track: #23292b;
      --bh-chart-label: var(--bh-text);
      --bh-inset-control: inset 0 0 5px rgb(0 0 0 / 35%);
    }
  }
  [data-theme="dark"] {
    --bh-canvas: #0d100f;
    --bh-surface: #15191a;
    --bh-surface-sunken: #1d2224;
    --bh-surface-hover: #1f2527;
    --bh-surface-hover-alt: #16242b;
    --bh-border: #2c3336;
    --bh-border-strong: #556065;
    --bh-border-subtle: #23292b;
    --bh-border-control: #333b3e;
    --bh-text: #eef1f2;
    --bh-text-strong: #ffffff;
    --bh-text-secondary: #b6bfc2;
    --bh-text-muted: #97a1a5;
    --bh-text-faint: #78848a;
    --bh-text-on-accent: var(--accent-on, #04120c);
    --bh-accent: var(--accent, #3ddc97);
    --bh-accent-hover: var(--accent-hover, #6ee7b0);
    --bh-accent-quiet: color-mix(in oklab, var(--bh-accent) 10%, var(--bh-canvas));
    --bh-link: var(--accent-ink, #5fe3a6);
    --bh-link-hover: color-mix(in oklab, var(--bh-link) 82%, var(--bh-text));
    --bh-focus-ring: var(--accent, #3ddc97);
    --bh-pip-booked: #e8ecee;
    --bh-pip-booked-label: #0d100f;
    --bh-pip-owing: #d98a0b;
    --bh-pip-owing-border: #f0b355;
    --bh-pip-owing-label: #1a0f00;
    --bh-pip-private: #394246;
    --bh-pip-private-label: #cfd6d9;
    --bh-pip-blocked-a: #2a3134;
    --bh-pip-blocked-b: #1a1f21;
    --bh-pip-free: #15191a;
    --bh-owing-text: #f0b355;
    --bh-test-mode: #fb923c;
    --bh-chart-fill: var(--accent-chart, #2f7d5b);
    --bh-chart-track: #23292b;
    --bh-chart-label: var(--bh-text);
    --bh-inset-control: inset 0 0 5px rgb(0 0 0 / 35%);
  }
}

@layer base {
  /* The staff area is a tool, not a brochure: the scale keeps still, so a
     wide window shows more rather than bigger. It has its own palette as
     well as its own scale — green carries the chrome here, where there is
     no brochure for it to compete with, and amber says money is owed. */
  body.staff {
    /* Nothing in the admin is set below 14px. The design asked for 12 and
       13 in places; a tool that is read all day does not get to be small,
       so the secondary sizes meet the body size instead and the weight,
       case and colour carry the difference. */
    --step--1: 0.875rem;
    --step-0: 0.875rem;
    --step-1: 1.125rem;
    --step-2: 1.375rem;
    --step-3: 1.75rem;
    --row: 0.9375rem;      /* the first line of a list row */
    --label: 0.875rem;     /* small labels and table headings */
    --ground: var(--bh-canvas);
    --card: var(--bh-border);
    --hair: var(--bh-border-subtle);
    --hover: var(--bh-surface-hover);
    --btn: var(--bh-border-control);
    --btn-hover: var(--bh-surface-hover-alt);
    --edge: var(--bh-border-strong);   /* what outlines a bed */
    --faint: var(--bh-text-faint);     /* a room number beside one */
    --testing: var(--bh-test-mode);
    --bar: var(--bh-chart-fill);
    --bar-track: var(--bh-chart-track);
    --bar-ink: var(--bh-chart-label);
    --green: var(--bh-accent);
    --green-hover: var(--bh-accent-hover);
    --on-green: var(--bh-text-on-accent);
    --link: var(--bh-link);
    --link-hover: var(--bh-link-hover);
    --ink: var(--bh-text);
    --muted: var(--bh-text-muted);
    --quiet: var(--bh-text-secondary);
    font-size: 14px;
    line-height: 1.4;
    background: var(--ground);
    color: var(--ink);
    /* The marketing body is a three-row grid for header, main and footer.
       The staff card is one block and centres itself, and an auto margin
       on a grid item shrink-wraps it instead of filling the row. */
    display: block;
    /* The admin follows the reader's machine like everything else. */
    color-scheme: light dark;
    --paper: var(--bh-surface);
    --grey: var(--bh-surface-sunken);
    --line: var(--card);
    --sea: var(--link);
    --sea-hover: var(--link-hover);
  }
  body.staff a { color: var(--link); &:hover { color: var(--link-hover); } }
}

@layer layout {
  /* Everything sits in one card on a grey ground: the tool has edges, so
     it does not read as a page that ran out. */
  app-card {
    max-inline-size: 1120px; margin: 0 auto;
    background: var(--bh-surface); border: 1px solid var(--card); border-radius: 0.5rem;
    /* Clipped rather than hidden, so it is not a scroller of its own and
       a header inside it can be pinned to the screen; flow-root keeps the
       new block formatting context that hidden gave it. */
    display: flow-root; overflow: clip;
  }
  body.staff { padding: 1.5rem 1.5rem 4rem; }
  app-head, app-tabs {
    display: flex; align-items: center; gap: 1.5rem;
    padding-inline: 1.5rem; border-block-end: 1px solid var(--card);
    & .spacer { flex: 1; }
  }
  app-head {
    min-block-size: 56px;
    & .brand { font-size: 1rem; font-weight: 500; color: var(--ink); text-decoration: none; }
    & .brand:hover { color: var(--green); }
  }
  /* Explain this page: the same words in the same corner of every page
     that has a guide. On a phone it says only "Explain", as New booking
     says only "New". */
  app-head a.explain {
    display: inline-flex; align-items: center; gap: 0.375rem;
    font-size: var(--step--1); color: var(--quiet); text-decoration: none;
    &:hover { color: var(--green); }
    & .ico { flex: none; }
  }
  /* The trial says so where it can be seen and nowhere else: a dot, not a
     banner across the top of the work. */
  test-mode {
    display: inline-flex; align-items: center; gap: 0.375rem;
    font-size: var(--label); color: var(--muted); margin-inline-start: -0.75rem;
    & span { inline-size: 6px; block-size: 6px; border-radius: 999px; background: var(--testing); }
  }
  app-tabs {
    font-size: var(--step-0); gap: 0;
    & tab-links { display: flex; gap: 1.5rem; }
    & a {
      color: var(--quiet); text-decoration: none; padding: 0.875rem 0;
      &:hover { color: var(--green); }
      &.here { color: var(--green); font-weight: 500; box-shadow: inset 0 -2px 0 var(--green); }
    }
    & a.cta {
      background: var(--green); border: 1px solid var(--green); color: var(--on-green);
      border-radius: 4px; padding: 0.375rem 0.875rem; margin-block: 0.375rem;
      &:hover { background: var(--green-hover); border-color: var(--green-hover); color: var(--on-green); }
    }
  }
  /* On a phone the grey ground around the card is width the grid needs,
     so the card runs to the edges, as the guest's cards do. The tabs close
     up and the button says only "New", which is enough beside them; if
     even that will not fit, it drops under the tabs rather than off the
     side of the card. */
  @media (max-width: 34rem) {
    body.staff:not(.out) {
      padding: 0;
      & app-card { border-width: 0 0 1px; border-radius: 0; }
      & app-head, & app-tabs { padding-inline: 1rem; }
      & main { padding: 1.25rem 1rem 2rem; }
    }
    app-tabs {
      flex-wrap: wrap;
      & tab-links { gap: 0.875rem; }
      /* The spacer keeps the button off the tabs, and stays behind on
         the first line if the button wraps, so it wraps flush left. */
      & .spacer { flex-basis: 0.5rem; }
      & a.cta { padding-inline: 0.625rem; }
      & a.cta .long { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
    }
    app-head { gap: 1rem;
      & a.explain .long { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
    }
  }
  /* The marketing main is a gutter grid with a large row gap; a tool wants
     neither, so the staff card's body is a plain block. */
  body.staff main {
    display: block; container: page / inline-size;
    padding: 2rem 1.75rem 3rem; row-gap: normal;
  }

  /* One card recipe for every panel on every screen. */
  panel-card {
    display: block; background: var(--bh-surface); border: 1px solid var(--card);
    border-radius: 0.5rem; overflow: hidden;
    &.spaced { margin-block-start: 1.5rem; }
  }
  panel-head {
    display: flex; align-items: baseline; gap: 0.5rem;
    margin-inline: 1rem; padding-block: 1rem 0.5rem;
    & h2 { font-size: var(--step-1); font-weight: 500; margin: 0; }
    & small { font-size: var(--step-0); color: var(--muted); }
    & .end { margin-inline-start: auto; font-size: var(--step-0); }
  }
  panel-card p.note, panel-card p.empty {
    margin: 0; padding: 0.25rem 1rem 1rem; color: var(--muted); font-size: var(--step-0);
  }
  /* Rows inside a card: hairlines between, nothing around. */
  table.rows {
    inline-size: 100%; border-collapse: collapse;
    & td {
      padding: 0.75rem 1rem; border-block-start: 1px solid var(--hair);
      vertical-align: top; font-size: var(--row);
    }
    & tr:hover td { background: var(--hover); }
    & td.quiet { color: var(--muted); font-size: var(--step-0); }
    & td.end { text-align: end; }
    & td.strip { inline-size: 1%; white-space: nowrap; }
    /* A guest's letter, drawn as one of their beds, so the eye goes from
       the name to the rooms card without a key. */
    & td.letter {
      inline-size: 1%; padding-inline-end: 0;
      & bed-dot { border: 1px solid var(--edge); border-radius: 4px; }
    }
    & td.beds { white-space: nowrap; }
  }

  /* The dashboard's heading and the day it is showing. */
  day-head {
    display: flex; align-items: start; gap: 1.5rem; flex-wrap: wrap;
    margin-block-end: 1.5rem;
    & hgroup { flex: 1; min-inline-size: 0; }
    & h1 {
      font-size: var(--step-3); font-weight: 500; color: var(--green);
      letter-spacing: -0.01em; margin: 0;
    }
    & hgroup p { margin: 0.25rem 0 0; font-size: var(--row); color: var(--quiet); }
  }
  /* A row of buttons that are one control: shared edges, outer corners. */
  btn-group {
    display: inline-flex;
    & > * {
      font: inherit; font-size: var(--step-0); color: var(--quiet);
      background: var(--ground); border: 1px solid var(--btn);
      padding: 0.375rem 0.75rem; margin-inline-start: -1px;
      text-decoration: none; cursor: pointer; white-space: nowrap;
      box-shadow: var(--bh-inset-control);
    }
    & > :first-child { margin-inline-start: 0; border-start-start-radius: 4px; border-end-start-radius: 4px; }
    & > :last-child { border-start-end-radius: 4px; border-end-end-radius: 4px; }
    & a:hover { background: var(--btn-hover); color: var(--green); }
    & .here { background: var(--bh-surface); color: var(--ink); font-weight: 500; box-shadow: none; cursor: default; }
  }

  /* The dashboard body: two columns that stack when there is not room. */
  day-body {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    align-items: start; gap: 1.5rem;
  }
  day-column { display: grid; gap: 1.5rem; align-content: start; }
  /* Arriving and leaving, together so the guide can point at the pair
     without the beds to change beneath them. */
  arrive-leave { display: grid; gap: 1.5rem; }
}

@layer components {
  /* Money that should already be here, and money that is simply coming.
     The words say which; the colour only agrees with them, so nothing
     depends on telling red from grey. */
  /* Money and how late it is. Amber says a balance is outstanding, which
     is what the bed's pip says beside it; red says the day for it has
     gone. Muting an amount that is merely coming would leave the pip
     saying one thing and the line under the name another. */
  small.overdue { color: var(--danger); font-weight: 600; }
  small.due { color: var(--bh-owing-text); font-variant-numeric: tabular-nums; }
  /* The money row on a booking's own page, when the day has gone. */
  booking-summary tr.overdue td { color: var(--danger); font-weight: 600; }
  /* A row of the import that cannot be read. */
  td.wrong { color: var(--danger); font-weight: 600; }
  h2 small.muted { font-family: var(--font-body); font-size: var(--step--1); margin-inline-start: 0.4em; }
  body.staff site-header { gap: var(--space-s) var(--space-m); }
  body.staff site-header nav ul { gap: 0.25rem 1.1rem; }
  body.staff site-header .brand { font-size: var(--step-1); }
  site-header .brand small { font-family: var(--font-display); font-size: 0.5em; color: var(--green); vertical-align: middle; }
  button.link { font: inherit; font-family: var(--font-display); font-size: var(--step--1); background: none; border: 0; padding: 0.4em 0; color: var(--ink); cursor: pointer; &:hover { color: var(--green); } }
  table.list { border-collapse: collapse; inline-size: 100%; font-size: var(--step--1); & td, & th { text-align: start; vertical-align: top; padding: 0.45em 0.6em 0.45em 0; border-block-end: 1px solid var(--line); } & th { font-family: var(--font-display); font-weight: 400; color: var(--muted); } & td:last-child, & th:last-child { padding-inline-end: 0; } }
  table.list.wide { min-inline-size: 48rem; }
  table.report { font-variant-numeric: tabular-nums; & td:nth-child(n+3), & th:nth-child(n+3) { text-align: end; } & tr.current td { font-weight: 600; } }
  /* The occupancy bar fills its own cell, so the column is the scale and
     two rows can be compared by looking rather than by reading. */
  occupancy-bar {
    display: block; block-size: 20px; background: var(--bar-track); border-radius: 3px;
    position: relative; overflow: hidden;
    &::before { content: ""; position: absolute; inset: 0; inline-size: var(--pct); background: var(--bar); }
    & b {
      position: relative; font-weight: 500; font-size: var(--step--1);
      color: var(--bar-ink); padding-inline-start: 0.375rem; line-height: 20px;
    }
  }
  table.list tr.bad td { background: color-mix(in oklab, var(--danger) 8%, var(--paper)); }
  form.details input[type=file] { border: 0; padding: 0; }
  /* The colour, typed or picked. The picker is a swatch the width of a
     button, beside the field that holds the actual value. */
  colour-field {
    display: flex; gap: var(--space-s); align-items: stretch;
    & input[name=accent] { inline-size: 10rem; font-variant-numeric: tabular-nums; }
    & input[type=color] {
      inline-size: 3.5rem; padding: 0.2rem; block-size: auto;
      border: 1px solid var(--btn, var(--line)); border-radius: 3px;
      background: var(--paper); cursor: pointer;
    }
  }
  p.note { max-inline-size: 44rem; font-size: var(--step--1); }
  ul.alternatives { list-style: none; padding: 0; margin: var(--space-s) 0 0; max-inline-size: 36rem;
    & li { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-m); padding-block: 0.6em; border-block-start: 1px solid var(--line); }
    & li:last-child { border-block-end: 1px solid var(--line); }
    & a { font-family: var(--font-display); font-size: var(--step--1); text-decoration: none; }
    & a:hover { text-decoration: underline; }
    & small { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; } }
  nav.jump { font-family: var(--font-display); font-size: var(--step--1); & a { text-decoration: none; } }
  section.settings { padding-block-start: var(--space-m); border-block-start: 1px solid var(--line); & h3 { margin-block-start: var(--space-m); } & form.details .row { align-items: end; } }
  table.rooms input[type=number] { inline-size: 5rem; }
  table.list input:not([type=checkbox]), table.list select { font: inherit; font-family: var(--font-body); font-size: var(--step-0); color: var(--ink); border: 1px solid color-mix(in oklab, var(--ink) 30%, var(--paper)); border-radius: 3px; padding: 0.35em 0.5em; inline-size: 100%; max-inline-size: 16rem; }
  table.list.narrow { inline-size: auto; & td { padding-inline-end: 2rem; } }
  .tw { overflow-x: auto; max-inline-size: 100%; container: table / inline-size; }
  /* The availability grid: seven columns where there is room for seven.
     Where there is not, the days wrap to as many as fit — down to one —
     and nothing scrolls sideways. A day is never narrower than its
     widest room of beds or its date; the second term only stops an
     eighth column, since eight of an eighth-plus-a-pixel will not fit.
     Every Monday starts a row, so a row is still a week or part of one,
     and a short week leaves its gap after the Sunday. */
  day-grid, day-cell { display: block; }
  day-grid {
    --day-min: max(6.5rem, calc(2.5rem + 2px + var(--button, 0px) + var(--beds, 4) * 22px));
    display: grid;
    /* Blocking wraps each room's beds in a button, and its edge and
       padding are width the day must find too. */
    &.editing { --button: 1rem; }
    grid-template-columns: repeat(auto-fill, minmax(max(var(--day-min), 100% / 8 + 1px), 1fr));
    gap: 1px;
  }
  /* The grid always opens on a Monday, so every seventh cell is one. */
  day-cell:nth-child(7n + 1) { grid-column-start: 1; }
  day-cell {
    padding: 0.625rem 0.625rem 0.75rem; position: relative;
    /* Each day rules the gap on all four sides of it. Neighbours draw
       the same line on the same pixel, so it never doubles; the space
       after a Sunday is ruled off by the days around it and stays blank,
       rather than being filled in and passing for a day gone by; and the
       card clips the lines at its edge, where its own border is. */
    box-shadow: 0 0 0 1px var(--hair);
    min-block-size: 96px; min-inline-size: 0;
    &.past { background: var(--bh-surface-sunken); }
    /* Today is drawn over the cell, not in its border, so it cannot move
       anything by a pixel or take a click. */
    &.today::after {
      content: ""; position: absolute; inset: 0;
      border: 2px solid var(--green); pointer-events: none;
    }
    & .date {
      display: block; font-size: var(--label); font-weight: 500; color: var(--ink);
      text-decoration: none; margin-block-end: 0.5rem;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    & a.date:hover { color: var(--green); }
  }
  grid-head {
    display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
    margin-block-end: 1rem;
    & .range { font-size: var(--step-1); color: var(--ink); margin: 0; }
    & .spacer { flex: 1; }
    /* On a phone the dates take a line of their own, and the controls
       sit under them at either end, whatever the dates' length. */
    @media (max-width: 34rem) {
      & .range { flex-basis: 100%; }
      & .spacer { display: none; }
      & a.switch { margin-inline-start: auto; }
    }
  }
  /* The blocking switch: a pill and a knob, the only control on the page
     that changes what the others do. */
  a.switch {
    display: inline-flex; align-items: center; gap: 0.5rem;
    font-size: var(--step--1); color: var(--quiet); text-decoration: none;
    & switch-track {
      inline-size: 34px; block-size: 20px; border-radius: 999px; flex: none;
      background: var(--bh-border-strong); display: flex; align-items: center; padding: 2px;
    }
    & switch-track::before {
      content: ""; inline-size: 16px; block-size: 16px; border-radius: 999px;
      background: var(--bh-surface); transition: translate 120ms;
    }
    &.on { color: var(--green); }
    &.on switch-track { background: var(--green); }
    &.on switch-track::before { translate: 14px 0; }
    &:hover switch-track { background: var(--bh-text-faint); }
    &.on:hover switch-track { background: var(--green-hover); }
  }
  @media (prefers-reduced-motion: reduce) { a.switch switch-track::before { transition: none; } }
  /* The legend sits under the card: five things a bed can be. */
  bed-key {
    display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem;
    margin-block-start: 1rem; font-size: var(--step--1); color: var(--muted);
    & span { display: inline-flex; align-items: center; gap: 0.45rem; }
    & bed-dot { border: 1px solid var(--edge); border-radius: 4px; inline-size: 22px; block-size: 18px; }
  }

  /* A page's guide. Without a script it is a card above the page, its
     callouts in order and the button that puts it away at the end. With
     one, guide.js shows the callouts a step at a time beside what each is
     about, and this card is never drawn. */
  guide-tour {
    display: grid; gap: 1.25rem 1.5rem; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    margin-block-end: 1.5rem; padding: 1.25rem;
    background: var(--bh-surface); border: 1px solid var(--card); border-inline-start: 3px solid var(--green); border-radius: 0.5rem;
    & form { grid-column: 1 / -1; margin: 0; }
  }
  guide-tour[hidden] { display: none; }
  @media (scripting: enabled) { guide-tour { display: none; } }
  :is(guide-step, guide-callout) {
    display: block; font-size: var(--step-0); color: var(--ink);
    & h2 { font-size: var(--step-1); font-weight: 500; margin: 0 0 0.5rem; }
    & p { margin: 0 0 0.5rem; }
    & ul.guide-key { margin-block-end: 0.5rem; }
    & ul:not(.guide-key) { margin: 0 0 0.5rem; padding-inline-start: 1.25rem; }
  }
  ul.guide-key {
    list-style: none; padding: 0; margin: 0; display: grid; gap: 0.5rem;
    & li { display: flex; align-items: start; gap: 0.625rem; }
    & bed-dot { flex: none; inline-size: 22px; block-size: 18px; margin-block-start: 0.05rem;
      border: 1px solid var(--edge); border-radius: 4px; }
  }
  /* The callout itself, and the ring round what it is about. The ring
     dims the rest of the page lightly, so the eye goes where the words
     point, but lets pointer and keyboard through: the booking step asks
     you to hover, and it would be a strange guide that stopped you. */
  guide-callout {
    position: absolute; z-index: 31; inline-size: min(22rem, calc(100vw - 2rem)); box-sizing: border-box;
    padding: 1rem 1.125rem; background: var(--bh-surface);
    border: 1px solid var(--card); border-radius: 0.5rem;
    box-shadow: 0 12px 32px rgb(0 0 0 / 18%), 0 2px 6px rgb(0 0 0 / 10%);
    &:focus { outline: none; }
    & .arrow {
      position: absolute; inline-size: 12px; block-size: 12px; rotate: 45deg;
      background: inherit; border: inherit; border-radius: 2px;
    }
    &.below .arrow { inset-block-start: -7px; border-inline-end: 0; border-block-end: 0; }
    &.above .arrow { inset-block-end: -7px; border-inline-start: 0; border-block-start: 0; }
    & footer { display: flex; align-items: center; gap: 0.5rem; margin-block-start: 1rem; }
    & .count { margin-inline-end: auto; color: var(--muted); }
    & button { font: inherit; font-size: var(--step--1); cursor: pointer; border-radius: 4px; padding: 0.5rem 0.875rem; }
    & button.skip { background: none; border: 0; padding-inline: 0.25rem; color: var(--muted); text-decoration: underline; }
    & button.back { background: var(--ground); color: var(--quiet); border: 1px solid var(--btn); }
    & button.primary { padding: 0.5rem 1rem; }
    /* On a phone there is no room beside anything, so the callout is a
       sheet along the bottom and the page scrolls what it is about into
       the space above it. */
    &.sheet { position: fixed; inset: auto 0.75rem 0.75rem; inline-size: auto;
      & .arrow { display: none; } }
  }
  guide-spot {
    position: absolute; z-index: 30; pointer-events: none; border-radius: 6px;
    box-shadow: 0 0 0 3px var(--green), 0 0 0 100vmax rgb(0 0 0 / 22%);
  }

  /* Both tables have a fixed track budget, so a long name cannot push the
     money off the end and two pages of results line up with each other. */
  table.grid-table {
    inline-size: 100%; border-collapse: collapse; table-layout: fixed;
    font-size: var(--step-0);
    & th, & td { box-sizing: border-box; padding: 0.75rem; vertical-align: top; text-align: start; }
    & th:first-child, & td:first-child { padding-inline-start: 1rem; }
    & th:last-child, & td:last-child { padding-inline-end: 1rem; }
    & th {
      font-size: var(--label); font-weight: 400;
      color: var(--muted);
    }
    & td { border-block-start: 1px solid var(--hair); }
    & tbody tr:hover td { background: var(--hover); }
    & .num { text-align: end; font-variant-numeric: tabular-nums; }
    & td.quiet { color: var(--muted); }
    & td.name { font-size: var(--row); }
    & td.strip { overflow: hidden; }
    & tr.current td { font-weight: 500; }
  }
  /* The columns are the sorting handoff's (2a), with the date the list
     is in order of first. Its heading is dark, since it is the one doing
     the ordering; the date under it is written once a day, and the rule
     above the first booking of a day is darker than the ones inside it,
     so each day reads as a block. */
  table.bookings {
    & .c-day { inline-size: 8.25rem; } & .c-mark { inline-size: 1.75rem; }
    & .c-ref { inline-size: 7rem; } & .c-other { inline-size: 9.375rem; }
    & .c-nights { inline-size: 7rem; } & .c-beds { inline-size: 12rem; }
    & .c-total { inline-size: 5.5rem; }
    & .c-name { min-inline-size: 200px; }
    & th.c-day { color: var(--ink); font-weight: 600; }
    & th:first-child, & td:first-child { padding-inline-start: 1.25rem; }
    & th:last-child, & td:last-child { padding-inline-end: 1.25rem; }
    & td { border-block-start-color: var(--hair); }
    & tr.newday td, & tr.today + tr td { border-block-start-color: color-mix(in oklab, var(--hair), var(--card)); }
    & td.day {
      & .wide { display: flex; flex-direction: column; gap: 0.125rem; }
      & strong { font-weight: 600; }
      & small { font-size: var(--step-0); color: var(--muted); }
      & .gutter { display: none; }
    }
    & tr.past td.day { color: var(--faint); }
    & td.mark { padding-inline: 0; }
    & td.name { color: var(--quiet); }
    & td.other .phone { display: none; }
    & td.nights { padding-inline-end: 1.75rem;
      & small { display: block; font-size: var(--step-0); color: var(--muted); white-space: nowrap; }
    }
    & td.total { font-weight: 500; }
    /* A reference is one word and must not break: it is what staff read
       out on the telephone. Nor should a date. */
    & td.day, & td.ref, & td.other { white-space: nowrap; }
    & td.ref a { letter-spacing: 0.06em; }
    /* The whole row opens the booking. The reference is still the one
       link, so a keyboard or a screen reader meets one stop a row, but it
       is stretched over the row it sits in; nothing else in a row is a
       link to be covered. The ring a focused link draws goes round the
       row it now fills. */
    & tbody tr { position: relative; }
    & td.ref a::after { content: ""; position: absolute; inset: 0; }
    & td.ref a:focus-visible { outline: none; }
    & tbody tr:has(td.ref a:focus-visible) { outline: 2px solid var(--green); outline-offset: -2px; }
    /* The line to show the arrivals before today, and the line for today
       once they are showing. A link lands on a row with a little room
       above it, and under the pinned header on a phone. */
    & tbody tr[id] { scroll-margin-block-start: 1rem; }
    & tr.more td {
      background: var(--bh-surface-sunken); padding-block: 0.75rem;
      & a { text-decoration: none; }
      & a + a { float: inline-end; }
    }
    & tr.more:hover td { background: var(--bh-surface-sunken); }
    & tr.today td {
      border: 0; padding-block: 0.5rem;
      & > span { display: flex; align-items: center; gap: 0.75rem;
        font-size: var(--label); font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--green); }
      & > span::after { content: ""; flex: 1; block-size: 2px; background: var(--green); }
    }
    & tr.today:hover td, & tr.none:hover td { background: none; }
    & tr.none td { color: var(--muted); }
  }
  table.reports {
    /* Wide enough for the current week and its "so far". */
    & .c-period { inline-size: 14rem; } & .c-bn { inline-size: 7.5rem; }
    & .c-bk { inline-size: 6.5rem; } & .c-pp { inline-size: 5.5rem; }
    & .c-in { inline-size: 6rem; } & .c-rc { inline-size: 6.5rem; }
    & .c-occ { min-inline-size: 200px; }
    & td:nth-child(2) { vertical-align: middle; }
    & td, & th:not(.c-occ):not(.c-period) { white-space: nowrap; }
  }
  /* Words a column heading says for the whole table, which a row has to
     say for itself once it is not in a column. */
  table.grid-table span.phone { display: none; }
  /* Where a table has no room for its columns, a fixed table that is
     squeezed writes one column over the next: its flexible column's
     200px minimum counts for nothing once the fixed tracks have taken
     their share. So each row becomes a small block of its own, in the
     order the eye wants it: for a period, the period and its bar, then
     the figures, each under its own label; the bookings have their own
     arrangement, further down. Nothing scrolls sideways.

     That happens on a tablet as well as a phone, so it asks the width of
     the table's own box rather than the screen's. The reports' tracks are
     46rem, and 59.5rem gives their occupancy bar 200px; an iPad held
     sideways keeps both tables as tables. */
  @media (max-width: 34rem) { panel-head { flex-wrap: wrap; } }
  /* The bookings card: its header holds the two orders as tabs, and it
     is measured as well as the table in it, so the header knows when the
     list has turned into cards. The card has a border and no padding, so
     its box is the table's. It clips rather than hides what overflows,
     so the header can be pinned while the list scrolls under it. */
  panel-card.bookings {
    container: list / inline-size; overflow: clip;
    & panel-head {
      flex-wrap: wrap; align-items: flex-end; gap: 0 1.75rem;
      margin: 0; padding: 0 1.25rem; border-block-end: 1px solid var(--card);
      background: var(--bh-surface);
      & h2 { font-size: 1.25rem; padding-block: 0.875rem; }
      & .end { display: flex; gap: 1.25rem; padding-block-end: 0.875rem; }
      & .end a { font-size: var(--step-0); }
    }
    & nav.sort-tabs {
      display: flex; gap: 1.375rem; font-size: var(--row);
      & a { color: var(--quiet); text-decoration: none; padding-block: 0.875rem 0.6875rem; border-block-end: 3px solid transparent; }
      & a:hover { color: var(--green); }
      & a.here { color: var(--green); border-block-end-color: var(--green); }
    }
    & p.list-foot { display: none; }
  }
  @container list (width < 62.5rem) {
    panel-card.bookings {
      & panel-head {
        position: sticky; inset-block-start: 0; z-index: 2;
        padding-inline: 1rem; column-gap: 1.25rem;
        & h2 { flex-basis: 100%; padding-block-end: 0; }
        & .end { margin-inline-start: auto; }
        & a.csv { display: none; }
      }
      & p.list-foot {
        display: block; margin: 0; padding: 1rem; border-block-start: 1px solid var(--hair);
        font-size: var(--step-0);
      }
    }
  }
  @container table (width < 59.5rem) {
    table.grid-table.reports {
      display: block; table-layout: auto;
      & thead { display: none; }
      & tbody { display: block; }
      & tr { display: grid; gap: 0.25rem 1rem; padding: 0.75rem 1rem; border-block-start: 1px solid var(--hair); }
      & tr:hover { background: var(--hover); }
      & tbody tr:hover td { background: none; }
      & td { display: block; padding: 0; border: 0; min-inline-size: 0; }
      & span.phone { display: inline; }
    }
    table.grid-table.reports {
      & tr { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 0.5rem; }
      & td:nth-child(-n + 2) { grid-column: 1 / -1; }
      & td.num { text-align: start; }
      & span.phone {
        display: block; font-size: var(--label);
        color: var(--muted); font-weight: 400;
      }
    }
  }

  /* The bookings as cards, where the columns do not fit: the handoff's
     1b. The date the list is in order of runs down a column on the left
     like a calendar's, once for each day, and the rest folds into three
     lines: the circle, who and how much; the other date and the nights;
     the reference and the beds. The second and third lines start under
     the name. The fixed tracks above come to 50rem, and the name wants
     200px more. */
  @container table (width < 62.5rem) {
    table.grid-table.bookings {
      display: block; table-layout: auto;
      & thead { display: none; }
      & tbody { display: block; }
      & tr {
        display: grid; column-gap: 0.625rem; row-gap: 0.3125rem;
        grid-template-columns: 4rem auto minmax(0, 1fr) auto;
        grid-template-areas: "day mark name total" "day . other other" "day . ref beds";
        padding-block: 0.75rem; padding-inline: 0 1rem;
        border-block-start: 1px solid var(--hair);
      }
      & tr.newday, & tr.today + tr { border-block-start-color: color-mix(in oklab, var(--hair), var(--card)); }
      & tr:hover { background: var(--hover); }
      & tbody tr:hover td { background: none; }
      & td { display: block; padding: 0; border: 0; min-inline-size: 0; }
      & th:first-child, & td:first-child, & th:last-child, & td:last-child { padding-inline: 0; }
      & td.day { grid-area: day; text-align: center;
        & .wide { display: none; }
        & .gutter { display: flex; flex-direction: column; align-items: center; gap: 0.0625rem; }
        & b { font-size: var(--label); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
        & big { font-size: 1.5rem; font-weight: 600; line-height: 1; }
        & small { font-size: var(--label); }
      }
      & td.mark { grid-area: mark; align-self: center; }
      & td.name { grid-area: name; font-size: 1rem; }
      & td.total { grid-area: total; }
      & td.other { grid-area: other; white-space: normal;
        & .wide { display: none; }
        & .phone { display: inline; }
      }
      & td.nights { display: none; }
      & td.ref { grid-area: ref; align-self: center; }
      & td.strip { grid-area: beds; justify-self: end; }
      & tbody tr[id] { scroll-margin-block-start: 6.5rem; }
      & tr.more, & tr.today, & tr.none { display: block; padding: 0; }
      & tr.more td { padding: 0.75rem 1rem; }
      /* "Today" sits in the date column, and its line runs across the
         rest. */
      & tr.today td { padding: 0.5rem 1rem 0.5rem 0;
        & > span { gap: 0.625rem; }
        & .label { inline-size: 4rem; text-align: center; }
        & .wide { display: none; }
      }
      & tr.none td { padding: 0.75rem 1rem; }
    }
  }

  /* Finding a booking: one field, and a line saying what it understands. */
  find-block {
    display: block; margin-block-end: 1.75rem;
    & label { display: block; font-size: var(--label); color: var(--quiet); margin-block-end: 0.375rem; }
    & .row { display: flex; gap: 0.625rem; align-items: center; }
    & input {
      font: inherit; flex: 1; min-inline-size: 0; color: var(--ink); background: var(--bh-surface);
      border: 1px solid var(--green); border-radius: 4px; padding: 0.5rem 0.75rem;
    }
    & button.find-go {
      font: inherit; font-size: var(--step--1);
      color: var(--green); background: none; border: 0; padding: 0.5rem 0.25rem; cursor: pointer;
      &:hover { color: var(--green-hover); }
    }
    & .hint { margin: 0.625rem 0 0; font-size: var(--step-0); color: var(--muted); & em { font-style: italic; } }
  }
  p.footnote { margin-block-start: 1rem; font-size: var(--step--1); color: var(--muted); max-inline-size: 60rem; }
  p.pager { margin-block-start: 1rem; font-size: var(--step-0); color: var(--muted); }

  /* A strip of beds. One visual language wherever beds appear: the strip
     has the edge, the segments divide it, and only the fill says what a
     bed is. The size changes with the screen, nothing else does. */
  bed-grid { display: flex; flex-wrap: wrap; gap: 0.3rem 0.45rem; }
  room-beds { display: flex; gap: 0.375rem; align-items: stretch; }
  bed-row {
    --bed-r: 4px;   /* the strip's radius less its one-pixel border */
    display: flex; border: 1px solid var(--edge); border-radius: 5px;
    inline-size: max-content;
  }
  /* One booking's neighbouring beds. The strip does not clip them, so the
     outline that marks a booking can be seen; the ends are rounded on the
     beds themselves instead. */
  bed-run { display: flex; border-radius: inherit; }
  bed-dot, a.bed, button.bed-dot {
    display: flex; align-items: center; justify-content: center;
    inline-size: 28px; block-size: 22px; box-sizing: border-box;
    border: 0; border-inline-start: 1px solid var(--edge);
    background: var(--bh-pip-free); font-size: var(--step--1); font-weight: 600; line-height: 1;
  }
  /* The end beds sit inside the strip's 1px border, so their corners take
     the strip's radius less that border. Matching it exactly makes the
     inner curve cut across the outer one and leaves a sliver of the
     border showing at each corner. */
  bed-row > :first-child > :first-child { border-inline-start: 0; }
  bed-row > :first-child > :first-child { border-start-start-radius: var(--bed-r); border-end-start-radius: var(--bed-r); }
  bed-row > :last-child > :last-child { border-start-end-radius: var(--bed-r); border-end-end-radius: var(--bed-r); }
  /* A bed somebody is in. Ink, because occupancy is what these pages are
     made of; amber when that booking still owes, which is the one thing
     a colour is spent on here. */
  bed-dot.taken, a.bed { background: var(--bh-pip-booked); color: var(--bh-pip-booked-label); text-decoration: none; }
  bed-dot.taken.owes, a.bed.owes { background: var(--bh-pip-owing); color: var(--bh-pip-owing-label); border-inline-start-color: var(--bh-pip-owing-border); }
  /* Pointing at a booking draws a line round the beds it holds — here and
     on every other night it covers. An outline, so it sits outside the
     beds and neither crowds the numbers nor squares off the strip; and a
     wide one, because it is doing two jobs at once: saying this is a thing
     you can press, and picking the booking out of a season of them. */
  bed-run.here {
    outline: 3px solid var(--bh-accent);
    outline-offset: 1px;
    border-radius: 4px;
    position: relative; z-index: 1;
  }
  /* A bed nobody is in that nobody may have: the room is private to a
     booking. Lettered, not shaded, so it is never mistaken for money. */
  bed-dot.held { background: var(--bh-pip-private); }
  bed-dot.held::after { content: "P"; color: var(--bh-pip-private-label); font-size: var(--step--1); font-weight: 600; }
  /* Blocked is told apart by its hatching, not by being a third grey. */
  bed-dot.blocked, button.bed-dot.blocked {
    background: repeating-linear-gradient(135deg, var(--bh-pip-blocked-a) 0 3px, var(--bh-pip-blocked-b) 3px 6px);
  }
  /* On the availability grid every room shows, so they stack: a line each,
     numbered, which reads the same whether there are three rooms or ten. */
  day-cell bed-grid { display: grid; justify-items: start; gap: 0.1875rem; }
  day-cell bed-dot, day-cell a.bed, day-cell button.bed-dot { inline-size: 22px; block-size: 18px; }
  day-cell bed-row { border-radius: 4px; --bed-r: 3px; }
  /* The room number is centred the way a bed's own number is — a flex box
     centring its line — rather than left to sit on a baseline in a box one
     em tall. A digit's ink is not centred in that box, so the two numbers
     on a line did not agree. */
  room-no {
    display: flex; align-items: center; justify-content: flex-end;
    font-size: var(--step--1); line-height: 1; color: var(--faint);
    min-inline-size: 0.75rem;
  }
  /* In a table the strips sit a shade shorter, so a row is a row. */
  table.grid-table bed-dot, table.grid-table a.bed { inline-size: 22px; block-size: 18px; }

  /* The key under the grid: the four things a bed can be, drawn the same
     way they are drawn above it. Standing alone, each is rounded all round. */
  ul.bed-key {
    list-style: none; margin: var(--space-s) 0 0; padding: 0;
    display: flex; flex-wrap: wrap; gap: 0.4rem 1.4rem;
    font-size: var(--step--1); color: var(--muted);
    & li { display: flex; align-items: center; gap: 0.45rem; }
    & bed-dot { border-radius: 0.45rem; flex: none; }
  }
  /* Where a stay stands, as a circle at the start of its row in the
     bookings list, and the key to them under it. Red is money that
     should already be here. */
  stay-mark {
    display: inline-flex; color: var(--muted);
    & svg { display: block; }
    &.late { color: var(--danger); }
  }
  /* Level with the first line of the name beside it. */
  td.mark stay-mark { margin-block-start: 0.2rem; }
  ul.stay-key {
    list-style: none; margin: var(--space-s) 0 0; padding: 0;
    display: flex; flex-wrap: wrap; gap: 0.4rem 1.4rem;
    font-size: var(--step--1); color: var(--muted);
    & li { display: flex; align-items: center; gap: 0.45rem; }
  }
  ul.stay-guide stay-mark { flex: none; margin-block-start: 0.15rem; }
  /* A charge or a refund is a small, deliberate thing, so it is asked for
     over the booking rather than on a page of its own. The dialog opens
     from the button's own command attribute — no script anywhere. */
  dialog.adjust {
    border: 1px solid var(--line); border-radius: 0.5rem; padding: var(--space-m);
    inline-size: min(28rem, calc(100vw - 2rem)); margin: auto; background: var(--paper); color: var(--ink);
    box-shadow: var(--shadow);
    /* The scrim pushes the page back, so it is dark in both themes: in
       dark mode a wash of --ink would lift the page rather than dim it. */
    &::backdrop { background: rgb(0 0 0 / 45%); }
    & h2 { margin-block-start: 0; }
    & label { display: grid; gap: 0.3rem; font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); }
    & input { font: inherit; font-family: var(--font-body); font-size: var(--step-0); color: var(--ink); background: var(--paper); border: 1px solid color-mix(in oklab, var(--ink) 30%, var(--paper)); border-radius: 3px; padding: 0.45em 0.6em; inline-size: 100%; }
    & p.actions { display: flex; gap: var(--space-s); align-items: center; }
  }

  /* Changing a booking is a short list of what there is to change, each
     with what it says now underneath. Hairlines rather than boxes, and the
     whole row is the link so there is no small target to find. */
  ul.choices {
    list-style: none; margin: 0; padding: 0;
    border-block-start: 1px solid var(--line); max-inline-size: 34rem;
    & li { border-block-end: 1px solid var(--line); }
    & a {
      display: grid; gap: 0.15rem; padding: var(--space-s) 0;
      text-decoration: none; color: var(--sea);
      & strong { font-family: var(--font-display); font-weight: 400; font-size: var(--step--1); }
      & span { color: var(--muted); font-size: var(--step--1); }
      &:hover strong, &:focus-visible strong { text-decoration: underline; }
    }
  }

  form.inline.amend input[type=number] { inline-size: 5rem; }
  form.inline { display: flex; flex-wrap: wrap; gap: var(--space-s) var(--space-m); align-items: end;
    & label { display: grid; gap: 0.3rem; font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); }
    & input, & select { font: inherit; font-family: var(--font-body); font-size: var(--step-0); color: var(--ink); border: 1px solid color-mix(in oklab, var(--ink) 30%, var(--paper)); border-radius: 3px; padding: 0.45em 0.6em; }
  }
  details.more { border-block-start: 1px solid var(--line); padding-block-start: var(--space-s);
    & summary { cursor: pointer; font-family: var(--font-display); font-size: var(--step--1); color: var(--green); }
    & summary::before { content: "▸ "; } &[open] summary::before { content: "▾ "; }
    & > * + * { margin-block-start: var(--space-s); } }
  /* What has happened to a booking, newest last: a line each, the moment
     and who did it in the quiet type, what they did in the loud one. */
  section.history { max-inline-size: none; }
  ol.history { list-style: none; margin: 0; padding: 0; max-inline-size: none; display: grid; gap: 0;
    & li { max-inline-size: none; display: grid; grid-template-columns: 11rem max-content minmax(0, 1fr) max-content; gap: 0.4rem var(--space-m); align-items: baseline; padding-block: 0.55em; border-block-start: 1px solid var(--line); }
    & li:last-child { border-block-end: 1px solid var(--line); }
    & time, & small { color: var(--muted); font-size: var(--step--1); }
    & time { font-variant-numeric: tabular-nums; }
    & b { font-family: var(--font-display); font-size: var(--step--1); font-weight: 400; }
    & .what { color: var(--ink); }
    & small { text-align: end; } }
  /* An email is one row, all of it the way in. The copy keeps the
     spacing it was sent with, so it is set in a fixed-width face. */
  ol.history.emails li { display: block; padding: 0; border: 0;
    & details { border-block-start: 1px solid var(--line); }
    & details[open] { padding-block-end: var(--space-s); }
    & summary { display: grid; grid-template-columns: 11rem minmax(0, 1fr) max-content 1rem; gap: 0.4rem var(--space-m); align-items: baseline; padding-block: 0.55em; cursor: pointer; list-style: none; }
    & summary::-webkit-details-marker { display: none; }
    & summary::after { content: "▾"; color: var(--muted); justify-self: end; }
    & details[open] summary::after { content: "▴"; }
    & summary:hover .what { color: var(--green); }
    & .what { color: var(--ink); }
    & .failed { color: var(--danger); }
    /* What happened after it left, as the platform reported it. Only the
       bad news is loud; a delivery is a quiet confirmation. */
    & .waiting { color: var(--warn); }
    & .arrived { color: var(--muted); font-weight: 400; }
    & .to { margin: var(--space-s) 0 0; color: var(--muted); font-size: var(--step--1); max-inline-size: none; }
    & pre { margin: 0; padding: var(--space-m); background: var(--grey); border-radius: 3px; font-family: var(--font-mono); font-size: var(--step--1); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
    /* The envelope, then the letter in whichever form is asked for. */
    & pre.head { margin-block-end: var(--space-s); color: var(--muted); }
    & email-view > pre.plain { background: var(--paper); } }
  ol.history.emails li:last-child details { border-block-end: 1px solid var(--line); }

  /* A step of the flow in the admin is the guest's column: 660px in the
     middle of the card, one thing under another, rather than a form pushed
     against the card's left edge or spread across two columns. */
  body.staff.flow main {
    margin-inline: auto; max-inline-size: calc(660px + 3.5rem);
    /* The admin reads at 14px; a step of the flow is a form, and reads at
       the guest's 16px like the fields and buttons in it. */
    font-size: 1rem; line-height: 1.5;
    /* An action row is not prose, so the measure does not hold it back
       from the edges of the column its buttons line up with. Nor are the
       callout and the summaries, which are cards the width of the column
       like every other card in it. */
    & :is(p.actions, notice-box, booking-summary) { max-inline-size: none; }
    /* The steps that were two columns stack now, and what was side by side
       needs the gap a stack has. */
    & .two-col.aside > * + *, & section.flow > * + * { margin-block-start: 1.5rem; }
    /* A step whose heading is for screen readers starts at its callout. */
    & > h1.sr-only + notice-box { margin-block-start: 0; }
  }
  /* Two fields on a line are one height, whatever kind of field each is. */
  body.staff.flow jb-card.fields .row :is(input, select) { block-size: 3.1875rem; box-sizing: border-box; }

  /* The flow's summary is a grey box on the guest's own pages; in the
     admin it is a panel like every other one, so the two columns of a step
     are the same kind of thing. */
  body.staff booking-summary {
    background: var(--paper); border: 1px solid var(--card); border-radius: 0.5rem; padding: 1rem;
    & table { margin-block-start: 1rem; }
    /* In the flow the labels are the size of what they label, as they are
       in the guest's summary card. */
    body.staff.flow & dt { font-size: inherit; }
  }

  /* A booking's own page. The stay and what has happened to it run down
     the left; the money, and what can be done to the booking, down a
     narrow rail on the right. Where there is not room for both the rail
     comes in under the stay, and on a phone the price lines and the
     activity fold away behind a line each. The handoff set its labels at
     11.5px in capitals and its secondary text at 12 and 13; here they are
     14px in sentence case, like the rest of the admin. */
  a.back-link {
    display: inline-block; font-size: var(--step-0); color: var(--muted); text-decoration: none;
    margin-block-end: 0.875rem;
    &:hover { color: var(--link-hover); }
  }
  booking-head {
    display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 1rem;
    padding-block-end: 1.25rem; margin-block-end: 1.5rem; border-block-end: 1px solid var(--hair);
    & > div { min-inline-size: 0; }
    & h1 { margin: 0 0 0.5rem; font-size: 1.625rem; font-weight: 500; line-height: 1.25; letter-spacing: -0.01em; color: var(--ink); }
    & .ref { font-family: var(--font-mono); font-size: 1.5rem; letter-spacing: 0.02em; color: var(--green); }
    & .who { padding-inline-start: 0.375rem; }
    & p.chips { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin: 0; font-size: var(--step-0); color: var(--muted); }
    & a.papers { font-size: var(--step-0); }
  }
  /* What state a booking is in, as a word on a pill. Green for a booking
     that stands; amber and red say what they say everywhere else, that
     money is owed and that its day has gone. */
  b.chip {
    display: inline-block; border-radius: 999px; padding: 0.1875rem 0.625rem; white-space: nowrap;
    font-size: var(--step-0); font-weight: 400; background: var(--bh-surface-sunken); color: var(--quiet);
    /* Words on a tint of their own colour need that colour's reading
       shade: the green's ink, and the amber taken a step towards the ink. */
    &.good { background: color-mix(in oklab, var(--green) 14%, var(--bh-surface)); color: var(--link); font-weight: 500; }
    &.owes { background: color-mix(in oklab, var(--bh-owing-text) 10%, var(--bh-surface)); color: color-mix(in oklab, var(--bh-owing-text) 85%, var(--ink)); font-weight: 500; }
    &.late { background: color-mix(in oklab, var(--danger) 10%, var(--bh-surface)); color: var(--danger); font-weight: 500; }
  }
  booking-body { display: grid; grid-template-columns: minmax(0, 1fr); align-items: start; gap: 1.5rem; }
  booking-main, booking-rail { display: grid; align-content: start; gap: 1.5rem; min-inline-size: 0; }
  @container page (width > 52rem) {
    booking-body { grid-template-columns: minmax(0, 1.75fr) minmax(300px, 1fr); }
  }
  /* In one column the rail comes in after the stay rather than after
     everything, so the money is not under a screen of history. */
  @container page (width <= 52rem) {
    booking-main, booking-rail { display: contents; }
    panel-card.stay { order: 1; }
    panel-card.money { order: 2; }
    panel-card.changes { order: 3; }
    panel-card.activity { order: 4; }
  }

  /* The stay: when, and where, across the top; who, underneath. */
  stay-strip {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px;
    background: var(--hair); border-block: 1px solid var(--hair);
  }
  stay-cell {
    display: block; min-inline-size: 0; padding: 0.875rem 1rem; background: var(--bh-surface);
    & .label { display: block; margin-block-end: 0.3125rem; font-size: var(--label); color: var(--muted); }
    & .value { font-size: 0.9375rem; color: var(--ink); }
  }
  /* The room, its beds as the grid draws them, and which are the party's. */
  stay-room {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.5rem;
    & + stay-room { margin-block-start: 0.75rem; }
    & small { flex-basis: 100%; font-size: var(--step-0); color: var(--muted); }
    & bed-dot { inline-size: 22px; block-size: 18px; }
  }
  dl.facts {
    display: grid; grid-template-columns: 5.625rem minmax(0, 1fr); gap: 0.625rem 1rem;
    margin: 0; padding: 1rem; font-size: var(--step-0);
    & dt { color: var(--muted); }
    & dd { margin: 0; min-inline-size: 0; color: var(--ink); overflow-wrap: anywhere; }
    & .none { color: var(--muted); }
  }
  table.lines {
    inline-size: 100%; border-collapse: collapse; font-size: var(--step-0);
    & td { padding: 0.6875rem 1rem; border-block-start: 1px solid var(--hair); color: var(--quiet); }
    & td:last-child { text-align: end; white-space: nowrap; color: var(--ink); font-variant-numeric: tabular-nums; }
    & tr.total td {
      padding-block: 0.75rem; border-block-start-color: var(--card); font-size: 0.9375rem; font-weight: 500; color: var(--ink);
      background: color-mix(in oklab, var(--bh-surface) 60%, var(--bh-surface-sunken));
    }
  }

  /* Payments, emails and the history, as one list in the order they
     happened. The list reads its own width rather than the page's, since
     the rail beside it decides how much it gets. */
  panel-card.activity { container: activity / inline-size; }
  ol.activity {
    list-style: none; margin: 0; padding: 0; max-inline-size: none;
    & > li { max-inline-size: none; border-block-start: 1px solid var(--hair); font-size: var(--step-0); }
    & :is(li:not(.email), li.email summary) {
      display: grid; grid-template-columns: 11rem 6.5rem minmax(0, 1fr) 7rem; align-items: baseline; gap: 0.75rem;
      padding: 0.6875rem 1rem;
      & > time { color: var(--muted); font-variant-numeric: tabular-nums; }
      & > b { font-weight: 500; color: var(--ink); }
      & > .what { min-inline-size: 0; color: var(--quiet); overflow-wrap: anywhere; }
      & > .end { text-align: end; color: var(--muted); font-size: var(--step-0); overflow-wrap: anywhere; }
    }
    & .quiet { color: var(--muted); }
    & li.email summary {
      cursor: pointer; list-style: none;
      &::-webkit-details-marker { display: none; }
      &:hover { background: var(--hover); }
      & > .end { color: var(--link); }
    }
    & li.email details[open] .open, & li.email details:not([open]) .shut { display: none; }
    & .failed { color: var(--danger); font-weight: 600; }
    & .waiting { color: var(--warn); font-weight: 600; }
    & .arrived { color: var(--muted); font-weight: 400; }
    & email-copy { display: block; padding: 0 1rem 1rem; }
    & email-copy pre { margin: 0; padding: var(--space-m); background: var(--grey); border-radius: 3px; font-family: var(--font-mono); font-size: var(--step--1); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
    & email-copy pre.head { margin-block-end: var(--space-s); color: var(--muted); }
    & email-copy email-view > pre.plain { background: var(--paper); }
  }
  /* Too narrow for four columns: what it was and when on one line, what
     it said on the next. */
  @container activity (width < 38rem) {
    ol.activity :is(li:not(.email), li.email summary) {
      grid-template-columns: max-content minmax(0, 1fr) auto;
      grid-template-areas: "kind time end" "what what what";
      gap: 0.125rem 0.5rem; padding: 0.625rem 1rem;
      & > b { grid-area: kind; }
      & > time { grid-area: time; }
      & > .what { grid-area: what; }
      & > .end { grid-area: end; }
    }
  }

  /* The money: what is still owed, large, and the way to take it. */
  money-figure {
    display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem;
    padding: 0.25rem 1rem 0.875rem;
    & > div { flex: 1; min-inline-size: 0; }
    & p { margin: 0.25rem 0 0; font-size: var(--step-0); color: var(--muted); }
    & p.big {
      margin: 0; font-size: 1.5rem; font-weight: 500; white-space: nowrap; color: var(--ink); font-variant-numeric: tabular-nums;
      & span { font-size: var(--step-0); font-weight: 400; color: var(--muted); }
    }
    & p.overdue { color: var(--danger); font-weight: 500; }
  }
  money-more {
    display: grid; justify-items: start; gap: 0.5rem; padding: 0.75rem 1rem; border-block-start: 1px solid var(--hair);
    & p { margin: 0; font-size: var(--step-0); }
    & p.overdue { color: var(--danger); }
  }
  form.take {
    display: block; padding: 0.875rem 1rem 1rem; border-block-start: 1px solid var(--hair);
    & .label { display: block; margin-block-end: 0.625rem; font-size: var(--label); color: var(--muted); }
    & take-fields { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.5rem; }
    & label { display: grid; gap: 0.25rem; font-size: var(--step-0); color: var(--quiet); }
    & input, & select {
      box-sizing: border-box; block-size: 2.25rem; font: inherit; font-size: var(--step-0); color: var(--ink); background: var(--bh-surface-sunken);
      border: 1px solid color-mix(in oklab, var(--ink) 30%, var(--paper)); border-radius: 4px; padding: 0.4375rem 0.5625rem;
    }
    & input { inline-size: 5.5rem; }
    & button.record {
      box-sizing: border-box; block-size: 2.25rem; font: inherit; font-size: var(--step-0); font-weight: 500; cursor: pointer;
      background: var(--green); color: var(--on-green); border: 1px solid var(--green); border-radius: 4px; padding: 0.4375rem 0.875rem;
      &:hover { background: var(--green-hover); border-color: var(--green-hover); }
    }
  }

  /* What can be done to the booking: a row each, what it is and what it
     does in a line, and the button. What each one means in full is said
     on the page or in the dialog it opens, when it is being done. */
  ul.acts {
    list-style: none; margin: 0; padding: 0;
    & li {
      display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 0.75rem;
      max-inline-size: none; padding: 0.75rem 1rem; border-block-start: 1px solid var(--hair);
      &:hover { background: var(--hover); }
    }
    & li > div { flex: 1 1 12rem; min-inline-size: 0; }
    & strong { display: block; font-size: var(--step-0); font-weight: 400; color: var(--ink); }
    & small { display: block; font-size: var(--step-0); line-height: 1.45; color: var(--muted); }
    & li.off strong { color: var(--quiet); }
    & form { margin: 0; flex: none; }
    & .pair { display: flex; flex-wrap: wrap; gap: 0.5rem; flex: none; }
  }
  /* A cancelled booking seen by someone who is not an admin has nothing
     left to change, and an empty card says nothing. */
  panel-card.changes:not(:has(li)) { display: none; }
  .act {
    display: inline-block; font: inherit; font-size: var(--step-0); line-height: 1.4; text-decoration: none; cursor: pointer;
    color: var(--link); background: none; border: 1px solid var(--btn); border-radius: 4px; padding: 0.375rem 0.75rem;
    &:hover { color: var(--link); border-color: var(--link); }
    &.warn { color: var(--bh-owing-text); &:hover { border-color: var(--bh-owing-text); } }
    &:disabled { color: var(--faint); border-color: var(--card); cursor: default; }
  }

  /* The price lines and the activity are details elements, so that a
     phone can fold them. Wider than that they are open whatever the
     element says, and the line that would open them is not wanted. */
  details.fold > summary {
    display: block; list-style: none; cursor: pointer;
    &::-webkit-details-marker { display: none; }
  }
  details.breakdown > summary { padding: 0.75rem 1rem; border-block-start: 1px solid var(--hair); color: var(--link); }
  details.activity > summary:hover h2 { color: var(--green); }
  details.activity .narrow { display: none; }
  @supports selector(::details-content) {
    @container page (width > 34rem) {
      details.fold::details-content { content-visibility: visible; }
      details.fold > summary { pointer-events: none; cursor: default; }
      details.breakdown > summary { display: none; }
    }
  }
  /* A phone: one column, the reference on a line of its own, folds shut,
     and targets a thumb can find. Inputs at 16px, or iOS zooms the page. */
  @container page (width <= 34rem) {
    booking-head {
      & h1 { font-size: 1.25rem; }
      & .ref { display: block; font-size: 1.0625rem; }
      & .who { padding-inline-start: 0; }
    }
    stay-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    stay-cell.rooms { grid-column: 1 / -1; }
    details.activity .wide { display: none; }
    details.activity .narrow { display: inline; }
    form.take {
      & take-fields { flex-wrap: nowrap; }
      & label:first-child { flex: 0 0 6rem; }
      & label:nth-child(2) { flex: 1; min-inline-size: 0; }
      & input, & select { inline-size: 100%; block-size: 2.875rem; font-size: 1rem; }
      & button.record { block-size: 2.875rem; }
    }
    ul.acts li { min-block-size: 48px; }
    .act { padding-block: 0.625rem; }
  }
  /* The settings area: the subjects down the left, the page beside them. */
  settings-layout { display: grid; grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); gap: var(--space-l); align-items: start; }
  /* The sidebar names the page, so its heading is for screen readers and
     what is left is one quiet line saying what the page is for. */
  settings-body > page-intro { margin-block-end: var(--space-m);
    & p { margin: 0; font-size: var(--step--1); color: var(--muted); max-inline-size: 44rem; }
    & p + p { margin-block-start: var(--space-s); } }
  settings-body { display: block; min-inline-size: 0;
    /* A save button is as wide as its words, not as wide as the form. */
    & form.details > button { justify-self: start; }
    /* Labels of different lengths still leave their fields in a line, and
       a settings form is wider than a guest's, since it is a desk. */
    & form.details { max-inline-size: 44rem; }
    & form.details .row { align-items: end; } }
  nav.side { position: sticky; inset-block-start: var(--space-m);
    & ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.15rem; }
    & li.apart { margin-block-start: var(--space-m); padding-block-start: var(--space-s); border-block-start: 1px solid var(--line); }
    /* Sentence case: these are the names of pages, and the pages carry
       them as titles. Uppercase was the old design's, and it made five
       plain words look like a control panel. */
    & a { display: block; padding: 0.4rem 0.625rem; border-radius: 4px; text-decoration: none; font-size: var(--step-0); color: var(--ink); }
    & a:hover { background: var(--grey); color: var(--sea); }
    & a[aria-current=page] { background: color-mix(in oklab, var(--sea) 10%, var(--paper)); color: var(--sea); } }
  @container page (max-width: 46rem) {
    settings-layout { grid-template-columns: 1fr; gap: var(--space-m); }
    nav.side { position: static; & ul { display: flex; flex-wrap: wrap; gap: 0.15rem 0.3rem; } & li.apart { margin: 0; padding: 0; border: 0; } } }

  /* ------------------------------------------------------------------
     Settings, read first.

     A settings page used to be a column of labelled boxes: correct, and
     unreadable. These pages say what the settings do in sentences, and
     keep the boxes in a dialog behind an Edit button.

     Two departures from the handoff, both deliberate. It asks for 13, 12
     and 11px for hints, column heads and pills; the admin's own rule is
     that nothing here goes under 14px, so those sizes meet the body size
     and the weight, case and colour carry the difference — the same trade
     the rest of this stylesheet makes. And its palette is the design
     system's violet; the app's staff pages are green, so the chrome is
     drawn from the accent tokens and follows dark mode with them.
     ------------------------------------------------------------------ */
  settings-head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 1rem; margin-block-end: 1.5rem;
    & hgroup { margin: 0; }
    & h1 { margin: 0 0 0.375rem; font-size: var(--step-3); font-weight: 300; letter-spacing: -0.01em; }
    & hgroup p { margin: 0; max-inline-size: 60ch; color: var(--muted); font-size: var(--row); }
    & p.changed {
      flex-shrink: 0; margin: 0; padding-block-start: 0.5rem;
      color: var(--muted); font-size: var(--step--1); white-space: nowrap;
    }
  }
  /* The panel behind an aside, a notice, or a restatement: the accent,
     thinned until it is a tint rather than a colour. */
  notice-box.info, plain-english {
    display: block; border-radius: 0.5rem;
    background: color-mix(in oklab, var(--green) 7%, var(--paper));
    border: 1px solid color-mix(in oklab, var(--green) 22%, var(--paper));
  }
  notice-box.info {
    margin-block-end: 1.25rem; padding: 0.75rem 0.875rem;
    & p { margin: 0; font-size: var(--step-0); color: var(--ink); }
  }
  settings-grid { display: flex; flex-wrap: wrap; gap: 1.25rem; align-items: flex-start; }
  settings-cards { display: flex; flex-direction: column; gap: 1.25rem; min-inline-size: 0; flex: 1 1 26rem; }
  panel-card.aside { flex: 1 1 18rem; max-inline-size: 21rem; }
  settings-body panel-head { align-items: flex-start; padding-block: 0.875rem 0.875rem; border-block-end: 1px solid var(--hair); margin-inline: 0; padding-inline: 1rem;
    & hgroup { margin: 0; }
    & small { display: block; margin-block-start: 2px; }
  }
  /* The Edit button on a card, and the neutral button in a dialog. */
  a.edit, .edit-dialog .cancel, .edit-dialog .neutral, copy-field button, tier-editor .add, room-editor .add {
    display: inline-flex; align-items: center; gap: 0.375rem;
    margin-inline-start: auto; flex-shrink: 0; white-space: nowrap;
    border: 1px solid var(--btn); border-radius: 4px; background: var(--paper);
    padding: 0.25rem 0.625rem; font: inherit; font-size: var(--step--1); color: var(--ink);
    text-decoration: none; cursor: pointer;
    &:hover { background: var(--hover); border-color: var(--green); color: var(--green); }
  }
  /* The statements. The sentence carries the meaning and the bold carries
     the number, so the eye can take either. The marker is the browser's
     own: a figure per line was a struggle to choose and no help to read. */
  ul.says {
    margin: 0; padding: 0.25rem 1rem 0.25rem 2.25rem; list-style: disc;
    & li { padding-block: 0.375rem; font-size: var(--row); line-height: 1.5; }
    & li::marker { color: var(--faint); }
    & b { font-weight: 600; }
  }
  /* The colour as each mode will use it, each on its own ground so both
     can be seen at once whichever mode the reader is in. The grounds are
     fixed rather than themed for the same reason. */
  colour-pair {
    display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem;
    margin: 0 1rem 1rem;
    & mode-sample {
      display: flex; align-items: center; gap: 0.75rem; min-inline-size: 0;
      padding: 0.75rem; border-radius: 0.375rem; border: 1px solid var(--card);
    }
    & mode-sample.light { background: #ffffff; color: #1b1b1b; }
    & mode-sample.dark { background: #161616; color: #ececec; }
    & .btn { flex-shrink: 0; padding: 0.375rem 0.75rem; border-radius: 4px; font-size: var(--step--1); white-space: nowrap; }
    & .what { font-size: var(--step--1); line-height: 1.4; min-inline-size: 0; }
    & code { font-family: inherit; font-variant-numeric: tabular-nums; opacity: 0.75; }
  }
  .edit-dialog colour-pair { margin: 0; }
  @container page (max-width: 46rem) { colour-pair { grid-template-columns: 1fr; } }
  /* Except where the marker is the thing being described. */
  ul.says li:has(swatch-chip) { list-style: none; }
  ul.says swatch-chip { display: inline-block; vertical-align: -2px; margin-inline: -1.5rem 0.5rem; }
  card-body { display: block; padding: 0.875rem 1rem 1rem;
    & h3 { margin: 0 0 0.5rem; font-size: var(--label); font-weight: 600; color: var(--muted); }
    & h3 + p.says-sub { margin-block-start: -0.25rem; }
    & ul.ladder + h3 { margin-block-start: 1.25rem; }
  }
  p.says-sub { margin: 0 0 0.5rem; color: var(--muted); font-size: var(--step-0); }
  /* The cancellation ladder. The last row is the one that was never drawn
     before: below the shortest tier, nothing comes back. */
  ul.ladder {
    list-style: none; margin: 0; padding: 0; display: grid; gap: 0.25rem;
    & li { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
      padding: 0.5rem 0.75rem; border-radius: 4px; background: var(--grey); font-size: var(--step-0); color: var(--ink); }
    & b { font-weight: 600; font-variant-numeric: tabular-nums; }
    /* The rows are grey, so the words on them take the reading shades:
       the green's ink, and the secondary grey rather than the muted one,
       which is 4.39:1 there. */
    & b.all { color: var(--link); }
    & b.part { color: var(--warn); }
    & b.none { color: var(--quiet); font-weight: 500; }
  }
  /* The worked examples: the same settings walked over two real bookings. */
  worked-example {
    display: block; padding: 0.875rem 1rem 0.25rem; border-block-end: 1px solid var(--hair);
    &:last-child { border-block-end: 0; }
    & p.title { margin: 0; display: flex; align-items: center; gap: 0.5rem; font-size: var(--step-0); font-weight: 500; }
    & span.pill { font-size: var(--step--1); font-weight: 600;
      padding: 0.0625rem 0.375rem; border-radius: 4px;
      color: var(--link); background: color-mix(in oklab, var(--green) 12%, var(--paper)); }
    & p.note { margin-block: 0.25rem 0.875rem; }
  }
  ol.timeline {
    list-style: none; margin: 0.75rem 0 0; padding: 0;
    & li { display: grid; grid-template-columns: 14px minmax(0, 1fr); gap: 0.75rem; }
    & span { padding-block-end: 0.875rem; font-size: var(--step-0); color: var(--ink); }
    & time { display: inline-block; color: var(--muted); font-variant-numeric: tabular-nums; }
    & li:last-child span { padding-block-end: 0.25rem; }
    /* The rail: a dot for the step and a line down to the next one. */
    & step-rail { display: flex; flex-direction: column; align-items: center; }
    & step-rail::before { content: ""; inline-size: 9px; block-size: 9px; border-radius: 999px; margin-block-start: 5px; background: color-mix(in oklab, var(--green) 35%, var(--card)); }
    & step-rail::after { content: ""; flex: 1; inline-size: 1px; background: var(--hair); }
    & li:last-child step-rail::after { background: none; }
    & li.money step-rail::before { background: var(--green); }
    & li.arrival step-rail::before { background: var(--green); box-shadow: 0 0 0 3px color-mix(in oklab, var(--green) 18%, transparent); }
  }

  /* A choice that is a box you can press, with the reason inside it. */
  label.toggle {
    display: flex; gap: 0.625rem; align-items: flex-start;
    border: 1px solid var(--card); border-radius: 0.5rem; padding: 0.75rem 0.875rem; cursor: pointer;
    &:hover { background: var(--hover); }
    & input { margin-block-start: 2px; inline-size: 16px; block-size: 16px; accent-color: var(--green); }
    & b { display: block; font-size: var(--step-0); font-weight: 500; }
    & small { display: block; margin-block-start: 0.125rem; color: var(--muted); font-size: var(--step--1); }
    &:has(:checked) { border-color: var(--green); background: color-mix(in oklab, var(--green) 5%, var(--paper)); }
  }
  fieldset.roles { display: grid; gap: 0.5rem; margin: 0; padding: 0; border: 0;
    & legend { padding: 0 0 0.375rem; font-size: var(--step-0); font-weight: 500; } }
  p.reads { margin: 0; font-size: var(--step-0); }
  ul.says copy-field { margin-block-start: 0.375rem; }
  ul.says code { font-size: var(--step--1); overflow-wrap: anywhere; }
  a.edit.primary {
    background: var(--green); border-color: var(--green); color: var(--on-green);
    &:hover { background: var(--green-hover); border-color: var(--green-hover); color: var(--on-green); }
  }
  ul.letters em.plain { font-style: normal; color: var(--muted); }

  /* The letters, one row each: what it is, when it goes, and your words
     under it in quotes. */
  ul.letters {
    list-style: none; margin: 0; padding: 0;
    & li { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 0.75rem 1rem; align-items: center;
      padding: 0.75rem 1rem; border-block-end: 1px solid var(--hair); }
    & li:last-child { border-block-end: 0; }
    & .what { min-inline-size: 0; }
    & b { display: block; font-size: var(--row); font-weight: 500; }
    & small { display: block; margin-block-start: 1px; color: var(--muted); font-size: var(--step-0); }
    & em { display: block; margin-block-start: 0.25rem; font-size: var(--step-0); color: var(--ink); }
  }
  /* The markers: when it goes, or that it is not going at all. */
  span.pill {
    font-size: var(--label); font-weight: 600;
    padding: 0.125rem 0.375rem; border-radius: 4px; white-space: nowrap;
    color: var(--link); background: color-mix(in oklab, var(--green) 12%, var(--paper));
    /* A letter that waits for the daily round is not the same as one that
       follows an event, and on a green page the difference has to be a
       different hue rather than a different green. */
    &.timed { color: color-mix(in oklab, var(--warn) 85%, var(--ink)); background: color-mix(in oklab, var(--warn) 14%, var(--paper)); }
    /* An admin reaches more than staff do, so the marker is more: the
       same green, filled rather than tinted. */
    &.admin { color: var(--on-green); background: var(--green); }
    &.off { color: var(--quiet); background: var(--grey); }
  }
  /* A letter as it will be sent, inside the dialog that edits it. */
  sample-letter {
    display: block;
    & .lbl { display: block; margin-block-end: 0.375rem; font-size: var(--label); font-weight: 600;
      color: var(--muted); }
    & > pre { margin: 0; padding: 0.875rem; border: 1px solid var(--card); border-radius: 0.375rem;
      background: var(--grey); font: inherit; font-size: var(--step-0); line-height: 1.55;
      white-space: pre-wrap; overflow-wrap: anywhere; }
  }
  letter-preview.plain { margin: 1rem; & p.off { color: var(--ink); } }
  .edit-dialog textarea {
    inline-size: 100%; box-sizing: border-box; font: inherit; font-size: var(--step-0);
    line-height: 1.5; padding: 0.5rem; resize: vertical;
    border: 1px solid var(--btn); border-radius: 4px; background: var(--paper); color: var(--ink);
    &:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--green); }
  }
  /* The wall displays: each with its address in full, to copy into a
     panel, and in its dialog the board as the panels see it. */
  copy-field {
    display: flex; align-items: center; gap: 0.5rem;
    & input { flex: 1; min-inline-size: 0; }
    & button { margin-inline-start: 0; }
  }
  ul.letters.displays copy-field { margin-block-start: 0.5rem; }
  settings-body copy-field input[readonly] {
    font: inherit; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--step--1);
    padding: 0.375rem 0.5rem; border: 1px solid var(--hair); border-radius: 4px;
    background: var(--grey); color: var(--ink);
  }
  panel-card > p.none { margin: 0; padding: 0.75rem 1rem; color: var(--muted); font-size: var(--step-0); }
  display-previews {
    display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.75rem;
    & a { display: block; line-height: 0; }
    & img { display: block; block-size: auto; max-inline-size: 100%; border: 1px solid var(--hair); background: #fff; }
  }
  dialog:has(input[name=orientation][value=portrait]:checked) display-previews .landscape,
  dialog:has(input[name=orientation][value=landscape]:checked) display-previews .portrait,
  dialog:has(input[name=panel][value=trmnl]:checked) display-previews .trmnl-x,
  dialog:has(input[name=panel][value=trmnl-x]:checked) display-previews .trmnl { display: none; }
  .edit-dialog button.neutral.danger {
    color: var(--danger);
    &:hover { border-color: var(--danger); color: var(--danger); background: color-mix(in oklab, var(--danger) 8%, var(--paper)); }
  }
  @container page (max-width: 46rem) {
    ul.letters li { grid-template-columns: minmax(0, 1fr); }
    ul.letters li .pill, ul.letters li a.edit { justify-self: start; margin-inline-start: 0; }
  }

  /* The room list, and the priced examples beside it. */
  ul.ladder.rooms b { font-weight: 400; color: var(--quiet); }
  ol.worked {
    list-style: none; margin: 0; padding: 0 1rem;
    & li { display: block; padding-block: 0.75rem; border-block-end: 1px solid var(--hair); }
    & li:last-child { border-block-end: 0; }
    & .who { display: block; font-size: var(--step-0); font-weight: 500; }
    & .maths { display: block; margin-block-start: 1px; color: var(--muted); font-size: var(--step--1); }
    & .total { display: block; margin-block-start: 0.25rem; font-size: 1rem; font-weight: 600; font-variant-numeric: tabular-nums; }
  }
  /* Rooms edit as rows of name, beds, en-suite — and a remove that is a
     checkbox wearing a cross, so that it still removes with no script. */
  room-editor {
    display: grid; grid-template-columns: minmax(0, 1fr) max-content max-content 28px; gap: 0.375rem 1rem; align-items: center;
    & tier-head { display: contents; }
    & tier-head span { font-size: var(--label); font-weight: 600; color: var(--muted); }
    & tier-row { display: contents; }
    & label.tick { justify-self: start; }
    & label.tick input { inline-size: auto; }
    & label.drop { display: grid; place-items: center; block-size: 28px; inline-size: 28px; border-radius: 4px; color: var(--faint); cursor: pointer; }
    & label.drop:hover { background: color-mix(in oklab, var(--danger) 10%, var(--paper)); color: var(--danger); }
    /* The checkbox is the removal; the cross is what it looks like. */
    & label.drop input { position: absolute; opacity: 0; inline-size: 1px; block-size: 1px; }
    & label.drop:has(:checked) { background: color-mix(in oklab, var(--danger) 12%, var(--paper)); color: var(--danger); }
    & .add { grid-column: 1 / -1; justify-self: start; margin-block-start: 0.25rem; margin-inline-start: 0; }
  }
  /* A row struck through is one that will go when this is saved. */
  room-editor tier-row:has(label.drop :checked) input[name^=room_name] { text-decoration: line-through; color: var(--muted); }

  /* The bunkhouse's own colour is data on this page, not chrome: a square
     of it beside the sentence that says how readable it is. */
  swatch-chip { display: block; inline-size: 16px; block-size: 16px; border-radius: 3px;
    margin-block-start: 3px; flex-shrink: 0; border: 1px solid color-mix(in oklab, var(--ink) 12%, transparent); }
  /* What is dropped and what is kept, side by side: the comparison is the
     point, and two neutral lists did not make it. */
  two-lists {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 1.5rem; padding: 0 1rem 0.5rem;
    & h3 { margin: 0 0 0.375rem; padding-block-end: 0.375rem; border-block-end: 1px solid var(--card);
      font-size: var(--label); font-weight: 600; }
    & h3.goes { color: var(--warn); }
    & h3.stays { color: var(--green); }
    & ul { list-style: none; margin: 0; padding: 0; }
    & li { padding-block: 0.4375rem; border-block-end: 1px solid var(--hair); font-size: var(--step-0); }
    & li:last-child { border-block-end: 0; }
  }
  p.card-foot { margin: 0; padding: 0.625rem 1rem 1rem; color: var(--muted); font-size: var(--step-0); }
  /* The top of a confirmation, so the fields above are seen in place. */
  letter-preview {
    display: block; margin: 1rem; padding: 0.875rem; border: 1px solid var(--card); border-radius: 0.375rem;
    font-size: var(--step-0); line-height: 1.55; color: var(--ink);
    & p { margin: 0 0 0.5rem; }
    & p:last-child { margin-block-end: 0; }
    /* The same colour the letter itself puts the name in: the accent's
       reading shade, which is chosen to be read as words on paper rather
       than to be a button. The fallbacks are the mail package's own, for a
       bunkhouse that has set no colour, and a test holds them to it. */
    & p.from { font-size: 1rem; font-weight: 600; padding-block-end: 0.5rem; border-block-end: 1px solid var(--card); margin-block-end: 0.625rem;
      color: var(--accent-ink, #00873f); }
    & p.off { white-space: pre-line; color: var(--muted); }
  }
  @media (prefers-color-scheme: dark) { letter-preview p.from { color: var(--accent-ink, #4cc98a); } }
  @container page (max-width: 46rem) { two-lists { grid-template-columns: 1fr; gap: 1rem; } }

  /* The edit dialog. One per card, each a real form posting where the page
     has always posted. */
  dialog.edit-dialog {
    max-inline-size: 35rem; inline-size: calc(100% - 2rem); padding: 0; border: 0;
    border-radius: 1rem; background: var(--paper); color: var(--ink);
    box-shadow: 0 4px 16px color-mix(in oklab, var(--ink) 10%, transparent);
    &::backdrop { background: color-mix(in oklab, #000 20%, transparent); }
    &[open] { animation: dlg-in 0.12s ease-out; }
    & header { padding: 1.125rem 1.25rem 0.875rem; border-block-end: 1px solid var(--hair); }
    & header h2 { margin: 0; font-size: var(--step-1); font-weight: 500; }
    & header p { margin: 0.25rem 0 0; color: var(--muted); font-size: var(--step-0); }
    /* The note and the buttons share a row while there is room for both.
       On a phone the note takes a line of its own and the buttons go
       under it, still to the right; no button ever breaks its words. */
    & footer {
      display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.75rem 1rem;
      padding: 0.875rem 1.25rem; border-block-start: 1px solid var(--hair); background: var(--grey);
      & > span:first-child { flex: 1 1 10rem; color: var(--muted); font-size: var(--step--1); }
      & .acts { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.5rem; margin-inline-start: auto; }
      & .acts > * { white-space: nowrap; margin-inline-start: 0; }
    }
  }
  @keyframes dlg-in {
    from { opacity: 0; transform: translateY(6px) scale(0.99); }
    to { opacity: 1; transform: none; }
  }
  /* The staff area's primary button is set in the display face at the
     label size. In a settings dialog it sits beside prose, so here it
     speaks at the same volume as the Cancel next to it. */
  settings-body button.primary {
    font-family: inherit; text-transform: none; letter-spacing: normal;
    font-size: var(--step-0); padding: 0.375rem 0.875rem; border-radius: 4px;
  }
  /* An offer in a notice: the button, and the way to turn it down. */
  settings-body notice-box form { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
  dialog-body { display: flex; flex-direction: column; gap: 1.125rem; padding: 1.25rem; max-block-size: 62vh; overflow: auto; }
  /* The app's fields are styled through form.details and form.stay, which
     a dialog's form is neither of, so they are dressed here instead.
     The steppers go: the field is two or three characters wide and the
     arrows take a third of it for something the keyboard already does. */
  .edit-dialog input:not([type=hidden]):not(num-box input), .edit-dialog select {
    font: inherit; font-size: var(--step-0); color: var(--ink); background: var(--paper);
    border: 1px solid var(--btn); border-radius: 4px; padding: 0.375rem 0.5rem;
    min-inline-size: 0;
  }
  .edit-dialog input[type=number] { appearance: textfield; }
  .edit-dialog input[type=number]::-webkit-outer-spin-button,
  .edit-dialog input[type=number]::-webkit-inner-spin-button { appearance: none; margin: 0; }
  .edit-dialog input:focus-visible:not(num-box input), .edit-dialog select:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--green); }
  field-row {
    display: block;
    & label { display: block; font-size: var(--step-0); font-weight: 500; }
    & small { display: block; color: var(--muted); font-size: var(--step--1); margin: 0.125rem 0 0.375rem; }
  }
  /* A field and whatever prose is left over: "[ 7 days ] before the balance
     is due". The unit belongs inside the box — three digits and "days" are
     one thing, not a field and a word beside it — so the box is what is
     bordered and the input inside it is bare. */
  span.units { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--muted); font-size: var(--step-0); }
  num-box {
    display: inline-flex; align-items: baseline; gap: 0.5rem;
    inline-size: fit-content; padding: 0.375rem 0.5rem;
    border: 1px solid var(--btn); border-radius: 4px; background: var(--paper);
    &:focus-within { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--green); }
    & i { font-style: normal; color: var(--muted); font-size: var(--step-0); }
    /* The box is the width of what can be typed into it: three digits, and
       the unit after them. Nothing here is longer — a percentage, a number
       of days, a number of nights — and a box sized for its content says
       so before the field is read. */
    & input { flex: none; inline-size: 3.25ch; border: 0; padding: 0; background: none;
      font: inherit; font-size: var(--step-0); color: var(--ink); font-variant-numeric: tabular-nums; }
    & input:focus, & input:focus-visible { outline: none; }
    &.money input { inline-size: 7ch; }
  }
  .edit-dialog fieldset { margin: 0; padding: 0; border: 0;
    & legend { padding: 0; font-size: var(--step-0); font-weight: 500; }
    & > small { display: block; color: var(--muted); font-size: var(--step--1); margin: 0.125rem 0 0.5rem; }
    & small.foot { margin-block-start: 0.5rem; } }
  tier-editor {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 28px; gap: 0.375rem 0.5rem; align-items: center;
    & tier-head { display: contents; }
    & tier-head span { font-size: var(--label); font-weight: 600; color: var(--muted); }
    & tier-row { display: contents; }
    /* A tier is two small boxes and a way to remove the row, not three
       stretched columns: the numbers are three digits at most. */
    grid-template-columns: max-content max-content 28px; gap: 0.375rem 1rem;
    & .drop { display: grid; place-items: center; block-size: 28px; inline-size: 28px; padding: 0;
      border: 0; border-radius: 4px; background: none; color: var(--faint); cursor: pointer; }
    & .drop:hover { background: color-mix(in oklab, var(--danger) 10%, var(--paper)); color: var(--danger); }
    & .add { grid-column: 1 / -1; justify-self: start; margin-block-start: 0.25rem; margin-inline-start: 0; }
  }
  plain-english { padding: 0.75rem 0.875rem;
    & .lbl { display: block; font-size: var(--label); font-weight: 600;
      color: color-mix(in oklab, var(--green) 60%, var(--muted)); margin-block-end: 0.25rem; }
    & p { margin: 0; color: var(--ink); font-size: var(--step-0); line-height: 1.5; } }
  /* With no script the Edit link is an ordinary jump, and the dialog it
     names opens in the page: not modal, but every field reachable and the
     same form underneath. */
  dialog.edit-dialog:target {
    display: block; position: static; margin: 1.25rem 0 0; max-inline-size: none;
    inline-size: auto; box-shadow: none; border: 1px solid var(--card);
    /* Nothing is covering the page, so the body has the room to be as long
       as it is rather than scrolling inside itself. */
    & dialog-body { max-block-size: none; overflow: visible; }
  }
  @container page (max-width: 46rem) {
    settings-head { flex-direction: column; gap: 0.25rem; }
    settings-head p.changed { padding-block-start: 0; }
  }

  /* The mark is the affordance, so the site nav's caret is not wanted;
     this out-specifies the rule that puts one after every nav summary. */
  site-header nav user-menu summary::after { content: none; }
  /* The account menu: initials in the header, the way out underneath. */
  user-menu { display: block;
    /* The website's is hidden until its script has a menu to put in it. */
    &[hidden] { display: none; }
    & details { position: relative; }
    & summary { list-style: none; cursor: pointer; display: block; }
    & summary::-webkit-details-marker { display: none; }

    & user-mark { display: grid; place-items: center; inline-size: 2.4rem; block-size: 2.4rem; border-radius: 50%; background: var(--green); color: var(--paper); font-family: var(--font-display); font-size: var(--step--1); letter-spacing: 0.04em; }
    & summary:hover user-mark { background: var(--green-hover); }
    & summary:focus-visible user-mark { outline: 3px solid var(--focus); outline-offset: 2px; }
    & user-panel { position: absolute; inset-inline-end: 0; inset-block-start: calc(100% + 0.5rem); z-index: 20; display: grid; gap: 0.15rem; min-inline-size: 14rem; padding: var(--space-s); background: var(--paper); border: 1px solid var(--line); border-radius: 3px; box-shadow: 0 6px 20px color-mix(in oklab, var(--ink) 12%, transparent); }
    & p.who { margin: 0 0 0.3rem; padding: 0.2rem 0.5rem 0.5rem; border-block-end: 1px solid var(--line); font-size: var(--step--1); line-height: 1.3; & small { color: var(--muted); overflow-wrap: anywhere; } }
    & a, & button.link { display: block; inline-size: 100%; text-align: start; padding: 0.5em; border: 0; border-radius: 3px; background: none; font-family: var(--font-display); font-size: var(--step--1); color: var(--ink); text-decoration: none; cursor: pointer; }
    & a:hover, & button.link:hover { background: var(--grey); color: var(--sea); }
    /* Which side of the app this is: a tick after its name. */
    & a { display: flex; align-items: center; gap: 0.5rem; }
    & .tick { margin-inline-start: auto; color: var(--green); }
    & hr { margin: 0.3rem 0; border: 0; border-block-start: 1px solid var(--line); } }


  /* The customise page: each email set out as a letter, with the owners'
     own words in a box where they will appear in it. */
  section.settings.letter { max-inline-size: 46rem; }
  email-letter { display: block; background: var(--grey); border-radius: 3px; padding: var(--space-m);
    & pre { margin: 0; font-family: var(--font-mono); font-size: var(--step--1); line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
    & pre.head { padding-block-end: var(--space-s); margin-block-end: var(--space-s); border-block-end: 1px solid var(--line); color: var(--muted); }
    /* The one part of a letter that can be changed. */
    & textarea { display: block; font: inherit; font-size: var(--step-0); color: var(--ink); background: var(--paper); border: 1px solid var(--green); border-radius: 3px; padding: 0.5em 0.6em; inline-size: 100%; resize: vertical; }
    & textarea:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; } }
  /* Two ways to read the same letter: as a guest's mail client draws it,
     or as the text it is made from. The tab is a radio, so it works
     without JavaScript; the box for the owners' words lives in the drawn
     letter, where it will appear. */
  email-view { display: block;
    & > input { position: absolute; inline-size: 1px; block-size: 1px; opacity: 0; }
    & > label { display: inline-block; font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); background: none; border: 1px solid transparent; border-radius: 3px 3px 0 0; padding: 0.5em 0.9em; cursor: pointer; }
    & > label:hover { color: var(--green); }
    & > input:checked + label { color: var(--green); background: var(--paper); border-color: var(--line); border-block-end-color: var(--paper); }
    & > input:focus-visible + label { outline: 3px solid var(--focus); outline-offset: 2px; }
    & > email-drawn, & > pre.plain { display: block; margin-block-start: -1px; background: var(--paper); border: 1px solid var(--line); border-radius: 0 3px 3px 3px; }
    & > pre.plain { padding: var(--space-m); }
    & > input[value=html]:checked ~ pre.plain, & > input[value=text]:checked ~ email-drawn { display: none; } }
  p.attached { margin-block-start: var(--space-s); font-size: var(--step--1); }
  p.actions { display: flex; flex-wrap: wrap; gap: var(--space-s); align-items: center; margin-block-start: var(--space-m); }
  @container page (max-width: 46rem) {
    ol.history li { grid-template-columns: 1fr max-content; & .what, & details { grid-column: 1 / -1; } }
    /* Narrow: the day, whether it went and the way in on one line, the
       subject under them. */
    ol.history.emails li summary { grid-template-columns: 1fr max-content 1rem;
      & .what { grid-column: 1 / -1; grid-row: 2; }
      & .failed, & .waiting, & .arrived { grid-column: 2; grid-row: 1; }
      &::after { grid-column: 3; grid-row: 1; } } }
  /* The offer of a phone call spans the page, not the form's column. */
  notice-box.aside { max-inline-size: none; }
  /* A tick or a radio reads as a sentence, not as a field with its label
     above it, so these opt out of the form's own label styling. */
  label.check, form.details label.check { display: flex; gap: 0.5rem; align-items: center; text-transform: none; letter-spacing: 0; font-family: var(--font-body); font-size: var(--step-0); color: var(--ink); align-self: end; padding-block-end: 0.6em;
    & input { inline-size: auto; flex: none; accent-color: var(--green); margin: 0; } }
  /* How much was taken is only a question for money in hand, so the field
     goes when the answer is a link or nothing yet. Browsers without :has
     leave it in place, where it is simply ignored. */
  form.details:has(input[name=taken][value=link]:checked) .amount,
  form.details:has(input[name=taken][value=none]:checked) .amount { display: none; }
  fieldset.taken { border: 0; padding: 0; margin: 0; display: grid; gap: 0.2em;
    & legend { padding: 0; font-family: var(--font-display); font-size: var(--step--1); color: var(--muted); }
    & label.check { align-self: start; padding-block-end: 0; } }
  form.details .row { display: grid; gap: var(--space-m); grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); }
  form.details select { font: inherit; font-family: var(--font-body); font-size: var(--step-0); color: var(--ink); background: var(--paper); border: 1px solid color-mix(in oklab, var(--ink) 30%, var(--paper)); border-radius: 3px; padding: 0.55em 0.7em; inline-size: 100%; }
  label small { text-transform: none; letter-spacing: 0; }

  /* A numeral centred in a box is centred as a line of text, so the line
     box decides where it lands rather than the digit. One line box the
     same everywhere, and the grid centres what is left. Fjalla One needed
     a nudge down with it, since it sat high in its line; the system faces
     do not, and the nudge is what put the numbers out of true. */
  booking-steps b { line-height: 1; }

  /* Form on the left, what they have chosen on the right. */
  .two-col.aside { gap: var(--space-m) var(--space-l); }
  @container page (min-width: 46rem) { .two-col.aside { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); } }

  /* The flow is a task, not a page to wander: less air between its parts. */
  body.booking main { padding-block: var(--space-m); row-gap: var(--space-m); }
  body.booking page-intro { gap: 0.2rem; }
  body.booking option-list { gap: var(--space-m); }
}

/* Reduced motion keeps every state change legible and takes the sequence
   out of it: colours still settle, faster, and all at once. */
@media (prefers-reduced-motion: reduce) {
  @layer components {
    booking-calendar .week li > * { transition-duration: 80ms; }
    .continue { transition-duration: 80ms; }
  }
}

/* ------------------------------------------------------------------
   The guest booking flow, to design_handoff_booking_flow.

   A deliberately different family from the staff admin: warm paper
   canvas, one decision per screen, 44px touch targets, and a single
   column that works at 360px. Guests are usually on a phone, often on
   poor signal, so nothing here needs a script to render.

   The tokens are the handoff's booking-palette.css, with one change:
   the accent reads the bunkhouse's own colour from Settings when one is
   set (see brandCSS), and falls back to the palette's green when it is
   not. One colour, one place, whichever design is wearing it.
   ------------------------------------------------------------------ */
@layer base {
  body.booking {
    --jb-canvas: #f4f2ee;
    --jb-raised: #faf9f6;
    --jb-surface: #ffffff;
    --jb-surface-hover: #f4f2ee;
    --jb-border: #e3ded4;
    --jb-border-inner: #efeae1;
    --jb-border-control: #d7d2c7;
    /* A night you can pick is outlined at 3.19:1 on the card behind it.
       The control border it used to share managed 1.51:1, which put an
       open night and a sold-out one within a hair of each other. */
    --jb-open-bd: #949086;
    --jb-rail: #e3ded4;
    --jb-text: #1a1a18;
    --jb-text-secondary: #5d5c56;
    --jb-text-muted: #6b6a64;          /* 5.5:1 on the canvas — do not lighten */
    --jb-accent: var(--accent, #00873f);
    --jb-accent-hover: var(--accent-hover, #046c35);
    --jb-accent-text: var(--accent-on, #ffffff);
    --jb-accent-ink: var(--accent-ink, #04512a);
    --jb-accent-tint: #eaf6ef;
    --jb-accent-tint-bd: #bfe3cd;
    --jb-soldout-bg: #ece5d9;   /* 1.25:1 against an open night, up from 1.12 */
    --jb-soldout-bd: #e8e2d7;
    --jb-soldout-text: #665e54;   /* 5.09:1 on that fill */
    --jb-past-bg: #f7f5f1;
    --jb-past-text: #b5b2a9;
    /* Undoing a booking is the one thing on these pages that cannot be
       undone, so it is the one thing not in the accent: 7.04:1 on the
       canvas as ink, and white on it at 7.87:1 as a fill. */
    --jb-danger: #9f1d1d;
    --jb-danger-text: #ffffff;
    --jb-column: 660px;

    /* The shared stylesheet's own names, pointed at the paper palette,
       so anything built on them comes along rather than sitting on the
       old white. */
    --paper: var(--jb-surface);
    --grey: var(--jb-canvas);
    --ink: var(--jb-text);
    --muted: var(--jb-text-muted);
    --line: var(--jb-border);
    --green: var(--jb-accent);
    --green-hover: var(--jb-accent-hover);
    --on-green: var(--jb-accent-text);
    /* A link is words, so it takes the accent's reading shade: the accent
       itself is fitted to white and falls under 4.5:1 on the canvas. */
    --sea: var(--jb-accent-ink);
    --sea-hover: color-mix(in oklab, var(--jb-accent-ink) 82%, var(--jb-text));
    --focus: color-mix(in oklab, var(--jb-accent) 70%, var(--jb-text));

    background: var(--jb-canvas);
    color: var(--jb-text);
    font-size: 16px;
    line-height: 1.5;
    display: block;
  }

  /* After dark the accent brightens, so text on a filled button flips to
     the dark ink: never white on the light green. */
  @media (prefers-color-scheme: dark) {
    body.booking {
      --jb-canvas: #14120f;
      --jb-raised: #1b1815;
      --jb-surface: #1f1c18;
      --jb-surface-hover: #272320;
      --jb-border: #332e28;
      --jb-border-inner: #2a2621;
      --jb-border-control: #453e36;
      --jb-open-bd: #7a6f62;      /* 3.46:1 on the surface */
      --jb-rail: #332e28;
      --jb-text: #f3efe8;
      --jb-text-secondary: #c3bcb0;
      --jb-text-muted: #a39b8e;
      --jb-accent: var(--accent, #35c273);
      --jb-accent-hover: var(--accent-hover, #5fd692);
      --jb-accent-text: var(--accent-on, #04180c);
      --jb-accent-ink: var(--accent-ink, #8de8b3);
      --jb-accent-tint: #12271a;
      --jb-accent-tint-bd: #2f5c40;
      --jb-soldout-bg: #2c2722;  /* 1.15:1 against an open night, up from 1.03 */
      --jb-soldout-bd: #342f28;
      --jb-soldout-text: #9e9385;  /* 4.9:1 on that fill */
      --jb-past-bg: #1a1714;
      --jb-past-text: #6b6358;
      --jb-danger: #ff8f8f;        /* 8.53:1 on the canvas */
      --jb-danger-text: #14120f;   /* and 8.53:1 the other way as a fill */
    }
  }
}

@layer pages {
  /* Masthead: a full-width bar, its contents on the column. */
  body.booking site-header {
    display: block;
    background: var(--jb-raised);
    border-block-end: 1px solid var(--jb-border);
    padding: 0;
    & brand-bar {
      display: flex;
      align-items: center;
      gap: 0.75rem;
      max-inline-size: var(--jb-column);
      margin-inline: auto;
      padding: 1rem 1.25rem;
    }
    & .brand {
      display: flex;
      align-items: center;
      gap: 0.75rem;
      flex: 1;
      min-inline-size: 0;
      font-size: 1.0625rem;
      font-weight: 500;
      letter-spacing: normal;
      text-transform: none;
      color: var(--jb-text);
      text-decoration: none;
      & img { inline-size: 26px; block-size: 26px; }
      & span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    }
    & .away {
      font-family: inherit;
      font-size: 0.875rem;
      text-transform: none;
      letter-spacing: normal;
      color: var(--jb-text-muted);
      text-decoration: none;
      white-space: nowrap;
      &:hover { color: var(--jb-accent); text-decoration: none; }
    }
  }

  /* On a phone the name and the address of the website cannot both have
     their room, and at 14px the address wins by being shorter — which
     truncates the bunkhouse's own name. The mark and the name are already
     a link to the website, so the second one goes and the name keeps its
     room. */
  @media (max-width: 30rem) {
    body.booking site-header .away { display: none; }
  }

  body.booking main {
    display: block;
    max-inline-size: var(--jb-column);
    margin-inline: auto;
    padding: 1.5rem 1.25rem 2.5rem;
  }

  body.booking site-footer {
    display: block;
    background: none;
    border: 0;
    max-inline-size: var(--jb-column);
    margin-inline: auto;
    padding: 1.5rem 1.25rem 4rem;
    font-size: 0.875rem;
    /* Who the bunkhouse is, where, and the number to ring: what a guest
       looks for when something has gone wrong, so it is set in the ink and
       not faded into the page. */
    color: var(--jb-text);
    & > p { margin: 0 0 0.75rem; max-inline-size: none; border-block-start: 1px solid var(--jb-border); padding-block-start: 1.5rem; }
    & ul { list-style: none; display: flex; gap: 1rem; margin: 0; padding: 0; }
    /* The links are green, taken a step towards the ink: the footer sits
       on the canvas rather than a card, and a bunkhouse's own text green is
       only sure of its contrast on white — the default measures 4.1:1 on
       the canvas, under what small text needs, and 5:1 once deepened. */
    & a { color: color-mix(in oklab, var(--jb-accent-ink) 82%, var(--jb-text)); text-underline-offset: 2px; }
    & a:hover { color: var(--jb-accent-hover); }
  }
}

@layer pages {
  /* Progress: six rails, one per step, the done ones linking back. The
     words are carried for anyone reading the page aloud but not shown:
     six labels squeezed across a phone were curt to the point of being
     no help, and the rails say how far along you are on their own. The
     step you are on is named by the heading under them anyway. */
  body.booking booking-steps {
    display: block;
    inline-size: auto;
    max-inline-size: none;
    margin-block-end: 1.75rem;
    & ol { display: flex; align-items: flex-start; gap: 0.25rem; margin: 0; padding: 0; list-style: none; font-size: 0.875rem; font-family: inherit; text-transform: none; letter-spacing: normal; }
    & li { flex: 1; min-inline-size: 0; display: flex; flex-direction: column; align-items: stretch; gap: 0.375rem; color: var(--jb-text-muted); }
    & a { display: flex; flex-direction: column; align-items: stretch; gap: 0.375rem; color: var(--jb-accent); text-decoration: none; }
    & a:hover step-label { text-decoration: underline; }
    & step-rail { display: block; block-size: 3px; border-radius: 2px; background: var(--jb-rail); }
    & li.done step-rail, & li.current step-rail { background: var(--jb-accent); }
    /* Out of sight, still in the accessibility tree. */
    & step-label { position: absolute; inline-size: 1px; block-size: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
    /* A three-pixel rail is no target, so the link keeps a thumb's worth
       of height around it without the rail itself growing. */
    & a { padding-block: 0.625rem; margin-block: -0.625rem; }
    & li.current { color: var(--jb-text); font-weight: 600; letter-spacing: normal; }
    /* The old progress line belongs to the numbered markers, not to this. */
    & progress-line { display: none; }
  }

  /* One decision per screen: the question, and a plain sub-line under it. */
  /* The handoff set these in Georgia. The house rule is one typeface and
     the difference carried by case, weight and tracking, so the serif
     goes and the weight comes up. 600 with a touch of negative tracking
     reads as a heading where 400 read as a large sentence — and a notch
     smaller than the handoff's 2rem, because a serif at 400 sits lighter
     on a page than a sans at 600 does. It is the size the admin's own
     h1 uses, so both halves of the app agree on how big a heading is. */
  :is(body.booking, body.staff.flow) main h1 {
    font-weight: 600;
    font-size: 1.75rem;
    line-height: 1.2;
    letter-spacing: -0.015em;
    color: var(--jb-text);
    margin: 0 0 0.5rem;
  }
  :is(body.booking, body.staff.flow) page-intro { display: block; gap: 0; }
  /* A section heading sits under the page's own. The shared stylesheet
     sets h2 for the marketing site, larger than this h1 and a long way
     below the text before it, which turned the terms into a list of
     headings with a title somewhere above them. Smaller than the h1 and
     the same weight, closer to what it follows. */
  body.booking main h2 { font-size: 1.25rem; font-weight: 600; line-height: 1.3; letter-spacing: -0.01em; color: var(--jb-text); }
  body.booking main .flow > * + h2 { margin-block-start: 2rem; }
  :is(body.booking, body.staff.flow) main h1 + p, :is(body.booking, body.staff.flow) p.lede { margin: 0 0 1.5rem; color: var(--jb-text-secondary); font-size: 1rem; max-inline-size: none; }

  /* Cards. Rows pull up a pixel so the first row does not double the
     card's own border. */
  :is(body.booking, body.staff.flow) jb-card {
    display: block;
    background: var(--jb-surface);
    border: 1px solid var(--jb-border);
    border-radius: 10px;
    overflow: hidden;
  }
  :is(body.booking, body.staff.flow) jb-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.125rem 1.25rem;
    border-block-start: 1px solid var(--jb-border-inner);
    margin-block-start: -1px;
  }

  /* Buttons: one primary per screen, and Back an outlined one beside it. */
  :is(body.booking, body.staff.flow) button.primary, :is(body.booking, body.staff.flow) a.button {
    font-family: inherit;
    text-transform: none;
    letter-spacing: normal;
    font-size: 1rem;
    padding: 0.75rem 1.5rem;
    border: 1px solid var(--jb-accent);
    border-radius: 8px;
    background: var(--jb-accent);
    color: var(--jb-accent-text);
    &:hover { background: var(--jb-accent-hover); border-color: var(--jb-accent-hover); color: var(--jb-accent-text); }
  }
  /* Back is the only way out of a step, so it reads as a button: the same
     height, corners and type as the way on beside it, drawn in outline
     with nothing filled, so the filled one is still the one to press. The
     ink rather than the secondary grey, and an arrow to say which way it
     goes. */
  :is(body.booking, body.staff.flow) :is(a, button).quiet, :is(body.booking, body.staff.flow) p.actions a.quiet {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-family: inherit;
    text-transform: none;
    letter-spacing: normal;
    font-size: 1rem;
    color: var(--jb-text);
    border: 1px solid var(--jb-border-control);
    border-radius: 8px;
    padding: 0.75rem 1.25rem;
    min-block-size: 44px;
    background: none;
    text-decoration: none;
    &:hover, &:focus-visible { color: var(--jb-accent); border-color: var(--jb-accent); }
  }
  /* Back on the left, the way on at the right edge. */
  :is(body.booking, body.staff.flow) p.actions {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-block-start: 1.75rem;
  }

  /* Inputs stay at 16px: anything smaller and iOS zooms the page on focus. */
  :is(body.booking, body.staff.flow) form.details input, :is(body.booking, body.staff.flow) form.details textarea,
  :is(body.booking, body.staff.flow) form.stay input, :is(body.booking, body.staff.flow) input, :is(body.booking, body.staff.flow) textarea,
  :is(body.booking, body.staff.flow) select {
    font-size: 1rem;
    padding: 0.75rem;
    border: 1px solid var(--jb-border-control);
    border-radius: 8px;
    background: var(--jb-surface);
    color: var(--jb-text);
  }
  :is(body.booking, body.staff.flow) label {
    font-family: inherit;
    text-transform: none;
    letter-spacing: normal;
    font-size: 0.875rem;
    color: var(--jb-text-secondary);
  }

  :is(body.booking, body.staff.flow) notice-box {
    margin-block-end: 1.5rem;
    background: var(--jb-surface);
    border: 1px solid var(--jb-border);
    border-inline-start: 3px solid var(--jb-accent);
    border-radius: 10px;
    color: var(--jb-text-secondary);
  }
  :is(body.booking, body.staff.flow) notice-box.warn { border-inline-start-color: #f97316; }
  /* The house rules sit between a step's cards and its actions, and are
     read in full before anybody pays, so they are the column's width and
     in the text's own colour rather than a muted aside. */
  :is(body.booking, body.staff.flow) notice-box.rules { margin-block: 1.5rem 0; max-inline-size: none; color: var(--jb-text);
    & p { margin: 0; max-inline-size: none; }
  }

  /* Step 1: what a row of a card looks like, and the counters. A press is
     44px across because that is what a thumb needs, and round so it does
     not read as another card. */
  :is(body.booking, body.staff.flow) row-what { display: block; flex: 1; min-inline-size: 0; }
  :is(body.booking, body.staff.flow) row-what strong { display: block; font-size: 1.0625rem; font-weight: 400; }
  :is(body.booking, body.staff.flow) row-what small { display: block; font-size: 0.875rem; color: var(--jb-text-muted); }
  :is(body.booking, body.staff.flow) counter-pair {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
    & .step {
      display: grid;
      place-items: center;
      inline-size: 44px;
      block-size: 44px;
      border-radius: 999px;
      border: 1px solid var(--jb-border-control);
      background: var(--jb-surface);
      color: var(--jb-text);
      font-size: 1.25rem;
      line-height: 1;
      text-decoration: none;
      &:hover { background: var(--jb-surface-hover); border-color: var(--jb-accent); color: var(--jb-accent); }
    }
    /* A press with nowhere to go keeps its place rather than vanishing:
       the row should not change width as the number does. */
    & .step.off { color: var(--jb-past-text); border-color: var(--jb-border-inner); background: var(--jb-surface); cursor: default; }
    & .step.off:hover { background: var(--jb-surface); border-color: var(--jb-border-inner); color: var(--jb-past-text); }
  }
  :is(body.booking, body.staff.flow) counter-value { min-inline-size: 1.5rem; text-align: center; font-size: 1.125rem; font-variant-numeric: tabular-nums; }
  :is(body.booking, body.staff.flow) p.actions .party { flex: 1; min-inline-size: 0; color: var(--jb-text-secondary); }
  :is(body.booking, body.staff.flow) p.aside { margin-block-start: 1.5rem; color: var(--jb-text-secondary); font-size: 0.9375rem; max-inline-size: none; }

  /* The calendar is the card on steps 2 and 3. Cells are square and never
     under 44px, because a thumb has to land on one. */
  :is(body.booking, body.staff.flow) booking-calendar {
    display: block;
    max-inline-size: none;
    background: var(--jb-surface);
    border: 1px solid var(--jb-border);
    border-radius: 10px;
    padding: 1.25rem;
    & cal-head {
      display: flex;
      align-items: center;
      gap: 1rem;
      margin-block-end: 1rem;
      /* The months either side are controls, not references in a
         sentence, so they are drawn as controls: outlined rather than
         filled, because the thing to press on this page is a night. */
      & .page {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-inline-size: 4.5rem;
        min-block-size: 44px;
        padding: 0 0.75rem;
        border: 1px solid var(--jb-border-control);
        border-radius: 8px;
        font-size: 0.875rem;
        white-space: nowrap;
        color: var(--jb-accent);
        text-decoration: none;
        &:hover, &:focus-visible { border-color: var(--jb-accent); background: var(--jb-surface-hover); color: var(--jb-accent-hover); }
      }
      /* The month with nothing before it still holds its side, so the
         label stays in the middle of the card rather than sliding. */
      & span.page { border-color: transparent; }
      & .range { flex: 1; min-inline-size: 0; margin: 0; text-align: center; font-size: 1.0625rem; font-weight: 500; text-transform: none; letter-spacing: normal; color: var(--jb-text); }
    }
    /* One grid rather than thirty separate tiles. The nights meet, and
       the colour behind them shows through a one-pixel gap to draw the
       lines — so there is one line between two nights rather than two
       rounded edges and a space, and the month reads as a month. */
    & ol { gap: 1px; }
    & .weekdays { font-family: inherit; font-size: 0.875rem; color: var(--jb-text-muted); text-transform: none; letter-spacing: normal; margin-block-end: 0.375rem; padding-inline: 1px; }
    & .week {
      margin-block-start: 0;
      padding: 1px 1px 0;
      background: var(--jb-open-bd);
    }
    /* The last row closes the box; the rest borrow the next row's top. */
    & .week:last-of-type { padding-block-end: 1px; }
    & .week li > * {
      position: relative;
      aspect-ratio: 1;
      min-block-size: 44px;
      border: 0;
      border-radius: 0;
      font-family: inherit;
      font-size: 0.9375rem;
      gap: 0;
      align-content: center;
    }
        /* Every state names the anchor it is on. The flow gives links a hover
       colour, and a cell is a link: without the `a` these rules tie with
       it on specificity and lose on source order, which is how a chosen
       night came to be drawn in green on green. */
    /* An open night is white like the card, so white alone said nothing
       — it read as an empty square. The date in the accent says it can be
       pressed, as the months either side already do, without filling it
       in: a fill of the accent is a night that has been chosen. */
    & a.free { background: var(--jb-surface); color: var(--jb-text); & b { color: var(--jb-accent); } }
    & a.free[href]:hover b, & a.free[href]:focus-visible b { color: var(--jb-accent-hover); }
    & a.free[href]:hover, & a.free[href]:focus-visible { background: var(--jb-surface-hover); color: var(--jb-accent-hover); }
    /* Every night of the stay is the same square, because every one of
       them is a night. The morning you leave is not, so it is the tint:
       plainly part of the stay, plainly not one of the nights counted. */
    & a.start, & a.in { background: var(--jb-accent); color: var(--jb-accent-text); }
    & a.end { background: var(--jb-accent-tint); color: var(--jb-accent-ink); box-shadow: inset 0 0 0 2px var(--jb-accent); }
    /* Hovering a night you have already chosen darkens it. It does not
       hollow it out: the pick is not being offered again. */
    & a.start:hover, & a.in:hover, & a.start:focus-visible, & a.in:focus-visible {
      background: var(--jb-accent-hover); color: var(--jb-accent-text);
    }
    & a.end:hover, & a.end:focus-visible { background: var(--jb-accent-tint); color: var(--jb-accent-ink); }
    /* The nights between the two picks are the stay, not another choice. */
    & a.can-end:hover { background: var(--jb-surface-hover); color: var(--jb-accent-hover); }
    /* Sold out keeps a border and a line through it; the past has neither,
       so the two never read as the same thing. Neither answers a hover. */
    /* A night with no beds left is filled and barely outlined, against an
       open one that is white with a firm edge. It used to be struck
       through as well, which made the date harder to read for a
       difference the fill and the edge were already making. */
    /* With the tiles gone there is no outline to tell an open night from
       a taken one, so the fill carries it: a fifth of a stop darker than
       it was — 1.25:1 against the open white rather than 1.12 — and the
       number on it a third of the weight of an open one. Fills alone
       cannot do much here, which is why both cues move together. */
    & a.full, & a.full:hover { background: var(--jb-soldout-bg); color: var(--jb-soldout-text); }
    /* The floor is 14px everywhere in this app. This is the one thing
       under it, and the reason is the box: a date and its month share a
       cell that is 44px square on a phone, and 14px twice does not fit.
       Being that small, it keeps the full colour of the date above it:
       faded, it fell under 4.5:1 on every fill but the open white. */
    & cell-month { display: block; font-size: 0.75rem; line-height: 1.1; color: inherit; }
    /* The two ends of the stay name themselves, in the same small type
       the month uses and for the same reason: the box. It sits at the top
       of the cell out of the flow, so the dates stay on one line across
       the row rather than the two tagged ones dropping half a line. */
    & cell-tag {
      position: absolute;
      inset-block-start: 0.25rem;
      inset-inline: 0;
      text-align: center;
      font-size: 0.75rem;
      line-height: 1.1;
    }
    & .past { background: var(--jb-past-bg); color: var(--jb-past-text); text-decoration: none; }
    /* A square where the month has not started or has already ended. It
       is not a night, so it is not drawn as a box. Left as a ruled white
       square it was an open night with no date, and white stopped saying
       open. Each blank covers the lines on its outer sides with the card
       and leaves the ones it shares with a night, so the grid's edge
       follows the month. Blanks only lead the first week and trail the
       last. */
    & li:has(> .blank) { position: relative; }
    & .week li > .blank { position: absolute; aspect-ratio: auto; min-block-size: 0; background: var(--jb-surface); }
    & .weekdays + .week .blank { inset: -1px 0 0 -1px; }
    & .week:last-of-type .blank { inset: 0 -1px -1px 0; }
  }
  :is(body.booking, body.staff.flow) p.foot { margin: 1rem 0 0; color: var(--jb-text-secondary); font-size: 0.9375rem; max-inline-size: none; }
  /* The leave step has nothing to say under the calendar until a morning
     is picked, and an empty line still takes its margin. */
  :is(body.booking, body.staff.flow) p.foot:empty { display: none; }
  /* Before a pick the way on is a sentence, not a dead button. */
  :is(body.booking, body.staff.flow) .waiting { color: var(--jb-text-muted); font-size: 0.9375rem; }
  /* Under the calendar, what it has been told, in words: the night they
     arrive, then how many nights. Said large, because it is the answer to
     the question the heading asked; the button beneath only says Next, so
     that what to do and what was chosen are each said once. Before a
     pick it asks for one, in the same size and weight and only a quieter
     colour, so picking a night changes the words and nothing moves. */
  :is(body.booking, body.staff.flow) cal-choice {
    display: block;
    margin-block-start: 1.25rem;
    text-align: center;
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.015em;
    color: var(--jb-text);
    /* Said again here, because the flow's own .waiting rule sets a smaller
       size and outranks the element. */
    &.waiting { font-size: 1.5rem; color: var(--jb-text-muted); }
  }
  :is(body.booking, body.staff.flow) cal-choice ~ p.actions { margin-block-start: 1rem; }


  /* Step 4: one card per room, the chosen one carrying a heavier border
     rather than a tick — the whole card is the control. The radio does
     the work, so the step needs no script. */
  /* Why the room the group is sized for is not among the cards. It reads
     with the line under the heading, closer to it than to the cards, and
     in the ink rather than the grey, because it answers the question the
     cards leave. */
  :is(body.booking, body.staff.flow) p.taken { margin: -0.75rem 0 1.5rem; font-size: 1rem; color: var(--jb-text); max-inline-size: none; }
  :is(body.booking, body.staff.flow) form.rooms { display: grid; gap: 0.75rem; max-inline-size: none; }
  :is(body.booking, body.staff.flow) label.room {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    background: var(--jb-surface);
    border: 1px solid var(--jb-border);
    border-radius: 10px;
    padding: 1.125rem 1.25rem;
    cursor: pointer;
    font-size: 1rem;
    color: var(--jb-text);
    text-transform: none;
    letter-spacing: normal;
    /* The border thickens rather than the box growing: two pixels in,
       one pixel of padding out, so nothing shifts as the choice moves. */
    &:has(:checked) { border: 2px solid var(--jb-accent); padding: calc(1.125rem - 1px) calc(1.25rem - 1px); }
    &:hover { border-color: var(--jb-accent); }
    & input { position: absolute; opacity: 0; inline-size: 1px; block-size: 1px; }
    &:has(:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; }
  }
  :is(body.booking, body.staff.flow) room-what { display: block; flex: 1; min-inline-size: 0; }
  :is(body.booking, body.staff.flow) room-what strong { display: block; font-size: 1.0625rem; font-weight: 400; }
  :is(body.booking, body.staff.flow) room-what small { display: block; font-size: 0.875rem; color: var(--jb-text-secondary); margin-block-start: 0.25rem; }
  :is(body.booking, body.staff.flow) chosen-mark { display: none; font-size: 0.875rem; color: var(--jb-accent-ink); margin-block-start: 0.375rem; }
  :is(body.booking, body.staff.flow) label.room:has(:checked) chosen-mark { display: block; }
  :is(body.booking, body.staff.flow) room-price { display: block; text-align: end; white-space: nowrap; }
  :is(body.booking, body.staff.flow) room-price strong { display: block; font-size: 1.125rem; font-weight: 400; }
  :is(body.booking, body.staff.flow) room-price small { display: block; font-size: 0.875rem; color: var(--jb-text-muted); }

  /* Step 5: the fields, then what it comes to. Inputs stay at 16px or iOS
     zooms the page the moment one is focused. */
  /* The form is a card like the one under it, so it is the width of the
     column like the one under it. The shared stylesheet caps a details
     form at 36rem, which is right where a form stands alone and wrong
     where it is one of two cards stacked. */
  :is(body.booking, body.staff.flow) form.details { max-inline-size: none; }
  :is(body.booking, body.staff.flow) jb-card.fields { display: grid; gap: 1.125rem; padding: 1.25rem; }
  /* Required, said in the label. The input carries `required` too, which
     is what a screen reader announces; this is for the eye. */
  :is(body.booking, body.staff.flow) req-mark { color: var(--jb-text-muted); }
  :is(body.booking, body.staff.flow) jb-card.fields textarea {
    /* It grows with what is typed, so there is nothing to drag and no
       scrollbar inside the box. */
    resize: none;
    overflow: hidden;
    min-block-size: 0;
  }
  :is(body.booking, body.staff.flow) jb-card.fields label { display: block; font-size: 0.875rem; color: var(--jb-text-secondary); }
  :is(body.booking, body.staff.flow) jb-card.fields label > input, :is(body.booking, body.staff.flow) jb-card.fields label > textarea, :is(body.booking, body.staff.flow) jb-card.fields label > select {
    display: block;
    inline-size: 100%;
    box-sizing: border-box;
    margin-block-start: 0.375rem;
    color: var(--jb-text);
  }
  :is(body.booking, body.staff.flow) jb-card.fields small { display: block; font-size: 0.875rem; color: var(--jb-text-muted); margin-block-start: 0.375rem; }
  :is(body.booking, body.staff.flow) jb-card.fields small.inline { display: inline; margin: 0; }
  :is(body.booking, body.staff.flow) jb-card.fields .row { display: grid; gap: 1rem; grid-template-columns: 1fr 1fr; }
  :is(body.booking, body.staff.flow) jb-card.fields label.check { display: flex; align-items: center; gap: 0.5rem; }
  :is(body.booking, body.staff.flow) jb-card.fields label.check input { inline-size: auto; margin: 0; }
  /* "Did you mean ann@gmail.com?", under the address it is about. */
  :is(body.booking, body.staff.flow) jb-card.fields email-check {
    display: block; margin-block-start: -0.5rem; padding-inline-start: 0.75rem;
    border-inline-start: 3px solid var(--warn); font-size: 0.875rem; color: var(--jb-text);
    & p { margin-block: 0 0.375rem; }
    & p:last-child { margin-block-end: 0; color: var(--jb-text-secondary); }
  }

  :is(body.booking, body.staff.flow) jb-card.summary { margin-block-start: 1rem; }
  :is(body.booking, body.staff.flow) card-title { display: block; padding: 1.125rem 1.25rem 0.75rem; font-size: 1.0625rem; font-weight: 500; }
  :is(body.booking, body.staff.flow) sum-row, :is(body.booking, body.staff.flow) total-row {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    padding: 0.5rem 1.25rem;
    font-size: 0.9375rem;
    & span:first-child { flex: 1; min-inline-size: 0; color: var(--jb-text-secondary); }
    & span:last-child { white-space: nowrap; font-variant-numeric: tabular-nums; }
  }
  /* The total is the same money said once more, so it is set larger and
     ruled off rather than coloured. */
  :is(body.booking, body.staff.flow) total-row {
    padding-block: 0.875rem;
    margin-block-start: 0.5rem;
    border-block-start: 1px solid var(--jb-border-inner);
    font-size: 1rem;
    & span:first-child { color: var(--jb-text); }
    & span:last-child { font-size: 1.25rem; }
  }
  /* A card that ends on a plain row gets the room a total would give it. */
  :is(body.booking, body.staff.flow) jb-card.summary sum-row:last-child { padding-block-end: 0.875rem; }
  :is(body.booking, body.staff.flow) p.fineprint { margin: 0.75rem 0 0; font-size: 0.875rem; color: var(--jb-text-muted); max-inline-size: none; }

  /* The flow is one column now; the aside layout belongs to the old one. */
  :is(body.booking, body.staff.flow) .two-col.aside { display: block; }
  /* Links in prose, and only in prose. A blanket rule on every `a` in the
     flow sits in the last layer, where it beats each component's own link
     colour however specific that is — layers outrank specificity. It put
     accent-coloured text on an accent-coloured calendar cell, and then on
     the Book button, which is what a rule this broad will keep doing.
     Everything that is a link but not a sentence — the masthead, the
     progress rails, calendar cells, the footer, buttons — brings its own
     colour, and this leaves them alone. */
  body.booking main :is(p, li, dd) a {
    color: var(--sea);
    text-underline-offset: 2px;
    &:hover { color: var(--sea-hover); }
  }

  /* Reading the terms part way through booking should not feel like
     leaving it: the way back sits at the top of the page, above the
     reading, and carries the dates and the step with it. */
  :is(body.booking, body.staff.flow) back-to { display: block; margin-block-end: 1.5rem; }

  /* The two things a guest can do to a booking they already have. Both
     are buttons of the flow's own shape rather than the old design's
     one, outlined rather than filled because neither is the way on from
     a step, and the one that cannot be undone is the only red on the
     page. */
  :is(body.booking, body.staff.flow) :is(a, button).outline {
    display: inline-block;
    font: inherit;
    font-size: 1rem;
    padding: 0.75rem 1.5rem;
    border: 1px solid var(--jb-accent);
    border-radius: 8px;
    background: var(--jb-surface);
    color: var(--jb-accent);
    text-decoration: none;
    cursor: pointer;
    &:hover { background: var(--jb-accent-tint); border-color: var(--jb-accent-hover); color: var(--jb-accent-hover); }
    &.danger {
      border-color: var(--jb-danger);
      color: var(--jb-danger);
      &:hover { background: color-mix(in oklab, var(--jb-danger) 8%, var(--jb-surface)); border-color: var(--jb-danger); color: var(--jb-danger); }
    }
  }
  /* The way out of that page, beside it, in the flow's type rather than
     the old design's display face. */
  :is(body.booking, body.staff.flow) a.quiet-link {
    font-family: inherit;
    text-transform: none;
    letter-spacing: normal;
    font-size: 1rem;
    color: var(--jb-accent);
    &:hover { color: var(--jb-accent-hover); }
  }

  /* And the button that actually does it, on the page that asks whether
     you are sure. It is the way on from that page, so it is filled — in
     the same red, because the way on is the irreversible thing. */
  :is(body.booking, body.staff.flow) button.primary.danger {
    background: var(--jb-danger);
    border-color: var(--jb-danger);
    color: var(--jb-danger-text);
    &:hover {
      background: color-mix(in oklab, var(--jb-danger) 88%, var(--jb-text));
      border-color: color-mix(in oklab, var(--jb-danger) 88%, var(--jb-text));
      color: var(--jb-danger-text);
    }
  }

  /* The one step with two ways on: a change that costs money is paid on
     the card the booking was made with or on another, and three controls
     will not sit on one phone-width line. */
  :is(body.booking, body.staff.flow) p.actions.pay { flex-wrap: wrap; row-gap: 0.75rem; }
  /* The other card is a real choice, not an afterthought, so it is the
     same shape as the button beside it: outline where that one is filled. */
  :is(body.booking, body.staff.flow) p.actions.pay button:not(.primary) {
    font: inherit;
    font-size: 1rem;
    padding: 0.75rem 1.5rem;
    border: 1px solid var(--jb-border-control);
    border-radius: 8px;
    background: var(--jb-surface);
    color: var(--jb-text);
    cursor: pointer;
    &:hover { border-color: var(--jb-accent); color: var(--jb-accent); }
  }

  /* On a phone the column's side padding is most of a calendar cell, so
     the cards give it up and run to both edges: no side border, no
     corners, and the grid inside gets the width back. A card that fills
     the screen is still a card — it is the only thing on it. */
  @media (max-width: 34rem) {
    :is(body.booking, body.staff.flow) :is(jb-card, booking-calendar, label.room) {
      margin-inline: -1.25rem;
      border-inline-width: 0;
      border-radius: 0;
    }
    :is(body.booking, body.staff.flow) booking-calendar {
      padding-inline: 0;
      & cal-head { padding-inline: 1.25rem; }
      /* A square is not enough box for a label, a date and a month at
         phone widths, so the nights get their height back and stop being
         squares. They are still a grid; they are just taller than wide. */
      & .week li > * { aspect-ratio: auto; min-block-size: 4.25rem; }
      /* The grid runs to both edges, so it needs no line down its sides. */
      & .week { padding-inline: 0; }
      & .weekdays { padding-inline: 0; }
    }
    /* Two ways to pay will not sit side by side on a phone, so each one
       takes the width and the recommended one stays underneath, where the
       thumb is and where every other step keeps the way on. */
    :is(body.booking, body.staff.flow) p.actions.pay button { flex: 1 1 100%; }
    /* The fields keep their own breathing room inside a card that has
       none left at the edges. */
    :is(body.booking, body.staff.flow) jb-card.fields,
    :is(body.booking, body.staff.flow) jb-card.summary sum-row,
    :is(body.booking, body.staff.flow) jb-card.summary total-row,
    :is(body.booking, body.staff.flow) jb-card.summary card-title,
    :is(body.booking, body.staff.flow) jb-row,
    :is(body.booking, body.staff.flow) label.room { padding-inline: 1.25rem; }
  }

}

/* Staff take bookings through the same templates, in their own layout, and
   the flow's own rules above draw them there too: the same cards, fields,
   calendar and buttons as the guest sees, in the admin's colours. These
   are the guest palette's names pointed at the admin's, so both halves of
   the app are one design in two sets of clothes. */
@layer base {
  body.staff.flow {
    --jb-canvas: var(--bh-canvas);
    --jb-raised: var(--bh-surface-sunken);
    --jb-surface: var(--bh-surface);
    --jb-surface-hover: var(--bh-surface-hover);
    --jb-border: var(--bh-border);
    --jb-border-inner: var(--bh-border-subtle);
    --jb-border-control: var(--bh-border-control);
    /* An open night's outline has to be seen at 3:1 against the card, and
       the admin's strong border is not quite: the muted ink, softened. */
    --jb-open-bd: color-mix(in oklab, var(--bh-text-muted) 80%, var(--bh-surface));
    --jb-rail: var(--bh-border);
    --jb-text: var(--bh-text);
    --jb-text-secondary: var(--bh-text-secondary);
    --jb-text-muted: var(--bh-text-muted);
    --jb-accent: var(--bh-accent);
    --jb-accent-hover: var(--bh-accent-hover);
    --jb-accent-text: var(--bh-text-on-accent);
    --jb-accent-ink: var(--bh-link);
    --jb-accent-tint: var(--bh-accent-quiet);
    --jb-accent-tint-bd: color-mix(in oklab, var(--bh-accent) 35%, var(--bh-surface));
    --jb-soldout-bg: color-mix(in oklab, var(--bh-text) 10%, var(--bh-surface));
    --jb-soldout-bd: color-mix(in oklab, var(--bh-text) 12%, var(--bh-surface));
    --jb-soldout-text: var(--bh-text-secondary);
    --jb-past-bg: color-mix(in oklab, var(--bh-text) 3%, var(--bh-surface));
    --jb-past-text: var(--bh-text-faint);
    --jb-danger: var(--danger);
    --jb-danger-text: var(--bh-surface);
    --focus: color-mix(in oklab, var(--bh-accent) 70%, var(--bh-text));
  }
}

@layer pages {
  /* The guest's cards run to the screen's edges on a phone by giving up
     the column's padding, which is 1.25rem there; the admin's is 1rem. */
  @media (max-width: 34rem) {
    body.staff.flow main { padding-inline: 1.25rem; }
  }
}

/* Signed out, the staff area is one card with one thing to do in it. The
   page it used to sit on was a tool's page — a header bar across the top
   and the card below it, opened to the height of the window with nothing
   in the rest. This holds it in the middle instead, at the width of what
   it asks for. */
@layer pages {
  body.staff.out {
    min-block-size: 100dvh;
    padding: 1.5rem;
    display: grid;
    /* The shared stylesheet lays a body out as three rows — header, main,
       footer — and a card dropped into that lands in the first of them
       with the rest of the window below it, which is what left this page
       hanging from the top. Here there is one thing on the screen, so the
       template goes back to a single cell and the cell holds the middle.
       Safe centring: a card taller than the window scrolls from its top
       rather than being centred with its head off the screen. */
    grid-template-rows: auto;
    grid-template-columns: min(25rem, 100%);
    align-content: safe center;
    justify-content: safe center;
    /* The card's own auto margins would shrink-wrap it to the width of
       its longest line; the cell is the width now. */
    & app-card { inline-size: 100%; margin-inline: 0; }
    & app-head { min-block-size: 52px; gap: 1rem; }
    /* A card is not a page: the title comes down a size to sit in one. */
    & page-intro h1 { font-size: var(--step-2); }
    & a.brand { display: flex; align-items: center; gap: 0.5rem; }
    & main { padding: 1.5rem; }
    & page-intro { gap: 0.375rem; & p { font-size: var(--step-0); } }
    /* The button used to sit against the sentence above it, close enough
       that its focus ring drew a line through the words. */
    & form.details { margin-block-start: 1.5rem; gap: 1rem; }
    & form.details button.primary { inline-size: 100%; }
    /* What went wrong is said above the title; what happened next, below
       it. Each needs air on the side it faces. */
    & p.error { margin-block-end: 1.25rem; }
    & notice-box { margin-block-start: 1.5rem; }
    & notice-box + p { margin-block-start: 1rem; color: var(--muted); }
    /* The test-mode sign-in link is one long word and was running out
       through the side of the card. */
    & main a { overflow-wrap: anywhere; }
  }
}
