/* Mahogany Courts — everything Bootstrap does not give us: the week grid, the
   booking modal, the admin booking blocks, the toasts. Bootstrap 5 (see the
   layout) supplies buttons, forms and badges. */

:root {
  --mc-ink: #1f2933;
  --mc-muted: #6b7280;
  --mc-line: #e2e6ea;
  /* The same grey, taken as far down as the grid's own palette goes: it is the
     colour a merged block is ringed in below. The hairline above rules the
     inside of a day — the hours, and the courts sharing the column; this one
     rules the frame around it, which the eye reads the week's shape from: the
     day boundaries, the header row, and the edge of the whole table. */
  --mc-line-strong: #aab1ba;
  --mc-open: #ffffff;
  --mc-open-hover: #eef6ff;
  --mc-accent: #2563eb;      /* hover, focus, links into the grid */
  --mc-reserved: #c7ccd3;    /* a taken slot: light-mid grey */
  --mc-reserved-ink: #454c56;
  --mc-reserved-line: #aab1ba;   /* the one border round a merged block */
  --mc-reserved-past: #e2e5e9;
  --mc-reserved-past-line: #ccd1d7;
  --mc-today: #fff8e6;
  --mc-past: #f4f5f7;
  --mc-brand: #7b3f21; /* mahogany */
  --mc-slot-height: 40px;      /* one bookable hour of the venue's day */
  /* The tab that stands on the top line of the table, over today's column. It
     is written down here because it is a grid measurement like the two below
     rather than a property of any one box: the band the tab is clipped in, the
     tab inside it and the drop that lands its foot on the line are three rules
     that have to agree about one height (see .wg-tabstrip). */
  --mc-todaytab-height: 1.1rem;
  /* Fits "10pm - 11pm", which is the widest an hour of the venue's day can be
     written (see buildWeekGrid): business hours must fall on the hour, so no row
     label ever carries a ":30", and the longest range is two two-digit hours.
     The same width on a phone as on a desk — the type does not shrink there, so
     the column cannot either. */
  --mc-time-col: 100px;
  /* The narrowest a day of the week may be drawn. Seven of these plus the time
     column is what the grid is at least as wide as, and anything past that is
     spare room shared out between the days — so on a desk it is a week that
     fits, and on a phone it is a week that scrolls. */
  --mc-day-col: 128px;
  /* The circles that ride the two ends of the week (see .wg-chev). Written down
     out here with the other grid measurements because that is what it is: each
     circle is centred on one of the grid's own vertical lines, and where it goes
     is that line's position less half of this. A number that has to be halved in
     two rules to place one control belongs in one place. */
  --wg-chev-size: 2.5rem;
}

/* The venue itself, behind everything.
 *
 * An aerial photograph of the two courts (app/assets/images/court-backdrop.jpg),
 * and nothing over it: the picture arrives already blurred and darkened, and it
 * is shown as it is. No wash, no tint, no gradient between the photograph and
 * the page.
 *
 * The colour stays as `background-color` rather than being folded into the
 * shorthand, so it is still what shows while the photo loads, if it 404s, and
 * on the printed page — where the @media print rules put the background back to
 * plain white (see the foot of this file).
 *
 * `fixed` so the courts sit still while a week scrolls over them, except where
 * that is a bad trade: a touch device repaints a fixed background on every
 * scroll frame, and phones are most of this app's traffic, so there it scrolls
 * with the page like an ordinary image. */
body {
  color: var(--mc-ink);
  background-color: #f7f8fa;
  background-image: url("/assets/court-backdrop-7876bbeb.jpg");
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
}
@media (hover: none), (max-width: 640px) {
  body { background-attachment: scroll; }

  /* A phone cannot show seven days at once, and the version of it that tries —
     seven 128px columns crushed into 412px of glass — is a week nobody can
     read: a name on a booking block is three letters and an ellipsis, and the
     times written across a selection do not fit at all. So the columns keep the
     width they need and the week scrolls sideways instead, which is the trade a
     phone is used to making. The frozen time column and the sticky day headers
     go on doing their jobs through it: both are `position: sticky` against the
     scroller, which is what they were before there was anything to scroll. */
  :root { --mc-day-col: 164px; }
}

/* --- toasts ---------------------------------------------------------------
   Every message this app has — the flash from the last request and every refusal
   a booking modal used to print on a line inside itself — arrives at the top of
   the screen, centred, and leaves on its own. Above everything: the tallest
   layer anything else claims is the user menu's panel at 1100 (Bootstrap's own
   ceiling is its tooltip at 1080), and a message has to clear all of it, because
   a modal's own error is one of the things being said.

   Centred by margin rather than a translate, so the stack keeps its own
   transform free for the toasts' entrance. */
.mc-toasts {
  position: fixed;
  top: 1rem;
  left: 0;
  right: 0;
  margin-inline: auto;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: min(24rem, calc(100vw - 2rem));
  pointer-events: none;   /* the band stays clickable between toasts */
}
/* The colour bar down the left is an inset shadow rather than a thick border, so
   it follows the rounded corner instead of curving away from the card. */
.mc-toast {
  --mc-toast-accent: var(--mc-muted);
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.65rem 0.5rem 0.65rem 1rem;
  border: 1px solid var(--mc-line);
  border-radius: 10px;
  background: #fff;
  color: var(--mc-ink);
  font-size: 0.92rem;
  line-height: 1.35;
  box-shadow: inset 4px 0 0 0 var(--mc-toast-accent), 0 10px 28px rgba(16, 24, 40, 0.18);
  transition: opacity 0.25s ease, transform 0.25s ease;
  animation: mc-toast-in 0.18s ease-out;
}
.mc-toast--notice { --mc-toast-accent: #157347; }
.mc-toast--alert { --mc-toast-accent: #b42318; }
.mc-toast.is-leaving { opacity: 0; transform: translateY(-0.4rem); }
.mc-toast__text { flex: 1 1 auto; min-width: 0; }
.mc-toast__close {
  flex: 0 0 auto;
  border: 0;
  background: none;
  padding: 0 0.35rem;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--mc-muted);
  cursor: pointer;
}
.mc-toast__close:hover { color: var(--mc-ink); }
@keyframes mc-toast-in {
  from { opacity: 0; transform: translateY(-0.5rem); }
  to { opacity: 1; transform: none; }
}

/* The question a booking dropped somewhere new is left standing in — "Move Jun
   Reyes to Saturday, 6 Jun 2026, 7:00pm?" with Yes and No under it. It wears
   the toast card's own treatment (the border, the corner, the shadow and the
   colour bar down the left) because it arrives in the same place for the same
   reader, and two message cards at the top of one screen that looked different
   would read as two different kinds of thing.

   Directly UNDER the toast stack, and that is the one number here worth
   defending: a move that is refused answers in a toast, and the refusal has to
   land over the question it is about rather than behind it.

   Wider than a toast, since it carries a name, a date, an hour and two buttons
   on one line. No backdrop anywhere — the week under it stays live on purpose,
   because taking hold of the block again is how a drop is corrected. */
.mc-moveask {
  position: fixed;
  top: 1rem;
  left: 0;
  right: 0;
  margin-inline: auto;
  z-index: 9998;
  width: min(28rem, calc(100vw - 2rem));
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.65rem 0.75rem 0.65rem 1rem;
  border: 1px solid var(--mc-line);
  border-radius: 10px;
  background: #fff;
  color: var(--mc-ink);
  font-size: 0.92rem;
  line-height: 1.35;
  box-shadow: inset 4px 0 0 0 var(--mc-accent), 0 10px 28px rgba(16, 24, 40, 0.18);
}
.mc-moveask[hidden] { display: none; }
.mc-moveask__text { flex: 1 1 auto; min-width: 0; margin: 0; }
.mc-moveask__actions { flex: 0 0 auto; display: flex; gap: 0.4rem; }
@media (prefers-reduced-motion: reduce) {
  .mc-toast { animation: none; transition: none; }
}

.mc-shell {
  max-width: 1180px;
  margin: 0 auto;
  padding: 4.25rem 1rem 2rem;
}
/* The tall top is for the public pages, where the card floats on the photograph
   and the logo disc rides up off its edge. Behind the admin bar the mark lives
   on the bar itself, so all that room would just be distance between the bar
   and the desk: any shell that follows the bar starts close under it. */
.mc-navbar + .mc-shell { padding-top: 1.5rem; }

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

.mc-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.mc-header h1 {
  margin: 0;
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--mc-brand);
}

/* The player page's logo disc — a 104px white badge riding the top edge of the
   calendar's card, and the door to the venue's Facebook page — was drawn here.
   It is gone: the mark lives on the navbar now (.mc-navlogo below), where a
   customer and a member of staff find it in the same corner of the same bar,
   and the band of padding the well kept clear for it went with it (see
   #player-page .mc-well). */

.mc-header .mc-sub {
  margin: 0.15rem 0 0;
  color: var(--mc-muted);
  font-size: 0.92rem;
}

/* A header with nothing in it but the venue's name, over a single centred card.
   On every other page the header is a bar with things at both ends of it, so it
   is laid out end to end; here there is nothing to put at the ends. */
.mc-header--centred {
  justify-content: center;
  text-align: center;
}

/* The booking page's letterhead, at the top of the card itself: the venue's
   logo, centred, at letterhead size — it IS the heading, so it gets a heading's
   presence. Contained rather than cropped, so a wide wordmark and a square
   badge both arrive whole.

   A venue with no logo uploaded puts its name here instead, and the name has to
   carry the same weight the picture would have, so it is styled to match the
   h1 every other page's header uses. */
.mc-letterhead {
  display: block;
  margin: 0 auto 0.75rem;
  max-height: 200px;
  max-width: 100%;
  object-fit: contain;
}
.mc-letterhead__name {
  margin: 0 0 0.75rem;
  text-align: center;
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--mc-brand);
}

.mc-navbar {
  /* AT THE TOP OF THE PAGE, ALWAYS. The bar carries the venue's mark and the way
     to every other page it has, and a reader half way down a month — or down a
     receipt, or a policy page — should not have to scroll back up to reach any
     of it.

     STICKY rather than fixed, which is the whole difference between this and a
     bar that has to be paid for: sticky leaves the element in the flow, so the
     page below it starts where it always did and nothing needs a padding-top
     that would have to be kept in step with the bar's own height.

     UNDER THE PANELS, deliberately. Everything modal in this app covers the
     screen (1080, and 1090 for one standing over another): a bar floating over a
     receipt would be the one piece of the page a reader cannot dismiss. 1000 is
     above everything on the page itself and below all of that.

     It was `position: relative`, for the burger's dropdown — which hangs off the
     bar rather than off the button — and sticky positions that just as well. */
  position: sticky;
  top: 0;
  z-index: 1000;
  background: #000000c7;
  color: #fff;
}
.mc-navbar .mc-shell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 1rem;
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
}
.mc-navbar .mc-brand {
  font-weight: 700;
  letter-spacing: 0.01em;
  color: #fff;
  text-decoration: none;
  margin-right: auto;
}
.mc-navbar a {
  color: rgba(255, 255, 255, 0.85);
  text-decoration: none;
  font-size: 0.92rem;
}
.mc-navbar a:hover { color: #fff; text-decoration: underline; }
.mc-navbar a.is-current { color: #fff; font-weight: 600; }
.mc-navbar form { display: inline; }
.mc-navbar .mc-signout {
  background: none;
  border: 0;
  padding: 0;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.92rem;
}
.mc-navbar .mc-signout:hover { color: #fff; text-decoration: underline; }
.mc-navbar .mc-who { font-size: 0.82rem; color: rgba(255, 255, 255, 0.65); }

/* The venue's mark where its name was, at the height the name was — so the bar
   does not grow to make room for it. The same white disc it wears over the
   player's calendar, at a size that reads on a bar rather than over a page. */
.mc-navlogo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 3px;
  border-radius: 50%;
  background: #fff;
  overflow: hidden;
}
.mc-navlogo img {
  display: block;
  height: 30px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}
.mc-navbar .mc-brand { display: inline-flex; align-items: center; }

/* The account menu: a disclosure, so the browser owns the opening and closing.
   The panel hangs off the right-hand end of the bar rather than pushing the bar
   about, which is what makes it a menu instead of a paragraph that appears. */
.mc-usermenu {
  position: relative;
  margin-left: 0.25rem;
}
.mc-usermenu > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.1rem;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.92rem;
  cursor: pointer;
  list-style: none;          /* the default marker, which we draw ourselves */
}
.mc-usermenu > summary::-webkit-details-marker { display: none; }
.mc-usermenu > summary:hover { color: #fff; }
.mc-usermenu__caret { font-size: 0.7rem; opacity: 0.8; }
.mc-usermenu[open] .mc-usermenu__caret { transform: rotate(180deg); }

.mc-usermenu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.45rem);
  z-index: 1100;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  min-width: 12rem;
  padding: 0.5rem 0.75rem 0.6rem;
  border: 1px solid var(--mc-line);
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 10px 28px rgba(16, 24, 40, 0.18);
}
/* The email a menu that can sign you out has to say it would be signing out.
   Two menus wear it — the desk's account dropdown and the phone's burger panel,
   which IS the account menu at that width — and they wear it identically,
   because they are the same card hanging off the same bar and any difference
   between them would read as a mistake. The phone's one takes a ceiling as
   well: the panel is shrink-to-fit, so a long address left to itself would drag
   it most of the way across the screen instead of wrapping. */
.mc-usermenu__who,
.mc-navbar__who {
  display: block;
  padding-bottom: 0.35rem;
  margin-bottom: 0.25rem;
  border-bottom: 1px solid var(--mc-line);
  width: 100%;
  color: var(--mc-muted);
  font-size: 0.78rem;
  overflow-wrap: anywhere;
}
.mc-navbar__who { max-width: 14rem; }
.mc-usermenu__panel a,
.mc-usermenu__panel .mc-signout {
  padding: 0.2rem 0;
  color: var(--mc-ink);
  font-size: 0.9rem;
  text-decoration: none;
}
.mc-usermenu__panel a:hover,
.mc-usermenu__panel .mc-signout:hover {
  color: var(--mc-brand);
  text-decoration: underline;
}

/* The page links, and the burger they go behind on a phone. Both bars are built
   this way — the customer's three and the desk's two-to-four — because there is
   one bar with two sets of links in it, not two bars.

   ONE SET OF LINKS AT EVERY WIDTH. `display: contents` is what buys that: the
   box is not drawn at all on a desk, so the links inside it are laid out as
   flex children of the bar exactly as they were before there was a box round
   them, and the phone rules below turn the same box into the panel. The
   alternative — a row for wide screens and a menu for narrow ones — is two
   copies of the same list waiting to disagree about which page the reader is
   on. */
.mc-navbar__links { display: contents; }

/* A section of the phone's menu: the super-admin's three, and the sign-out at
   the bottom. `display: contents` again, so a group is nothing at all on a desk
   and the links inside it stay flex children of the bar — the group exists to
   carry the rule drawn over it on a phone, and a rule is not a thing a desk's
   bar has. */
.mc-navbar__group { display: contents; }

/* And the parts of that menu the desk has its own copy of: the email, Settings,
   the sign-out form. They are in the links box because a phone gets ONE menu;
   they are not drawn at all above 640px because up there the account dropdown
   beside the bar is carrying every one of them. Last of these three rules on
   purpose — it is what takes the display away from the group above. */
.mc-navbar__phone { display: none; }

.mc-navbar__burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  background: none;
  color: rgba(255, 255, 255, 0.85);
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
}
.mc-navbar__burger:hover { color: #fff; }

@media (max-width: 640px) {
  .mc-navbar__burger { display: inline-flex; }
  .mc-navbar__links { display: none; }

  /* ONE MENU ON A PHONE. The account dropdown goes, and what it carried is
     carried by the panel below instead (see admin/_nav, which renders the email,
     Settings and Sign out into the links box a second time for this width).
     Two menus a thumb's width apart on a bar with room for neither is one menu
     too many, and the one that went is the one whose target was the width of an
     email address. Nothing on the customer's bar is touched by this: that bar
     has no account menu to take away. */
  .mc-usermenu { display: none; }

  /* The same white card the account menu hung, off the same edge of the same
     bar, because on a phone this panel IS that menu now. The links inside are
     white on the bar and have to stop being white in here — the panel is white
     too. */
  .mc-navbar.is-open .mc-navbar__links {
    position: absolute;
    right: 1rem;
    top: calc(100% + 0.45rem);
    z-index: 1100;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15rem;
    min-width: 10rem;
    padding: 0.4rem 0.75rem 0.5rem;
    border: 1px solid var(--mc-line);
    border-radius: 10px;
    background: #fff;
    box-shadow: 0 10px 28px rgba(16, 24, 40, 0.18);
  }
  .mc-navbar.is-open .mc-navbar__links a {
    padding: 0.3rem 0;
    color: var(--mc-ink);
    font-size: 0.95rem;
    text-decoration: none;
  }
  .mc-navbar.is-open .mc-navbar__links a:hover {
    color: var(--mc-brand);
    text-decoration: underline;
  }
  .mc-navbar.is-open .mc-navbar__links a.is-current {
    color: var(--mc-brand);
    font-weight: 600;
  }

  /* The parts of the panel that only exist down here. `block` rather than a
     display of their own: the email is a line and Settings is a link, and the
     one of these that is a section gets its display back from the rule under
     this one, which is why that rule comes second. */
  .mc-navbar.is-open .mc-navbar__links .mc-navbar__phone { display: block; }

  /* A section, and the thin rule over it that makes it one. The rule is a
     border on the section rather than a separator element between sections, so
     that a section which is not rendered — the super-admin's, to everybody
     else — takes its own divider away with it and cannot leave a line with
     nothing under it. The email at the top draws the first line from below in
     the same way (.mc-navbar__who), for the same reason. */
  .mc-navbar.is-open .mc-navbar__links .mc-navbar__group {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15rem;
    width: 100%;
    margin-top: 0.3rem;
    padding-top: 0.35rem;
    border-top: 1px solid var(--mc-line);
  }

  /* Sign out is a form and a button rather than a link, so none of the panel's
     link rules reach it, and the bar's own white-on-black rule does. It is
     drawn to match the links either side of the rule above it — the same size,
     the same ink, the same hover — because in this menu it is one of them. */
  .mc-navbar.is-open .mc-navbar__links form { display: block; }
  .mc-navbar.is-open .mc-navbar__links .mc-signout {
    padding: 0.3rem 0;
    color: var(--mc-ink);
    font-size: 0.95rem;
  }
  .mc-navbar.is-open .mc-navbar__links .mc-signout:hover {
    color: var(--mc-brand);
    text-decoration: underline;
  }
}

/* --- week toolbar --------------------------------------------------------- */

.mc-weekbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}
.mc-weekbar .mc-week-label {
  font-weight: 600;
  font-size: 1.02rem;
  min-width: 14rem;
}
.mc-weekbar .mc-spacer { margin-left: auto; }

/* --- turning the month -----------------------------------------------------
   A chevron, the month's name, a chevron — the shape a calendar has on every
   phone, so the way to April is a thing to press rather than a thing to read
   first. The two circles are the WEEK GRID'S OWN (.wg-chev, further up): same
   disc, same guillemet, same shadow, same mahogany under a pointer, because a
   reader who has met one of the two views of this venue should find the way
   sideways in the other by the same mark.

   The label is given a width so the chevrons do not shuffle as the name between
   them changes length — a control that moves when its subject changes is one
   people press twice — and that width is smaller than the week's own 14rem,
   which was cut for "4 – 10 August 2026" and would push the pair apart here. */
.mc-monthnav {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

/* WHERE THE READER IS, ON A LINE OF ITS OWN, and under it the two things the
   card is set by: which view is on, and what the colours mean.

   TWO ROWS RATHER THAN ONE. All three used to share a line — the toggle at the
   left, the month between the chevrons in the middle, the key at the right — and
   the middle of that line is the one place on the bar the eye does not go first:
   it is read as the third thing in a row of three, after a control it did not
   ask about and beside a key it reads once and never again. "August 23 – 29" is
   the answer to WHERE AM I, which is the first question anybody has of a
   calendar, and a line to itself is what makes it the first thing on the card
   rather than the middle thing on a row.

   It also gives the other two their own room back. The key had a third of the
   bar and wrapped onto two lines on a narrow desktop; on the second row it has
   everything from the toggle to the card's edge.

   THE COLUMNS ARE STILL THREE and still outer-equal, because the second row is
   read as two ends of one line — the toggle hard against the left, the key hard
   against the right — and because the phone rule below turns the whole thing
   into a single column by changing this one declaration.

   The week's bar keeps the old row — it has a range, a pair of buttons and a
   legend to fit, and nothing in it is the thing to centre on. */
.mc-weekbar--month {
  display: grid;
  /* minmax(0, …) rather than a bare 1fr, and it is what makes the second row
     true: a plain 1fr track will not shrink below its own contents, so the key
     would widen its side of the bar by however much wider than the toggle it
     grew. Told it may shrink, the two sides stay equal and the key wraps
     instead. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  /* One row: the nav on the card's centre line and the toggle at its right end.
     The key that used to make a second row stands under the board now (see
     .mc-legend--foot). */
  grid-template-rows: auto;
  align-items: center;
}
/* AND THE GUTTER IS PAID FOR ON BOTH SIDES. The customer's bar is given a
   2.5rem gutter on the right so the legend clears the ? pinned in the card's
   corner (#player-page .mc-weekbar, further down) — which narrows the bar's
   content box on one side only, and a middle column centred in THAT is half a
   gutter left of the middle of the card. The same gutter on the left costs
   nothing (there is nothing over there to clear) and puts the month back on the
   card's own centre line, which is where the eye looks for it. */
.mc-weekbar--month { padding-left: var(--mc-weekbar-gutter, 0); }
/* WEEKLY | MONTHLY, at the RIGHT end of the nav's row — hard against the bar's
   edge, which on the customer's card is the gutter that clears the ? (see
   #player-page .mc-weekbar), so the pair and the mark stand together. */
.mc-viewtoggle {
  grid-row: 1;
  grid-column: 3;
  justify-self: end;
}
/* WHICH VIEW IS ON, drawn off the one fact that says so — `aria-pressed`, which
   is also what a screen reader reads out (see month_calendar_controller's
   paintToggle). No second class to keep in step, and no state that can be true
   for the eye and false for everybody else. The venue's own mahogany, which is
   what every filled control on this card is. */
.mc-viewtoggle .btn[aria-pressed="true"] {
  background: var(--mc-brand);
  border-color: var(--mc-brand);
  color: #fff;
}
/* AND "SETUP OPEN PLAY" AT THE OTHER END OF THAT ROW — the toggle's mirror
   image, left column and hard against the bar's left edge, so the two controls
   on the bar stand at its two ends with the month centred between them. */
.mc-weeksetup {
  grid-row: 1;
  grid-column: 1;
  justify-self: start;
}
/* It is about the WEEK on screen, so it is not on the bar of a month. Written
   against the calendar's own root element for the reason the [data-view] rules
   further down are. */
[data-controller~="month-calendar"][data-view="month"] .mc-weeksetup { display: none; }
/* AND THE NAV IS THE WHOLE OF THE FIRST ROW, centred on the card.

   Centred by `justify-self` on a cell that runs the full width, rather than by
   sitting in a middle column between two equal ones, which is how it was held
   on the card's centre line while it shared a row. Both put it in the same
   place — the bar's content box is symmetrical, the gutter being paid on both
   sides (above) — and this one goes on being true whatever the second row does,
   which is the point of taking it out of that row.

   Nothing else is on this row, so nothing else can move it. That was the other
   half of what the old arrangement cost: a key one word wider pushed the month
   off centre until the outer columns were taught to shrink. */
.mc-weekbar--month .mc-monthnav {
  grid-row: 1;
  grid-column: 1 / -1;
  justify-self: center;
}
.mc-weekbar--month .mc-spacer { display: none; }
/* A phone has no room for any two of these beside each other, so all three
   stack and all three centre — one column, and the rows said out loud rather
   than left to the order they happen to be written in: the nav first, because
   it is the first thing anybody wants to know and because that is where it
   stands on the desktop too; then the toggle; then the key, which is the one
   thing on the bar a reader consults rather than uses.

   Said explicitly for that reason. Auto-placement would put them in document
   order — toggle, nav, key — which is the order the markup keeps for a reason
   of its own (the toggle is the first control on the card), and a phone that
   read the bar in a different order from the desktop would be a second layout
   to remember rather than the same one folded. */
@media (max-width: 640px) {
  .mc-weekbar--month { grid-template-columns: minmax(0, 1fr); }
  .mc-weekbar--month .mc-monthnav { grid-row: 1; }
  .mc-weekbar--month .mc-viewtoggle { grid-row: 2; }
  /* A row of its own under the toggle, on the same reasoning: nothing on this
     bar fits beside anything else on a phone. */
  .mc-weekbar--month .mc-weeksetup { grid-row: 3; }
  .mc-weekbar--month .mc-viewtoggle,
  .mc-weekbar--month .mc-weeksetup,
  .mc-weekbar--month .mc-monthnav {
    grid-column: 1;
    justify-self: center;
  }
  /* AND THE ? IS A REAL OCCUPANT OF THAT CORNER ON A PHONE. The nav is the
     widest thing on this bar — two 2.5rem circles with a fixed-width name
     between them — and on the first row it now stands at the same height as the
     mark pinned in the card's top right (.mc-well > .mc-help). On a desktop
     there is half a screen between them; at 360px the pair of them want the same
     forty pixels, and the chevron won, sitting under the ?.

     So on a phone the nav is centred in the room LEFT OF the mark rather than on
     the card: the gutter that clears it (--mc-weekbar-gutter, see
     #player-page .mc-weekbar) is reserved on the nav's own right, and what is
     left over is what the pair of chevrons is centred in. Fifteen pixels off the
     card's centre line on a 360px screen, which is a shift nobody can see, for a
     collision anybody can.

     It costs the desk's phone nothing, and that is the variable rather than a
     coincidence: the desk's calendar has no ? in its corner, so it never sets
     the gutter, so this resolves to a margin of zero and the nav stays dead
     centre there. */
  .mc-weekbar--month .mc-monthnav { margin-right: var(--mc-weekbar-gutter, 0); }
}
/* AND ON THE VERY SMALLEST SCREENS THERE IS NO ROOM BESIDE IT AT ALL. The nav is
   two 2.5rem circles either side of a name that is 9rem wide by declaration —
   about 235px, and it cannot be made smaller without either shrinking the two
   targets a thumb aims at or letting the chevrons shuffle as the name between
   them changes length, which is the thing that width exists to stop. At 320px
   the card is 288px wide and the mark in its corner wants 52 of them: the sum
   does not come out however it is shared, so on those screens the bar starts
   BELOW the mark instead of beside it.

   A band of white at the top of the card on a 320px phone, and nothing at all on
   any other screen — 360px, which is the narrowest phone in common use, clears
   the mark by thirteen pixels on the rule above. Paid where the room actually
   ran out rather than everywhere as insurance. */
@media (max-width: 340px) {
  .mc-weekbar--month { padding-top: 2rem; }
  .mc-weekbar--month .mc-monthnav { margin-right: 0; }
}
/* THE VENUE'S OWN MAHOGANY, which is what every heading in this app is written
   in — the day popup's "WEDNESDAY, 26 AUG 2026", the booking panel's "YOUR
   RESERVATION", the form's "MAKE A RESERVATION" (see .mc-modal__panel h2). The
   month between the chevrons is the heading of the card it stands on, so it is
   the same colour rather than the body ink it was. --mc-brand is the one place
   that colour lives. */
.mc-weekbar .mc-monthnav__label {
  min-width: 9rem;
  text-align: center;
  color: var(--mc-brand);
}


.mc-legend {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: center;
  font-size: 0.82rem;
  color: var(--mc-muted);
}
.mc-legend span { display: inline-flex; align-items: center; gap: 0.35rem; }
.mc-legend i {
  width: 0.9rem;
  height: 0.9rem;
  border-radius: 3px;
  display: inline-block;
  border: 1px solid var(--mc-line);
}
/* The key under the board (see common/calendars/_month): centred on the card,
   a little air over it. */
.mc-legend--foot {
  justify-content: center;
  margin-top: 0.6rem;
}
/* The colours both grids are read by. The white one has to read as a swatch
   rather than as a gap in the sentence, so its outline is darker than the grid's
   hairlines. Green and yellow are the booking blocks, and are the same two
   colours .wgb is drawn in below — a legend that has drifted from the grid it
   explains is worse than no legend. */
.mc-legend .sw-open { background: var(--mc-open); border-color: #b9c0c8; }
.mc-legend .sw-reserved { background: var(--mc-reserved); border-color: var(--mc-reserved-line); }
.mc-legend .sw-unverified { background: #fdf1c4; border-color: #e0c24e; }
.mc-legend .sw-verified { background: #d9f2e3; border-color: #94d3b3; }
/* The day popup's closed block (.wgb--closed): the venue took these hours off. */
.mc-legend .sw-closed { background: #ededed; border-color: var(--mc-line-strong); }

/* --- the week grid -------------------------------------------------------- */

/* The grid scrolls inside its own box, spreadsheet-style: the day headers stay
   frozen at the top and the time column stays frozen on the left, so the page
   itself never has to scroll to keep your bearings. */
.wg-scroll {
  overflow: auto;
  /* The 15rem is everything above the grid on the page — the shell's margins,
     the well's own padding and the week bar — and what is left is the grid's.
     It is deliberately not trimmed now that the status line under the bar has
     gone to the toast stack: the budget erring high costs the grid a row and
     the alternative is a page that scrolls. A well that carries a footer under
     the scroller (see
     shared/_calendar_shell) hands that line's height back out of the same
     budget, so the card still ends where it ended and the PAGE still does not
     scroll: the grid gives up the rows, not the reader. */
  max-height: calc(100vh - 15rem - var(--mc-grid-footer, 0rem));
  min-height: 22rem;
  background: #fff;
  border: 1px solid var(--mc-line-strong);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
}

/* --- the bars the week is moved by ----------------------------------------
   Scoped to this box and to nothing else. The page's own scrollbar and every
   other scroller in the app are left exactly as the platform draws them: a bar
   restyled everywhere is a bar the reader has to learn, and the only one worth
   the lesson is the one standing inside the card all day.

   A pill of mahogany floating in a gutter wider than itself. The 3px of
   transparent border with `background-clip: padding-box` is the whole of the
   floating: the thumb is still the full ten pixels the gutter is wide — still
   ten pixels to the pointer, which is what it has to be, since a bar that is
   slim to GRAB is a bar that gets grabbed twice — and only the four in the
   middle of it are painted.

   The colour is --mc-brand (#7b3f21) at 35%, written out in channels rather
   than referred to, because a custom property holding a hex cannot be given an
   alpha without being torn into its three numbers first, and three more
   variables to say one colour once is not a trade this file makes. Translucent
   rather than a lighter brown so it reads over what it crosses: the grid is
   white nearly everywhere, but today's column is cream and a booking block is
   green or yellow, and the bar passes over all of them. */
.wg-scroll::-webkit-scrollbar { width: 10px; height: 10px; }
.wg-scroll::-webkit-scrollbar-track { background: transparent; }
.wg-scroll::-webkit-scrollbar-thumb {
  background-color: rgba(123, 63, 33, 0.35);
  border-radius: 999px;
  border: 3px solid transparent;
  background-clip: padding-box;
}
/* `background-color` rather than the shorthand, here and above: `background:`
   would reset the clip to the border box along with the colour, and the pill
   would fill the gutter the moment the pointer touched it. */
.wg-scroll::-webkit-scrollbar-thumb:hover { background-color: rgba(123, 63, 33, 0.55); }
.wg-scroll::-webkit-scrollbar-corner { background: transparent; }

/* And where the two bars BEGIN, which is the point of all this.
   The day headings scroll in this box along with the hours — they are sticky
   against it, which is what freezes them, so they cannot be lifted out of it —
   and the frozen time column is the grid's first track inside it. So a bar
   drawn the whole length of its side runs past both: a vertical thumb sliding
   up alongside SUN MON TUE, which do not move, and a horizontal one running
   under the hour labels, which do not move either. Both are then reporting a
   scroll position for something that is not scrolling.

   Insetting the TRACK is what fixes that, rather than insetting the thumb:
   margin on the track shortens the runway, and the thumb is laid out inside
   whatever the runway is left as — so the bar not only starts below the
   headings, it reaches its far end when the LAST HOUR does.

   --wg-head-h is written onto this element by JavaScript after every rebuild,
   because the height of a heading is the height of the type in it and this app
   cannot know what that is (see sizeScrollbarInset in calendar.js). The 84px is
   what it is worth at the default size with a court strip under the date, and
   it is only ever seen in the frames before the first measurement lands.
   --mc-time-col needs no such help: the column is that wide by declaration, on
   a phone exactly as on a desk (see :root). */
.wg-scroll::-webkit-scrollbar-track:vertical { margin-top: var(--wg-head-h, 84px); }
.wg-scroll::-webkit-scrollbar-track:horizontal { margin-left: var(--mc-time-col); }

/* Firefox, which has the two standard properties and none of the pseudo
   elements. It gets the colour and a thin bar and it does not get the inset:
   there is no way to tell `scrollbar-color` where to start, so a Firefox reader
   sees a brown bar running the full height of the box, past the headings. That
   is a knowingly worse version of the same bar rather than a broken one, and
   the alternative — a scroller with its overflow moved somewhere the standard
   properties could be aimed at — costs the sticky headings, the scroll sync and
   three JavaScript files' worth of `closest(".wg-scroll")`. Not for two pixels
   of margin.

   The @supports is NOT a nicety. Chromium understands both spellings, and when
   a box is given both it takes the standard one and throws every ::-webkit rule
   above away — so left unguarded, this short block would silently be the whole
   design everywhere, thin grey-brown bar and no inset at all. `selector()` is
   false in Chromium (it HAS ::-webkit-scrollbar) and true in Firefox (it has
   not); an engine too old to parse `selector()` at all fails the query and
   keeps the pseudo elements, which is the right answer for old Safari. */
@supports not selector(::-webkit-scrollbar) {
  .wg-scroll {
    scrollbar-width: thin;
    scrollbar-color: rgba(123, 63, 33, 0.45) transparent;
  }
}

/* The minimum is stated twice on purpose. `minmax` is what stops a column being
   squeezed below it; the `min-width` is what makes the GRID BOX as wide as its
   own tracks, so that everything measured against that box — the crosshair
   bands, the selection rectangle, the sticky day headers — is measured against
   the whole week rather than against the slice of it currently on screen. */
.wg {
  position: relative;   /* the row band below is positioned against this */
  display: grid;
  grid-template-columns: var(--mc-time-col) repeat(7, minmax(var(--mc-day-col), 1fr));
  min-width: calc(var(--mc-time-col) + (var(--mc-day-col) * 7));
}

/* The crosshair: the hour you are reading across and the day you are
   reading down, tinted end to end under the hover the one cell beneath the
   cursor gets. Both bands are translucent and pointer-transparent. They sit
   under the frozen time column (z-index 4, raised above the closed-day panel
   so a shut day cannot scroll over the axis), so the row band's tint stops at
   the axis instead of washing the hour label. The day headers are higher
   still; the hovered one takes the tint as a class instead, since a
   sticky header is not where a band drawn at the top of the grid would be. */
.wg__rowband,
.wg__colband {
  position: absolute;
  z-index: 2;
  pointer-events: none;
  background: rgba(37, 99, 235, 0.06);
}
.wg__rowband {
  left: 0;
  right: 0;
  box-shadow: inset 0 1px 0 rgba(37, 99, 235, 0.16), inset 0 -1px 0 rgba(37, 99, 235, 0.16);
}
.wg__colband {
  bottom: 0;
  box-shadow: inset 1px 0 0 rgba(37, 99, 235, 0.16), inset -1px 0 0 rgba(37, 99, 235, 0.16);
}
.wg__rowband[hidden],
.wg__colband[hidden] { display: none; }

/* --- the hours being picked ------------------------------------------------
   A press dragged down a column is a booking being drawn on the week, and this
   is it: one rectangle over the hours it has taken in, laid over the grid the
   same way the crosshair bands are — absolutely positioned, pointer-transparent,
   and therefore unable to disturb the placement of a single cell underneath.
   One element moved and resized rather than a class put on every cell in the
   range, which is what keeps it right over a row whose free time is only half
   the column wide.

   It takes no z-index of its own, which puts it exactly where it belongs in the
   stack: over the cells, which are ordinary grid items, and UNDER the booking
   blocks and the frozen time column, which both claim one. That matters on a row
   whose free time is half a column — the half a booking is standing on keeps its
   own colour instead of going blue behind the selection, which would be the
   rectangle claiming courts it cannot have.

   The fill is the accent at a weight that reads as "chosen" over white and over
   today's cream alike, and the inset edge is what gives it a boundary without
   spending a pixel of the grid's own hairlines. */
.wg__sel {
  position: absolute;
  /* A centred column, because the rectangle carries up to two lines of caption —
     the courts over the times — and they have to sit as one stack in the middle
     of a box whose height is however many hours have been taken. Centring the
     PAIR is what keeps a one-hour selection's label inside its own 40px row;
     two separately-centred labels would each want the middle and the upper one
     would climb out of the top. Either line alone still lands dead centre, which
     is why the admin grid, which writes only the times, looks exactly as it did.
     The grips are positioned absolutely and take no part in this. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  pointer-events: none;
  border-radius: 6px;
  background: rgba(37, 99, 235, 0.16);
  box-shadow: inset 0 0 0 2px var(--mc-accent);
}
.wg__sel[hidden] { display: none; }

/* The times, written across the middle of the rectangle: "6:00pm – 8:00pm".
   The rectangle says how many hours have been taken and this says which — read
   where the hand already is, instead of in the time column at the far side of
   the week.

   A pill rather than bare text, because what is behind it is a pale blue wash
   over white, over today's cream, and over the hairlines between the rows; the
   near-white plate is what makes one set of type legible over all three. It is
   centred on the rectangle whatever the rectangle's height — by the flex column
   above rather than by any offset of its own — so the label of a one-hour
   selection sits in a single row exactly as a six-hour one sits in six.

   It inherits `pointer-events: none` from the rectangle and must go on doing
   so: the double tap that books a standing selection is a tap on the CELL
   underneath, and a label that answered a finger would swallow it.

   `white-space: nowrap` is deliberate over any kind of clipping. A range broken
   across two lines in a 40px row, or cut off at "6:00pm – 8:0", is worse than
   one that reaches a few pixels past a narrow column — this is a label that is
   only on screen while a hand is moving, and being readable is the whole of its
   job. */
.wg__selrange {
  padding: 0.1rem 0.35rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  color: var(--mc-accent);
  font-size: 0.625rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
/* Nothing to say when there is no range — an empty pill is a white blob. */
.wg__selrange:empty { display: none; }

/* The courts, on the line above the times: "Court #1", "Court #1 and #2".
   Written only where a page asks for it — the player grid does, the admin grid
   does not — and the asking is the whole of the difference, because a span
   nobody has written into is empty, and an empty pill is not drawn.

   Same plate, same accent, same weight as the range beneath it: the two lines
   are one caption and should read as one. A step smaller, and with less padding,
   for the two reasons that pull the same way — it is the quieter half of what
   the box says, and both pills together have to fit inside the 40px of a
   one-hour selection, which at this size they do with about five pixels to
   spare at either end.

   `nowrap` for the same reason the range has it: "Court #1 and #2" broken over
   two lines in a half-column-wide rectangle is worse than one that reaches a
   little past its sides, and this is type that is only on screen while a
   selection is being made. */
.wg__selcourts {
  padding: 0.05rem 0.3rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  color: var(--mc-accent);
  font-size: 0.5625rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.wg__selcourts:empty { display: none; }

/* The tab over the top edge of a selection a finger has left standing: "DOUBLE
   TAP". A phone has no hover and no status bar, so the one thing the grid never
   said out loud is the thing that finishes a booking — a tap picks the hour and
   a second tap on the same rectangle opens the form, and a customer meeting a
   blue box for the first time has no reason to try the second one. It borrows
   the TODAY tab's vocabulary — small white caps, wide tracking, a rounded tab
   over the thing it names — in the accent rather than the brand, because it is
   about the blue rectangle underneath it and not about the week.

   Drawn only where the page asked for the words AND only while the selection is
   standing: the first is what keeps it off the admin grid (the desk's paint()
   writes nothing into the span, and an empty tab is not drawn), and the second
   is what keeps it off a rectangle still being dragged out, where an instruction
   about letting go would be answering a question nobody has finished asking.
   The `:not(:empty)` is load-bearing rather than belt-and-braces: the standing
   rule is the more specific of the two and would otherwise put an empty blue
   blob over every selection on the desk's own grid.

   It clears the top grip rather than sitting on it — 0.9rem is the 12px the
   grip stands above the edge plus a couple to see daylight through — and takes
   no pointer of its own, so the double tap it is describing lands on the cell
   underneath instead of on the words about it. z-index 4 is the grips': above a
   booking block, and below the sticky day headings, which is what makes a
   selection on the topmost row visible slide under them the way the rectangle
   itself does rather than float over a heading it is no longer near. */
.wg__seltip {
  display: none;
  position: absolute;
  bottom: calc(100% + 0.9rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  padding: 0.1rem 0.4rem;
  border-radius: 6px;
  background: var(--mc-accent);
  color: #fff;
  font-size: 0.5625rem;
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  /* The words break where the page put the break and nowhere else: `pre-line`
     honours the newline in the hint and still collapses everything a line of
     source code might otherwise contribute, and what it does NOT do is let a
     narrow column choose its own breaks — the two lines are a sentence in two
     halves ("Double tap" / "to book"), and a column that broke them anywhere
     else would be reading the reader something they did not write. Both halves
     are short enough to stand in a half-column at this size. */
  white-space: pre-line;
  /* And the box is as wide as its longest line rather than as wide as whatever
     is left of a half-column, which is what an absolutely positioned box would
     otherwise shrink to — 35px, and "Double tap" broken after "Double". */
  width: max-content;
  text-align: center;
  pointer-events: none;
  box-shadow: 0 1px 3px rgba(16, 24, 40, 0.3);
}
.wg__sel.is-standing .wg__seltip:not(:empty) { display: block; }
/* Under the rectangle on the day's first hour, where there is no grid above to
   stand on — see paint(). The same clearance the other way round, so it misses
   the bottom grip exactly as it misses the top one. */
.wg__sel.is-tip-below .wg__seltip { top: calc(100% + 0.9rem); bottom: auto; }

/* The grips: the four edges of a selection a finger has left standing, and the
   only part of the rectangle that answers a touch. They exist because a phone
   has no hover and no second button — a range you cannot correct without
   starting again is a range you will get wrong — and they are absent on the
   mouse's own drag, where letting go opens the form and there is nothing left to
   correct.

   Sized for a fingertip and centred on the edge they move, with a white ring so
   they read against a booking block as well as against an empty cell.
   `touch-action: none` is what stops the page scrolling out from under one
   while it is being pulled. */
.wg__grip {
  display: none;
  position: absolute;
  /* Above the booking blocks, unlike the rectangle they hang off: the fill may
     go behind a block, but a control that cannot be seen cannot be pulled. And
     above a blanked closed column too — a selection on the day beside one hangs
     half of its side grip over the boundary, and half a handle is worse than
     none. */
  z-index: 4;
  width: 1.5rem;
  height: 1.5rem;
  margin: -0.75rem 0 0 -0.75rem;
  border: 2px solid #fff;
  border-radius: 999px;
  background: var(--mc-accent);
  box-shadow: 0 1px 3px rgba(16, 24, 40, 0.4);
  pointer-events: auto;
  touch-action: none;
}
.wg__sel.is-standing .wg__grip { display: block; }
/* The two on the ends move the HOURS, so they sit halfway across the rectangle
   and on its top and bottom lines — pulled up and down, which is the direction
   the week's hours run in. */
.wg__grip--top { top: 0; left: 50%; }
.wg__grip--bottom { top: 100%; left: 50%; }
/* The two on the sides move the COURTS, so they sit halfway down the rectangle
   and on its left and right lines — pulled across, which is the direction a day
   column's courts are laid out in. A selection with a handle on all four sides
   says, without a word of instruction, that it can be made taller and it can be
   made wider; the pair that was here before said only the first of those, and a
   player wanting the second court had no reason to think there was one.
   Drawn only where the venue has more than one court — see buildWeekGrid. */
.wg__grip--left { top: 50%; left: 0; }
.wg__grip--right { top: 50%; left: 100%; }

/* And the same four handles on the month popup's day, moved to the CORNERS.
   There a court is a column and an hour is a row of one small grid, so a
   rectangle is adjusted the way a rectangle is adjusted everywhere else on a
   phone: take a corner and pull it, and the corner across from it stays put —
   both axes at once, because both are within a thumb's reach and neither pull
   has to be made separately. Same dot, same size, same refusal to let the page
   scroll out from under it; only the four places differ. */
.mc-day__grip--nw { top: 0; left: 0; }
.mc-day__grip--ne { top: 0; left: 100%; }
.mc-day__grip--sw { top: 100%; left: 0; }
.mc-day__grip--se { top: 100%; left: 100%; }
/* Against the hour labels or the header, the dots on that side sit inside the
   block's edge rather than half over it, so the labels stay readable. */
.mc-day__sel.is-at-left .mc-day__grip--nw,
.mc-day__sel.is-at-left .mc-day__grip--sw { margin-left: 0; }
.mc-day__sel.is-at-top .mc-day__grip--nw,
.mc-day__sel.is-at-top .mc-day__grip--ne { margin-top: 0; }

/* While a range is actually being dragged out, the week is not a document to
   select words in — and the crosshair, which follows the same pointer, would
   only argue with the rectangle it is drawing. */
.wg-selecting {
  user-select: none;
  -webkit-user-select: none;
}
.wg-selecting .wg__rowband,
.wg-selecting .wg__colband { display: none; }

/* And the same two things said again while a BOOKING is being carried across
   the week rather than a range drawn on it. Copied from the rule above rather
   than folded into it because they are two gestures that happen to want the
   same two things: the crosshair follows the pointer either one is using and
   would only argue with what that pointer is drawing, and a week being dragged
   on is not a document to sweep words out of. */
.wg-moving {
  user-select: none;
  -webkit-user-select: none;
}
.wg-moving .wg__rowband,
.wg-moving .wg__colband { display: none; }

/* The week while one booking is in the hand. A drag that has been armed by a
   press held on a block has to be UNMISTAKABLE — it is a mode, it was entered
   by holding still, and the desk that did not mean to enter it has to be able
   to see that it has. So the week steps back and the booking steps forward:
   every other block goes half-strength, and the hours this one cannot reach go
   with them, leaving the places it CAN go standing at full strength beside the
   block that is ringed in the accent (.wgb.is-moving) and the ghost that is
   standing on one of them.

   Which cells those are is not something CSS can work out — it is the same list
   the magnet snaps to, courts and all — so the controller marks them (see
   markDropCells) and this only says what a mark means. Nothing here costs
   anything when the class is off, and the class and the marks come off
   together in endMove. */
.wg-moving .wgb { opacity: 0.45; }
.wg-moving .wg__cell { opacity: 0.55; }
.wg-moving .wg__cell.is-drop { opacity: 1; }

/* Where the booking would land: the block drawn again, at the hour and on the
   courts the magnet has snapped it to, while the booking itself stays where it
   still is with the same ring round it (.wgb.is-moving). It is the answer
   rather than a hint — the drop
   writes exactly what this is standing on — so it is drawn as the thing it
   would become, in the settled green a moved booking will still be, with the
   accent ring round it saying it has not happened yet.

   Absolutely positioned inside the grid like the selection rectangle and the
   crosshair, so the grid's own placement never sees it, and pointer-transparent
   so it can never come between the pointer and the block being dragged — or
   between it and the cell underneath, which is what a snap has to be measured
   against.

   z-index 4 puts it over the booking blocks (1) and over a blanked closed
   column (3), and under the frozen headings (5), so a ghost carried to the
   top of the week slides under the dates exactly as the blocks it is
   standing among do.

   The ring is a pixel heavier than a block's own border, and it is the same
   accent the block in hand is ringed in: the two of them are the ends of one
   move — where the booking is, and where it would be — and they are the only
   two things on a faded week drawn at full strength. */
.wg__ghost {
  position: absolute;
  z-index: 4;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 1px;
  min-width: 0;
  overflow: hidden;
  padding: 2px 3px;
  border-radius: 6px;
  background: #d9f2e3;
  box-shadow: inset 0 0 0 3px var(--mc-accent);
  color: #145b36;
  font-size: 0.72rem;
  line-height: 1.2;
  text-align: center;
  pointer-events: none;
}

/* A heading is a column: the date, and — where the venue has more than one
   court — the strip of court numbers under it. A column rather than plain flow
   because the two parts have to be anchored at opposite ends of a box whose
   height is not its own: every heading in the row is stretched to the tallest
   of them, and the tallest is today's, whose date is a circle. */
.wg__head {
  position: sticky;
  top: 0;
  /* Above everything the grid body can put under it, the panel that blanks a
     closed column included (.wg__closed, z-index 3) — a heading a column can
     scroll over is a heading that stops being frozen. */
  z-index: 5;
  background: #fff;
  border-bottom: 1px solid var(--mc-line-strong);
  border-left: 1px solid var(--mc-line-strong);
  padding: 0.5rem 0.35rem;
  text-align: center;
  line-height: 1.2;
  display: flex;
  flex-direction: column;
}
/* Which is what this is for: the date takes all the slack, so whatever is under
   it starts from the FOOT of the heading rather than from wherever that day's
   own date happened to end. Without it, Sunday's numbers sit under a line of
   text and today's sit under a circle nine pixels lower, and a row that is
   meant to read as one band reads as seven. */
.wg__date { flex: 1 1 auto; }
.wg__head:first-child { border-left: 0; }
/* The corner, above the time column, is a heading of the same shape as the rest
   of the row and not a box with a word centred in it: the month on top, and the
   court strip's caption at the foot where the strips are. So it keeps the column
   and the stretch it inherits from .wg__head — the centring that used to be
   declared here is gone, and .wg__month below does that job for the month alone,
   which is what leaves the caption free to sit against the bottom edge. */
.wg__head--time {
  position: sticky;
  left: 0;
  z-index: 6;
  border-right: 1px solid var(--mc-line-strong);
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--mc-brand);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.5rem 0.2rem;
}
/* The month, and the corner's half of the mechanism the whole heading row is
   lined up by: it takes the slack exactly as .wg__date does in the seven
   headings beside it, so the caption under it starts from the FOOT of the corner
   rather than from wherever the month happened to end — the same line, by the
   same means, as the seven strips it is naming. The centring is here rather than
   on the cell because it is the MONTH's, not the corner's: one line, centred in
   whatever room the caption left it. On a one-court venue, where there is no
   caption at all, that room is the whole cell and the month sits dead centre in
   it the way it always did. */
.wg__month {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.wg__head .wg__dow {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--mc-muted);
}
.wg__head .wg__dom {
  display: block;
  font-size: 1.05rem;
  font-weight: 600;
}
/* The courts, named across the foot of every day heading: | #1 | #2 |.
   A day column is not one space — it is the venue's courts side by side, every
   cell in it is drawn on one court's own half, and this is what says which half
   is which. Equal columns, so a number sits centred over the cells it belongs
   to; the rule between them is the same hairline the cells below are divided by,
   and it lands on the same fraction of the column, so the caption and the week
   under it are one grid rather than two.
   Drawn only where there is more than one court — see buildWeekGrid.

   The negative margins are what make that true. The strip is pulled out to the
   heading's padding edges — sideways so its halves are the same halves the cells
   below are placed in, and downwards so it sits ON the heading's bottom edge,
   its rule reading as one line with the border under it rather than as a second
   line floating above it. Its own top rule is the only thing that separates it
   from the date, so the band is bounded the same way every other row of this
   grid is: hairlines, no fills, nothing of its own. */
.wg__head .wg__courts {
  display: flex;
  margin: 0.3rem -0.35rem -0.5rem;
  border-top: 1px solid var(--mc-line);
  font-size: 0.66rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--mc-muted);
}
.wg__head .wg__court {
  flex: 1 1 0;
  padding: 0.12rem 0;
  border-left: 1px solid var(--mc-line);
}
.wg__head .wg__court:first-child { border-left: 0; }

/* And the caption at the foot of the corner — "COURT", against the row of
   numbers it belongs to. It is written as the same two elements the strips are
   (see buildWeekGrid) so that everything above is already true of it: pulled to
   the foot by the same negative margin, ruled off by the same hairline, set in
   the same small muted type. Nothing here restates any of that, and nothing here
   can drift out of step with it.

   The side margins are the one thing it cannot take as it stands. That pull is
   out to the HEADING's padding edge and the corner is padded 0.2rem where a day
   is padded 0.35rem, so the distance is different while the intent is identical —
   without this the strip would hang a couple of pixels past the frozen column's
   own edge and over Sunday.

   A word rather than a numeral, so it is kept to one line and cut with an
   ellipsis rather than wrapped: in a 100px column "COURT" has room to spare,
   but the failure worth designing for is the one where it does not, and a
   caption that grew a second line would push the month up and take the corner
   out of the row it is meant to be flush with. */
.wg__head--time .wg__courts {
  margin-left: -0.2rem;
  margin-right: -0.2rem;
}
.wg__head--time .wg__court {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.wg__head.is-today { background: var(--mc-today); }
/* The head of the day under the pointer, tinted with the column below it. After
   is-today so it wins on today's column too — it is a hover, not a state. */
.wg__head.is-hovered { background: #eef4fe; }
.wg__head.is-today .wg__dom {
  color: #fff;
  background: var(--mc-brand);
  border-radius: 999px;
  width: 1.8rem;
  height: 1.8rem;
  line-height: 1.8rem;
  margin: 0 auto;
}

/* --- today, framed --------------------------------------------------------
   The circle under SUN and the cream behind the hours are both true, and
   neither of them survives the week being read at arm's length: cream over
   white is a shade rather than a boundary, and the circle is one mark at the
   top of a column that is a foot long. So today is also given an EDGE — a line
   over the heading, down both sides, and along the foot of the last hour — and
   that is what says, from across the room, where the day begins and ends.

   Round the OUTSIDE and nowhere else. The hairlines between today's own cells
   stay the hairlines every other day is ruled by, because what is being drawn
   is the boundary of the day, not a box round each of its hours: a column ruled
   in mahogany twelve times over would read as twelve things rather than as one.

   It takes two elements, and the reason is the sticky heading. A single box
   over the whole column would have its top edge scroll up out of the box while
   the heading it belongs to stayed frozen at the top of it — a frame with the
   lid slid off. So the heading carries its own three edges and travels with
   them, and the overlay below carries the sides and the foot of the hours;
   unscrolled they are one line, and scrolled they are a heading with a top and
   a column with sides, which is the honest picture of both.

   The overlay carries the lower three-quarters wherever it can be seen, which
   is every day but one: a day the venue does not open on is blanked by an
   opaque panel standing above it, and there the panel draws the same three
   edges itself (see .wg__closed.is-today-col). The heading half is untouched by
   that — it is the same heading whether the day below it opens or not. */
.wg__head.is-today {
  border-top: 2px solid var(--mc-brand);
  border-left: 2px solid var(--mc-brand);
  border-right: 2px solid var(--mc-brand);
}

/* --- the tab that says TODAY -----------------------------------------------
   The circle, the cream and the mahogany edge all say WHICH column today is,
   and not one of them says it in a word — somebody opening the week for tonight
   is looking for one day out of seven, and a word is the fastest thing on a
   page to find. So today's column is given a tab: a band of the same mahogany
   standing on the table's top line with TODAY on it, rounded at the top corners
   and square where it meets the heading, which is the shape of the tab on a
   folder in a drawer and reads as a label ON this column rather than as a row
   above the week.

   It costs the table nothing, and that is the first thing about it rather than
   a happy result. The tab is not in the grid, not in the heading and not in the
   box the week scrolls in: it hangs off the wrapper round the scroller
   (.mc-weekload, positioned already for the spinner it centres) and is painted
   over the whitespace that has always been between the week bar and the table.
   A week with a today in it and a week without are the same table at the same
   place at the same size, scrolling through the same box; the only difference
   is whether something is floating above the line.

   Outside the scroller because there is nowhere inside it to stand. The
   scroller clips at its own edges both ways — which is what freezes the
   headings and the time column — so anything drawn above the first row of the
   table is cut off by the top of the box. Room can be made for it, and was,
   twice; but any room the tab stands in is room the table has given up, which
   shows as a white band between the card's border and the week and as a week
   scrolling in a shorter box, both for the sake of a label.

   Which is why the placing is JavaScript (see trackTodayTab). The tab has to
   stay over a column that moves, and the column moves because the week scrolls
   sideways inside a box the tab is not in — from out here, nothing follows it
   for free. So it is told where today's heading is, on every redraw and on
   every scroll of the scroller: the heading's own left in the grid, less how
   far the grid has been scrolled. A transform rather than anything that
   reflows, because what it is keeping up with is a thumb.

   The strip round it is the frozen time column's doing. A column scrolled far
   enough goes UNDER the time labels and stays there, and a tab drawn from
   outside the box would have gone on floating over them with no column beneath
   it. So the tab sits inside a band that begins where the frozen column ends
   and is cut off at the far side of the scrollport, with its overflow hidden:
   today sliding under the labels takes its tab under them too, a slice at a
   time, and nothing has to be told when to stop drawing it.

   Vertically it does not move at all, and does not need to. The table's top
   line is where today's heading carries its mahogany top border, and that is
   where the heading is at every scroll position there is — a sticky heading at
   the top of the box IS the top of the box. So the tab is dropped until its
   foot laps two pixels over that border, and the joint is the same joint
   scrolled or unscrolled: brown over brown, where two browns merely touching
   can be parted by a hair of rounding on a fractional column width.

   Nothing to press and nothing to read out. It is a mark ON a column, and a
   screen reader brought to it here would meet a word standing after the table
   with no column attached to it; the heading it names is in the reading order
   already, with the date it is about. */
.wg-tabstrip {
  position: absolute;
  /* The scroller's top left corner is the wrapper's own, so both of these are
     measured from the table: down past the card's 1px border and the 2px of
     lap, then up again by the whole height of the tab; and in from the left by
     the frozen column, which is the first track the grid lays down. The width
     is the one measurement left to JavaScript, because the far side of the
     scrollport is wherever the browser's own scrollbar has left it. */
  top: calc(1px + 2px - var(--mc-todaytab-height));
  left: calc(1px + var(--mc-time-col));
  height: var(--mc-todaytab-height);
  overflow: hidden;
  pointer-events: none;
}
.wg-todaytab {
  display: block;
  height: 100%;
  border-radius: 8px 8px 0 0;
  background: var(--mc-brand);
  color: #fff;
  text-align: center;
  font-size: 0.64rem;
  font-weight: 700;
  line-height: var(--mc-todaytab-height);
  letter-spacing: 0.06em;
}

/* The other three-quarters: a grid item placed in today's column and stretched
   down every hour of it, which is what keeps it right without a measurement
   anywhere. It is the column by construction — at whatever width the week has
   been given, through a phone's sideways scroll, and through every redraw,
   because it is part of the markup a redraw rebuilds (see buildWeekGrid).

   Empty and pointer-transparent: it lies over every cell in the column and not
   one of them may notice, or the day the week is most likely to be booked on
   would be the one day nothing on it could be pressed.

   z-index 1 is chosen twice over. It puts the frame above the cells, and —
   drawn after them in the DOM at the same level — above the booking blocks,
   which claim 1 themselves and would otherwise cover the sides wherever a
   reservation takes the whole width of the column. And it keeps the frame BELOW
   the frozen time column at 2 and the headings above that, so a week scrolled
   sideways slides today under the time labels exactly the way it slides
   everything else. Which is also what puts a closed day's panel, at 3, over the
   top of it — a price paid knowingly, and paid back by the panel. */
.wg__todayframe {
  position: relative;
  z-index: 1;
  pointer-events: none;
  border-left: 2px solid var(--mc-brand);
  border-right: 2px solid var(--mc-brand);
  border-bottom: 2px solid var(--mc-brand);
}

/* --- the chevrons on the ends of the week -----------------------------------
   Two circles riding the two ends of the WEEK ITSELF, one on each, and between
   them the whole of what a reader needs to get across seven days that do not
   fit. Held, they walk the grid sideways; pressed at the end of the week, they
   turn it, by calling the same two actions the ← Previous / Next → buttons
   call. Which of the two happens is decided once, at the moment of the press,
   from where the scroller already is — see trackWeekChevrons in calendar.js,
   where that reasoning is written out, and shared/_calendar_shell, where these
   are drawn.

   They hang off .mc-weekload rather than living in the scroller, for the same
   reason the TODAY tab does: everything inside .wg-scroll is clipped by it and
   swept along by it, and here there is a second reason on top of that — the
   contents of the scroller are what its scrollWidth is, and scrollWidth is the
   number the edge test reads. A control that changed the measurement it is
   deciding on would be a control arguing with itself.

   ACROSS: each circle is centred on one of the WEEK'S OWN two edges — not on
   the card's. The card's border is the outermost line the calendar has and it
   belongs to the whole instrument, week bar and legend and footer included; a
   handle hung on it points at the card. These point at the week, so they sit on
   the two lines the week is bounded by, and the well's border stays clearly
   outside both of them:

     ‹  the left border of the FIRST DAY, which is the right-hand edge of the
        frozen time column. That line is stationary whatever the week does — the
        column is sticky against the left of the scrollport, so its far edge is
        one time column in from there at every scroll position — which is why it
        can be written here at all. From the wrapper it is the scroller's own
        border plus --mc-time-col, and the circle is that less half of itself.

     ›  the right border of the LAST DAY IN VIEW, which is the far inner edge of
        the scrollport. Inboard of the vertical scrollbar, not over it: the bar
        is a thing to be grabbed and a circle sitting on it would take half the
        runway away. From the wrapper that is the border plus the width of the
        scrollbar gutter, and again less half a circle.

   Which puts them OVER THE WEEK, and that is the price of the position rather
   than an oversight of it. Half of the ‹ lies on the hour labels and half on the
   first day's cells; the › covers a slice of whichever day happens to be at the
   right-hand edge. A circle is 40px on a 128px column, level with the middle of
   the scrollport, so what it hides is part of one cell in one column out of
   seven at one hour out of the day — and the cell either side of it, above it
   and below it is untouched and still takes a press. That is the trade: a
   control on the week's own edge is a control the eye finds without being told,
   and a week has room to give up 40px of one cell for it.

   .mc-weekload has no padding of its own, so the scroller's corners are the
   wrapper's own corners and both offsets are measured straight from them — the
   same arithmetic, from the same corner, that puts the TODAY tab's strip at
   `1px + var(--mc-time-col)` a few rules above. Nothing hangs outside the card
   any more, so the page keeps the gutter every other page has and no calendar
   page asks for room it does not need.

   The gutter is the one number here a stylesheet cannot know — a scrollbar is
   ten pixels of styled pill on this desk, an overlay of no width at all on a
   phone, and whatever the reader's own platform says everywhere else — so it is
   measured and written on the wrapper by the same pass that writes the vertical
   one below. The 10px fallback is what this app's own bar is worth (see
   .wg-scroll::-webkit-scrollbar) and is only ever seen in the frames before the
   first measurement lands.

   DOWN: on the middle of the hours in view. Not the heading row, which is where
   these first went: a control level with the day names sits over the one band
   of the grid that is a label rather than a thing, and reads as punctuation on
   the header instead of as a way across the week. The middle of the VISIBLE
   hours is the middle of what the reader is actually looking at — at any window
   height, on any week, and on a phone as much as on a desk — and because the
   buttons hang off the wrapper rather than off the grid, that point stands
   still while the hours scroll under it.

   Which leaves the two numbers no rule can know, both written on the wrapper by
   JavaScript after every redraw and on every resize:

     --wg-chev-gutter
                     how wide the scrollport's vertical scrollbar is, which is
                     the reader's platform's business and not this file's: the
                     difference between the box's outer width and the width it
                     shows, less its two borders.

     --wg-chev-mid   how far below the top of the scrollport the middle of the
                     hours falls: the headings' own height, which is the height
                     of the type in them and whether this venue has a court
                     strip under its dates, plus half of whatever is left of the
                     scrollport underneath them — and what is left is the
                     window's height, the venue's opening hours and whether the
                     card is carrying a footer.

   --wg-head-h, which is the first half of that second sum and is already being
   taken, CANNOT be borrowed: it is set on .wg-scroll, because that is the element
   whose scrollbar track reads it, and a custom property travels DOWN from the
   element it is set on and never sideways to a sibling. The fallback is 50% of
   the wrapper — the same point with the headings ignored, which is a few dozen
   pixels high rather than wrong — and it is only ever seen in the frames before
   the first measurement lands. The 1px in front of it is the scroller's own
   border, which the measurement is taken inside of.

   Quiet, but not hiding: on a desk they rest a shade under full and take the
   venue's mahogany when they are pointed at or tabbed to — the same flip the ?
   in the well's corner does. On a phone there is no pointing at anything, so
   there they are simply on. */
.wg-chev {
  position: absolute;
  top: calc(1px + var(--wg-chev-mid, 50%));
  transform: translateY(-50%);
  /* Over everything the grid has, which now matters: the ‹ lands on the seam
     between the frozen time column and the first day, and the highest thing in
     there is the month corner at 6. A circle half-swallowed by the column it is
     standing on would read as a rendering fault. */
  z-index: 7;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--wg-chev-size);
  height: var(--wg-chev-size);
  padding: 0;
  border: 1px solid var(--mc-line);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.82);
  color: var(--mc-muted);
  font-size: 1.4rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  opacity: 0.9;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.08);
  transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease,
              border-color 0.15s ease;
  /* A press on one of these is a hold, and every default a browser has for a
     hold on a small round thing is wrong here: panning the page under the
     finger, the callout menu, the double-tap zoom, the word-selection sweep of
     a mouse dragged off the edge. The gesture is answered in full by the
     script; nothing is left for the browser to also do with it. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
/* THE GLYPH IS NOT THE INK. ‹ and › are punctuation, and a font sets punctuation
   against the baseline rather than in the middle of the em box: the ink of these
   two runs from a little above the baseline to about the cap line, and a whole
   descender's worth of empty space is counted in underneath it all the same.
   What the flexbox above centres is the SPAN — the em box, its leading and that
   empty descender and all — so the arrow lands LOW in the circle by half of what
   is hanging below the baseline. Measured on this app's own type it is 1.47px of
   ink adrift in a 22.4px glyph, which is nothing on a line of text and a plainly
   crooked button once it is the only thing inside a 2.5rem disc.

   So the span is lifted back by two pixels, which is the owner's own eye on the
   rendered button — a scan of the ink put the drift at about a pixel and a half,
   so the eye and the measurement agree on everything but the rounding, and on a
   button this is drawn by eye the eye gets the final say. It is a nudge for ONE
   font — every sans-serif hangs its guillemets differently, over a range of
   about a pixel at this size — but every one of them hangs them low, so the
   correction is right in direction everywhere.

   HORIZONTALLY THERE IS NOTHING TO CORRECT, which is worth writing down because
   sideways is where the eye goes first and where the next person will reach. The
   same scan puts the ink's bounding box 0.21px LEFT of centre for ‹ and 0.19px
   right for › — mirrored, as mirrored glyphs will be — while the ink's centre of
   MASS falls on the other side of the line by 0.08px. The two honest answers to
   "where is the middle of this arrow" straddle the circle's centre by a fifth of
   a pixel, under the grid it is drawn on. A per-side nudge in there would be
   fitting to noise, and to one platform's font at that.

   A TRANSFORM, and on the span rather than the button, because the button's own
   transform is load-bearing twice: translateY(-50%) is what holds it on the
   middle of the hours, and :active scales it. Nothing here may join that
   argument. Inside, the arrow simply rides the press. */
.wg-chev > span {
  transform: translateY(-2px);
}

/* Each line's own position, less half a circle to centre the circle on it. */
.wg-chev--prev {
  left: calc(1px + var(--mc-time-col) - (var(--wg-chev-size) / 2));
}
.wg-chev--next {
  right: calc(1px + var(--wg-chev-gutter, 10px) - (var(--wg-chev-size) / 2));
}

/* Nowhere behind this week to go — the player's calendar on the current week,
   where the server hands back no previous week at all (see syncPreviousWeek).
   Dimmed rather than shut, because the two jobs this button does have different
   answers to that fact: there is no week behind, but there is plenty of THIS
   week off the left of a phone, and it is still the way to it. So the attribute
   only takes the colour down; the press still scrolls, and the press AT the
   edge is quietly inert, refused inside previousWeek() where the rule already
   lives. Never `disabled`, which would take the scrolling away with it.

   Desktop only. On a phone the circles are the only way across the week that
   announces itself, and a faded one reads as broken.

   Written BEFORE the hover rule below on purpose: a dimmed chevron pointed at
   is still a working scroll control, and it should light up like the other. */
@media (hover: hover) {
  .wg-chev[data-limit] { opacity: 0.35; }
}

.wg-chev:hover,
.wg-chev:focus-visible {
  opacity: 1;
  background: var(--mc-brand);
  border-color: var(--mc-brand);
  color: #fff;
}
/* The transform is restated because it is what holds the circle on the middle
   of the hours; a bare scale() here would drop it half its own height down the
   page for as long as it was held. */
.wg-chev:active { transform: translateY(-50%) scale(0.94); }

/* --- the same circle, in the month bar ------------------------------------
   The month is turned by a pair of these standing in a row (see .mc-monthnav),
   which is the whole reason the modifier exists.

   The same circle, standing in a row instead of riding the edge of a scroller.
   Everything the week's version needs to hang off a scrollport — the absolute
   placement and the translate that centres it on the hours — is given back, and
   `:active` restates the press on its own, since the transform it was joining no
   longer exists. */
.wg-chev--inline {
  position: static;
  transform: none;
  flex: 0 0 auto;
}
.wg-chev--inline:active { transform: scale(0.94); }

/* Nowhere behind this month to go, on the month a customer is standing in. The
   same 0.35 the week fades its own chevron to, and genuinely disabled with it:
   the week's is still a scroll control when it has no week behind it, and this
   one has nothing left to do. Said again against hover and focus so a pointer
   cannot light up a button that will not answer. */
.wg-chev--inline:disabled { opacity: 0.35; cursor: not-allowed; }
.wg-chev--inline:disabled:hover,
.wg-chev--inline:disabled:focus-visible {
  opacity: 0.35;
  background: rgba(255, 255, 255, 0.82);
  border-color: var(--mc-line);
  color: var(--mc-muted);
}

/* A phone is where these earn their keep — the week is at its widest relative
   to the screen and there is no scrollbar worth aiming at — so there is no
   resting state to fade into and no hover to come out of. The size is the same
   as the desk's and always was meant to be: 2.5rem is a fingertip's worth of
   circle, and a control that changed size between a phone and a laptop would be
   two controls. What is left here is the white it stands in — solid rather than
   the desk's near-white, because it stands over the week itself, hour lines and
   day borders and booking blocks, and there is no cursor coming to firm it up
   the moment it matters. */
@media (hover: none), (max-width: 640px) {
  .wg-chev {
    opacity: 1;
    background: #fff;
  }
}

/* The time column also holds the rows open. A reserved block can swallow every
   day cell of a row, and on a busy week every column at once — the label left in
   column 1 is what keeps that row the height it would have been. */
.wg__time {
  position: sticky;
  left: 0;
  /* Above the closed-day panel (.wg__closed, z-index 3): the panel is opaque
     and spans every hour of its column, so at anything lower a shut day
     scrolled sideways slid OVER the axis and blanked the times — the one
     column that must stay put. Still under the sticky headings (5), which the
     hours scroll beneath. */
  z-index: 4;
  min-height: var(--mc-slot-height);
  border-top: 1px solid var(--mc-line);
  /* The one line of the axis that is a day boundary rather than an hour rule:
     it is the left edge of Sunday, and it is drawn as one. */
  border-right: 1px solid var(--mc-line-strong);
  /* Barely any side padding, and that is the centring's doing rather than a
     taste for tight margins: a label ranged right only had to clear one edge,
     and a centred one has to fit BETWEEN two. "10pm - 11pm" is 88px of type in a
     100px column, so what used to be breathing room on the right is now most of
     the margin the widest hour of the day has left to sit in. */
  padding: 0.2rem 0.1rem 0;
  font-size: 0.74rem;
  color: var(--mc-muted);
  /* Centred rather than ranged against the day boundary. Set right, the times
     read as a caption hanging off Sunday's edge; centred, the column reads as an
     axis of its own — which is what it has to be before one of its hours can be
     picked out without that hour looking as though it has slipped. Top of the
     row, still: the label names the hour's START, and the row is the hour. */
  text-align: center;
  background: #fff;
}
/* --- the hour it is now ----------------------------------------------------
   The clock, marked on the axis: the label of the hour that is happening is
   written in the venue's own mahogany, on a wash of the same, with a stub of it
   against the outer edge. Mahogany because the week already has exactly one way
   of saying "this is the one that is now" — today's date, in a mahogany circle,
   at the top of a mahogany-framed column — and a second colour would be a
   second thing to learn.

   Not a filled pill, which is what the circle at the top of the column would
   suggest, and the reason is the width of the track it would have to sit in.
   The time column is 100px on every screen, which is as much as can be spared
   from a week that is already scrolling sideways on a phone — "10pm - 11pm"
   fills very nearly the whole of it at this size, and a plate round the type
   would need several pixels more on each side than the column has to give. It
   would overhang into Sunday, and only on the handful of hours whose label runs
   to two two-digit hours, which is the worst kind of fault: one that looks right
   all afternoon and breaks at ten, at eleven and at midnight. So the mark is
   made out of things that take up no room at all — a colour, a weight, the brand
   at a wash, and an inset rule down the outer edge — and every hour of the day
   wears it identically.

   Which is also what keeps the grid still. Nothing here changes the width of
   the column or the height of a row, so the mark can come and go on the hour
   (see markCurrentHour) without a single cell moving under the reader.

   The hover band stops at the axis: the band sits at z-index 2 and this
   column at 4 (see .wg__time — the axis has to stand above the closed-day
   panel), so a hovered row tints the days and leaves this label alone. */
.wg__time.is-now {
  background: #f4ebe5;
  box-shadow: inset 3px 0 0 var(--mc-brand);
}
/* On the label rather than on the cell, and that is not fussiness: the player
   grid sets the weight of this column through an id (see below), which would
   beat any class put on the cell itself. The wrapper is a plain span until it
   is this hour — see buildWeekGrid, which wraps every label alike so that a
   row's markup never depends on the time of day. */
.wg__time.is-now .wg__hour {
  color: var(--mc-brand);
  font-weight: 700;
}
/* On the player grid the axis is the last thing left reading down the page: the
   free cells beside it are blank until pointed at, so the times down the edge
   are what a player scans to find the evening they want. Bold enough to be
   scanned, and only here — the admin grid draws its free time the same way now,
   but it is a week of blocks carrying names and hours, and an axis competing
   with those would be noise. */
#player-page .wg__time { font-weight: 600; }

.wg__cell {
  border-top: 1px solid var(--mc-line);
  border-left: 1px solid var(--mc-line);
  min-height: var(--mc-slot-height);
  padding: 3px;
  margin: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  justify-content: center;
  align-items: stretch;
  font: inherit;
  font-size: 0.76rem;
  text-align: center;
  background: var(--mc-open);
  color: var(--mc-muted);
  transition: background-color 0.12s ease, box-shadow 0.12s ease;
}
.wg__cell.is-today-col { background: var(--mc-today); }

/* A free cell on either grid is a real <button>, because it is really a
   control — and it must not look like one. The grid rules every cell with a
   border on its top and left only, letting the neighbours below and to the right
   draw the other two sides, so a button left to its own devices keeps the
   browser's heavy outset border on exactly the two edges the grid never touches,
   and every open cell reads as a boxed key on a keyboard.
   `appearance` strips the native widget, and the two zeroed sides put the cell
   back on the same hairlines as the divs around it. */
button.wg__cell {
  appearance: none;
  -webkit-appearance: none;
  border-right: 0;
  border-bottom: 0;
  border-radius: 0;
}

/* A free hour answers a press as well as a click now — held, it is the start of
   a range dragged down the column — so nothing about it may be text as far as
   the browser is concerned: no words swept up by a drag, no magnifier or callout
   under a long press, and no double-tap zoom to fight the double tap that opens
   the form. `manipulation` leaves ordinary scrolling exactly where it was, which
   is the one gesture the grid must never take away from a phone. */
button.wg__cell.is-open {
  cursor: pointer;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
button.wg__cell.is-open:focus-visible {
  background: var(--mc-open-hover);
  box-shadow: inset 0 0 0 2px var(--mc-accent);
  color: var(--mc-accent);
  outline: none;
}
/* A free cell is blank until it is pointed at, and then it says the one thing it
   has to say: the time it starts. Blank is the point — the week reads as free
   space and taken space at a glance, with no wall of repeated times to look past,
   and the label arrives on the one cell being considered. It answers to
   :focus-visible as well as :hover so tabbing through the grid reads the same way
   as pointing at it, and neither has anything to do with whether the cell can be
   pressed: it is a button all along.

   Both grids draw free time this way. The admin's open cells are the same
   buttons carrying the same .is-open, and what is different about them — how many
   courts are left in the hour — is on the tooltip rather than printed into
   the week. */
button.wg__cell.is-open .wg__cta { display: none; font-weight: 600; }
button.wg__cell.is-open:focus-visible .wg__cta { display: block; }

/* And the hover half of it is only ever offered to something that can actually
   hover, which a phone cannot.

   A touch screen has no pointer resting anywhere, so it has nothing honest to
   put :hover on — and what it does instead is leave the state on whatever was
   last touched, until something else arrives to take it away. On this grid
   nothing does: every press the selection engine deals with ends in
   preventDefault(), which is what stops the browser inventing a second gesture
   out of the same finger, and it takes the phantom mouse move that would have
   moved the hover along with it. So the first cell a thumb rested on lit up and
   stayed lit — through the next long press, through the selection made three
   hours below it, through everything — and a week with two cells claiming to be
   the one under the finger is a week telling a lie about where the hand is.

   Wrapping the hover rules in a query for a device that hovers is the whole fix:
   a mouse still lights the cell under it, and a phone is simply never told about
   a state it has no way to leave. The keyboard's :focus-visible above is
   deliberately NOT in here — focus is a real place on any device, and it moves
   when it is asked to. */
@media (hover: hover) {
  button.wg__cell.is-open:hover {
    background: var(--mc-open-hover);
    box-shadow: inset 0 0 0 2px var(--mc-accent);
    color: var(--mc-accent);
    outline: none;
  }
  button.wg__cell.is-open:hover .wg__cta { display: block; }
}

/* A taken slot is grey and says nothing: what is booked is drawn as a block over
   it, and a bucket whose courts are gone with no block on it — time held by a
   booking nobody has verified yet — is grey for the same reason it is
   unclickable. The word is on the cell's title and aria-label, for the reader
   that cannot see the colour. */
.wg__cell.is-reserved {
  background: var(--mc-reserved);
  color: var(--mc-reserved-ink);
  font-weight: 600;
  border-left-color: var(--mc-reserved);
  cursor: not-allowed;
}

.wg__cell.is-past {
  background: #ededed;
  color: #cfcfcf;
  cursor: not-allowed;
}
.wg__cell.is-past.is-reserved {
  background: var(--mc-reserved-past);
  color: #9aa1aa;
  border-left-color: var(--mc-reserved-past);
}

/* --- a day the venue does not open on -------------------------------------- */

/* A closed day is not an hour-by-hour picture of nothing available: it is a day
   that does not happen, and the week says so by drawing it as one unbroken
   thing. The player grid draws no cells at all in that column (see
   player_calendar_controller#cell), and since every hairline on this grid is
   drawn BY a cell — its own top and left edge — leaving the cells out is the
   whole of what takes the rules out of the column. What is left is this: one
   panel down the length of the day with the word on it.

   One line comes back, and it is the one the column is not the column without:
   the boundary against the day before it. That line is a cell's left edge
   everywhere else on the grid (see the day-boundary rule below), so a column
   with no cells had nothing to draw it — and an opaque panel standing over the
   place it would have been fused a closed Monday to the Sunday beside it into
   a single grey field with no telling where one ended. The panel rules its own
   left edge instead, in the same stronger grey a day boundary is said in
   anywhere else. Its right edge needs nothing: the next day's first cell draws
   that same boundary as its own left, and a closed day beside a closed day is
   two panels each ruling the one edge it owns.

   The grey is the SAME grey a played hour is drawn in (.wg__cell.is-past), and
   deliberately the same: a player is reading this week for time they can take,
   and an hour that has gone and a day that never opens are one answer to that.
   Two greys for one meaning would be the week inventing a distinction it does
   not have. What the closed day does not take from that treatment is the
   hairlines inside it — it is one flat field rather than a stack of hours — and
   its near-invisible dash ink, which is right for an em-dash and would lose a
   word.

   The word is set the way this grid sets every other small label on itself —
   the court strip under the dates, which is the same 0.66rem at the same weight
   in the same muted tone (see .wg__head .wg__courts). Two sizes for two labels
   of the same standing would be the week disagreeing with itself, and the
   weight is what carries the tone at about 4:1 on this grey: heavy enough to
   read at arm's length, quiet enough not to announce a day nobody can book.

   Opaque, and above the crosshair bands at z-index 2 rather than under them.
   The bands are one row-wide strip drawn across the FULL width of the week, so
   pointing at any hour of any day would otherwise wash a tinted line, with a
   blue rule top and bottom, straight through the column and hand back the very
   grid lines this is here to take away. Masking them is what keeps the day one
   flat field whatever the pointer is doing — hence the ladder this sits in the
   middle of, and the raised headings and grips above it.

   And it takes the pointer rather than letting it through, for one reason: the
   cursor. `not-allowed` is what a grey hour and a taken court already answer a
   mouse with, and a closed day owes the same answer — but a rule about the
   cursor is a rule about the element under it, so the panel has to be under it.
   Nothing else is bought by that and nothing is lost: the crosshair reads the
   pointer's own coordinates rather than what it is over (trackGridHover), a
   selection is only ever started from a `button.wg__cell` and there is not one
   in this column (trackGridSelection#cellAt), and a finger that lands on no cell
   falls through to the page with the gesture untouched. There is nothing under
   the panel to reach either: the customer's payload carries no reservations at
   all on a day the venue does not open (see the availability endpoint's
   public_bookings), so what this covers is empty column and not a booking
   somebody might have wanted to press. */
.wg__closed {
  position: relative;
  z-index: 3;
  cursor: not-allowed;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #ededed;
  border-left: 1px solid var(--mc-line-strong);
  color: var(--mc-muted);
  font-size: 0.66rem;
  font-weight: 600;
}

/* And when the day the venue is shut is also today, this panel is the frame.
   The line round today is drawn in two halves, and the lower one — the sides
   and the foot — is an overlay pinned beneath everything the grid body can lay
   over it, for a reason that has nothing to do with closed days and cannot be
   given up (see .wg__todayframe above). This panel is opaque and stands higher,
   so on a shut today the reader saw a heading in mahogany with a top and two
   ears and then nothing at all down either side of it: three-quarters of a
   frame missing, on the one column of the week the frame exists to find.

   So the panel wears the frame at the height it is actually visible from. The
   same two pixels of the same mahogany on the same three edges, over a column
   that is exactly today's and hours that are exactly all of them, which is what
   makes it the frame rather than an imitation of it — and it meets the
   heading's own borders above squarely, both being borders drawn inside the
   same grid track. The overlay underneath is left where it is: it is covered
   entire, it costs nothing, and a closed day is not a reason for buildWeekGrid
   to learn what a closed day is.

   The grey stays. Closed is still closed, and the frame is a boundary rather
   than an offer — the only thing being said here is where today is. */
.wg__closed.is-today-col {
  border-left: 2px solid var(--mc-brand);
  border-right: 2px solid var(--mc-brand);
  border-bottom: 2px solid var(--mc-brand);
}

/* Where one day ends and the next begins, said in the stronger grey.
   A day column is the venue's courts side by side and every court is a cell of
   its own, so the vertical hairlines in the body are two different lines wearing
   one colour: the boundary BETWEEN days, which the week is read by, and the rule
   between courts INSIDE a day, which is a detail of the column. Only the first
   kind is drawn up.
   Which a cell is, is in where it was placed: courtStyle gives every cell the
   left edge of its own court's band, so a cell at `margin-left:0%` — or one with
   no band at all, which is a past hour drawn across the whole day — is standing
   on the boundary, and every other is standing inside the day.
   Last of the cell rules, and specific enough to carry a taken slot too: a
   boundary that vanishes down a grey run of reserved hours is the week losing
   its shape exactly where it is busiest. The rule between COURTS keeps the
   reserved grey it had, so a taken hour still reads as one block.
   A column with no cells in it has no first cell to ask, which is the one place
   this rule cannot reach: a closed day draws the same boundary out of its own
   panel, in the same colour, for the same reason (see .wg__closed). */
.wg .wg__cell[style*="margin-left:0%"],
.wg .wg__cell:not([style*="margin-left:"]) {
  border-left-color: var(--mc-line-strong);
}

/* --- a booking is one block on the grid ------------------------------------ */

/* A booking is a box as tall as the time it takes, laid over the hour cells
   it covers, on both grids. It sits above the cells (which come later in the
   DOM) but below the frozen time column (4) and the hover bands (2), so the
   column still covers it when the box is scrolled sideways and the crosshair
   still tints across it.

   On the admin grid colour is the verification and nothing else: yellow is
   waiting to be checked, green has been. There is no tick on it — the whole
   block already says so. The player grid only ever draws the green ones, because
   an unchecked booking is not something to show a stranger as settled. */
.wgb {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 1px;
  min-width: 0;
  overflow: hidden;
  padding: 2px 3px;
  border: 1px solid;
  border-radius: 6px;
  font: inherit;
  font-size: 0.72rem;
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
  /* A block is held for a second and a half to pick it up and move it (see
     trackBlockDrag), and a phone answers a long press on a piece of text by
     offering to select it, magnify it, or put a menu over the very thing being
     dragged. All three are taken away here.

     `touch-action` is deliberately `manipulation` rather than `none`: the week
     is a box that scrolls both ways, and a block that refused to be panned
     would be a hole in the middle of the grid a thumb could not get past. What
     `manipulation` drops is only the double-tap zoom, which is the one thing a
     hold-and-drag would otherwise have to compete with. The hold itself does the
     rest: a finger that travels before they are up is scrolling, and the engine
     lets it. */
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}
/* The booking while it is in the air. It stays exactly where it is — that is
   still where the booking IS until the server says otherwise — and it is the
   one block on the week drawn at full strength, ringed in the accent the ghost
   is ringed in, so the two read as the two ends of one move. Everything else
   steps back; see the .wg-moving rules beside the selection ones above.

   Written under the container's class rather than on the block alone, and that
   is load-bearing: the verified and unverified colours below name a border
   colour of their own at the same weight as `.wgb.is-moving` would have, and
   the block in hand has to out-argue whichever of them it is wearing. The two
   classes are put on and taken off together, so there is no state this fails to
   describe. */
.wg-moving .wgb.is-moving {
  opacity: 1;
  border-width: 2px;
  border-color: var(--mc-accent);
}
.wgb.is-unverified {
  background: #fdf1c4;
  border-color: #e0c24e;
  color: #6b4e07;
}
.wgb.is-verified {
  background: #d9f2e3;
  border-color: #94d3b3;
  color: #145b36;
}
/* The viewer's own booking: the one green block that answers the pointer (it
   is a button where the others are painted on). The heavier edge is what lets
   it be spotted as theirs before it is ever hovered. */
.wgb.is-own { border-width: 2px; border-color: #2e9e68; }
.wgb:hover,
.wgb:focus-visible {
  box-shadow: inset 0 0 0 2px currentColor;
  outline: none;
}

/* --- a court the venue has closed ----------------------------------------
   THE ONE BLOCK ON EITHER CALENDAR THAT IS NOT A BOOKING. The venue took these
   hours off the market — maintenance, a private event, a tournament — and what
   is drawn is the closed-day panel's own grey, at the size of a block
   (see .wg__closed, which is the whole-day version of the same fact and where
   these two colours come from). A customer meeting one on a Saturday should
   recognise it as the same "not this one" they already know from a shut column,
   rather than as a fourth colour to learn.

   The words are the venue's reason, and they are the point: a grey hour with
   nothing written on it says a court has gone and not why. So the name wraps
   over as many lines as the block has room for, exactly as a booker's name
   does. */
.wgb.wgb--closed {
  background: #ededed;
  border-color: var(--mc-line-strong);
  color: var(--mc-muted);
  cursor: default;
}
/* The desk's version holds two presses, so the block is a frame with buttons in
   it rather than a button (an element that opens the record cannot contain the
   one that reopens the court). The body fills the frame and carries the words;
   nothing about it should read as a control of its own, so it borrows the
   block's own type and colour and draws no chrome at all. */
.wgb--closed .wgb__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 1px;
  flex: 1 1 auto;
  align-self: stretch;
  min-width: 0;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
}
.wgb--closed .wgb__body:focus-visible {
  outline: 2px solid var(--mc-accent);
  outline-offset: -2px;
}
/* GIVING THE COURT BACK, on the thing itself — the super-admin's, and drawn for
   nobody else (see month_calendar_controller#closedBlock). Closing courts is
   done in fives on a maintenance morning and undone in fives when the work
   finishes, and a two-step errand through a panel for each is four presses that
   should be one.

   Top-right and out of the way of the reason underneath it, on its own layer so
   that a press lands on the X and not on the body behind it, and never on the
   grid: the block takes no pointer at all for a customer, and here the two
   buttons are the only things in it that do. */
.wgb--closed .wgb__x {
  position: absolute;
  z-index: 2;
  top: 1px;
  right: 1px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  border: 1px solid var(--mc-line-strong);
  border-radius: 4px;
  background: #fff;
  color: var(--mc-muted);
  font-size: 0.8rem;
  line-height: 1;
  cursor: pointer;
}
.wgb--closed .wgb__x:hover,
.wgb--closed .wgb__x:focus-visible {
  border-color: #b3453b;
  color: #8a1c11;
  outline: none;
}

/* --- the hours given over to open play -------------------------------------
   THE OTHER BLOCK THAT IS NOT SOMEBODY'S RESERVATION. The court is taken and
   nobody booked it: the venue has opened these hours to whoever turns up, at a
   price per head rather than by the hour.

   Cream with a brown edge, and deliberately neither of the two colours already
   on the grid — yellow is a booking waiting to be checked and green is one that
   has been, and an open-play hour is neither of those questions. The heavier
   border is what carries it at block size, where the fill alone would read as a
   pale version of the unverified yellow beside it.

   The words are the venue's per-head rate on the first line and the hours on the
   second, built in the browser from the rate the payload carries (see
   Tenant#as_public_json and the three calendars' openPlayWords). */
.wgb.wgb--open-play {
  background: #fff6d9;
  border-width: 2px;
  border-color: #8a4b1f;
  border-radius: 8px;
  color: #6b3a15;
}
.wgb--open-play .wgb__when { opacity: 0.7; }
.wgb--open-play .wgb__rate { font-size: 0.66rem; font-weight: 600; }

/* A session this browser has already reserved on. The cream block stays cream —
   it is still open play — and takes the green edge every other block of the
   reader's own wears. Said with both classes so it beats `.wgb.is-own` and
   `.wgb.wgb--open-play` alike, which are the same weight as each other. */
.wgb.wgb--open-play.is-own { border-color: #2e9e68; }

/* A block with nothing behind it to open: a label rather than a control. It
   used to be every booking on the player grid; now that pressing one asks the
   server what it is, it is only the block that arrived without the id to ask
   with (see player_calendar_controller's block()). Taking it out of the pointer
   entirely is what says so — no hover, no cursor, and the crosshair and the
   cell underneath carry on as if the block were painted on them. */
.wgb.is-static {
  cursor: default;
  pointer-events: none;
}

/* Half a column is narrow, and a name cut to "John Sm…" is worth less than a
   name on two lines — so it wraps, and only what will not fit in the block at
   all is lost. The hours underneath stay on one line, always. */
.wgb__name {
  max-width: 100%;
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* The player's blocks carry a booking reference where the admin's carry a name.
   A reference is one token that is worth nothing half-read, so it is never
   wrapped: it fits or it is cut with an ellipsis, and the block is sized so it
   fits. */
.wgb__ref {
  max-width: 100%;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wgb__when {
  max-width: 100%;
  font-size: 0.66rem;
  opacity: 0.85;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The third line an open-play block carries: how many slots are going, or how
   many of them are already the reader's. Smaller and quieter than the hours
   above it — it is the answer to "can I still join?", not the block's name. */
.wgb__note {
  max-width: 100%;
  font-size: 0.62rem;
  opacity: 0.75;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- one calendar, two views ----------------------------------------------
   The toggle on the bar writes `data-view` on the calendar's own root element
   (see month_calendar_controller's switchView) and these four rules are the
   whole of the swap: one surface and one key are hidden, the other pair is not.
   Done in the stylesheet rather than by script because it is a question about
   what is on screen rather than about what is true — nothing is rebuilt, nothing
   is refetched, and the board the reader comes back to is the board they left.

   Written against `[data-controller~="month-calendar"]` rather than against a
   bare `[data-view]`, because `data-view` is a word plain enough that some other
   page in this app may want it one day and these rules would go with it. */
[data-controller~="month-calendar"][data-view="week"] .mc-month-surface,
[data-controller~="month-calendar"][data-view="week"] .mc-legend--month { display: none; }
[data-controller~="month-calendar"][data-view="month"] .mc-week,
[data-controller~="month-calendar"][data-view="month"] .mc-legend--week { display: none; }

/* --- the customer's month -------------------------------------------------
   The page an anonymous visitor lands on: seven columns, Sunday to Saturday,
   and a cell for every day of one month. It is the same instrument as the week
   grid at a different zoom — same card, same legend, same colours meaning the
   same things — and it answers the question a customer actually starts from,
   which is WHICH DAY rather than which hour of which of seven days.

   Nothing about how full a day is is drawn here, on purpose (see
   Api::V1::AvailabilityController#month): a cell is a date, and whether it can
   be pressed. What is on a day arrives when the day is opened.

   The grid is plain 1fr columns rather than the week grid's fixed 128px ones,
   because seven DATES fit on a phone where seven days of hours do not — a cell
   has a number in it and nothing else. So the month never scrolls sideways and
   there is nothing here for a chevron on the card's edge to drive. */

.mc-month {
  background: var(--mc-open);
  border: 1px solid var(--mc-line-strong);
  border-radius: 10px;
  /* The hairlines below are drawn by the cells themselves, on their top and
     left only — the same trick the week grid uses — so the frame round the
     whole month is this border and the corners have to clip to it. */
  overflow: hidden;
  /* …and sideways it scrolls instead, for the 6rem floor on the date boxes. */
  overflow-x: auto;
}

.mc-month__head,
.mc-month__grid {
  display: grid;
  /* A date box is never narrower than 6rem: seven of them make the month at
     least 42rem wide, and on a phone the month scrolls sideways inside its
     frame (see .mc-month) rather than squeezing the pills to "MC…". */
  grid-template-columns: repeat(7, minmax(6rem, 1fr));
}

/* SUN..SAT, rendered by the server because it never changes (see
   player/month.html.erb). Quiet, small and in capitals: it is a key to the
   columns rather than a heading over the month, which is what the bar above the
   card already says. */
.mc-month__head {
  background: #f7f8fa;
  border-bottom: 1px solid var(--mc-line-strong);
}
.mc-month__weekday {
  padding: 0.35rem 0.25rem;
  text-align: center;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mc-muted);
}

/* One date. A button where the day can be opened and a div where it cannot, so
   the two rules below dress two different elements and there is no such thing
   as a greyed-out control that still takes a press. */
.mc-month__cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  /* A day is a BOX with room in it, the shape a month calendar is drawn in
     everywhere else somebody has read one. At 3.6rem the six rows of a month
     read as a strip of numerals — the dates are closer to the date above and
     below them than a week is wide — and the month it is headed with is not the
     thing the eye finds first. This is not space being made for content: what
     goes in a cell is a date and at most one word, and it goes on being the
     shape of the month rather than a summary of the day. */
  min-height: 6rem;
  min-width: 6rem;
  width: 100%;
  padding: 0.3rem 0.4rem;
  border-top: 1px solid var(--mc-line);
  border-left: 1px solid var(--mc-line);
  border-right: 0;
  border-bottom: 0;
  border-radius: 0;
  background: var(--mc-open);
  font: inherit;
  color: var(--mc-ink);
  text-align: left;
  appearance: none;
  -webkit-appearance: none;
  transition: background-color 0.12s ease, box-shadow 0.12s ease;
}
/* The frame is the card's, so the first row and the first column give their own
   hairline back rather than doubling it. */
.mc-month__grid > .mc-month__cell:nth-child(7n + 1) { border-left: 0; }
.mc-month__grid > .mc-month__cell:nth-child(-n + 7) { border-top: 0; }

/* The cells that are not this month at all: the shape of the month, not part of
   it. No number, nothing to press, and paler than an empty day so the eye reads
   the block of dates as the month it is headed with. */
.mc-month__cell.is-out { background: #fafbfc; }

.mc-month__cell.is-past {
  background: var(--mc-past);
  color: #b6bcc4;
  cursor: not-allowed;
}
/* The desk may press a played or closed day to review it (the server says so
   per reader — `openable`), and it is then a BUTTON wearing the same grey: the
   grey stays, the forbidding cursor does not. */
button.mc-month__cell.is-past,
button.mc-month__cell.is-closed { cursor: pointer; }
/* A day the venue does not open on, in the grey a taken slot wears on the week
   — because to a customer it is the same answer: not this one. It says the word
   as well, which the past does not need to (see month_calendar_controller). */
.mc-month__cell.is-closed {
  background: var(--mc-reserved);
  color: var(--mc-reserved-ink);
  cursor: not-allowed;
}
/* --- today, said the way the week says it -----------------------------------
   Three marks, and all three are the week grid's own: a mahogany TAB standing on
   the cell's top line with the word on it, the date in a filled mahogany
   CIRCLE, and a lightly tinted box behind both. It used to be a cream fill with
   the word "Today" set small underneath the number — true, and invisible from
   more than a foot away, because cream over white is a shade rather than a
   boundary and a caption in 0.6rem type is not a thing an eye lands on. The tab
   and the circle are what the week has always used to answer "which one is
   today" at a glance, and a customer who has met one of the two views of this
   venue should not have to learn a second vocabulary for the same fact. */
.mc-month__cell.is-today {
  position: relative;
  /* The tab hangs off the top edge, so this box may not clip its own children —
     a button clips in some engines by default, and half a tab is worse than
     none. */
  overflow: visible;
  background: #eef4fe;
  box-shadow: inset 0 0 0 2px var(--mc-brand);
}
/* The date in the circle the week draws it in: white on mahogany, round, and
   the same 1.8rem across, so the two grids' todays are the same mark at the
   same size (see .wg__head.is-today .wg__dom, which this is copied from). It is
   left-aligned here rather than centred because a month cell's contents are. */
.mc-month__cell.is-today .mc-month__num {
  width: 1.8rem;
  height: 1.8rem;
  line-height: 1.8rem;
  border-radius: 999px;
  background: var(--mc-brand);
  color: #fff;
  text-align: center;
}
/* The tab, in the week's own clothes (.wg-todaytab: mahogany, white caps,
   rounded at the top and square where it meets the cell). Out here it is placed
   by the stylesheet rather than by JavaScript, because a month cell does not
   move — the week's has to keep up with a column being scrolled sideways under
   a frozen time strip, and this one has nothing to keep up with.

   It stands ABOVE the cell's top line, lapping two pixels over it so brown
   meets brown with no hair of rounding between them, which puts it over the
   empty foot of the day above — a month cell is six rems tall and everything in
   it is at the top, so there is nothing up there to collide with. */
.mc-month__todaytab {
  position: absolute;
  left: 0.4rem;
  top: calc(2px - var(--mc-todaytab-height));
  height: var(--mc-todaytab-height);
  padding: 0 0.45rem;
}
/* Except on the first row of the month, where there is no day above to stand
   over and the band with SUN..SAT on it is what the tab would land on instead.
   There it tucks INSIDE the cell, at its own top line, and the number is pushed
   down by exactly the height it takes — the same tab in the same place relative
   to the box, one step lower. */
.mc-month__grid > .mc-month__cell.is-today:nth-child(-n + 7) { padding-top: calc(0.3rem + var(--mc-todaytab-height)); }
.mc-month__grid > .mc-month__cell.is-today:nth-child(-n + 7) .mc-month__todaytab { top: 2px; }

.mc-month__cell.is-open { cursor: pointer; }
/* A press on a phone is not a hover, and a cell left lit under a finger that has
   moved on is a month telling a lie about where the hand is — the same reason
   the week grid wraps its own hover rules in this query. Focus is deliberately
   outside it: focus is a real place on any device. */
@media (hover: hover) {
  .mc-month__cell.is-open:hover {
    background: var(--mc-open-hover);
    box-shadow: inset 0 0 0 2px var(--mc-accent);
    color: var(--mc-accent);
  }
}
.mc-month__cell.is-open:focus-visible {
  background: var(--mc-open-hover);
  box-shadow: inset 0 0 0 2px var(--mc-accent);
  outline: none;
}

.mc-month__num {
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.1;
}
/* "Today" under today's number, "Closed" under a shut day's, and nothing at all
   under the rest — an empty span, which draws nothing but keeps every cell the
   same shape. */
.mc-month__note {
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  opacity: 0.75;
}

/* --- what is already on a day ----------------------------------------------
   The day's bookings, at the foot of its cell: one small pill each, green with
   the venue's reference on it or yellow saying somebody is at the till. Same two
   fills, edges and inks as the blocks in the day popup (.wgb.is-verified and
   .wgb.is-unverified) and as the swatches in the legend on the bar, because they
   are the same two facts drawn smaller.

   A GRID OF TWO rather than a wrapping row, so the pills line up down the month
   instead of re-flowing per cell: seven cells side by side with their pills in
   the same two columns is a month somebody can read across. `margin-top: auto`
   puts them at the bottom of the cell, which is a flex column, so the date stays
   where it has always been and the pills fill from under it.

   OVERFLOW IS THE BACKSTOP AND NOT THE PLAN. The controller only ever draws a
   capped number of them (see `pillCap`) and the last of those counts the rest,
   so this box should never be over its two rows; the max-height and the hidden
   overflow are here so that a long reference, a big font or a narrow column
   cannot push a cell past the 6rem every other cell in the month is. */
.mc-month__pills {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px;
  width: 100%;
  margin-top: auto;
  max-height: 2.9rem;
  overflow: hidden;
}
.mc-month__pill {
  min-width: 0;
  padding: 0 0.25rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 0.58rem;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: 0.01em;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mc-month__pill.is-verified {
  background: #d9f2e3;
  border-color: #94d3b3;
  color: #145b36;
}
.mc-month__pill.is-hold {
  background: #fdf1c4;
  border-color: #e0c24e;
  color: #6b4e07;
}
.mc-month__pill.is-open-play {
  background: #fff6d9;
  border-color: #8a4b1f;
  color: #6b3a15;
}
/* On a played day — which only the desk is shown pills on; the public payload
   drops them — the pills fade: the record is there to be read back, not to be
   mistaken for something still coming. */
.mc-month__cell.is-past .mc-month__pill { opacity: 0.22; }
/* The one that is not a booking but a count of them. Grey, because it is the
   cell saying it ran out of room rather than a third kind of reservation. */
.mc-month__pill.is-more {
  background: #eef0f2;
  border-color: var(--mc-reserved-line);
  color: var(--mc-reserved-ink);
}
/* A phone's cell is a seventh of the screen, and a reference is nearly all of
   it: one pill per row there, and the controller draws two of them (see
   `pillCap`, which keeps the "+N more" count honest against this rule). */
@media (max-width: 640px) {
  .mc-month__pills { grid-template-columns: minmax(0, 1fr); }
  .mc-month__pill { font-size: 0.54rem; padding: 0 0.15rem; }
}

/* --- one day, court by court ----------------------------------------------
   What a pressed date opens: the venue's courts across the top, its opening
   hours down the side, and one cell per court per hour. It is the legacy week
   grid's own picture with the axis changed — a day instead of a week — so the
   classes a booking block wears in it are literally the week's (.wgb and
   friends), and only the cells and the frame are its own.

   AND THESE RULES DRESS BOTH BOARDS. Since the calendar grew a second view the
   week board is this same grid seven times across, wearing these same
   `.mc-day__*` classes because it is drawn by the same routine (see
   month_calendar_controller's drawBoard, and .mc-week further down, which is
   only the four things a week has that a day does not). So a rule here is a rule
   about the popup AND about the board: what belongs to one of them alone goes in
   that one's own section.

   THE PANEL GROWS WITH THE VENUE. Two courts is a narrow dialog and six is a
   wide one, which is what `--mc-day-courts` is for: it is set on the panel by
   the browser when the day is drawn (see month_calendar_controller#drawDay) and
   both the panel's width and the grid's columns are built from it. Past the
   width of the screen the panel stops growing and the COURTS scroll inside it —
   never the page, which is the one thing that must not move sideways. */

/* The day panel, which is also where the height of its scroller is DECLARED
   rather than merely used: the box that waits in that scroller's place has to be
   exactly as tall as it will be, or the panel jumps when the hours land, and a
   variable set on the scroller itself is no use to its sibling. Both read it
   from here — see .mc-day__scroll and .mc-loading--tall. */
.mc-day { --mc-day-scroll-max: min(58vh, 30rem); }

/* THE PANEL IS AS WIDE AS THE VENUE HAS COURTS, on both calendars that render
   the popup — the customer's month landing and the desk's (see
   common/modals/_day, which is one file rendered by both). The desk's id is
   named beside the customer's rather than the pair being written as one class
   rule, because what this has to beat is id-scoped: #admin-calendar's booking
   panel is two columns wide at every size (further down), and a day of courts
   drawn to that width would be a screenful of white beside a two-court grid. */
#player-page .mc-modal__panel.mc-day,
#admin-calendar .mc-modal__panel.mc-day {
  width: 100%;
  max-width: min(100%, calc(8rem + (var(--mc-day-courts, 1) * 9rem)));
}

/* The day scrolls INSIDE its panel, both ways, and the panel does not move: a
   venue with six courts is wider than a phone and eighteen opening hours are
   taller than one, and the two things that must stay where they are while a
   reader gets to either are the page (which must never scroll sideways) and the
   row of buttons under the grid (which is how the day is left, and how a
   selection is taken to the form).

   The frame lives out here rather than on the grid, because a scroller is the
   thing whose corners have to be clipped — and because an `overflow` on the grid
   itself would become the box the sticky headings inside it stick to, which is a
   box that never scrolls. */
.mc-day__scroll {
  overflow: auto;
  overscroll-behavior: contain;
  max-height: var(--mc-day-scroll-max, min(58vh, 30rem));
  border: 1px solid var(--mc-line-strong);
  border-radius: 8px;
  background: var(--mc-open);
}

.mc-day__grid {
  /* Room for the selection's corner grips. They are 1.5rem dots centred on the
     block's corners (see .wg__grip), so a range on the last court or the last
     hour hangs 0.75rem past the grid's edge — and an overhang past the edge of
     the thing that scrolls is a scrollbar. The padding gives it that much floor
     to land on instead. */
  padding-right: 0.75rem;
  padding-bottom: 0.75rem;
  display: grid;
  grid-template-columns: var(--mc-day-time-col, 5.75rem)
                         repeat(var(--mc-day-courts, 1), minmax(5.5rem, 1fr));
  grid-auto-rows: var(--mc-slot-height);
  /* Wider than the scroller is what makes it scroll; narrower and the columns
     share out the room. */
  min-width: min-content;
  /* A press dragged down a column is a booking being drawn, and none of what it
     is dragged over may be treated as text on the way. `manipulation` leaves
     ordinary scrolling alone, which is the gesture a phone must keep. */
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}

/* The corner, the court numbers and the hours: the three parts of the grid that
   name the rest of it. The numbers are written "#1", "#2" for the reason the
   week grid writes them that way — a lone "1" over a column of times is one more
   numeral in a table full of them. */
.mc-day__corner,
.mc-day__court,
.mc-day__time {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f7f8fa;
  color: var(--mc-muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
/* Both stay put while the day is scrolled under them — the courts along the top
   and the hours down the side — for the reason the week grid freezes the same
   two: a cell in the middle of a scrolled grid means nothing without the court
   over it and the hour beside it. They claim a z-index above the booking blocks
   (which take 1), so a block sliding past goes under the heading rather than
   over it. */
.mc-day__corner,
.mc-day__court {
  position: sticky;
  top: 0;
  /* Above the selection's grips as well (.wg__grip takes 4): a dot on the edge
     of a block that has scrolled under the heading or the hour labels must go
     under them with the block, not float over "1pm" on its own. */
  z-index: 6;
  grid-row: 1;
  border-bottom: 1px solid var(--mc-line-strong);
}
.mc-day__corner {
  grid-column: 1;
  left: 0;
  z-index: 7;
  font-size: 0.58rem;
}
.mc-day__time {
  position: sticky;
  left: 0;
  z-index: 5;
  grid-column: 1;
  border-right: 1px solid var(--mc-line-strong);
  border-top: 1px solid var(--mc-line);
  font-size: 0.66rem;
  font-weight: 600;
  white-space: nowrap;
}

/* One court, for one hour. Same colours as the week grid's cells, meaning the
   same things, because the legend over the month is the week's legend. */
.mc-day__cell {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--mc-slot-height);
  padding: 2px;
  border-top: 1px solid var(--mc-line);
  border-left: 1px solid var(--mc-line);
  border-right: 0;
  border-bottom: 0;
  border-radius: 0;
  background: var(--mc-open);
  color: var(--mc-muted);
  font: inherit;
  font-size: 0.72rem;
  appearance: none;
  -webkit-appearance: none;
  transition: background-color 0.12s ease, box-shadow 0.12s ease;
}
.mc-day__cell.is-open { cursor: pointer; }
.mc-day__cell.is-reserved {
  background: var(--mc-reserved);
  border-left-color: var(--mc-reserved);
  color: var(--mc-reserved-ink);
  cursor: not-allowed;
}
/* A court somebody is at the till for. It is mostly covered by the block drawn
   over it — a draft is on this grid the same way it is on the week — and the
   tint is what is left showing at the edges of it: this is a state that may undo
   itself in minutes, and it is worth being able to tell from the grey that will
   not. */
.mc-day__cell.is-reserved.is-pending {
  background: #f7e9b8;
  border-left-color: #f7e9b8;
  color: #6b4e07;
}
.mc-day__cell.is-past {
  background: #ededed;
  border-left-color: #e4e4e4;
  color: #cfcfcf;
  cursor: not-allowed;
}
/* An hour that is over and still on offer, which is the desk entering this
   morning's walk-in at four o'clock: the server says whether it may be pressed
   (`bookable`) and the clock says what colour it is (`past`), so the cell is a
   BUTTON wearing the played hour's grey. The grey stays, the forbidding cursor
   does not — the same pair of rules, for the same reason, that the month's own
   played dates are drawn under (see button.mc-month__cell.is-past above, and
   month_calendar_controller's slotCell). */
button.mc-day__cell.is-past { cursor: pointer; }
/* The hour the venue is standing in, marked exactly the way the month marks
   today — cream, ringed in mahogany, with one small word under the figure —
   because it is the same fact one scale down and deserves the same picture. The
   word is NOW rather than TODAY: the whole popup is one day already, and what
   this row adds is the time of it.

   On the LABEL and not on the courts beside it. A cell is a thing that can be
   pressed and chosen, and tinting a whole row of them would be the grid saying
   something about availability that it does not mean; the axis is where the
   grid names its rows, and this is a name. */
.mc-day__time.is-now {
  flex-direction: column;
  gap: 1px;
  background: var(--mc-today);
  box-shadow: inset 0 0 0 2px var(--mc-brand);
  color: var(--mc-ink);
}
/* "Now", in the same small caps the month writes "Closed" in. */
.mc-day__note {
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  opacity: 0.75;
}

/* The hour written on the cell, shown only where a pointer is considering it —
   so the day reads as free space and taken space, and the label arrives on the
   one cell being looked at. */
.mc-day__cta { display: none; }
@media (hover: hover) {
  .mc-day__cell.is-open:hover {
    background: var(--mc-open-hover);
    box-shadow: inset 0 0 0 2px var(--mc-accent);
    color: var(--mc-accent);
  }
  .mc-day__cell.is-open:hover .mc-day__cta { display: block; }
}
.mc-day__cell.is-open:focus-visible {
  background: var(--mc-open-hover);
  box-shadow: inset 0 0 0 2px var(--mc-accent);
  outline: none;
}
.mc-day__cell.is-open:focus-visible .mc-day__cta { display: block; }

/* --- the hours being taken -------------------------------------------------
   ONE BOOKING IS ONE BLOCK, here exactly as on the week grid.

   A range used to be drawn as a class on every cell of it: seven hours chosen
   was seven bordered, separately tinted boxes each repeating its own o'clock,
   which is a picture of seven bookings rather than of the one evening somebody
   is about to pay for. The week has never said it that way — a selection there
   is one tinted region with one edge round the whole of it and one caption
   inside (.wg__sel, up beside the crosshair bands) — and a customer who has met
   one of the two views of this venue should not have to learn the other.

   So the rectangle here IS that one: same class, same fill, same pair of pills.
   Only the way it is put in place differs, and the difference is in this grid's
   favour — a court is a column and an hour is a row, so the block is placed on
   tracks the way the bookings beside it are (.wgb, which this popup also borrows
   whole) rather than measured onto the grid in pixels. See paintSelection, where
   that is written out.

   Which leaves `position` as the one thing the week's rule has to give back: it
   is absolute there because a rectangle measured in pixels has to be out of the
   flow to be placed at all, and a grid item cannot be. Written as a child of
   this grid so it wins on specificity rather than on which of the two rules a
   5,000-line stylesheet happens to reach second. */
.mc-day__grid > .mc-day__sel {
  position: relative;
  /* THE BLOCK IS EXACTLY AS WIDE AS THE COURT IT IS ABOUT, and nothing about the
     words in it may change that. A grid item is otherwise at least as wide as
     content that will not squash — and the content here is two pills that refuse
     to wrap — so in a column narrow enough (5.5rem is the narrowest a court is
     ever drawn) the block would grow past the column's own edge and its border
     would be claiming ground the selection does not hold. Zeroed, the block
     takes the column and the pills spill a few pixels past it instead, which is
     the trade the week grid makes for the same type and for the same reason (see
     .wg__selrange), and the same one .wgb makes beside it. */
  min-width: 0;
}

/* AND IT IS A THING THAT CAN BE PICKED UP. A range that is the right shape in
   the wrong place is the commonest correction on this grid, so the block itself
   answers the pointer and drags — courts and hours together — to wherever the
   hand puts it (see blockDown).

   Which needs two things from here rather than from the script. The rectangle
   has to be pressable at all, which it is not by inheritance: .wg__sel is out of
   the pointer entirely, because on the week grid it is only ever a picture. And
   `touch-action: none` has to already be true of the element the finger comes
   down ON, before the gesture starts — a page that has begun scrolling cannot be
   talked out of it by preventDefault afterwards.

   Only while it is STANDING, which is the same condition the grips appear under
   and for the same reason: a rectangle still being dragged out has the hand on
   it already, and one that answered the pointer mid-drag would swallow the
   pointerenter of the cell under the cursor and stall the drag it is drawing. */
.mc-day__grid > .mc-day__sel.is-standing {
  pointer-events: auto;
  touch-action: none;
  cursor: grab;
}
.mc-day__grid > .mc-day__sel.is-moving { cursor: grabbing; }

/* And the cells underneath give up everything they would otherwise say for
   themselves: their ring, their hour, and the hairlines that rule one of them
   off from the next. All three are said by the block over them now, and a
   hairline showing through a wash this pale is exactly the subdivision the block
   exists to be rid of.

   They are still MARKED, and this is what marks them — without it the hover
   rules above would light one hour inside a standing selection and print its
   time across the caption of the block on top of it. */
.mc-day__cell.is-open.is-chosen,
.mc-day__cell.is-open.is-chosen:hover {
  background: var(--mc-open);
  box-shadow: none;
  color: var(--mc-muted);
  border-top-color: transparent;
  border-left-color: transparent;
}
.mc-day__cell.is-open.is-chosen .mc-day__cta { display: none; }
/* Except the keyboard's own place, which is not decoration: Enter twice is how a
   range is chosen without a pointer, and the second press has to land somewhere
   the reader can see. The ring is drawn UNDER the block's fill, which is the
   same accent at a sixth of its weight — so it reads through, the way a focused
   cell under the week's own rectangle does. */
.mc-day__cell.is-open.is-chosen:focus-visible {
  box-shadow: inset 0 0 0 2px var(--mc-accent);
}

/* What has been chosen, in words, beside the button that acts on it: "Court #1 ·
   6:00pm – 8:00pm". It stands in the actions row rather than under the grid so
   that the sentence and the button that commits to it are read together. */
.mc-day__chosen {
  /* Takes the room between Done and Reserve Now and centres what it says in it. */
  flex: 1 1 auto;
  text-align: center;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--mc-accent);
}
/* And what it says INSTEAD while a booking is being carried across the day:
   "Rescheduling Mode: ON". The same slot in the footer, because it is the same
   question — what is this panel doing right now — and a mode that is on has to
   out-say a selection that is merely standing. Mahogany rather than the accent,
   which is the one colour on this page that means the venue rather than the
   pointer. See month_calendar_controller's syncChoice. */
.mc-day__chosen.is-rescheduling {
  color: var(--mc-brand);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* --- the rescheduling mode, on either board ------------------------------- */

/* THE BOARD STEPS BACK AND THE BOOKING STEPS FORWARD, which is the legacy week
   grid's own answer to the same gesture (see .wg-moving) said about this grid:
   a press held on a block has entered a MODE, and the desk that did not mean to
   enter it has to be able to see that it has. Written against `.mc-day__grid`,
   so it dresses the day popup and the week board alike — the class goes on
   whichever grid the block was picked up off (see beginMove). Every other block — every other booking, and
   every hour the venue closed — goes half-strength, and the one in the hand is
   the only thing on the day at full strength, ringed in the accent.

   Written under the grid's class rather than on the block alone for the reason
   the week's is: the verified and unverified colours name a border colour of
   their own at the same weight, and the block being carried has to out-argue
   whichever of them it is wearing. Both classes go on and come off together (see
   beginMove and endMove), so there is no state this fails to describe. */
.mc-day__grid.is-rescheduling .wgb { opacity: 0.45; }
.mc-day__grid.is-rescheduling .wgb.is-moving {
  opacity: 1;
  border-width: 2px;
  border-color: var(--mc-accent);
  cursor: grab;
}

/* --- the week board --------------------------------------------------------
   THE DAY POPUP'S GRID, SEVEN TIMES ACROSS, and nearly all of it is that grid's
   own rules: the board wears `.mc-day__grid` and `.mc-day__scroll` and every
   cell, block, heading and chosen rectangle on it is a `.mc-day__*` (see
   month_calendar_controller's drawBoard, which draws one day or seven from one
   routine). What is here is only the four things a week has and a day does not —
   seven days' worth of columns, two bands over the court numbers (the weekday,
   and the date under it), a boundary where one day ends and the next begins, and
   a box tall enough to read in without the PAGE scrolling. */

.mc-week {
  /* How tall the band of dates is: the date, and the room the disc round today's
     needs to stand in. 1.8rem of circle with a little air either side of it,
     which is what a date alone asks for — it was 3rem while the maroon tab was
     tucked inside the heading, and the tab stands above the table now (see
     .mc-week__tabstrip below), so the row is back to the height of the thing in
     it. Named rather than repeated, because the dates freeze at exactly this
     much below the strip above them and the court numbers freeze at the two
     heights added, and a second copy of the number is how they come to
     disagree. */
  --mc-week-dayhead-h: 2rem;
  /* AND HOW TALL THE BAND OF WEEKDAYS OVER IT IS, which is deliberately less:
     it is the coarsest of the three names a column carries and the one a reader
     needs least often — the dates are what a day is chosen by — so it is a
     strip rather than a row, read as a heading FOR the numerals rather than as
     a second row of them. Named for the same reason the date's height is: the
     dates freeze at exactly this and the court numbers freeze at this plus the
     dates', and a second copy of the number is how the three come to disagree. */
  --mc-week-dowhead-h: 1.35rem;
  /* AND THE ROOM THE TAB STANDS IN. The board used to sit on the bar's own
     0.75rem, which is the gap every other card in the app keeps — but the tab
     hangs ABOVE the board's top line now (see .mc-week__tabstrip below), and
     1.1rem of it in a 0.75rem gap is a label touching the WEEKLY/MONTHLY toggle.
     So the week is dropped by the height of the tab and a little over: the bar's
     own gap is kept above the tab, and the tab is what fills the rest.

     ON THE BOARD RATHER THAN ON THE BAR, because the bar is not always what is
     directly above it: a customer with a court waiting to be paid for has the
     resume strip in between (see common/calendars/_month's `before_grid`), and a
     gap declared on the bar would push that strip down and leave the tab lying
     over it. Whatever the board's neighbour is, this is measured from it — and
     the two margins COLLAPSE, so what stands between them is this number rather
     than this number plus theirs.

     It costs the month nothing: the month surface is a different element and
     this one is not on the page at all while the month is up. And the tab moves
     with it — the band hangs off this wrapper's own top left corner, which a
     margin carries down and a padding would not. */
  margin-top: calc(0.75rem + var(--mc-todaytab-height) + 0.35rem);
}

/* Seven days of the venue's courts rather than one day's, which is the only
   thing this grid changes about .mc-day__grid's own columns. Its OWN variable
   and not --mc-day-courts: that one is set on the day popup's panel and is what
   the panel's width is worked out from, so a board seven days wide told through
   it would open a modal off the side of the screen. */
.mc-week__grid {
  /* An hour is a little shorter on the board than in the popup: seven days of
     them have to fit under the fold. */
  --mc-slot-height: 34px;
  grid-template-columns: var(--mc-day-time-col, 5.75rem)
                         repeat(var(--mc-week-cols, 7), minmax(5.5rem, 1fr));
  /* The three explicit rows on this grid: the strip of weekdays, the band of
     dates under it and, shorter than an hour, the court numbers under that.
     Every hour of the venue's day falls to .mc-day__grid's own grid-auto-rows,
     which is what keeps a row here exactly as tall as a row in the popup. */
  grid-template-rows: var(--mc-week-dowhead-h) var(--mc-week-dayhead-h) 1.6rem;
}

/* THE BOARD SCROLLS INSIDE ITS OWN BOX, both ways, and the page does not: seven
   days of courts is wider than any screen and eighteen opening hours are taller
   than most, and the two things that must stay where they are are the page
   (which must never scroll sideways) and the row under the board that takes a
   selection to the reservation form.

   The height is the week grid's own budget, not the popup's 58vh cap (see
   .wg-scroll, where the 15rem of page furniture above the grid is written out):
   this board stands on a page rather than in a panel, and a card that ends below
   the fold is a card whose Reserve Now has to be scrolled to. The extra 3rem is
   the row of actions under the scroller, which the popup pays for out of the
   panel and this pays for out of the same budget the footer line is paid out of
   — the board gives up the rows, not the reader. */
.mc-week__scroll {
  /* AND THE ROOM THE TAB TOOK COMES OUT OF THE SAME BUDGET, in the same words it
     was given in (see .mc-week's margin-top): the board was dropped to make room
     for the tab above it, and a budget that did not know it would end the card
     below the fold — which at 1280x900 it did, by ten pixels. The grid gives up
     the rows, not the reader.

     THE FURNITURE IS ONE NUMBER, named, because it is not the same number on
     every page or every screen: what stands above the board (navbar, the card's
     top, the bar's one row, the bar's gap) and under it (the board's 0.75rem
     foot, the card's bottom, the page's 2rem of air) — 13.3rem on the customer's
     desktop, measured at 1280x900 (181px over, 21px under in the card, 32px of
     page under that). The tab and its gap are added separately because they are
     the same words .mc-week's margin-top is written in. The bar's second row,
     the row of actions and the price line are no longer in it: the toggle rides
     the nav's row, the actions float over the board, and the rates and the key
     are in the poster (see player/_how_to_reserve). A card that ends a hand's
     width above the bottom of the screen is a budget that is still paying for
     furniture that has left. */
  --mc-week-furniture: 13.3rem;
  max-height: calc(100vh - var(--mc-week-furniture) - var(--mc-todaytab-height) - 0.35rem -
                   var(--mc-grid-footer, 0rem));
  /* THE DEVICE'S HEIGHT AS IT IS, not as it would be with the address bar out
     of the way: a phone's `100vh` is the viewport with the browser chrome
     hidden, which is taller than what is on screen while the bar is showing, and
     a budget taken out of that ends the card — and Reserve Now — under the fold.
     `dvh` is the height the reader actually has, bar in or out, and follows it
     as the bar comes and goes. The `vh` line above is the fallback where it is
     not understood; this one wins everywhere it is. */
  max-height: calc(100dvh - var(--mc-week-furniture) - var(--mc-todaytab-height) - 0.35rem -
                   var(--mc-grid-footer, 0rem));
  min-height: 10rem;
}
/* A phone stacks the bar — the toggle takes a row of its own under the nav (see
   .mc-weekbar--month's phone rule) — which is that row and the bar's gap over it
   on top of the furniture. */
@media (max-width: 640px) {
  .mc-week__scroll { --mc-week-furniture: 15.75rem; }
}
/* AND TWO REMS MORE OF IT ON THE DESK, because the desk's page has two rems more
   above the card: a page heading and the row of controls over the calendar,
   where the customer's landing puts the card almost at the top. The 15rem in the
   budget above is the WEEK GRID'S figure for the customer's page (see
   .wg-scroll), and a budget that errs low on one page and high on the other is
   a page that scrolls on the second — which on the desk it did, by nineteen
   pixels. Measured rather than guessed, and scoped to the id the rest of this
   file already scopes the desk's calendar by (see the day panel's width, above).

   The grid gives up the rows, not the reader: what this buys back is that the
   row of actions under the board — the sentence and Reserve Now — is on screen
   without the page moving. */
#admin-calendar .mc-week__scroll {
  /* The customer's 13.3rem, the desk's 0.75rem more over the card, and the key
     the desk still keeps under its board (0.6rem over a 1.25rem line) — derived
     from the customer's measurement rather than measured on the desk. */
  --mc-week-furniture: 15.9rem;
}
@media (max-width: 640px) {
  #admin-calendar .mc-week__scroll { --mc-week-furniture: 18.35rem; }
}

/* The chosen hours and the way on with them, under the board — the day popup's
   own row of actions (it wears .mc-modal__actions), minus the way out: there is
   no panel to leave here. Closer to the board than the popup's is to its grid,
   because it is inside a card rather than at the foot of a dialog. */
.mc-week__actions { margin-top: 0.5rem; }
/* AND IT FLOATS: a pill that stands OVER the board's last rows and keeps to the
   screen while the board is in view — sticky against the page, a rem off the
   foot of the viewport — so the sentence and Reserve Now are never under the
   fold whatever the device's height. The negative margin is what lifts it onto
   the board; the scroller underneath is given the same much bottom padding (see
   below) so the last hour can still be scrolled out from under it. It is only
   as wide as what is in it, and the spacer that pushed the button to the far
   right has no room to push in. Above the board's frozen headings (which take
   6 and 7) and the today frame (2). Written against its parent too, because
   .mc-modal__actions' own margin is declared further down this file and would
   win on order alone. */
.mc-week > .mc-week__actions {
  position: sticky;
  bottom: 1rem;
  z-index: 8;
  width: fit-content;
  max-width: 100%;
  margin: -4.25rem auto 0;
  padding: 0.5rem 0.5rem 0.5rem 0.9rem;
  gap: 0.75rem;
  background: #fff;
  border: 1px solid #999;
  border-radius: 6px;
  box-shadow: 0 4px 14px rgba(16, 24, 40, 0.18);
}
.mc-week__actions .mc-spacer { display: none; }
.mc-week__actions .mc-day__chosen { flex: 0 1 auto; }
/* The sentence wraps on a phone; the button does not. */
.mc-week__actions .btn { white-space: nowrap; }
.mc-week__scroll {
  padding-bottom: 4.25rem;
  /* The band under the last hour, where the pill lands: the grey the headings
     and the hour column are drawn in, rather than a blank run of white. */
  background: #f7f8fa;
}
/* And the board is closed off above that band — the cells draw their top and
   left lines only, so the last row needs a line under it — and stays white on
   the grey. The grip room the day popup's grid keeps at its foot is the band
   itself here. */
.mc-week__grid {
  background: var(--mc-open);
  padding-bottom: 0;
  border-bottom: 1px solid var(--mc-line-strong);
}
/* What the pill's negative margin takes out of the block's height — the pill is
   ~3.5rem in a 4.25rem lift — given back, so whatever stands under the board
   (the price line, the key) is measured from the board's foot and not from
   inside it. */
.mc-week { padding-bottom: 0.75rem; }

/* WHICH WEEKDAY, over the courts of it — the top tier of a three-tier heading,
   and QUIET: the same grey furniture the court numbers along the bottom of the
   heading are drawn in, three letters in caps at the muted ink. It names the
   dates rather than competing with them, which is the whole of what a weekday
   is doing on a band of seven CONSECUTIVE days: the shape of the week is what
   it gives, and a day is still chosen by its date.

   AND IT IS THINNER THAN THE DATES UNDER IT (see --mc-week-dowhead-h). Of the
   three names a column carries this is the coarsest and the least often looked
   for, so it takes the least of the board's height. The words are uppercased
   HERE rather than in the payload, which carries "Mon" for both boards to write
   as each of them likes (see month_calendar_controller's weekDowHead, and
   .wg__dow, which does the same).

   THE THREE TIERS SHARE ONE Z-INDEX and can, because they never overlap: each
   freezes at its own `top` — 0, then the strip's height, then the strip's plus
   the dates' — and the three bands stand edge to edge rather than on top of one
   another. What the number is for is everything else on the board: above the
   booking blocks (which take 1) and the selection's grips (which take 4), so a
   block sliding past goes under the heading rather than over it, and below the
   corner over the hour column (7), so a board scrolled sideways takes all three
   tiers under it together. */
.mc-week__dow {
  position: sticky;
  top: 0;
  z-index: 6;
  grid-row: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--mc-week-dowhead-h);
  background: #e9ebee;
  color: #4b5563;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* WHICH DATE, under the weekday and over the courts of it. The middle tier: it
   freezes under the weekday strip and the court numbers freeze under it
   (below), so a cell in the middle of a scrolled board still has its weekday
   and its date over it and its hour beside it. */
.mc-week__day {
  position: sticky;
  top: var(--mc-week-dowhead-h);
  z-index: 6;
  grid-row: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--mc-week-dayhead-h);
  background: #f7f8fa;
  border-bottom: 1px solid var(--mc-line-strong);
  color: var(--mc-muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
/* THE DATE, AND NOTHING ELSE ON THIS TIER — the week grid's own figure at the
   week grid's own size (see .wg__head .wg__dom). The weekday used to be written
   beside it, "SUN 16", and it has a band of its own above instead (see
   .mc-week__dow): two names in one cell made a row of small grey furniture that
   read as one thing, and split apart the dates are a row of numerals that reads
   at a glance under a band that says which days they are. What a screen reader
   is given is the WHOLE date, on this heading — the tier above is hidden from
   it, so the day is not said twice. */
.mc-week__dom {
  display: block;
  color: var(--mc-ink);
  font-size: 0.85rem;
  font-weight: 600;
  /* The heading centres it, but the DISC below is a box of its own with the
     figure inside it, and a box centred in the heading is not a figure centred
     in the box: without this, today's date sits against the left of its circle.
     The week grid gets it from .wg__head's own text-align and this is the same
     line said where this board keeps it. */
  text-align: center;
  letter-spacing: normal;
}
/* Today, in the cream the whole app marks it in — the month's own cell, the week
   grid's own column, the popup's own NOW row. */
.mc-week__day.is-today { background: var(--mc-today); }
/* And its date as a disc of the venue's mahogany, which is the mark the week
   grid puts on the same day (see .wg__head.is-today .wg__dom). A fixed square
   with its own line-height rather than padding, so the circle is a circle at any
   number of digits AND the heading it stands in is exactly as tall as the six
   beside it: a row of dates where one box is nine pixels deeper than the rest is
   a band that reads as seven things. */
.mc-week__day.is-today .mc-week__dom {
  color: #fff;
  background: var(--mc-brand);
  border-radius: 999px;
  width: 1.5rem;
  height: 1.5rem;
  line-height: 1.5rem;
  margin: 0 auto;
}
/* And the corner over the hour column spans all three rows of the heading: one
   word, "COURT", against a band that is three tiers deep here and one in the
   popup. */
.mc-week .mc-day__corner { grid-row: 1 / span 3; }
/* The court numbers are the THIRD tier and freeze under both bands above them —
   the weekday strip and the dates, added rather than a fourth number written
   out, so the three offsets cannot drift apart. */
.mc-week .mc-day__court {
  top: calc(var(--mc-week-dowhead-h) + var(--mc-week-dayhead-h));
}

/* WHERE ONE DAY ENDS AND THE NEXT BEGINS, said in the stronger grey — the same
   distinction the week grid draws between its own columns (see the .wg__cell
   boundary rule): the hairlines on this board are two different lines wearing
   one colour, the rule between COURTS inside a day and the boundary BETWEEN
   days, and only the second is worth drawing up. It rides on the first court of
   each day, whichever tier it is on: the weekday band, the date under it, the
   number under that and every hour below. */
.mc-week .is-day-start { border-left: 2px solid var(--mc-line-strong); }

/* A DAY THE VENUE DOES NOT OPEN ON, said once over the whole of its columns
   rather than by a hundred grey cells with nothing written on them. It is the
   week grid's own closed panel (.wg__closed) at this scale, in the same grey,
   for the same reason — and out of the pointer entirely, so the cells underneath
   go on being what they are rather than being covered by something that could be
   pressed. Below the headings and level with the blocks, which is where a thing
   that lies over the hours belongs. */
.mc-week__closedday {
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  background: var(--mc-reserved);
  border-left: 2px solid var(--mc-line-strong);
  color: var(--mc-reserved-ink);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* --- today, framed ---------------------------------------------------------
   The cream behind the heading and the disc round its date are both true, and
   neither survives the board being read at arm's length: cream over white is a
   shade rather than a boundary, and the disc is one mark at the top of a column
   a foot long. So today is also given an EDGE — a line over the heading, down
   both sides and along the foot of the last hour — and that is what says, from
   across the room, where the day begins and ends. It is the week grid's own
   frame (see .wg__head.is-today and .wg__todayframe, where the whole of the
   reasoning is), drawn on this board in the pieces this board is built from.

   Round the OUTSIDE and nowhere else. The hairlines between today's own courts
   and hours stay the hairlines every other day is ruled by: what is being drawn
   is the boundary of the day, not a box round each of its cells.

   IT TAKES FOUR PIECES, and the reason is the frozen headings. A single box
   over the whole column would have its top edge scroll up out of the scroller
   while the three rows of heading it belongs to stayed frozen at the top of it —
   a frame with the lid slid off. So the WEEKDAY BAND, which is the top tier,
   carries the top and its own two sides and travels with them; the date under it
   carries two sides; the court numbers carry the two sides where they stand, on
   the first court of the day and the last (see drawBoard, which marks them); and
   the overlay below carries the sides of the hours and the foot. Unscrolled they
   are one line, and scrolled they are a heading with a top and a column with
   sides, which is the honest picture of both. They meet squarely at every joint,
   all being borders drawn inside the same grid tracks. */
.mc-week .mc-week__dow.is-today {
  background: var(--mc-brand);
  color: #fff;
  border-top: 2px solid var(--mc-brand);
  border-left: 2px solid var(--mc-brand);
  border-right: 2px solid var(--mc-brand);
}
/* The second tier: the sides only. The top of the frame is on the band above,
   which is where the column now begins. */
.mc-week .mc-week__day.is-today {
  border-left: 2px solid var(--mc-brand);
  border-right: 2px solid var(--mc-brand);
}
/* The third tier. Written past .mc-week .is-day-start, which puts the stronger
   grey down the first court of every day: on today that boundary is the frame.
   (The two tiers above are written past it by the same rule, on the class the
   day heading itself wears.) */
.mc-week .mc-day__court.is-today-first { border-left: 2px solid var(--mc-brand); }
.mc-week .mc-day__court.is-today-last { border-right: 2px solid var(--mc-brand); }

/* And the hours: a grid item placed in today's columns and stretched down every
   row of the venue's day, which is what keeps it right without a measurement
   anywhere — it is the column by construction, at whatever width the board has
   been given, through a phone's sideways scroll and through every redraw,
   because it is part of the markup a redraw rebuilds.

   Empty and pointer-transparent: it lies over every cell in the column and not
   one of them may notice, or the day the board is most likely to be booked on
   would be the one day nothing on it could be pressed.

   z-index 2 is chosen three times over. It puts the frame above the cells and
   above the booking BLOCKS, which claim 1 and would otherwise cover the sides
   wherever a reservation takes the whole width of a court. It puts it above the
   panel that blanks a day the venue does not open on (.mc-week__closedday, also
   1), so a shut today is framed like any other — which is the one thing the week
   grid could not do from out here and had to draw on the panel itself (see
   .wg__closed.is-today-col). And it keeps the frame BELOW the frozen hour column
   at 5 and the three rows of heading above that, so a board scrolled sideways
   slides today under the hour labels exactly the way it slides everything else —
   and below the selection's grips at 4, because a handle that cannot be seen
   cannot be pulled. */
.mc-week__todayframe {
  position: relative;
  z-index: 2;
  pointer-events: none;
  border-left: 2px solid var(--mc-brand);
  border-right: 2px solid var(--mc-brand);
  border-bottom: 2px solid var(--mc-brand);
}

/* THE TAB THAT SAYS TODAY, standing on the board's top line over today's column
   — the week grid's own tab (.wg-tabstrip and .wg-todaytab, where the whole of
   the reasoning is written out) hung off this board's wrapper, which is a
   .mc-weekload like the week grid's and is positioned already for the spinner it
   centres. It used to be tucked inside today's heading, which cost the band of
   dates a row's worth of height it had nothing else to do with and put the word
   in the table rather than on it.

   ONE MEASUREMENT IS THIS BOARD'S OWN and it is the only thing here: the tab
   begins where the frozen hour column ends, and that column is this board's
   4.75rem rather than the week grid's --mc-time-col. Everything else — the drop
   until the tab's foot laps two pixels onto the heading's mahogany top border,
   the clipping that takes it under the hour labels along with the column it
   belongs to, and the mahogany it is drawn in — is the rule above, unchanged.
   The width and the sideways travel are JavaScript's, for the reason they are
   there: the column moves, and nothing out here follows it for free (see
   month_calendar_controller's placeWeekTodayTab). */
.mc-week__tabstrip { left: calc(1px + var(--mc-day-time-col, 5.75rem)); }
/* Not shown on this board any more: the weekday tier's own mahogany cell says
   which column is today (see .mc-week__dow.is-today). */
.mc-week__tabstrip { display: none; }

/* And the board goes dim while another week is on its way, exactly as the week
   grid's own does (see .mc-weekload, whose spinner this board also borrows): the
   going week fades and stops answering the pointer, so a press on a booking
   cannot open a panel onto a week that is being replaced. Named here because
   that rule is written against `.wg-scroll`, and this scroller is the day
   popup's. */
.mc-week.is-loading > .mc-week__scroll {
  opacity: 0.5;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.mc-week.is-loading > .mc-week__actions { opacity: 0.5; }

/* --- modal ---------------------------------------------------------------- */

.mc-modal {
  position: fixed;
  inset: 0;
  z-index: 1080;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.mc-modal[hidden] { display: none; }
.mc-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(16, 24, 40, 0.45);
}
/* The panel tracks Bootstrap's column widths — col-xs-12 col-sm-10 col-md-8
   col-lg-5 — at Bootstrap's own breakpoints, so it takes proportionally MORE of
   the screen the smaller that screen is: all of a phone, most of a tablet, two
   thirds from md, and a little over 40% on a laptop or bigger. The max-width is
   the one addition, so a 4K monitor does not get an absurdly wide form. */
.mc-modal__panel {
  position: relative;
  width: 100%;
  max-width: min(100%, 40rem);
  max-height: 92vh;
  overflow-y: auto;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 18px 45px rgba(16, 24, 40, 0.28);
  padding: 1.25rem;
}
@media (min-width: 576px) { .mc-modal__panel { width: 83.3333vw; } }
@media (min-width: 768px) { .mc-modal__panel { width: 66.6667vw; } }
@media (min-width: 992px) { .mc-modal__panel { width: 41.6667vw; } }
/* A panel carrying the GCash QR beside the form needs the extra third, so the
   form itself stays as wide as it is without one. Below lg the columns stack and
   the normal widths already fit. */
.mc-modal__panel.is-wide { max-width: min(100%, 60rem); }
@media (min-width: 992px) { .mc-modal__panel.is-wide { width: 66.6667vw; } }
/* The player's reservation modal is the widest thing the page opens: a form
   that is asking for a lot, and with a GCash QR beside it two columns of equal
   weight. So it takes two or three more of Bootstrap's spans than the curve
   above gives it, at every size with the room to spare — col-8 rather than
   col-5 on a laptop, col-10 rather than col-8 on a tablet, and col-10 rather
   than col-8 again once the QR is there. Below sm it was already the whole
   screen and there is nothing left to widen.

   Scoped to that one modal by the Stimulus target that opens it, so the
   confirmation panel shown afterwards — which has one short line to say — keeps
   the narrower curve rather than being dragged wide with it. */
#player-page [data-player-calendar-target="modal"] .mc-modal__panel {
  max-width: min(100%, 60rem);
}
@media (min-width: 768px) {
  #player-page [data-player-calendar-target="modal"] .mc-modal__panel { width: 83.3333vw; }
}
@media (min-width: 992px) {
  #player-page [data-player-calendar-target="modal"] .mc-modal__panel { width: 66.6667vw; }
}
#player-page [data-player-calendar-target="modal"] .mc-modal__panel.is-wide {
  max-width: min(100%, 76rem);
}
@media (min-width: 992px) {
  #player-page [data-player-calendar-target="modal"] .mc-modal__panel.is-wide { width: 83.3333vw; }
}
/* The admin's booking modal is two columns — the booking on the left, the GCash
   transaction on the right — so it keeps col-sm-10's share of the page at every
   size instead of narrowing as the screen grows, the way the player's
   single-column form does. Scoped to the admin page, and by id, so it wins over
   the widths above at every breakpoint without repeating them. */
#admin-calendar .mc-modal__panel { max-width: min(100%, 76rem); }
@media (min-width: 576px) { #admin-calendar .mc-modal__panel { width: 83.3333vw; } }
/* Unless the second column has nothing in it. A plain manual booking has no
   gateway to report and no code to scan, and neither has a settled one read by
   an ordinary admin — the PayMongo box is the super-admin's alone — so the
   width taken for two columns would be a screenful of white beside one. The
   panel then takes exactly the curve every other single-column form on the site
   takes, which is what the rules at the top of this section say; only the
   admin-scoped widths above have to be given back, and only where they apply.
   Below sm the columns stack and the panel is the width of the phone either
   way. Put on the modal by admin_calendar_controller#syncPanelWidth, which is
   the one place that knows what is standing over there. */
#admin-calendar .mc-modal.is-narrow .mc-modal__panel { max-width: min(100%, 40rem); }
@media (min-width: 768px) {
  #admin-calendar .mc-modal.is-narrow .mc-modal__panel { width: 66.6667vw; }
}
@media (min-width: 992px) {
  #admin-calendar .mc-modal.is-narrow .mc-modal__panel { width: 41.6667vw; }
}
/* And the details take the whole of that narrower panel rather than half of it.
   The columns are Bootstrap's, which know nothing about what was put in them: a
   col-sm-6 with an empty twin is still a half, so narrowing the panel alone
   would leave the booking's own fields squeezed into half of half and the blank
   space merely smaller. So the one column with something in it is widened to
   the full row and the empty one is taken out of the flow — which is only ever
   the second, since everything the payload can put on the right lives there. */
#admin-calendar .mc-modal.is-narrow .row > .col-sm-6:first-child { width: 100%; }
#admin-calendar .mc-modal.is-narrow .row > .col-sm-6:last-child { display: none; }

.mc-modal__panel h2 {
  font-size: 1.15rem;
  font-weight: 700;
  margin: 0 0 0.9rem;
}
/* MAKE A RESERVATION — the player's booking heading is the venue's own, so it
   takes the mahogany the "Mahogany Courts" title is written in, in capitals.
   Set here rather than in the string so the heading text stays one readable
   sentence in player_calendar_controller.js. */
#player-page .mc-modal__panel h2 {
  text-transform: uppercase;
  color: var(--mc-brand);
}
.mc-modal__actions {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-top: 1.1rem;
}
.mc-modal__actions .mc-spacer { margin-left: auto; }
/* Submit before the policies have been agreed to. It has to LOOK shut and still
   TAKE the click, because the click is how a player asks what is missing and the
   toast is the answer — so this is drawn by hand rather than with Bootstrap's
   own .disabled, which sets pointer-events: none and would swallow exactly the
   press worth answering. */
.mc-modal__actions .btn[aria-disabled="true"] {
  opacity: 0.65;
  cursor: not-allowed;
}

/* The day popup's Reserve Now, before anything is chosen: present, greyed and
   not pressable, so the row reads "Done … (pick something) … Reserve Now" from the
   first moment rather than a button appearing out of nowhere. */
.mc-modal__actions .btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: auto;
}
/* A button that has to be a form to be a DELETE (button_to). It is one button in
   the row and nothing else, so the form around it is given no size of its own. */
.mc-inline-form { margin: 0; }

/* --- the venue's weekly open play, as rows -------------------------------
   [days][start][end][×][status] per row, and under all five the note that says
   which day of the row could not be set and why (see
   common/modals/_open_play_week). ONE grid for the head and every row — each
   row is `display: contents`, so its cells sit in the container's columns and
   the head lines up with what is under it. */
.mc-weekrows {
  display: grid;
  grid-template-columns: auto 7.5rem 7.5rem auto 4.5rem auto auto 1.5rem;
  gap: 0.6rem 0.6rem;
  align-items: center;
  justify-content: start;
}
.mc-weekrow { display: contents; }
/* Keep the numeric fields from stretching, and the courts on one line. */
.mc-weekrow__num { width: 4.5rem; }
.mc-weekrow__price { width: 6.5rem; }
.mc-weekrow__courts { display: flex; gap: .25rem; white-space: nowrap; }
.mc-weekrow__courts .form-check { margin: 0; }
.mc-weekrow--head > span {
  font-size: 0.8rem;
  color: var(--bs-secondary-color);
}
/* The note runs the whole width, one line per day it has something to say
   about — `pre-line`, because the text is joined with newlines and nothing
   about it is HTML. */
.mc-weekrow__note {
  grid-column: 1 / -1;
  white-space: pre-line;
}
/* A ticked day, in the venue's own mahogany — the same fill the view toggle
   wears when it is the one that is pressed. */
.mc-weekrow__days .btn-check:checked + .btn {
  background: var(--mc-brand);
  border-color: var(--mc-brand);
  color: #fff;
}
.mc-weekrow__status {
  text-align: center;
  font-weight: 600;
}
.mc-weekrow__status.is-ok { color: var(--bs-success); }
.mc-weekrow__status.is-bad { color: var(--bs-danger); }
/* The panel: wide enough for the eight columns, sized to them rather than past
   them — the rows pack left (justify-content: start), so a wider panel would
   only add empty gutter. */
#admin-calendar .mc-modal__panel.mc-weeksetup__panel { max-width: min(100%, 64rem); }
/* On a phone the eight columns will not fit: each row stacks and the head goes.
   The numeric inputs' placeholders (Slots / Price) name them with the head gone. */
@media (max-width: 640px) {
  .mc-weekrows { display: block; }
  .mc-weekrow { display: block; padding: .6rem 0; border-top: 1px solid var(--bs-border-color); }
  .mc-weekrow--head { display: none; }
  .mc-weekrow > * { margin-bottom: .4rem; }
  .mc-weekrow__num, .mc-weekrow__price { width: auto; display: inline-flex; }
}

/* --- agreeing to the court policies ---------------------------------------
   One sentence across the foot of the form rather than a field in the column
   above it, so it is centred as a sentence: the box rides in the flow of the
   text instead of floating off to the left of it, which is what keeps the whole
   thing in the middle on a phone, where it takes two lines. */
.mc-agree {
  margin-top: 1rem;
  text-align: center;
}
.mc-agree .form-check {
  display: block;
  padding-left: 0;
  margin-bottom: 0;
}
.mc-agree .form-check-input {
  float: none;
  margin: 0 0.4rem 0 0;
  vertical-align: -0.15em;
}
/* Inline, against Bootstrap's inline-block label: an inline-block cannot break
   across lines, so the sentence would drop whole to the line under the box
   instead of starting beside it. */
.mc-agree .form-check-label {
  display: inline;
  font-size: 0.88rem;
}
/* The link is a name, so it wraps as one rather than leaving "Court" at the end
   of a line and "Policies" at the start of the next. */
.mc-agree a { white-space: nowrap; }
/* "(REQUIRED)" — said in the venue's own voice, the way every other insistence
   on this page is said: shouted in the styling rather than in the sentence, so
   what the label READS as text stays the plain English a screen reader gets. */
.mc-agree__required {
  color: var(--mc-muted);
  font-weight: 700;
  text-transform: uppercase;
}
/* --- the boxed sections of a booking modal (Details, proof of payment) ----- */

.mc-box {
  margin-top: 1rem;
  padding: 0.85rem 0.9rem 0.95rem;
  border: 1px solid var(--mc-line);
  border-radius: 10px;
  background: #fbfcfd;
}
.mc-box legend {
  float: none;
  width: auto;
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--mc-muted);
  margin-bottom: 0.4rem;
}
/* The field labels inside a box are the bold ones: Ref. Number, Amount Paid,
   Screenshot. Labels outside (name, hours, courts) keep Bootstrap's weight. */
.mc-box .form-label {
  margin-bottom: 0.2rem;
  font-weight: 700;
}
.mc-required { color: #b42318; }

/* The booking, as one table: the two boxes that are typed on the top rows and
   the four values they add up to underneath, labels left and values right, so
   every row lines up on the same two columns. */
.mc-details {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: center;
  gap: 0.35rem 0.6rem;
  margin: 0;
  font-size: 0.88rem;
}
/* The label of a typed row is a <label>, and has to sit exactly where the plain
   ones do rather than carrying Bootstrap's own spacing. */
.mc-details dt .form-label {
  margin: 0;
  font-weight: inherit;
  color: inherit;
  font-size: inherit;
}
/* A number that never runs past two digits does not need a box the width of the
   panel; it lines up with the values under it instead. */
.mc-details .form-control {
  max-width: 6.5rem;
  padding-top: 0.15rem;
  padding-bottom: 0.15rem;
}
/* The rows that are typed WORDS rather than counted things — the name and the
   phone number — need the width the counts do not, so they take the column.
   Same rule for the +63 group, whose own box is inside it. */
.mc-details .mc-details__text { max-width: none; width: 100%; }
.mc-details .mc-details__text .form-control { max-width: none; }
/* A typed row and the rate that prices it: the box keeps its own narrow width
   and the rate sits beside it, where it reads as an annotation on the number
   being typed rather than as part of the question in the label. Wraps under the
   box on a narrow phone rather than squeezing it. */
.mc-details__field {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.15rem 0.5rem;
}
.mc-details__rate {
  font-weight: 400;
  color: var(--mc-muted);
  font-size: 0.82rem;
  white-space: nowrap;
}
/* Which courts, as one tick box per court on one line. Bootstrap's inline form
   check carries a right margin meant for a form laid out in rows; in a two-column
   details table it pushes the last box out of its cell, so the spacing is the
   row's own gap instead. The label sits with its box and never wraps away from
   it — "Court 1" split across two lines reads as two answers. */
.mc-courts { gap: 0.15rem 0.9rem; }
.mc-courts__choice { margin-right: 0; }
.mc-courts__choice .form-check-label { white-space: nowrap; }
/* The rules between the table's groups. Full width of the grid, and the same
   hairline every other border in the app is drawn in — a divider that is darker
   than the box it is inside reads as a cut rather than as a pause. */
.mc-details__rule {
  grid-column: 1 / -1;
  margin: 0.4rem 0;
  border: 0;
  border-top: 1px solid var(--mc-line);
  opacity: 1;   /* Bootstrap's reboot fades an <hr>; this one is already faint */
}
.mc-details dt {
  font-weight: 600;
  color: var(--mc-muted);
}
.mc-details dd {
  margin: 0;
  font-weight: 600;
  color: var(--mc-ink);
  white-space: nowrap;   /* "August 8, 2026" is one line, never two */
}
.mc-details .mc-amount { font-weight: 800; }
/* The footnote under the gateway box, explaining why the panel it is in cannot
   be typed into. Ruled off from the details above it, so it reads as a note
   about the box rather than as one more row of it. */
.mc-payment__note {
  margin: 0.7rem 0 0;
  padding-top: 0.6rem;
  border-top: 1px solid var(--mc-line);
}

/* A state, said as a tag rather than as a word in a sentence: Bootstrap's badge
   in shape and weight, but square, because everything else on these pages is
   drawn with corners and a pill would be the only thing on the card pretending
   to be a button. One base class and a modifier per state, so a second tag is a
   colour rather than a new shape. */
.mc-tag {
  display: inline-block;
  padding: 0.2em 0.55em;
  border: 1px solid transparent;
  border-radius: 3px;
  font-size: 0.78em;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
  vertical-align: 0.05em;
}
/* Amber: the same colour the grids draw a booking nobody has checked the money
   for, which is exactly what this is. */
/* The chevrons that page between one reader's reservations on a session, on the
   left and right edges of the open-play payment dialog. Positioning only — the
   button itself is the ordinary outline button this app draws everywhere else.
   Overlapping the panel edge rather than inside it, so the card underneath is
   not narrowed by two controls that are usually not there at all. */
.mc-modal__panel { position: relative; }
/* The month bar's circle (see .wg-chev--inline), fixed in the gutter beside the
   dialog. */
.mc-modal__nav,
.mc-modal__nav:active {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  opacity: 1;
}
.mc-modal__nav:active { transform: translateY(-50%) scale(0.94); }

/* The dialog's pair only: black with a white mark, brand brown under the
   pointer. The glyph is nudged up a hair so it sits on centre. */
.mc-modal__nav {
  background: #111;
  border-color: #111;
  color: #fff;
  padding-bottom: 0.15em;
}
.mc-modal__nav:hover,
.mc-modal__nav:focus-visible {
  background: var(--mc-brand);
  border-color: var(--mc-brand);
  color: #fff;
}
/* In the gutter beside the panel: half the viewport minus half the panel's
   width (see .mc-modal__panel) minus the button and a breath. */
.mc-modal__nav--prev { left: max(0.5rem, calc(50% - min(50%, 20rem) - 3.5rem)); }
.mc-modal__nav--next { right: max(0.5rem, calc(50% - min(50%, 20rem) - 3.5rem)); }

/* The same tag, as a control. The desk's open-play register makes each status
   pill a button that opens that reservation's own receipt, so the only thing
   added here is what a <button> would otherwise lose or impose of its own. */
button.mc-tag {
  font: inherit;
  font-size: 0.78em;
  font-weight: 700;
  cursor: pointer;
}
button.mc-tag:hover,
button.mc-tag:focus-visible { filter: brightness(0.95); }

.mc-tag--unpaid { background: #fdf1c4; border-color: #e0c24e; color: #6b4e00; }
/* Money that came in and went back out again — the venue refunded it at
   PayMongo and said so here (see GatewayRefundConfirmation).

   THE SAME YELLOW AS UNPAID, and that is the choice rather than an economy. The
   three colours on this page mean settled, still moving, and came to nothing,
   and a refund is none of the three: it is a transaction that is over with no
   money left in it, which is exactly what yellow already says about a court
   nobody has paid for. Green would be a lie, red is the palette of an ending
   somebody suffered — an expiry, a refusal — and this is neither. So the tag is
   told apart from Not paid by its WORD, which is the honest place for the
   difference: two states that mean "the venue is not holding this money" read
   the same at a glance and say which is which on the second look. */
.mc-tag--refunded { background: #fdf1c4; border-color: #e0c24e; color: #6b4e00; }
/* Green, the colour both grids draw a booking whose money is settled. */
.mc-tag--paid { background: #d9f2e3; border-color: #94d3b3; color: #14603c; }
/* Red: the only one of the three that is not on the way anywhere. */
.mc-tag--expired { background: #fbe3e1; border-color: #e39a94; color: #8a1c11; }
/* Grey, and deliberately none of the three above: a booking being written down
   has no money question yet, and a colour that means something about a payment
   would answer one nobody has asked. The grid's own reserved palette, so the
   neutral here is the neutral this app already draws. */
.mc-tag--new { background: #eef0f2; border-color: var(--mc-reserved-line); color: var(--mc-reserved-ink); }
/* Not a payment state at all: the venue closed this court and there is nothing
   to pay for. The closed-day grey, so the tag and the block on the grid are
   plainly the same fact. */
.mc-tag--closed { background: #ededed; border-color: var(--mc-line-strong); color: var(--mc-muted); }

/* --- the booking reference (MC-10059) --------------------------------------
   The player's copy, on the panel that goes up when a booking is taken. It is
   there to be photographed, so it is the biggest thing on the panel, in the
   venue's mahogany, with the digits spaced far enough apart to be read back off
   a phone screen — and it sizes itself down on a narrow one rather than
   wrapping mid-reference. */
.mc-reference {
  text-align: center;
  padding: 0.9rem 1rem 1rem;
  border: 1px solid var(--mc-line);
  border-radius: 10px;
  background: #fbfcfd;
}
.mc-reference__label {
  margin: 0;
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--mc-muted);
}
.mc-reference__id {
  margin: 0.2rem 0 0.35rem;
  font-size: clamp(1.9rem, 9vw, 2.75rem);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: 0.05em;
  color: var(--mc-brand);
  white-space: nowrap;
}
.mc-reference__note {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--mc-ink);
}

/* The admin's copy, IN the edit modal's heading: "Booking MC-10181". The string
   an admin scans for while holding a player's screenshot against it, which is
   why it is the heading rather than a row under one — the number is what the
   panel is about, and the word in front of it only says what kind of thing the
   number names. Not a field: it is derived from the booking's id and there is
   nothing to type. A booking being entered has no id yet, so the chip is hidden
   and the heading stands as its own sentence. */
.mc-refno__id {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.1rem 0.45rem;
  border: 1px solid var(--mc-line);
  border-radius: 6px;
  background: #fff;
  font-size: 1.05rem;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--mc-brand);
}
.mc-refno__id[hidden] { display: none; }

/* Whether the money arrived, on the row under what was owed — the tag, the
   Verified button that judges it, and the sentence saying why that button
   cannot be pressed. The row wraps so the hint drops under the two controls in
   a narrow panel rather than squeezing them. The tag brings its own colours
   from .mc-tag, which is the customer receipt's vocabulary and must stay the
   one this says it in. */
.mc-status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
}
/* And the button is cut to the tag's height rather than the other way round.
   The two stand against each other on one row saying two halves of one thing —
   what the money did, and whether anybody has checked — and a btn-sm is half
   again as tall as a tag, which read as one control beside a label rather than
   as a pair. The tag is the reference because it is the customer's own
   vocabulary (see .mc-tag, and bookings/_receipt): its size is a fact this row
   borrows and must not restate.

   So the four things that make a height are taken from it exactly — the type
   size, the leading, the padding and the one-pixel border the tag already
   draws — and the corner radius with them, which is what stops a matched pair
   still reading as two families. Nothing else moves: it is the same button in
   the same place with the same classes, so btn-success and btn-outline-secondary
   go on saying which state it is in (see setVerified), disabled goes on looking
   disabled, and it is still what the keyboard lands on. Written against
   .mc-status .btn rather than a class of its own, because the row has exactly
   one button and a class would have to be kept in step in two files. */
.mc-status .btn {
  font-weight: 700;
  font-size: 0.78em;
  line-height: 1.2;
  padding: 0.2em 0.55em;
  border-radius: 3px;
}

/* The attached screenshot, as a thumbnail that opens full size in a new tab. */
/* The picture is the proof, so it is shown at a size the transfer can be read
   at rather than as a 92px chip — still a link to the full-size original in a
   new tab, with the filename, Remove and the box that replaces it underneath
   it, in that order. */
.mc-proof__shot { display: block; }
.mc-proof__shot[hidden] { display: none; }
.mc-proof__shot a { display: block; }
.mc-proof__shot img {
  display: block;
  max-width: 100%;
  max-height: 20rem;   /* its own shape, just never taller than the box */
  border: 1px solid var(--mc-line);
  border-radius: 8px;
  background: #fff;
}
.mc-proof__shot a:hover img { border-color: var(--mc-accent); }
.mc-proof__meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.4rem;
}
.mc-proof__meta .mc-spacer { margin-left: auto; }

/* Verified: one button in two states, in the box with the proof it judges. */
/* --- the venue's GCash QR, beside the player's reservation form ------------ */

/* The QR takes the full height of the form beside it rather than floating small
   at the top of it. Bootstrap already stretches the column to the row's height;
   these rules hand that height down — column to aside to the image. All of it
   here, so the markup carries nothing but the grid. The QR is the second of the
   row's two halves, which is what :last-child picks out. */
#player-page .mc-modal__panel .row > .col-lg-6:last-child {
  display: flex;
}
.mc-qr {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  text-align: center;
}
/* The form is what sets the height of the row; the QR follows it and must never
   extend it. A tall portrait QR would otherwise be the taller of the two columns
   and push the modal down past what the form alone needs, so once the two are
   side by side the aside is lifted out of the flow: the column then contributes
   no height of its own, Bootstrap stretches it to whatever the form comes to,
   and the image scales down inside that. Below lg the row stacks, the aside goes
   back into normal flow, and it is the only thing setting its own height. */
@media (min-width: 992px) {
  #player-page .mc-modal__panel .row > .col-lg-6:last-child {
    position: relative;
  }
  #player-page .mc-modal__panel .row > .col-lg-6:last-child > .mc-qr {
    position: absolute;
    inset: 0;
    padding: 0 calc(var(--bs-gutter-x) * 0.5);
  }
}
/* The image is the only thing in the column now, so it takes all of it — scaled
   to fit rather than stretched, so the QR keeps its shape. That is what caps it:
   the column is taller than it is wide, so the QR grows to the column's width
   and the leftover height is empty space above and below it. flex-basis stays
   auto, so when the row stacks below the lg breakpoint and there is no spare
   height to grow into, the image is simply its own size. */
.mc-qr__image {
  flex: auto;
  min-height: 0;
  width: 100%;
  object-fit: contain;
  border: 1px solid var(--mc-line);
  border-radius: 10px;
  background: #fff;
  padding: 0.4rem;
}

/* --- the venue's uploads on the settings page ------------------------------
   A preview of what is stored now, beside what it is for and a Remove button.
   The QR and the logo sit in a square box — contained, not cropped, so a wide
   wordmark still fits whole; the court policy is a portrait page, so it is
   sized by its height and keeps its own aspect ratio instead. */

.mc-upload__current {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
}
.mc-upload__current[hidden] { display: none; }
.mc-upload__current img {
  border: 1px solid var(--mc-line);
  border-radius: 8px;
  background: #fff;
  padding: 0.25rem;
}
.mc-upload__current a:hover img { border-color: var(--mc-accent); }
.mc-upload__square {
  width: 108px;
  height: 108px;
  object-fit: contain;
}
.mc-upload__page {
  height: 150px;
  width: auto;
  max-width: 130px;
  object-fit: contain;
}

/* --- how to reserve --------------------------------------------------------
   The poster that opens over the calendar on a first visit, and the ? on the
   corner of the calendar's card that brings it back. It covers the viewport, so
   nothing behind it can be clicked, and the page under it is blurred for as long
   as it is up. */

.mc-blurred {
  filter: blur(6px);
  pointer-events: none;
  user-select: none;
}

.mc-splash {
  position: fixed;
  inset: 0;
  z-index: 1090;   /* over the booking modal, which is 1080 */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  /* Every part of it is the way out — see splash_controller#close — so every
     part of it is drawn as something to click. */
  cursor: pointer;
}
/* It is a flex box, so the browser's own [hidden] rule has to be said again to
   win. Hiding rather than removing is what lets the ? put it back. */
.mc-splash[hidden] { display: none; }
.mc-splash__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(16, 24, 40, 0.55);
}
.mc-splash__panel {
  position: relative;
  width: 100%;
  max-width: min(100%, 34rem);
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 18px 45px rgba(16, 24, 40, 0.35);
  padding: 1.25rem;
}
/* The poster is portrait and taller than a phone: it scrolls inside the panel
   rather than being shrunk until the steps on it cannot be read. */
.mc-splash__scroll {
  overflow-y: auto;
  border: 1px solid var(--mc-line);
  border-radius: 8px;
  background: #fbfcfd;
  padding: 0.5rem;
}
.mc-splash__image {
  display: block;
  margin: 0 auto;
  max-width: 100%;
  height: auto;
}
/* The foot of the poster: the hourly rates and the key to the board's colours
   (see player/_how_to_reserve). Outside the scroller, so it is read whatever
   the poster is scrolled to, and never squeezed by it. */
.mc-splash__foot {
  flex: 0 0 auto;
  text-align: center;
}
/* A shade smaller than under the wide card, so the sentence is one line in a
   34rem panel. */
.mc-splash__foot .mc-rates { font-size: 0.78rem; }

/* The ? that puts the poster back, in the well's top corner past the end of the
   legend. Pinned rather than laid out — the well is positioned for exactly this,
   and the week bar keeps its whole layout whatever the viewport does, so nothing
   here can crowd the navigation or shove the legend along. It used to ride the
   band of top padding the logo disc was given; that band is gone with the disc,
   so it stands level with the week bar's first row now and the bar carries a
   gutter on its right for it (see #player-page .mc-weekbar).

   Deliberately quiet: it is there for the one player in twenty who wants it,
   and the other nineteen should read it as a mark on the card rather than a
   control to be dealt with — so it is drawn in the legend's own muted grey on
   the card's own white, and only takes the brand when it is pointed at. */
.mc-well > .mc-help {
  position: absolute;
  /* Centred on the nav's row: 1.5em of card top + half of a 2.5rem chevron,
     less half of this 2rem mark. */
  top: 1.75rem;
  right: 1.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--mc-line);
  border-radius: 50%;
  background: #fff;
  color: var(--mc-muted);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
.mc-well > .mc-help:hover,
.mc-well > .mc-help:focus-visible {
  background: var(--mc-brand);
  border-color: var(--mc-brand);
  color: #fff;
}

/* --- sign in -------------------------------------------------------------- */

.mc-signin {
  max-width: 25rem;
  margin: 3.5rem auto;
  padding: 0 1rem;
}
.mc-signin__card {
  background: #fff;
  border: 1px solid var(--mc-line);
  border-radius: 12px;
  padding: 1.5rem;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
}

/* --- paying through the gateway --------------------------------------------
   Everything the PayMongo flow put on screen that manual capture never needed:
   the note where the proof boxes used to be, the panel a player waits behind on
   the way out, and the pages they come back to. */

/* The note that replaces PROOF OF PAYMENT in the booking modal. It is prose, not
   fields, so it does not get the bold field labels the other boxes do. */
.mc-box--gateway .mc-gateway {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.45;
  color: var(--mc-ink);
}

/* A panel with one sentence on it has no business being as wide as the form it
   replaced. */
/* Reschedule to: [ date ][ time ]. Two boxes on one line, wrapping under each
   other on a narrow phone rather than squeezing to nothing. The date takes the
   room it needs and the time takes what a "12:30 PM" needs. */
.mc-reschedule { margin-top: 1rem; }
.mc-reschedule__inputs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}
.mc-reschedule__inputs .form-control { flex: 1 1 11rem; min-width: 9rem; }
.mc-reschedule__inputs .form-select { flex: 0 1 9rem; }
/* The rule above shortens every .form-control inside a details table, and a
   <select> in one has to be the same height as the boxes beside it or the Set
   Open Play row reads as three controls from two different forms (see
   common/modals/_open_play_form, the only place a select stands in one). Said
   here rather than on that row, because the mismatch is this table's making. */
.mc-details .form-select {
  padding-top: 0.15rem;
  padding-bottom: 0.15rem;
}
/* The one details table in the app whose values are allowed to wrap. The nowrap
   on .mc-details dd is there so "August 8, 2026" is never broken across two
   lines, and every row it was written for is short by construction; this one
   carries a whole appointment on a single row — "(Tuesday) August 18, 2026,
   5:00pm - 7:00pm" — inside a panel that is deliberately slim, which is three
   times the width there is. Wrapped it reads; nowrap it runs off the card. */
.mc-reschedule__details dd { white-space: normal; }
/* Switch Courts: the panel's own tick boxes, standing on their own. In the
   booking panel they sit in a details table and take their row from
   .mc-details__field; here there is no table under them, so the row is said
   again — the spacing itself still comes from .mc-courts, which is what keeps
   the two surfaces one shape. */
.mc-reschedule__courts {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
/* Switch Courts, on the customer's own copy of the dialog, standing clear of the
   two boxes above it. The desk's version runs the two questions together because
   an admin moving a booking is working down a form they use all day; a customer
   meets this once, in the minute after paying, and the gap is what stops the
   tick boxes reading as part of the answer to "when". A whole number of pixels
   rather than an em, because what is being set is a gap between two questions
   rather than a space in a paragraph. */
.mc-reschedule__switch { margin-top: 20px; }
/* And the countdown under them: it is a note about the offer rather than a field
   of it, so it takes the quiet size .mc-sub gives everything of its kind and
   keeps a line of its own above the buttons. */
.mc-reschedule__window { margin: 0.6rem 0 0; }
/* A dialog whose window has run out. Everything in it is properly `disabled` —
   there is nothing left to ask, so unlike the button that opened it there is no
   press worth taking — and the note that says so is what the reader is left
   looking at. */
.mc-reschedule.is-closed .form-label { opacity: 0.65; }

/* A question asked OVER a panel that is already open, so it has to sit above it
   and dim it the way that panel dims the page. */
.mc-modal--over { z-index: 1090; }
/* A dialog asked FROM one of the --over panels (the customer's reschedule,
   opened off their booking while the receipt may be up): one layer higher
   again, so it is never under the panel it was opened from. */
.mc-modal--top { z-index: 1100; }

.mc-modal__panel--slim { max-width: min(100%, 28rem) !important; width: auto !important; }

/* Something is happening elsewhere and this is the line that says so: a spinner
   and a sentence, on one row, vertically centred against each other. The same
   pair serves the "taking you to GCash" panel and the "confirming your payment"
   line on the page they come back to. */
.mc-redirect {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 0.75rem;
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--mc-ink);
}
/* It is a flex row, so the browser's own [hidden] rule has to be said again to
   win — the panels that put a wait in front of their content take it away
   again when the content arrives. */
.mc-redirect[hidden] { display: none; }

/* --- waiting, with nothing to read -----------------------------------------
   What a panel shows while what goes in it is on its way: THE SHAPE IT WILL BE,
   empty, with one spinner in the middle of it. No sentence.

   It replaces a line of text with a spinner beside it (.mc-redirect above, which
   is still what the PAGE-level waits use — "taking you to GCash", "confirming
   your payment" — because those are about something happening elsewhere and are
   worth a sentence). Inside a panel the sentence was never worth reading: it is
   on screen for a few hundred milliseconds, it says what the reader has just
   asked for, and it is a different shape from the thing that replaces it, so the
   panel jumps when the answer lands. A box of the right size with a spinner in
   the middle says the same thing, in the place the answer will appear, and does
   not move when it does.

   The min-height is the whole point and is why there are two of them: a panel
   that collapses to a heading and a button while it waits is the jump this
   exists to stop. `--tall` is the day popup, whose courts-by-hours grid is most
   of a screen.

   ERRORS STILL SPEAK. `.mc-loading__text` is the same element carrying a
   sentence instead — "That day could not be opened" — with the spinner taken
   away beside it, because a panel that has stopped waiting and has nothing to
   show has to say why. It is hidden whenever there is nothing to say. */
.mc-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 11rem;
  margin: 0;
}
.mc-loading[hidden] { display: none; }
/* The day popup, whose courts-by-hours grid is most of a screen: the waiting box
   is exactly the height the scroller will be, and the scroller stands aside
   while it is up. Both halves matter — a box the right size ADDED to an empty
   scroller is a panel that shrinks when the hours land, which is the same jump
   the other way round. The scroller is a LATER sibling of this
   box — the key to the grid's colours stands between the two — which is what the
   combinator leans on (see common/modals/_day). */
.mc-loading--tall { min-height: var(--mc-day-scroll-max, 30rem); }
/* And the two shared booking panels, whose heights are the sum of what they draw
   — a reference block and a details table for one, the venue's letterhead over
   both for the other. They cannot be exact: a booking with no paddles has one
   row fewer, and a venue that has uploaded no logo gets its name in text where
   the mark would be. These are the ordinary case measured, which is as close as
   a box can be to something it has not been told yet. */
.mc-loading--panel { min-height: 21rem; }
.mc-loading--receipt { min-height: 39rem; }
.mc-loading--tall:not([hidden]) ~ .mc-day__scroll { display: none; }
/* The same spinner the rest of the app turns, at the size a thing standing alone
   in the middle of a panel has to be — the 1.1rem one is drawn to sit beside a
   line of text. */
.mc-spinner--lg {
  width: 2rem;
  height: 2rem;
  border-width: 3px;
}
.mc-loading__text {
  color: var(--mc-muted);
  font-size: 0.92rem;
  text-align: center;
}
.mc-loading__text[hidden] { display: none; }
/* Standing in the receipt's action row where Generate QR stood a moment ago:
   no bottom margin, so the row keeps the shape the button gave it. */
.mc-modal__actions .mc-redirect { margin: 0; }
.mc-spinner {
  flex: 0 0 auto;
  width: 1.1rem;
  height: 1.1rem;
  border: 2px solid var(--mc-line);
  border-top-color: var(--mc-brand);
  border-radius: 50%;
  animation: mc-spin 0.8s linear infinite;
}
@keyframes mc-spin { to { transform: rotate(360deg); } }
/* The same spinner, sitting inside a button while it waits on the server: small
   enough not to change the button's height, and drawn in the button's own ink
   rather than the venue's mahogany, which would disappear against the blue. */
.mc-spinner--button {
  width: 0.85rem;
  height: 0.85rem;
  border-width: 2px;
  border-color: rgba(255, 255, 255, 0.45);
  border-top-color: #fff;
  display: inline-block;
  vertical-align: -0.12em;
  margin-right: 0.45rem;
}
/* Still turning, because it is the only thing saying the page is alive — just
   slowly enough not to be movement anyone has to look away from. */
@media (prefers-reduced-motion: reduce) {
  .mc-spinner { animation-duration: 3s; }
}

/* --- a week on its way -----------------------------------------------------
   Moving between weeks is one week giving way to the next, so the week already
   on screen stays where it is and goes dim under the same spinner everything
   else in the app waits behind. It used to be a sentence on the status line,
   which is the wrong place to say it: the line is under the bar and the reader
   is looking at the grid, and a page that answers "is anything happening?"
   somewhere other than where the change will appear is not answering it.

   The wrapper is the box the wait is measured against — see
   shared/_calendar_shell for why it is out here rather than in the scroller.

   THREE SURFACES WEAR IT NOW and they share only the positioning and the
   spinner: the legacy week grid, whose dimming is the rules directly below; the
   month surface, which dims as one box; and the week board, which has dimming of
   its own because its scroller is a `.mc-week__scroll` rather than a `.wg-scroll`
   (see .mc-week.is-loading). One wait, said the same way in all three. */
.mc-weekload { position: relative; }

/* Out of reach as well as dimmed. A stale week is still a week full of
   buttons, and a booking pressed while the next week is landing would open a
   panel onto the week that is going. The fade is what keeps a load too quick
   to read from registering as a flinch.

   The tab over today's column fades with it, being the going week's own mark
   and not the wrapper's: a label left at full strength over a week that has
   gone pale is the one thing on the card claiming to be current. It has
   nothing to put out of reach — there was never anything on it to press. */
.mc-weekload > .wg-scroll,
.mc-weekload > .wg-tabstrip { transition: opacity 0.15s ease; }
.mc-weekload.is-loading > .wg-scroll {
  opacity: 0.5;
  pointer-events: none;
}
.mc-weekload.is-loading > .wg-tabstrip { opacity: 0.5; }

/* The chevrons go with it, and unlike the tab they have something to put out of
   reach. A press on one while the next week is landing is a second week asked
   for on top of the one already in the air — or, worse, a scroll driven against
   a grid that is about to be replaced under it. They come back the instant the
   week does, which on a load quick enough to read is no time at all. They are
   dimmed further than the week is because they are chrome: the reader should be
   watching the grid. The fade needs no rule of its own here: .wg-chev already
   carries a transition on opacity for the hover, and one is all this wants. */
.mc-weekload.is-loading > .wg-chev {
  opacity: 0.35;
  pointer-events: none;
}

/* Over the middle of whatever is behind — an empty grid on the first load,
   last week's on every one after — and never in the way of it: the scroller
   keeps the whole of the pointer, which matters on the frames either side of a
   wait rather than during one. Faded in and out with the dimming it belongs
   to, and taken out of the accessibility tree between times, so the live
   region inside speaks once per wait rather than sitting there mid-sentence. */
.mc-weekload__wait {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.15s ease, visibility 0.15s;
}
.mc-weekload.is-loading .mc-weekload__wait {
  opacity: 1;
  visibility: visible;
}

/* --- the QR Ph code, in the dialog Pay opens -------------------------------
   The whole payment, on the venue's own page: a code, the name and the amount it
   is drawn for, and the clock it is good for. Centred, because a QR is a picture
   to point a phone at and everything else in the panel is a caption to it.

   (Distinct from .mc-qr above, which is the venue's own GCash poster beside the
   reservation form — that one is an image the venue uploaded once, this one is
   minted per booking and dies in ten minutes.) */

.mc-qrph { text-align: center; }
/* Both of these are display-something in their own right, so the browser's own
   [hidden] rule has to be said again to win. Four states share the panel and
   only one may ever be on screen. */
.mc-qrph[hidden],
.mc-qrph__state[hidden] { display: none; }

/* Who is being paid and how much, under the code. A QR says nothing a person can
   read, so these are said in words — in the booking's own label/value table
   (.mc-details) rather than in a layout invented for this panel, muted labels
   and dark values like every other row on the page.

   Inline, so the pair sits centred under the code the way everything else in
   here is centred, and left-aligned within itself, so both values start on one
   column instead of drifting about under labels of different lengths.

   A size up on the table's own 0.88rem: in the Booked box these are two rows
   among six and read as a table, and here they are two rows on their own, read
   at arm's length on a phone. */
.mc-qrph__payee {
  display: inline-grid;
  grid-template-columns: max-content max-content;
  margin: 0.85rem 0 0;
  text-align: left;
  font-size: 1.05rem;
}
/* Capped rather than stretched. The code arrives as a data URI of whatever size
   PayMongo drew it at, and a QR blown up past its own resolution scans no better
   for being bigger — 15rem is comfortably wider than any phone camera needs. */
.mc-qrph__image {
  display: block;
  width: 100%;
  max-width: 15rem;
  margin: 0 auto;
  padding: 0.5rem;
  border: 1px solid var(--mc-line);
  border-radius: 10px;
  background: #fff;
}
/* The one sentence in the panel, and it sits over the code rather than under it:
   by the time the phone is up, nobody is reading. Its bottom margin is the gap
   to the code — in the expired panel, where it is the only thing there, it has
   nothing to be a gap to and does no harm. */
.mc-qrph__note {
  margin: 0 0 0.85rem;
  font-size: 0.86rem;
  line-height: 1.45;
  color: var(--mc-muted);
}
/* Saving the code: in the action row opposite Close, because on the phone this
   is meant for those are the two things left to do. The same primary blue as
   Generate QR, because it is that same errand carried on rather than a second
   one. Bootstrap gives .btn a display of its own, so [hidden] has to be said
   again to win — the same note as .mc-qrph above, for the same reason. */
.mc-qrph__download[hidden] { display: none; }
/* PAYMENT CONFIRMATION — the heading over the code in the calendar's booking
   panel, and the only heading that panel has. Everything about how it is drawn
   is already decided by the modal it lives in (capitals, the venue's mahogany,
   the panel's own heading size); all it needs of its own is to be centred over
   the code it introduces, which is centred too. */
.mc-booking-panel__title { text-align: center; }
/* The whole of the payment as one white card, in the panel the week calendar
   opens over itself: the code, the name the money goes to, and the total. A
   player is holding a phone up to this, and a slip with a payee and an amount
   on it is a thing everybody already knows how to read — where a picture, a
   table and a grey well around the pair of them was three things asking to be
   understood as one.

   The picture gives up its own frame inside here (it carries one of its own
   for the dialog on the booking page, where it IS the card), so this is one
   box rather than a box in a box.

   Sized by what is ON it rather than by the modal it happens to be in. Left to
   fill the panel it drew a slip nearly 470px wide around a 240px code, which is
   a lot of white paper either side of the only thing anybody is pointing a
   phone at — and a payment slip that is mostly margin reads as a section of the
   page rather than as one object. `fit-content` hands the width back to the
   picture and the two lines under it, and the auto margins put the whole thing
   back in the middle of the panel; the clock below stays where it was, outside
   the card and centred by .mc-qrph. `max-width: 100%` is the promise that on
   the narrowest phone the card gives way rather than pushing the panel sideways.

   Slightly more padding than before, because on a card this size the border is
   close enough to the code to be read as part of it. */
.mc-qrph__card {
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
  padding: 1rem 1.25rem 1.15rem;
  border: 1px solid var(--mc-line);
  border-radius: 12px;
  background: #fff;
}
/* And the code itself is asked for a size here instead of taking whatever the
   box gives it, which is what makes the box a size at all. 13.75rem is a little
   under the 15rem cap it wears in the dialog on the booking page — it is being
   read at arm's length inside a panel rather than being the whole of the
   screen — and still far more than any phone camera needs to decode it. */
.mc-qrph__card .mc-qrph__image {
  width: 13.75rem;
  max-width: 100%;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}
/* The two lines under the code, and they are values with no labels: "Pay to"
   and "Amount" were answering questions nobody asks about a payment slip. A
   name under a QR code is who is being paid, a peso figure under that is what
   it costs, and with the labels gone both can be centred and bold under the
   picture where they are read at a glance. */
.mc-qrph__value {
  margin: 0.55rem 0 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--mc-ink);
}
/* The clock, and it is OUTSIDE the card: it is not one of the things being paid,
   it is how long the card is good for. Small, centred and muted, with the one
   thing in ink being the number — the only part of any of this that changes
   while somebody is looking at it — in tabular figures, so counting down from
   10:00 does not shuffle the words either side of it every second. */
.mc-qrph__line {
  margin: 0.6rem 0 0;
  font-size: 0.82rem;
  line-height: 1.4;
  color: var(--mc-muted);
}
.mc-qrph__line strong {
  color: var(--mc-ink);
  font-variant-numeric: tabular-nums;
}
/* The same button under the clock instead of in an action row, which is where
   the calendar's own booking panel puts it (see bookings/_panel): a phone is
   the only device it ever appears on, and on a phone the panel is read straight
   down — the code, how long it is good for, then the way to get it into GCash.
   Full width because it is the only thing on that screen to press, and [hidden]
   said once more so the browser's rule still wins over the display below. */
.mc-qrph__download--under {
  display: block;
  width: 100%;
  margin-top: 0.6rem;
}
.mc-qrph__download--under[hidden] { display: none; }

.mc-qrph__clock {
  margin: 0.5rem 0 0;
  font-size: 0.86rem;
  color: var(--mc-muted);
}
/* Tabular figures, so a clock counting down from 10:00 does not shuffle the
   words either side of it every second. */
.mc-qrph__clock strong {
  color: var(--mc-ink);
  font-variant-numeric: tabular-nums;
}
/* The waiting line is the app's usual spinner-and-a-sentence, centred here
   because everything else in this panel is. */
.mc-qrph__state { justify-content: center; }

/* The two things there are to do about a transaction still waiting for its
   money (see the admin calendar's Scan to pay box): they are alternatives, so
   they stand side by side rather than one under the other, and they wrap rather
   than shrink when the panel is narrow. */
.mc-qrph__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin: 0.7rem 0 0;
}

/* The test-mode stand-in for a phone. Deliberately the quietest thing in the
   panel — it is scaffolding for the venue's own staff before they go live, and
   it never appears against a live key at all. */
.mc-qrph__test {
  margin: 0.4rem 0 0;
  font-size: 0.78rem;
  color: var(--mc-muted);
}
.mc-qrph__test[hidden] { display: none; }

/* The clock on a draft. Said where the decision to pay is made and on the page
   they come back to while it is still running — never on the receipt, where the
   deadline has already been met. Plain, and quiet: it is a fact about the
   booking, not a warning about it. */
.mc-hold-note {
  margin: 0.9rem 0 0;
  font-size: 0.86rem;
  line-height: 1.4;
  color: var(--mc-muted);
}
.mc-hold-note strong { color: var(--mc-ink); }

/* At the foot of the Booked box it is a footnote to the table above it, so it
   sits inside the box's own margins with a hairline between them rather than
   floating under it like a second paragraph. */
.mc-box .mc-hold-note {
  margin: 0.7rem 0 0;
  padding-top: 0.6rem;
  border-top: 1px solid var(--mc-line);
}

/* --- the pages PayMongo sends the player back to ---------------------------
   One card in the middle of an otherwise empty page. There is nothing else on
   these pages — no grid, no week bar — so the shell narrows to the card rather
   than leaving it stranded at the left of a 1180px column. */

.mc-shell--narrow { max-width: 34rem; }

.mc-panel {
  background: #fff;
  border: 1px solid var(--mc-line);
  border-radius: 12px;
  padding: 1.5rem;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
}

/* The well the calendar sits in: week bar, legend and grid as one card, on both
 * the player's page and the admin's. The same face as .mc-panel with room-sized
 * padding — a week grid is wider furniture than a booking receipt.
 *
 * The top was 4em, which was room for the logo disc that used to ride the card's
 * edge; the mark is on the navbar now, and 1.5em is what the card wants at the
 * top with only a bar under it. */
.mc-well {
  position: relative;
  background: #fff;
  border: 1px solid var(--mc-line);
  border-radius: 12px;
  padding: 1.5em 1.25rem 1.25rem;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
}

/* The line under the grid, and the room it is given. The variable is declared on
   the well rather than on the line itself because the height has to be read by a
   SIBLING — the scroller above it — and a value set on the footer would be no
   use up there. 2rem is the line and the gap over it, which is what the grid
   goes shorter by. */
.mc-well.has-footer { --mc-grid-footer: 2rem; }

/* The player's calendar keeps the well's own top — the two pages were 1.25rem
   here and 4em in the base rule, and are 1.5em both now (see .mc-well).

   Which leaves the ? in that corner. It is pinned, so it does not push the week
   bar about — the bar is given the gutter instead, and the two numbers have to
   agree: 1.25rem of card padding plus the 2rem mark is the 2.5rem asked for
   here, with the rounding up as the air between the mark and the end of the
   legend. */
#player-page .mc-well { padding-top: 1.5em; }
#player-page .mc-weekbar {
  /* Named as well as set, so the month bar can pay for the same gutter on its
     other side and centre the month on the card rather than on what is left of
     it — see .mc-weekbar--month. */
  --mc-weekbar-gutter: 2.5rem;
  padding-right: var(--mc-weekbar-gutter);
}

.mc-rates {
  margin: 0.75rem 0 0;
  font-size: 0.82rem;
  color: var(--mc-muted);
  text-align: center;
}

/* --- the court policies poster ---------------------------------------------
   The same well, a shade tighter at the top. The band this used to be giving
   back is gone — the well's own top is 1.5em now that the logo disc has left
   the card's edge (see .mc-well) — so what is left of the override is the
   quarter-rem the three flat pages share between them, which is what a card
   with a sheet in it rather than a bar wants. */
#court-policies-page .mc-well { padding-top: 1.25rem; }

/* The poster is a wide sheet, wider than the card it is in on every screen, so
   it is only ever being shrunk — and nothing caps it, because the card is
   already as wide as the shell allows. On a phone it lands small and is read by
   pinching, the way the printed one on the wall is read by stepping closer. */
.mc-policies__image {
  display: block;
  margin: 0 auto;
  max-width: 100%;
  height: auto;
}

/* The same voice the booking modal speaks in — mahogany, in capitals — because
   this is the same conversation, finished on a different page. */
#booking-page .mc-panel h2,
#booking-cancelled-page .mc-panel h2 {
  margin: 0 0 0.9rem;
  font-size: 1.15rem;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--mc-brand);
}
/* Except the thank-you. Every other heading here is the venue announcing a
   state — confirming, cancelled, not paid — and capitals suit that. This one is
   the venue speaking to a person who has just paid them, and shouting it back
   would undo the warmth it is there for. It keeps the mahogany and the weight;
   it just uses its indoor voice.

   It is also the only heading here that is centred, and for the same reason:
   it sits directly under the venue's own name, which is centred over the card,
   and the two of them read as one greeting rather than as a title and a
   left-aligned announcement under it. The reference below is centred too, so
   the top of the receipt is one column down the middle. */
#booking-page .mc-panel h2.mc-thanks {
  text-transform: none;
  text-align: center;
  font-size: 1.3rem;
  letter-spacing: -0.01em;
}

/* The unpaid page's heading is centred for the same reason — under the venue
   name, down the same column — but it stays in the app's capitals, because
   "what happens next" is an announcement rather than an answer. */
#booking-page .mc-panel h2.mc-centred { text-align: center; }
#booking-page .mc-panel .mc-sub,
#booking-cancelled-page .mc-panel .mc-sub {
  color: var(--mc-muted);
  font-size: 0.92rem;
  line-height: 1.5;
}


/* The gateway's own transaction id: a long opaque string, and the one thing on
   this page that is read character by character. Monospace, and allowed to wrap
   rather than be cut — half a transaction id is worth nothing. */
.mc-details dd.mc-txn {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8rem;
  font-weight: 500;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* "Save or screenshot this page." The only instruction on the page, so it is
   the only thing on it that looks like one. */
.mc-keepsake {
  margin: 0.9rem 0 0;
  padding: 0.6rem 0.75rem;
  border: 1px dashed var(--mc-brand);
  border-radius: 8px;
  background: #fdf8f4;
  color: var(--mc-brand);
  font-size: 0.88rem;
  font-weight: 600;
  line-height: 1.4;
}

/* --- admin: the payment state of a booking ---------------------------------
   Read-only reporting in the left column of the edit modal. */

.mc-badge {
  display: inline-block;
  padding: 0.12rem 0.55rem;
  border: 1px solid;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* The same three colours the grid is read by, so a badge and a block never
   disagree about what a booking is: green settled, yellow still moving, grey
   came to nothing. Blue is the fourth thing — a booking no gateway ever saw. */
/* Verified and unverified share those two exactly, because they ARE those two:
   the badge beside the reference and the block on the grid are reporting the
   same state, and a badge that has drifted from the block it explains is worse
   than no badge. */
.mc-badge--paid,
.mc-badge--verified { background: #d9f2e3; border-color: #94d3b3; color: #145b36; }
.mc-badge--pending,
.mc-badge--unverified,
/* And the refund, in the same yellow its tag wears, for the reason written at
   .mc-tag--refunded: a transaction that is over with no money left in it. */
.mc-badge--refunded { background: #fdf1c4; border-color: #e0c24e; color: #6b4e07; }
.mc-badge--dead { background: var(--mc-past); border-color: #ccd1d7; color: var(--mc-muted); }
.mc-badge--manual { background: #eef4fe; border-color: #b6cdf5; color: #1d4ed8; }

.mc-payment__state {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.6rem;
  margin: 0 0 0.6rem;
}
.mc-payment__state .mc-sub { flex: 1 1 12rem; min-width: 0; font-size: 0.82rem; }

/* The one line in the box that is asking for something to be done, so it is the
   one line that is coloured like a warning rather than like a label. */
.mc-payment__attention {
  margin: 0 0 0.6rem;
  padding: 0.5rem 0.65rem;
  border: 1px solid #f0c2bd;
  border-radius: 8px;
  background: #fdf3f2;
  color: #8a2018;
  font-size: 0.84rem;
  font-weight: 600;
  line-height: 1.4;
}
.mc-payment__attention[hidden] { display: none; }

/* The gateway ids. Opaque strings nobody reads unless they are looking one up,
   so they are small, monospace and allowed to wrap — a truncated id is worse
   than a long one, since the only thing anyone does with it is copy it. */
.mc-payment__refs {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px dashed var(--mc-line);
  font-size: 0.78rem;
}
.mc-payment__refs[hidden] { display: none; }
.mc-payment__refs dd {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 500;
  font-size: 0.74rem;
  white-space: normal;
  overflow-wrap: anywhere;
}
.mc-details dt[hidden], .mc-details dd[hidden] { display: none; }

/* --- a court taken without a payment ---------------------------------------
   The desk's override, in the same well the rest of the panel is built from:
   .mc-box draws the border and the legend, and what is added here is only what
   the record needs — a label, and somebody's own words shown afterwards as a
   quotation — plus the little the two sides of ASKING for one need. */
/* Somewhere to type the reason, on the form that enters a booking. It sits in
   the details table, where every other control is a box for a number and is
   capped to the width of one, so it takes the column back (.mc-details__text)
   and asks for the height a sentence or two wants. Draggable, because a reason
   that runs longer than that is the venue's business rather than this rule's. */
.mc-override__input { min-height: 5rem; resize: vertical; }
/* The price of a booking that is not sold at the rate card, in the row where
   the computed figure otherwise stands. A little wider than the counted boxes
   beside it — those hold two digits and this holds an amount in pesos with its
   centavos and a spinner. */
.mc-amount__input { max-width: 8rem; }
/* The two ways an override is finally paid for, under the reason they are about.
   Borrowed whole from .mc-qrph__actions, which is the row this app puts a pair
   of alternatives in — and turned back to the left, because everything else in
   this box reads down the left edge and a centred pair would be the only thing
   in it that does not. */
.mc-override__settle { justify-content: flex-start; }
/* And the code one of them puts there, under the buttons. Nothing but the gap
   that keeps it off them: what is inside is drawn in the same classes every
   other code in this app is (see .mc-qrph__card), and centres itself. */
.mc-override__code { margin-top: 0.7rem; }
.mc-override__label {
  margin: 0.7rem 0 0.3rem;
  font-size: 0.88rem;
  font-weight: 700;
}
/* Typed by a person about one booking, so it is set as the quotation it is —
   and `pre-wrap` because the line breaks somebody typed are part of what they
   wrote. */
.mc-override__quote {
  margin: 0;
  padding-left: 0.6rem;
  border-left: 3px solid var(--mc-line);
  font-size: 0.88rem;
  font-style: italic;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- a court somebody is at the till for -----------------------------------
   A draft is drawn as one block over the hours it holds, the same as any other
   booking and the same as the admin grid draws it: yellow because it is not
   settled, hatched and dashed (.wgb.is-hold) because it is the one kind of
   booking that can still evaporate on its own. A three-hour hold is one block
   saying one thing, rather than three hours each saying it separately. */
.mc-legend .sw-pending {
  background: #fdf1c4 repeating-linear-gradient(-45deg,
    rgba(255, 255, 255, 0.8) 0 2px, rgba(255, 255, 255, 0) 2px 5px);
  border-color: #e0c24e;
  border-style: dashed;
}

/* The one yellow block that is a way back INTO something: the draft this
   browser is paying for, which opens the code to scan (.is-own, the same word
   the green block wears for the same reason). Solid where every other hold is
   dashed: this one is not a court that might evaporate, it is a court the
   reader can still keep. Every other hold on the week — a stranger's, and every
   one of them under an admin's eye — is a court that may still go, and is drawn
   dashed and hatched to say so. */
button.wgb.is-hold.is-own {
  border-style: solid;
  border-color: #d8a51f;
}
button.wgb.is-hold.is-own:hover,
button.wgb.is-hold.is-own:focus-visible {
  background-color: #fbe8a6;
  box-shadow: inset 0 0 0 2px #b7860b;
  outline: none;
}

/* The same offer, made above the grid, for the player whose draft is not on the
   week they happen to be looking at. Yellow for the same reason, and laid out
   like the week bar it sits under. */
.mc-resume {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.9rem;
  margin-bottom: 0.75rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid #e0c24e;
  border-radius: 10px;
  background: #fdf1c4;
  color: #6b4e07;
  font-size: 0.9rem;
}
.mc-resume[hidden] { display: none; }
.mc-resume .mc-spacer { margin-left: auto; }
.mc-resume__when { color: #7d5f10; }
.mc-resume--panel { margin: 0 0 0.25rem; }

/* The payment sits in the action row at the foot of the booking, the same size
   and shape as every other primary button in the app — it is the obvious thing
   to press because it is the only thing to press, which needs no help from a
   larger button, and needs no styles of its own at all. */

/* A held court, on the admin grid. It is a booking and it is drawn as one — it
   takes its courts exactly like the rest — but it is the only kind that can
   still evaporate on its own, so it is hatched and its border is dashed. The
   colour underneath stays the verification, the way every other block's does. */
.wgb.is-hold {
  border-style: dashed;
  background-image: repeating-linear-gradient(-45deg,
    rgba(255, 255, 255, 0.65) 0 4px, rgba(255, 255, 255, 0) 4px 9px);
}
.mc-legend .sw-hold {
  background: #fdf1c4 repeating-linear-gradient(-45deg,
    rgba(255, 255, 255, 0.8) 0 2px, rgba(255, 255, 255, 0) 2px 5px);
  border-color: #e0c24e;
  border-style: dashed;
}

/* --- the walk-in store -----------------------------------------------------
   A table of transactions rather than a grid of hours, so almost nothing on
   this page could be borrowed from the calendar — but everything it is BUILT
   from is: the same well, the same boxed sections, the same modal, the same
   mahogany. What is new here is the table itself, the stepper, and the receipt
   the customer photographs.

   The well is a shade tighter at the top. The band this used to be giving back
   is gone — the well's own top is 1.5em now that the logo disc has left the
   card's edge (see .mc-well) — and what is left is the quarter-rem the policies
   poster and the settings page take too: a card with a heading in it rather than
   a calendar bar wants nothing more. */
.mc-well--flat { padding-top: 1.25rem; }

.mc-storebar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}
.mc-storebar .mc-spacer { margin-left: auto; }
.mc-storebar h1 {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--mc-brand);
  text-transform: uppercase;
}
/* The one thing there is to do on this page, so it is the one filled button on
   it and it says what it does in the venue's own shorthand. */
.mc-storebar__add {
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* The table of takings. It scrolls SIDEWAYS inside its own box on a narrow
   screen rather than pushing the card off the page — the same trade the week
   grid makes, and for the same reason: three columns of real words do not
   compress into 360px of glass without one of them becoming an ellipsis. */
.mc-txtable__scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.mc-txtable {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.mc-txtable th {
  padding: 0.5rem 0.75rem;
  text-align: left;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mc-muted);
  border-bottom: 2px solid var(--mc-line-strong);
  white-space: nowrap;
}
/* Money is read down a column, so it is right-aligned and set in tabular
   figures — a list of amounts whose digits do not line up is a list nobody can
   add up by eye. */
.mc-txtable__figure {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Including its HEADING, which needs saying twice because `.mc-txtable th`
   above is a class AND an element and so beat the class on its own — leaving
   the one column head in the table sitting over the left edge of figures
   stacked against the right. A column label belongs over its column. */
.mc-txtable th.mc-txtable__figure { text-align: right; }

/* On the metrics page the box also scrolls DOWN, inside the viewport, so the
   Total row is on the screen whatever the period: the rows move, the heading
   stays at the top of the box and the total at its foot. Sticky rows need a
   background or the rows show through them. 22rem is what stands above and
   below the box (bar, title, five stats, filter bar, card edges).
   ponytail: fixed offset; measure it with JS if the stats ever wrap to three
   lines. The store's table (admin/store/index) keeps scrolling with the page. */
#admin-metrics .mc-txtable__scroll {
  overflow-y: auto;
  max-height: calc(100dvh - 22rem);
  min-height: 12rem;
}
/* The payouts page has no stat row above its table, so less stands above it. */
#admin-payouts .mc-txtable__scroll {
  overflow-y: auto;
  max-height: calc(100dvh - 15rem);
  min-height: 12rem;
}
#admin-metrics .mc-txtable thead th,
#admin-metrics .mc-txtotal td,
#admin-payouts .mc-txtable thead th,
#admin-payouts .mc-txtotal td {
  position: sticky;
  background: #fff;
}
#admin-metrics .mc-txtable thead th,
#admin-payouts .mc-txtable thead th { top: 0; }
#admin-metrics .mc-txtotal td,
#admin-payouts .mc-txtotal td { bottom: 0; }

/* A transaction is a row you can press, so it says so on hover and carries the
   caret every disclosure in this app carries. */
.mc-txrow {
  cursor: pointer;
  border-bottom: 1px solid var(--mc-line);
}
.mc-txrow:hover { background: var(--mc-open-hover); }
.mc-txrow td { padding: 0.55rem 0.75rem; vertical-align: middle; }
.mc-txrow__ref {
  font-weight: 700;
  white-space: nowrap;
  color: var(--mc-brand);
}
/* The state of the money, as a bar down the left edge rather than as another
   column. It is the fact a person scanning the list is actually looking for —
   which of these is still owed — and a colour answers it without costing the
   table a fourth thing to read. */
.mc-txrow.is-paid .mc-txrow__ref { box-shadow: inset 3px 0 0 #2e9e68; }
.mc-txrow.is-pending .mc-txrow__ref { box-shadow: inset 3px 0 0 #e0c24e; }

/* The sum of the rows above it, which is .mc-carttotal drawn as a table row: the
   same 2px line ruled under the last transaction, the same small uppercase muted
   word, the same amount in the ink of the page. The label sits at the RIGHT of
   the column before the money, so the two read as one phrase across the gutter
   rather than as a word stranded three columns away from its figure — and the
   figure itself needs no alignment of its own, standing in the same
   .mc-txtable__figure column the amounts it adds up stand in. */
.mc-txtotal td {
  padding: 0.7rem 0.75rem 0.55rem;
  border-top: 2px solid var(--mc-line-strong);
}
.mc-txtotal__label {
  text-align: right;
  text-transform: uppercase;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--mc-muted);
  white-space: nowrap;
}
.mc-txtotal .mc-txtable__figure {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--mc-ink);
}

/* --- the cart --------------------------------------------------------------
   One line per thing the venue sells, read in two rows rather than three
   columns: what it is and what it costs at the top left, what that comes to
   opposite it at the top right, and the stepper on its own line underneath at
   the left.

   The pair a person checks against each other while building a cart is the
   THING and its PRICE, so those two are the ones set side by side; how many of
   it is what they are in the middle of deciding, and it sits under them rather
   than between them. It also gives the stepper a whole line to itself, which is
   what keeps it thumb-sized on the phone at the counter instead of being the
   first thing squeezed when a product has a long name.

   A grid rather than a wrapping flex row, because the arrangement is a
   DECISION: every one of the three is placed by name below, so a long product
   name or an empty total cannot rearrange the row by running out of space. */
.mc-cartline {
  display: grid;
  /* The right-hand column keeps the width the total was given when it stood
     where the stepper stands now, so a figure appearing or disappearing as the
     count changes does not shuffle the name beside it every press. */
  grid-template-columns: 1fr minmax(5.5rem, auto);
  /* Baselines, so the total lines up with the product NAME rather than with the
     middle of the name-and-unit-price block beside it. */
  align-items: baseline;
  column-gap: 0.75rem;
  row-gap: 0.4rem;
  padding: 0.5rem 0;
  /* And room down the left, so the mahogany edge below is a rule beside the row
     rather than a bar the words are pressed up against. On the row rather than
     on the text, so the name, the unit price and the stepper under them share
     one left edge — and on EVERY row rather than only the marked ones, so
     nothing shifts sideways at the moment a line is added to the cart. */
  padding-left: 0.6rem;
  border-bottom: 1px solid var(--mc-line);
}
.mc-cartline:last-of-type { border-bottom: 0; }
.mc-cartline__what { grid-column: 1; grid-row: 1; min-width: 0; }
.mc-cartline__total {
  grid-column: 2;
  grid-row: 1;
  text-align: right;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.mc-cartline .mc-stepper { grid-column: 1; grid-row: 2; }
/* The row's own title, so it is a step above the body text around it — enough
   to be found by eye down a list of products, and not enough to read as a
   heading in a form that already has a legend over it. */
.mc-cartline__name { display: block; font-size: 1.05rem; font-weight: 600; }
.mc-cartline__unit { display: block; font-size: 0.8rem; color: var(--mc-muted); }
/* A line with something on it is worth seeing at a glance while the cart is
   being built, so the name goes to ink and the row keeps a faint mahogany
   edge. */
.mc-cartline.is-chosen { box-shadow: inset 2px 0 0 var(--mc-brand); }
.mc-cartline.is-chosen .mc-cartline__name { color: var(--mc-brand); }

.mc-stepper {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
/* Square, and big enough for a thumb at a counter. The number between them is
   typed as often as it is stepped — ten of something is a number somebody types
   — so it is a real input rather than a label. */
.mc-stepper .btn {
  width: 2.1rem;
  padding: 0.2rem 0;
  font-weight: 700;
  line-height: 1.4;
}
.mc-stepper input {
  width: 3.4rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
/* The spinner arrows a number input draws are a second, tinier stepper beside
   the one that is there for thumbs. */
.mc-stepper input::-webkit-outer-spin-button,
.mc-stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.mc-stepper input { -moz-appearance: textfield; appearance: textfield; }

.mc-carttotal {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0.8rem 0 0;
  padding-top: 0.6rem;
  border-top: 2px solid var(--mc-line-strong);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--mc-muted);
}
.mc-carttotal .mc-amount {
  margin-left: auto;
  font-size: 1.25rem;
  color: var(--mc-ink);
  font-variant-numeric: tabular-nums;
}

/* --- the receipt -----------------------------------------------------------
   The one thing in the store that is not for the venue: a customer is holding a
   phone up to it, and what they are holding it up to should be the same piece of
   paper their booking receipt is.

   So there is almost nothing here. The letterhead, the reference band and the
   details card are .mc-letterhead, .mc-reference and .mc-box — the very rules
   the player's booking receipt is drawn with (see bookings/show and
   bookings/_receipt) — and borrowing them rather than answering them again is
   the whole point: a house style that is copied is a house style that drifts.
   What is left below is only the two things that are true of this receipt and
   not of that one. */

/* --- how much room the purchase panel gets ---------------------------------
   Wider than the app's other dialogs, all of it. This panel is not a question
   with two buttons under it — it is a counter: a cart with a stepper per
   product on the left and prices down the right, and then a code, and then a
   receipt. The slim width the reschedule and delete panels wear was making
   every one of those work harder than it had to.

   The width is stated here rather than left to .mc-modal__panel's own
   breakpoint curve, which narrows as the screen GROWS (41.67vw from lg) — a
   sensible shape for a short form and the wrong one for a document. One
   max-width and a full-width box under it: on a phone that is the whole screen
   inside the modal's padding, and on a desk it is a panel of a fixed, readable
   measure. */
#admin-store .mc-modal__panel {
  max-width: min(100%, 36rem);
  width: 100%;
}

/* And the receipt gets more again, because it is the one face of this panel
   that is not a dialog at all: a customer is holding a phone up to a document,
   and a receipt folded into a dialog's column reads as a dialog.

   The metrics table opens the very same receipt over its own page — press a DR-
   row and the purchase is drawn in the dialog rather than navigated to (see
   metrics_controller#drawPurchaseReceipt) — so it is the same rule and not a
   second one. Two selectors on one declaration, because a receipt that were
   44rem at the counter and 28rem on the metrics page would be two documents. */
#admin-store .mc-modal__panel.is-receipt,
#admin-metrics .mc-modal__panel.is-receipt {
  max-width: min(100%, 44rem);
  width: 100%;
  padding: 1.75rem 1.5rem 1.5rem;
}

/* The order summary under the code. The panel around it is centred, because
   almost everything in it is a picture or a line about a picture (see
   .mc-qrph) — a label/value table is neither, so it takes its alignment back.
   The same trade .mc-qrph__payee makes on the customer's own booking page. */
.mc-qrph__order { text-align: left; }

/* And the lines the controller writes into the details card, which are the one
   part of it that varies in number. A dotted rule under each, because a list of
   things bought is read down rather than across — the static rows around them
   (Name, Total, Status) are single facts and keep the plain spacing every other
   .mc-details in the app has. */
.mc-receipt .mc-receipt__item {
  padding-bottom: 0.3rem;
  border-bottom: 1px dotted var(--mc-line);
}

/* --- misc ----------------------------------------------------------------- */

.mc-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--mc-muted);
}

/* The time column used to be narrowed here, back when a row said one time and a
   phone could be given "12:00pm" in 64px. A row now says the whole hour, and
   there is nothing left to take: the label is the same string at the same size
   whatever the screen is, so a narrower track would only clip it. The week
   scrolls sideways on a phone either way. */
@media (max-width: 640px) {
  .mc-header h1 { font-size: 1.3rem; }
}

/* --- on paper --------------------------------------------------------------
   Print is offered on one page in this app — a settled booking, where the panel
   IS the player's receipt (see bookings/show and print_controller). So these
   rules have one job: put that panel on the sheet and take everything that is
   screen off it.

   Nothing is rebuilt for print. What comes out is the page as it stands, minus
   the things that only make sense to a pointer — the buttons, the dialogs
   behind them, the toast stack — and minus its own on-screen instruction to
   screenshot it, which is not advice anybody needs while holding the paper.
   What is left is the venue's letterhead, the MC- reference, the booking, the
   amount, and the PAID row with the date it was paid on: everything the desk
   would ever be shown this sheet for.

   The panel goes flat — no shadow, no card, no page background — because paper
   is already the card, and a printer asked for a grey field will happily use
   half a cartridge agreeing with it. The colours that MEAN something (the
   mahogany letterhead, the green PAID tag) are kept with print-color-adjust, so
   a receipt printed in colour still reads the way the screen did, while a
   black-and-white printer simply renders them grey. */
@media print {
  @page { margin: 1.4cm; }

  body {
    background: #fff;
    color: #000;
  }

  /* Everything that is chrome rather than receipt. `!important` because most of
     these carry a display of their own (flex, or the modal's own layout) that
     would otherwise win. */
  .mc-toasts,
  .mc-modal,
  .mc-modal__actions,
  .mc-keepsake,
  .mc-navbar,
  .mc-weekbar,
  .wg-chev,
  .mc-resume { display: none !important; }

  .mc-shell,
  .mc-shell--narrow {
    max-width: none;
    margin: 0;
    padding: 0;
  }

  /* The card was a card because the screen around it was grey. */
  .mc-panel {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
  }

  /* The venue's mark, at a size that leaves room for the booking under it on
     one sheet. */
  .mc-letterhead { max-height: 140px; }

  /* The three boxed things on the receipt keep their outlines — they are what
     separates the reference from the booking on a page with no colour left —
     but lose the tints that would be printed as flat grey blocks. */
  .mc-reference,
  .mc-box {
    background: none;
    break-inside: avoid;
  }

  /* Colour that carries meaning survives a colour printer; the rest of the
     sheet is ink on white either way. */
  .mc-tag,
  .mc-letterhead,
  .mc-reference__id {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* --- the receipt panel, which is the one modal that IS the receipt ---------

     The rule above takes every .mc-modal off the paper, and that is right for
     all of them but one. The shared receipt panel (see common/modals/_receipt)
     is the venue's letterhead with the booking under it — the same sheet
     bookings/show prints — and while it is open the page BEHIND it is the
     chrome: a month of dates, a week of hours, a desk's calendar.

     So the two are swapped over, and only while one is standing: the panel opens
     `mc-printing` on the root element and tags everything that is not on the
     path from itself up to the body with `mc-print-away` (see
     booking_modal_controller's markForPrint). Nothing about the host page is
     assumed by either — whatever the page is, what prints is this panel and the
     ancestors it hangs from. None of it means anything on screen: every rule
     here is inside @media print.

     The panel stands DOWN out of its fixed, centred, scrolling box and becomes
     an ordinary block of ink on the sheet, because a 92vh scroller is a receipt
     with its bottom half cut off. */
  .mc-printing .mc-print-away { display: none !important; }

  .mc-printing .mc-modal.mc-receipt {
    display: block !important;
    position: static;
    padding: 0;
  }
  .mc-printing .mc-modal.mc-receipt .mc-modal__backdrop { display: none !important; }
  .mc-printing .mc-modal.mc-receipt .mc-modal__panel {
    width: auto;
    max-width: none;
    max-height: none;
    overflow: visible;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
  }

  /* --- the payouts page as a sheet -------------------------------------------
     Landscape, because seven columns; the bar of controls, the export button and
     the receipt dialog off; the table's scroller opened out so nothing is clipped
     and the heading and total stop sticking. Rows the status menu hid stay hidden
     ([hidden] is display:none), so the sheet is the table as filtered. */
  #admin-payouts { page: payouts; }
  @page payouts { size: A4 landscape; margin: 1.2cm; }
  #admin-payouts .mc-payoutbar,
  #admin-payouts .mc-exportbtn { display: none !important; }
  /* The card was a card because the screen around it was grey — the same reason
     .mc-panel loses its outline above. */
  #admin-payouts .mc-well { border: 0; box-shadow: none; background: #fff; padding: 0; }
  #admin-payouts .mc-report { display: block; margin-bottom: 0.6rem; }
  #admin-payouts .mc-report__title { margin: 0; font-size: 1.1rem; font-weight: 700; }
  #admin-payouts .mc-report__line { margin: 0; font-size: 0.85rem; color: #444; }
  #admin-payouts .mc-txtable__scroll { max-height: none; min-height: 0; overflow: visible; }
  #admin-payouts .mc-txtable thead th,
  #admin-payouts .mc-txtotal td { position: static; }
  #admin-payouts .mc-txtable { font-size: 0.8rem; }
  #admin-payouts .mc-txrow__open { text-decoration: none; }
  #admin-payouts .mc-txrow__payid a { color: inherit; text-decoration: none; }
}

/* --- the metrics page -------------------------------------------------------
   Five figures across the top, then the payments they add up to. The boxes wrap
   rather than scroll: a stat nobody can see is a stat that is not on the page,
   and five short numbers fit two-up on a phone without any of them shrinking. */
.mc-statrow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}
.mc-stat {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.85rem 0.9rem;
  border: 1px solid var(--mc-line);
  border-radius: 0.5rem;
  background: #fff;
}
.mc-stat__label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mc-muted);
}
/* Tabular figures for the same reason the amount column has them: five numbers
   read across a row have to line up as numbers rather than as words. */
.mc-stat__value {
  font-size: 1.35rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--mc-brand);
}
.mc-stat__note {
  font-size: 0.74rem;
  color: var(--mc-muted);
}
.mc-stat__note[hidden] { display: none; }

/* The filter bar: what to look for at one end, and when to look at it at the
   other. A flex row rather than two blocks, because the two controls are one
   question and belong on one line — and it WRAPS, so on a phone the menu drops
   under the box at full width instead of squeezing it to nothing. */
.mc-metricsearch {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}
.mc-metricsearch .form-control { max-width: 24rem; }
/* Pushed to the far end by the space left over rather than by a width on the
   box beside it, so the search input keeps its own size and the menu keeps the
   right edge whatever is between them. `auto` survives the wrap: on a line of
   its own it is still the thing at the end of it. */
.mc-metricsearch__range {
  width: auto;
  margin-left: auto;
}

/* The payouts bar: a quick-range menu, two date boxes and a status menu on one
   wrapping line. Every control keeps its own width; nothing is pushed to the end. */
.mc-payoutbar .form-select, .mc-payoutbar .form-control { width: auto; max-width: 14rem; }

/* The heading of the printed sheet. Nothing on the screen: the screen has the
   bar above the table saying the same thing. */
.mc-report { display: none; }

/* A payout's own row — the digital tax PayMongo takes once per payout — sits
   among the payments in a quieter ink, so a column of payments still reads as one. */
.mc-txrow.is-adjustment td { color: var(--mc-muted); font-style: italic; }

/* The spinner is built for a flex parent (`flex: 0 0 auto`, no display of its
   own); the empty line it stands in is a plain <p>, so it is given one here. */
#admin-payouts .mc-empty .mc-spinner {
  display: inline-block;
  vertical-align: -0.2em;
  margin-right: 0.35rem;
}

/* The reference is the one thing on the row that does something, so it is a
   button rather than a clickable cell — a keyboard has to be able to reach it —
   and it is drawn as the text it already was. */
.mc-txrow__open {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.mc-txrow__payid { font-size: 0.82rem; word-break: break-all; }
.mc-txrow__when { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Which counter a row came from, as a bar down its left edge rather than as a
   sixth column — the same trick the store's own table plays with paid and
   pending (see .mc-txrow.is-paid). */
.mc-txrow.is-booking .mc-txrow__ref { box-shadow: inset 3px 0 0 #2e9e68; }
.mc-txrow.is-store   .mc-txrow__ref { box-shadow: inset 3px 0 0 #7a5cc4; }

/* The mark beside a customer's name that says what they paid for, and the panel
   it opens.

   THE SAME DISC THE PLAYER'S CARD WEARS (.mc-well > .mc-help) at the size a
   table cell can hold: that one is a 2rem control standing in the corner of a
   card and this one has to sit inside a line of text without breaking the line's
   rhythm, so it is measured in `em` and follows whatever the row is set in. Quiet
   for the same reason the other one is quiet — it is there for the reader who
   wants it, and two hundred of them shouting down a column would be a column
   nobody can read past — and it takes the accent only when it is pointed at. */
.mc-hint {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15em;
  height: 1.15em;
  margin-left: 0.4em;
  padding: 0;
  border: 1px solid var(--mc-line);
  border-radius: 50%;
  background: #fff;
  color: var(--mc-muted);
  font-size: 0.8em;
  font-weight: 700;
  line-height: 1;
  vertical-align: middle;
  cursor: pointer;
}
.mc-hint:hover,
.mc-hint:focus-visible {
  border-color: var(--mc-accent);
  color: var(--mc-accent);
}

/* FIXED TO THE VIEWPORT rather than to the cell it points at, because the cell
   is inside .mc-txtable__scroll and that box clips what overflows it sideways —
   a panel drawn in the table would be cut in half on a phone. There is one of it
   for the whole page and the controller moves it (see
   metrics_controller#placeHint).

   z-index 1070 puts it over the page and UNDER everything that stands over the
   page: the modals on this very page are .mc-modal--over at 1090, the account
   menu is 1100 and a toast is 9999. A tooltip is the smallest thing here and
   loses to all of them.

   The card is the account menu's own recipe — one hairline, a 10px radius, white,
   and the same soft shadow — because it is the same kind of small panel hanging
   off the same kind of small control. */
.mc-hintpanel {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1070;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--mc-line);
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 10px 28px rgba(16, 24, 40, 0.18);
  color: var(--mc-ink);
  font-size: 0.82rem;
  line-height: 1.35;
  pointer-events: none;      /* a glance, never something to be aimed at */
}
.mc-hintpanel__line { white-space: nowrap; }

/* The caret, as the card's own bottom corner turned forty-five degrees: a
   rotated square carrying two of the same hairline and the same white, half of
   it tucked behind the panel so only the point shows. Drawn this way rather than
   as a border triangle because a triangle cannot carry the border the rest of
   the card has, and a caret with no outline on an outlined card reads as a
   smudge.

   WHERE ALONG THE EDGE is the controller's to say: the panel is pulled back
   inside the screen when it would hang off it, and a caret left at the middle
   would then point at nothing (see placeHint, which writes --mc-hint-caret). */
.mc-hintpanel::after {
  content: "";
  position: absolute;
  bottom: -5px;
  left: var(--mc-hint-caret, 50%);
  width: 9px;
  height: 9px;
  margin-left: -5px;
  transform: rotate(45deg);
  border-right: 1px solid var(--mc-line);
  border-bottom: 1px solid var(--mc-line);
  background: #fff;
}
/* And the one row too near the top of the window to stand over: the panel goes
   under the icon instead and the caret moves to the top edge, carrying the two
   borders that are now the ones facing out. */
.mc-hintpanel.is-below::after {
  bottom: auto;
  top: -5px;
  border-right: 0;
  border-bottom: 0;
  border-left: 1px solid var(--mc-line);
  border-top: 1px solid var(--mc-line);
}

/* --- the traffic page -------------------------------------------------------
   The same five boxes across the top the metrics page has (.mc-statrow above is
   reused whole rather than copied), then one bar of controls, then one chart.

   THE BAR IS THE SAME KIND OF THING .mc-metricsearch IS and is deliberately not
   that class: this one carries two menus and a three-part period stepper rather
   than a box and a menu, and inheriting a layout to override half of it is how a
   shared class stops meaning anything. What it borrows is the behaviour — a flex
   row that WRAPS, so on a phone the stepper drops under the menus at full width
   instead of squeezing them to nothing. */
.mc-trafficbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.mc-trafficbar__label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mc-muted);
}
.mc-trafficbar__select { width: auto; }

/* The period and its two chevrons, held together so a wrap never leaves a
   chevron on one line and the week it steps on another. */
.mc-trafficbar__period {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
/* Square, so the two chevrons are the same object at either end of the label
   whatever is written between them. */
.mc-trafficbar__step {
  min-width: 2.25rem;
  padding: 0.25rem 0.5rem;
  line-height: 1.4;
}
.mc-trafficbar__now {
  min-width: 11rem;
  text-align: center;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.mc-trafficbar__current[hidden] { display: none; }

/* The chart's own box. A minimum height so the card does not collapse and then
   jump when the library lands — the page is drawn before ApexCharts has
   finished being fetched, and a section that changes height under the reader is
   the whole reason lazy loading gets a bad name. */
.mc-trafficchart {
  min-height: 360px;
  margin-bottom: 0.5rem;
}

/* The tooltip is the library's own box with our words in it (see
   traffic_controller#tooltipFor): the box, its border and its shadow are
   ApexCharts', and what is set here is the type and the little two-column table
   inside it.

       Thursday
       Income:    ₱4,230 (+100%)
       Average:   ₱2,115

   A GRID RATHER THAN SPACES OR A <table>. The two values have to start at the
   same x or the comparison the whole chart exists for is a thing the eye has to
   hunt for, and "Income" and "Bookings Made" are not the same width — so the
   label column is `auto` and sizes itself to whichever measure is being drawn,
   and both values line up behind it whatever that turns out to be. */
.mc-charttip {
  padding: 0.5rem 0.7rem;
  font-size: 0.82rem;
  line-height: 1.45;
}
.mc-charttip__title {
  font-weight: 700;
  margin-bottom: 0.15rem;
}
.mc-charttip__rows {
  display: grid;
  grid-template-columns: auto auto;
  column-gap: 0.75rem;
  row-gap: 0.05rem;
  margin: 0;
}
/* dt and dd both, because Bootstrap's own reset gives one of them a weight and
   the other a bottom margin, and a definition list is what this is. */
.mc-charttip__label {
  margin: 0;
  font-weight: 500;
  color: var(--mc-muted);
}
.mc-charttip__value {
  margin: 0;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The comparison against the all-time average, and it is DELIBERATELY SMALLER
   than the number it follows. The value is the fact; the percentage is a
   remark about it, and a remark set at the same size as its subject reads as a
   second number to be compared against a third.

   The two colours are this app's own — #157347 is the notice toast's accent and
   #b42318 is the alert's (see .mc-toast--notice / --alert), which is the same
   pair the desk already reads "that worked" and "that did not" in. Nought is
   grey rather than green: a bucket that landed exactly on its average has not
   done well, it has done usual. */
.mc-charttip__delta {
  font-size: 0.8em;
  font-weight: 600;
}
.mc-charttip__delta--up { color: #157347; }
.mc-charttip__delta--down { color: #b42318; }
.mc-charttip__delta--flat {
  color: var(--mc-muted);
  font-weight: 500;
}

/* This device, in or out of the venue's own figures. A footnote rather than a
   control on the bar: it is set once per device and then never again. */
.mc-trafficopt { margin-top: 1rem; }
.mc-trafficopt__switch {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
  cursor: pointer;
}
.mc-trafficopt__note {
  margin: 0.4rem 0 0;
  font-size: 0.8rem;
  color: var(--mc-muted);
}

/* --- the About Us hero ------------------------------------------------------
   THE WHITE MAT ROUND THE PICTURES, which is the poster by the courts said
   again. The policies page hangs its sheet in a thin white frame on this same
   photographic backdrop (see .mc-well, and #court-policies-page's 1.25rem
   top override), and these two pages are the venue's two pieces of signage: a
   reader moving between them should be looking at the same object twice. So the
   numbers here are the well's own and are not eyeballed — #fff, the same
   hairline, the same 12px corner, the same shadow, and 1.25rem of white all
   round. .mc-well itself is deliberately NOT reused: its top padding and its
   --mc-grid-footer plumbing are the calendar's furniture, and inheriting them to
   throw them away is how a shared class stops meaning anything.

   THIS IS THE OUTSIDE OF THE CARD AND ONLY THE OUTSIDE, which is the whole of
   the distinction. What was refused was white INSIDE the card — a mat between
   the frame and the photographs, framing each picture in its own margin — and
   that is still refused: below this rule the pictures reach every edge of the
   box they are in, with no padding and no gutter between the panel and the
   picture. White between the card and the page is a different thing entirely,
   and it is what makes this read as a print on a wall rather than as a browser
   window with a photograph in it. */
.mc-about-frame {
  background: #fff;
  border: 1px solid var(--mc-line);
  border-radius: 12px;
  padding: 1.25rem;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
}

/* ONE BOX, THREE LAYERS. The photographs fill the whole of it and the panel is a
   VEIL over them, not a column beside them — so the left of this band is the
   same picture, dimmed, with white type on it. That is the venue's own spec, and
   the reference image (testa.png) is a layout guide to it: the proportions, the
   chevrons and the dots come from there, the flat black does not.

   No border and no shadow of its own: the frame outside it carries the card edge
   now, and two hairlines 1.25rem apart would be the same card drawn twice. The
   corner is 8px against the frame's 12px, so the inner clip sits just inside the
   outer curve and the two nest rather than crossing.

   `isolation` gives the layers a stacking context of their own, so nothing on
   this card can be climbed over by a z-index somewhere else in a 4200-line
   stylesheet. */
.mc-about-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: 8px;
  background: #000;             /* what shows while the first frame decodes */
  /* Room at the foot for the control row, so the chevrons and the dots never
     land on the type. On a desk they move to the right-hand half instead and
     this goes away — see the media query below. */
  padding-bottom: 3.5rem;
}

/* Under everything, and across ALL of it. */
.mc-about-hero__slides { position: absolute; inset: 0; z-index: 0; }

.mc-about-hero__slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;            /* mixed orientations, and the venue adds its
                                   own: most of these photographs are portrait
                                   and are cropped to their middle third by this.
                                   The alternatives are black bars, which look
                                   broken, and a picture floating in a box, which
                                   looks unfinished. */
  object-position: center;
  opacity: 0;
  transition: opacity 900ms ease;
}
.mc-about-hero__slide.is-current { opacity: 1; }

/* The veil. 0.72 here because on a phone it is over the WHOLE picture and there
   is no undimmed half to balance it.

   NEITHER OPACITY IS A TASTE. White type over a see-through layer is only as
   readable as the brightest thing that can ever be behind it, and these are
   outdoor courts in Philippine sunlight — pale concrete, white line paint, blown
   sky — so both numbers are chosen for a worst case of pure #fff underneath
   rather than for the photographs as they happen to look today. Composited over
   white, 0.66 gives 7.3:1 against white text and 0.72 gives 9.2:1, so the type
   clears WCAG AAA in either case; 0.55 would only scrape AA. If the picture
   needs to be more present the answer is a better crop, never thinner ink. */
.mc-about-hero__panel {
  position: relative;
  z-index: 1;
  width: 100%;
  padding: 2rem 1.5rem;
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
}

/* The controls layer. On a phone it is the reserved strip at the foot; on a desk
   it becomes the undimmed half of the picture. It passes clicks through to
   nothing — only the buttons inside it are pressable, because the layer covers
   more than half the photograph and would otherwise swallow every one. */
.mc-about-hero__controls {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3.5rem;
  z-index: 2;
  pointer-events: none;
}
.mc-about-hero__controls button { pointer-events: auto; }

/* Bare glyphs at the vertical midline, as the reference draws them. No disc
   behind them: a plate over a photograph is chrome the picture has to make room
   for, and these have to be legible over any picture the venue drops in, which a
   shadow does and a fixed-colour plate does not. */
.mc-about-hero__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  padding: 0.35rem 0.6rem;
  border: 0;
  background: none;
  color: #fff;
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.75);
}
.mc-about-hero__arrow.is-prev { left: 0.25rem; }
.mc-about-hero__arrow.is-next { right: 0.25rem; }
.mc-about-hero__arrow:hover { color: var(--mc-open-hover); }
.mc-about-hero__arrow:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
  border-radius: 6px;
}

/* Where in the run this picture is. Along the bottom of the photograph itself —
   no strip, band or gutter is made for these, because a strip is a region the
   photograph does not fill, which is the white-mat problem in another colour. */
.mc-about-hero__dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.9rem;
  display: flex;
  justify-content: center;
  gap: 0.5rem;
}

/* White filled, 45% white hollow — not mahogany. --mc-brand (#7b3f21) is a dark
   colour and would disappear into the dark half of a photograph, which is the
   one place a "you are here" mark must never vanish. White on a shadow is the
   only pair that holds over every frame, including ones nobody has taken yet. */
.mc-about-hero__dot {
  width: 0.6rem;
  height: 0.6rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.45);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
  transition: background 0.15s ease;
}
.mc-about-hero__dot.is-current { background: #fff; }
.mc-about-hero__dot:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* The type on the veil. --mc-muted is deliberately not used anywhere in here: it
   is a grey mixed for white backgrounds (see the top of this file), and over a
   dark veil it is neither one thing nor the other. Secondary text is white at
   82%, which over the desktop veil still lands near 6:1 — comfortably past AA
   for body copy, and a floor rather than a preference. */
.mc-about__title {
  margin: 0 0 1.25rem;
  font-size: 2.1rem;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.01em;
  /* In the stylesheet and not in the template: the venue's name is a proper noun
     in the database, and capitals typed into the markup are what makes a screen
     reader spell it out letter by letter. The same rule the booking page's
     panel headings keep. */
  text-transform: uppercase;
  color: #fff;
}

.mc-about__section {
  margin: 1.5rem 0 0.6rem;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
}
.mc-about__section:first-of-type { margin-top: 0; }

.mc-about__body {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.82);
}

.mc-about__links {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  font-size: 0.92rem;
  color: rgba(255, 255, 255, 0.82);
}
.mc-about__links li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
}
/* A fixed column for the marks, so the four labels line up down one edge even
   though the glyphs are different widths. */
.mc-about__mark {
  flex: 0 0 1.1rem;
  text-align: center;
  font-style: normal;
}
.mc-about__label { flex: 0 0 8.5rem; color: rgba(255, 255, 255, 0.82); }

.mc-about__rates {
  margin: 0;
  display: grid;
  grid-template-columns: max-content auto;
  gap: 0.35rem 1.25rem;
  font-size: 0.92rem;
}
.mc-about__rates dt { color: rgba(255, 255, 255, 0.82); font-weight: 400; }
.mc-about__rates dd { margin: 0; color: #fff; font-weight: 600; }

.mc-about__credit {
  margin: 1.5rem 0 0;
  font-size: 0.82rem;
  color: rgba(255, 255, 255, 0.82);
}

/* Every link on the veil is white and underlined. A coloured link over a
   photograph is a colour competing with whatever is behind it; an underline is
   not. */
.mc-about-hero__panel a {
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.mc-about-hero__panel a:hover,
.mc-about-hero__panel a:focus { color: var(--mc-open-hover); }

/* The "← Back to Main" that sat in the white band at the foot of both signage
   cards was styled here, by one rule, so the two pages went on reading as the
   same object hung twice. Both links are gone: the bar over them carries a
   Schedule link on every page at every width, and a second way home at the foot
   of a card somebody has to scroll to the end of is the harder one to find. */

/* A desk splits it down the middle, which is the reference. */
@media (min-width: 992px) {
  .mc-about-hero { min-height: 34rem; display: flex; padding-bottom: 0; }

  /* 36% — narrowed from the reference's 44% by the venue's own eye, to give the
     photograph more of the band. `min-width` stops the paragraph setting to a
     column too narrow to read at the awkward widths just past the breakpoint.
     0.66 rather than the phone's 0.72 — the veil is over a third of the picture
     here, with an undimmed side beside it to carry the composition. */
  .mc-about-hero__panel {
    width: 36%;
    min-width: 22rem;
    padding: 3rem 2.5rem;
    background: rgba(0, 0, 0, 0.66);
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  /* THE CONTROLS MOVE TO THE UNDIMMED HALF. Inset from the left by exactly the
     panel's width, so the midline the chevrons sit on and the line the dots run
     along belong to the part of the picture nothing is covering. The two 36%s
     have to agree; they are the only pair of numbers in this block that do. */
  .mc-about-hero__controls { top: 0; left: 36%; height: auto; }
}

/* The other half of the reduced-motion answer, and it matters on its own: the
   controller reads matchMedia once, at connect, so a reader who flips the OS
   setting mid-visit still has a live timer. With the transition gone the worst
   that happens is an instant swap rather than a fade. The chevrons and the dots
   are deliberately NOT touched here — reduced motion is a request not to be
   moved at, not a request to be denied the controls. */
@media (prefers-reduced-motion: reduce) {
  .mc-about-hero__slide { transition: none; }
}

/* --- the venue's settings, as boxes across a desk ---------------------------
   The page is read sitting down, on a screen wide enough to hold the whole of
   it at once, so its questions — what the venue IS, and what it CHARGES — are
   columns side by side rather than one long scroll with a Save at the bottom
   nobody can see from the top. Up to three at a desk, two at a tablet width
   where a third column would be too narrow for a ₱ box and its number, one on a
   phone.

   `minmax(0, 1fr)` and not `1fr`: a grid column's default minimum is its
   content, so one long product name in the store block would push the column
   wider than its share and shove the others off the card.

   `align-items: start` so a short box keeps its own height instead of being
   stretched to the tallest one beside it — the boxes are three separate
   subjects, not three cells of a table. */
.mc-settings {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: 1rem;
}
@media (min-width: 768px) {
  .mc-settings { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 992px) {
  .mc-settings { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Two boxes: two equal columns. */
  .mc-settings--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* The same box the booking modal's Details and Payment sections are drawn as —
   same border, same radius, same uppercase legend — with the top margin dropped
   (the grid's gap does that job here) and a card's own white and shadow, so a
   column reads as a card standing in the well rather than as a shaded inset. */
.mc-settings__box {
  margin-top: 0;
  padding: 1rem 1.1rem 1.15rem;
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
}
/* Mahogany, and a shade larger than the modal's: these are the headings of the
   page rather than labels on a section of one, and there is no h1 above them. */
.mc-settings__box legend {
  color: var(--mc-brand);
  font-size: 0.88rem;
  margin-bottom: 0.85rem;
}

/* One rhythm for every field in a box, so a column of six questions has the
   same air between each pair as the column beside it. */
.mc-settings__fields { display: grid; gap: 0.85rem; }
.mc-settings__field { min-width: 0; }
.mc-settings__field .form-label { font-size: 0.85rem; }
.mc-settings__field .form-text { margin-top: 0.15rem; }

/* Two short answers on one line — courts and paddles, opens and closes, weekday
   and weekend. They stay two even in the narrowest column, because both halves
   are a handful of digits and splitting them would say they were unrelated. */
.mc-settings__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
}

/* Seven boxes that wrap as many times as the column makes them. The inline
   check's own right margin is dropped in favour of the flex gap, so the last
   box on a line does not hold open a margin against the edge of the card. */
.mc-settings__days {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem 0.9rem;
}
.mc-settings__days .form-check-inline { margin-right: 0; }

/* A block of questions that belongs to the box but is not the box's subject —
   the store's shelf under the court's prices, the notification line under the
   venue's hours. A rule and a quiet title rather than a second border: a box
   inside a box inside a card is three frames for one form. */
.mc-settings__sub {
  margin-top: 0.35rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--mc-line);
}
.mc-settings__sub-title {
  margin-bottom: 0.6rem;
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--mc-muted);
}

/* The well is a shade tighter at the top, the way the store and the policies
   poster are. The band this used to be giving back is gone — the well's own top
   is 1.5em now that the logo disc has left the card's edge (see .mc-well) — and
   what is left is the quarter-rem those three pages share: a form in a card
   wants no band over it. */
#admin-settings .mc-well { padding-top: 1.25rem; }

/* The open-play session register on the desk's panel. */
/* The roster scrolls inside its box; the modal around it stays where it is. */
.mc-session-scroll { max-height: 50vh; overflow-y: auto; }
.mc-session-table { font-size: 0.85rem; }
.mc-session-table thead th { position: sticky; top: 0; background: #fff; z-index: 1; }
.mc-session-table th { font-weight: 600; color: var(--mc-muted); white-space: nowrap; }
.mc-session-table td { vertical-align: middle; white-space: nowrap; }
