/* App-owned structure for mvp.dancesimple.org. Every colour, space and type
   VALUE comes from the vendored tokens (public/brand/tokens.css); the brand
   lockup, fonts, .wrap/.band-inner and the table-scroll pattern come from the
   vendored brand.css. This file adds only what the launch app needs. */

/* The stylesheet had no box-sizing reset, so every `width: 100%` meant "100% of the container,
   then add my padding and border on top". Two rules do exactly that: the phone-width
   `.btn { width: 100% }` below, and `input/select { width: 100% }`. Inside anything padded, the
   element therefore overhangs its container: measured at 390px, "See the membership" and "Join the
   group" ran from x=48 to x=384 inside a .card whose inner edge is x=342, a 42px overhang past the
   plate and 6px from the screen edge, and the door's search field ran under its own Find button.
   border-box makes 100% mean 100%. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* The type tokens had never been applied to anything. tokens.css defines --font-body,
   --font-size-base and --line-height-base, and brand.css declares both @font-face blocks and
   serves both woff2 files, but the rule that binds them lives in the ORG site's main.css, which
   scripts/vendor-brand.sh does not vendor. So every heading, paragraph, table cell, form label and
   legal page rendered in the browser's default serif, and nunito-sans-var.woff2 was served by the
   app and never once requested by a browser. Measured, not inferred: computed font-family on body,
   h1, h2, td and footer was "Times New Roman", and the only font file fetched on / was
   fredoka-var.woff2. Nothing caught it because no test has ever rendered a pixel. Fredoka leads,
   Nunito Sans follows: the operator's pick, tokens.css:39-42. */
body {
  font-family: var(--font-body);
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
}

h1,
h2,
h3 {
  font-family: var(--font-display);
}

.skip-link {
  position: absolute;
  left: -999px;
}
.skip-link:focus {
  position: static;
  display: inline-block;
  padding: var(--space-2);
}

.site-header {
  border-bottom: 1px solid var(--color-border);
  padding: var(--space-3) 0;
}
.site-header .wrap,
.site-footer .wrap {
  max-width: var(--max-width-wide);
}
.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
  flex-wrap: wrap;
}
/* The header's quick-access button, half the size of a page button (operator 2026-09-19, the
   scanner: "top right after the logo ... half size button so it's like quick access"). At phone
   width every .btn is stretched full width (the 760px rule below); this one stays small and at
   the right end, which the two-class selector guarantees. */
.site-header .header-link {
  width: auto;
  margin-left: auto;
  padding: 0.35rem 0.7rem;
  font-size: 0.85rem;
}
.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-nav a {
  color: var(--color-text);
  text-decoration: none;
  font-family: var(--font-display);
}
.site-nav a[aria-current='page'],
.site-nav a:hover {
  color: var(--color-accent);
}

main.wrap {
  padding-top: var(--space-4);
  padding-bottom: var(--space-5);
}

.site-footer {
  border-top: 1px solid var(--color-border);
  padding: var(--space-4) 0;
  color: var(--color-muted);
  font-size: 0.9rem;
}
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  list-style: none;
  margin: 0 0 var(--space-3);
  padding: 0;
}
.footer-links a,
.site-link a {
  color: var(--color-text);
}
.entity-line {
  margin: 0 0 var(--space-2);
}

.draft-banner {
  background: var(--color-field-butter);
  border-bottom: 1px solid var(--color-border);
  padding: var(--space-2) 0;
  font-weight: 600;
}

h1 {
  font-size: 2rem;
  line-height: 1.15;
  margin: 0 0 var(--space-3);
}
h2 {
  font-size: 1.4rem;
  margin: var(--space-4) 0 var(--space-2);
}
.lede {
  font-size: 1.1rem;
  max-width: 60ch;
}
.when {
  font-family: var(--font-display);
  font-size: 1.1rem;
  margin: 0 0 var(--space-3);
}

.card {
  border-radius: var(--radius);
  padding: var(--space-3);
  background: var(--color-field-blush);
}
/* A form straight after a conditions card was touching it (operator 2026-09-19: "the yellow
   box is too close" to Your details on /friend); the error box between them has its own margin. */
.card + form {
  margin-top: var(--space-3);
}
.card-mint {
  background: var(--color-field-mint);
}
.card-butter {
  background: var(--color-field-butter);
}
.card-sky {
  background: var(--color-field-sky);
}
.card h2,
.card h3 {
  margin-top: 0;
  font-size: 1.2rem;
}
.card .conditions {
  margin: var(--space-2) 0;
  padding-left: 1.2rem;
  font-size: 0.95rem;
}
.share-link {
  overflow-wrap: anywhere;
}

/* Staff pages are tools, not reading matter. main.wrap is capped at --max-width (42rem / 672px),
   which is right for a privacy notice and wrong for the metrics tables: on a 1440px screen the
   "Total" column of "Events per night" and "Scan outcomes" sat outside that 672px box and had to be
   scrolled to, with around 380px of empty page beside it. The door list gets the same room for
   names and Admit buttons. Reading pages are untouched. */
.wrap-staff {
  max-width: var(--max-width-wide);
}

.btn {
  display: inline-block;
  padding: 0.7rem 1.2rem;
  border-radius: var(--radius);
  border: 2px solid var(--color-accent);
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  text-decoration: none;
  cursor: pointer;
}
.btn-secondary {
  background: transparent;
  color: var(--color-accent);
}
/* The one hover for every pink button (operator 2026-09-18: "it should be a reusable format
   ... same with any other pink type buttons"). Every filled one darkens the same way on hover
   and keyboard focus: the app's own .btn, the source's .btn-primary and every live Book. The
   outlined ones, .btn-secondary and the source's .btn-ghost, take the source's pale wash. A
   disabled control keeps its own look. The values are the source's own. */
.btn:not(.btn-secondary):not(.btn-ghost):not(.btn-blue):not([disabled]):hover,
.btn:not(.btn-secondary):not(.btn-ghost):not(.btn-blue):not([disabled]):focus-visible,
.btn-book:not([disabled]):hover,
.btn-book:not([disabled]):focus-visible {
  background: #be185d;
  border-color: #be185d;
  color: var(--color-accent-contrast);
}
/* The one blue button: the Event ledger, outlined like the other secondary buttons, in the
   Pair mark's blue (operator 2026-09-19: "blue instead of pink", then "you should have kept
   the Event ledger design the same, but just made it blue. it's standing out too much"). On
   hover it takes a pale blue wash, as the pink outlined ones take a pale pink one. */
.btn-blue {
  background: transparent;
  border-color: var(--plate-blue);
  color: var(--plate-blue);
}
.btn-blue:not([disabled]):hover,
.btn-blue:not([disabled]):focus-visible {
  background: #eff6ff;
  color: #1d4ed8;
}
.btn-secondary:not([disabled]):hover,
.btn-secondary:not([disabled]):focus-visible,
.btn.btn-ghost:hover,
.btn.btn-ghost:focus-visible {
  background: #fdf2f8;
  color: #be185d;
}
.btn + .btn {
  margin-left: var(--space-2);
}
.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-3) 0;
}
.actions .btn + .btn {
  margin-left: 0;
}

table {
  width: 100%;
  border-collapse: collapse;
}
th,
td {
  text-align: left;
  padding: var(--space-2);
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}
th {
  font-family: var(--font-display);
  font-weight: 600;
}
td.price {
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 600;
}

form {
  max-width: 34rem;
}
fieldset {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-3);
  margin: 0 0 var(--space-3);
}
legend {
  font-family: var(--font-display);
  font-weight: 600;
  padding: 0 var(--space-2);
}
label {
  display: block;
  margin: var(--space-2) 0 var(--space-2);
}
label.choice {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
}
/* The display rules above would beat the UA's [hidden]; public/js/signup.js hides the ticket
   choices a picked night does not sell, so the hidden state is restated. */
label[hidden] {
  display: none;
}
input[type='text'],
input[type='email'],
select {
  display: block;
  width: 100%;
  padding: 0.6rem;
  margin-top: 0.3rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font: inherit;
}
input[type='checkbox'],
input[type='radio'] {
  width: 1.2rem;
  height: 1.2rem;
  margin-top: 0.2rem;
  /* A tick sits in a flex label, and a flex item shrinks to make room for long text, so the
     box beside a two-line label came out smaller than the one beside "I am 18 or over."
     (operator 2026-09-18: "why the checkboxes are all different sizes?"). Never shrink it. */
  flex: 0 0 auto;
}
.hint {
  color: var(--color-muted);
  font-size: 0.9rem;
}
.privacy-summary {
  background: var(--color-field-sky);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  margin: var(--space-3) 0;
  font-size: 0.95rem;
}
.notice,
.error-box {
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  margin: var(--space-3) 0;
}
.notice {
  background: var(--color-field-mint);
}
.error-box {
  background: var(--color-field-butter);
  border-left: 4px solid var(--color-accent);
}

.legal h2 {
  font-size: 1.2rem;
}
.legal table {
  font-size: 0.95rem;
}
.legal .contract-block {
  background: var(--color-field-sky);
  border-radius: var(--radius);
  padding: var(--space-3);
}
pre.form-text {
  white-space: pre-wrap;
  background: var(--color-field-sky);
  border-radius: var(--radius);
  padding: var(--space-3);
  font: inherit;
}

@media (max-width: 760px) {
  h1 {
    font-size: 1.6rem;
  }
  .btn {
    width: 100%;
    text-align: center;
  }
  .btn + .btn {
    margin-left: 0;
    margin-top: var(--space-2);
  }
}

/* ticket + pass pages */
.ticket {
  text-align: center;
}
.ticket-name {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 600;
  margin: 0;
}
/* The homepage's date tile beside the name, the kind chip and the time under it (operator
   2026-09-19: the date "needs to be clear and easy to see" and the kind must be told apart).
   The tile and .chip rules are vendored brand CSS; this is only their arrangement. */
.ticket-card {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-2) auto var(--space-3);
  text-align: left;
}
.ticket-card-body p {
  margin: 0;
}
.ticket-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.35rem 0 !important;
}
.ticket-when {
  color: var(--color-muted);
}
/* One colour per kind of ticket, so the door helper sees which at a glance. A special event
   keeps the homepage's accent chip (the same chip its row wears) plus the age band chip; the
   ordinary kinds take the brand's other plate colours, white ink on each as the plates do. */
.ticket-party .ticket-format {
  background: var(--plate-teal);
  color: #ffffff;
}
.ticket-dance-express .ticket-format {
  background: var(--plate-blue);
  color: #ffffff;
}
.ticket-fundamentals .ticket-format {
  background: var(--plate-green);
  color: var(--plate-green-ink);
}
.ticket-super-dance-express .ticket-format {
  background: var(--plate-amber);
  color: var(--plate-amber-ink);
}
/* The membership pass wears the same card (operator 2026-09-19: "needs to follow our badge and
   easy to read for membership too"). The tile says MEMBER where a ticket says its date, in the
   date's slot and the date's tile, sized so the word fits; the tier chip takes the colour of the
   top session the tier covers, so it matches the ticket of the same kind. */
.pass-tile {
  width: auto;
  min-width: 4.6rem;
  padding: 0 0.6rem;
}
.pass-tile .dt-day {
  font-size: 1.05rem;
  letter-spacing: 0.06em;
}
.pass-party .ticket-format {
  background: var(--plate-teal);
  color: #ffffff;
}
.pass-dance-express .ticket-format {
  background: var(--plate-blue);
  color: #ffffff;
}
.pass-everything .ticket-format {
  background: var(--plate-green);
  color: var(--plate-green-ink);
}
.qr {
  display: block;
  margin: var(--space-3) auto;
  width: 240px;
  height: 240px;
  max-width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: #fff;
}
/* USED and REFUNDED read in red, so the door helper notices a ticket that is not valid
   (operator 2026-09-19: "the USED should be red, so the door help notices it"). The brand
   tokens carry no red, so this one is the app's own; white on it passes AA. */
.used-banner {
  display: inline-block;
  margin: 0 0 var(--space-3);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius);
  background: #b91c1c;
  color: #ffffff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.4rem;
  letter-spacing: 0.08em;
}

/* The door scanner (public/js/door-scan.js): the camera view, one line of status, and the
   answer big enough to read at arm's length, green for a tick and the ticket's red for a no. */
.scan-video {
  display: block;
  width: 100%;
  max-width: 480px;
  margin: var(--space-3) auto;
  border-radius: var(--radius);
  background: #000;
}
.scan-status {
  text-align: center;
}
.scan-result {
  margin: var(--space-3) 0;
  padding: var(--space-3);
  border-radius: var(--radius);
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 600;
  text-align: center;
}
.scan-result.ok {
  background: var(--color-field-mint);
}
.scan-result.refused {
  background: #b91c1c;
  color: #ffffff;
}
.scan-form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: flex-end;
}
.scan-form label {
  flex: 1 1 16rem;
}

/* the four-step stepper after payment */
.stepper {
  display: flex;
  gap: var(--space-2);
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-size: 0.9rem;
  color: var(--color-muted);
}
.stepper li {
  padding: 0.2rem 0.7rem;
  border-radius: 999px;
  background: var(--color-field-sky);
}
.stepper li[aria-current='step'] {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}
.resend-form {
  margin: var(--space-2) 0 var(--space-3);
}
.resend-form button[disabled] {
  opacity: 0.5;
  cursor: default;
}

/* the door list (staff phone or laptop) */
/* The no-payment banner in the brand's butter, not the notice's mint (operator 2026-09-19:
   "the other brand pastel yellow instead of green"). */
.door-banner {
  font-weight: 600;
  background: var(--color-field-butter);
}
.door-search {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: flex-end;
  max-width: none;
}
.door-search label {
  flex: 1 1 14rem;
  margin: 0;
}
.walkin-form,
.door-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  max-width: none;
}
/* The tally: expected, admitted, walk-ins, no-shows, on one line (operator 2026-09-19: "a
   compact version so it doesn't take up much screenspace"). */
.door-tally {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  margin: 0 0 var(--space-2);
  font-size: 0.9rem;
  color: var(--color-muted);
  max-width: none;
}
.door-tally b {
  font-size: 1.05rem;
  color: var(--color-text);
}
/* The list in groups that fold on their heading, each heading carrying its count (operator
   2026-09-19: "make it a collapseable/uncollapseable list for each"). The details element
   folds by itself; public/js/door.js hides a group with no match while the helper types, so
   the hidden state is restated. */
.door-group {
  margin: 0 0 var(--space-3);
}
.door-group summary {
  cursor: pointer;
  padding: var(--space-2) 0;
  border-bottom: 2px solid var(--color-border);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.1rem;
}
.door-group[hidden] {
  display: none;
}
.door-count {
  display: inline-block;
  min-width: 1.6rem;
  padding: 0 0.5rem;
  border-radius: 999px;
  background: var(--color-field-sky);
  font-family: var(--font-body);
  font-size: 0.85rem;
  text-align: center;
  vertical-align: middle;
}
/* a walk-in taken back (operator 2026-09-19): the question, then Yes or No */
.undo-ask p {
  margin: 0 0 var(--space-2);
}
.undo-ask .undo-form {
  display: inline;
  max-width: none;
}
.door-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.door-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
  align-items: center;
}
/* the grid above would beat the UA's [hidden]; public/js/door.js hides the rows the name
   filter drops, so the hidden state is restated */
.door-row[hidden] {
  display: none;
}
.door-name {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 600;
}
.door-detail,
.door-status {
  grid-column: 1;
  font-size: 0.95rem;
}
.admit-form {
  grid-column: 2;
  grid-row: 1 / span 3;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: flex-end;
  max-width: none;
}
.btn-small {
  padding: 0.5rem 1rem;
}
.btn-small[disabled] {
  opacity: 0.4;
  cursor: default;
}
label.choice.inline {
  margin: 0;
  font-size: 0.9rem;
}
/* The door's 18+ tick was a default browser checkbox, measured at about 17x19 CSS px, roughly a
   third of the 44px a thumb needs. It is the one control on the page that protects the licence,
   and it is used one-handed, in the dark, with a queue waiting. The whole label is made the target
   so a near miss still lands, and the box itself is scaled up to match. */
.door-row label.choice.inline {
  align-items: center;
  min-height: 44px;
  padding: 0 var(--space-2) 0 0;
  cursor: pointer;
}
.door-row label.choice.inline input[type='checkbox'] {
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  accent-color: var(--color-accent);
}
.tag {
  display: inline-block;
  padding: 0.1rem 0.6rem;
  border-radius: 999px;
  background: var(--color-field-sky);
  font-size: 0.85rem;
}
.tag-used {
  background: var(--color-text);
  color: var(--color-bg);
}
.tag-refused,
.tag-banned {
  background: var(--color-field-butter);
  font-weight: 600;
}
.tag-member {
  background: var(--color-field-mint);
}
.tag-pending {
  background: var(--color-field-blush);
}
.door-banned .door-name {
  text-decoration: line-through;
}

/* the operator's metrics page */
.table-scroll {
  max-width: 100%;
  overflow-x: auto;
  margin: 0 0 var(--space-3);
}
table.metrics {
  width: auto;
  min-width: 100%;
  margin: 0;
}
table.metrics caption {
  text-align: left;
  font-family: var(--font-display);
  font-weight: 600;
  padding: var(--space-2) 0;
}
table.metrics td {
  white-space: nowrap;
}
table.metrics td.total {
  font-weight: 600;
}

/* ---- The London city page, ported from dancesimple-org assets/css/main.css ----
   / is a duplicate of https://dancesimple.org/cities/uk/london/dsteam/ (src/views/home.ts).
   Everything its markup needs that brand.css does not vendor is copied here by selector
   (never by line number, as scripts/vendor-brand.sh does), in the source's own values; the
   rules for the sections the MVP hides are not. Two renames: .pm-payg-cell is
   .pm-ticket-cell and .pricing-payg-note is .pricing-ticket-note, because in this app "PAYG"
   may only ever name the walk-in door price and src/pages.test.ts greps every rendered page
   for the token. The rules under the last comment are the app's own: Book is a LINK here
   where the source renders an inert button, and the app's .btn margins are cancelled inside
   the two button pairs. */

/* base */
.prose h1 {
  line-height: 1.2;
}
.prose a {
  color: var(--color-accent);
}
.prose .btn {
  color: var(--color-accent-contrast);
  text-decoration: none;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* section 1, the operator bracket */
.title-operator {
  display: inline-block;
  font-size: 0.6em;
  font-weight: 600;
  color: var(--color-muted);
}
.title-operator.is-official {
  color: var(--color-accent);
}

/* the event tables */
.school-list {
  width: 100%;
  border-collapse: collapse;
}
.school-list th,
.school-list td {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-border);
}

/* section 2, the row controls */
.event-actions {
  white-space: nowrap;
}
.event-actions-stack {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.3rem;
}
.event-actions-stack .btn-details,
.event-actions-stack .btn-book {
  width: 100%;
  text-align: center;
}
.btn-details,
.btn-book {
  font: inherit;
  font-size: 0.85rem;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  border: 1px solid #1a1a1a;
  background: #fff;
  cursor: pointer;
}
.btn-details:hover {
  background: #f3f4f6;
}
.btn-book {
  border-color: #db2777;
  background: #db2777;
  color: #fff;
}
.btn-book[disabled] {
  background: #e5e7eb;
  border-color: #d1d5db;
  color: #6b7280;
  cursor: not-allowed;
}
.btn-book.is-sold-out[disabled] {
  background: #fff;
  border-color: #9ca3af;
  color: #4b5563;
  text-decoration: line-through;
}
.special-events-listing {
  min-width: 40rem;
}

/* section 3 */
.regular-date {
  white-space: nowrap;
  width: 1%;
}
#regular-table {
  min-width: 36rem;
}

/* section 4, the buttons, the fixed bar and the modal */
.city-actions {
  margin: var(--space-3) 0;
}
.actions-line {
  margin: 0 0 0.5rem;
}
.actions-buttons {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.btn-primary,
.btn-ghost {
  display: inline-block;
  padding: 0.45rem 1rem;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 600;
  border: 1px solid #db2777;
}
.btn.btn-primary {
  background: #db2777;
  color: #fff;
}
.btn.btn-ghost {
  background: #fff;
  color: #db2777;
}
/* Their hover and focus states are the shared ones next to .btn above, so every pink button
   on the site behaves the same, not just these two. */

.member-bar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 40;
  background: #fff;
  border-top: 1px solid #e5e7eb;
  box-shadow: 0 -2px 10px rgb(0 0 0 / 0.06);
}
.member-bar[hidden] {
  display: none;
}
.member-bar-inner {
  max-width: var(--wrap, 68rem);
  margin: 0 auto;
  padding: 0.55rem 1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.member-bar-text {
  margin: 0;
  font-weight: 600;
}
.member-bar-actions {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
@media (max-width: 32rem) {
  .member-bar-text {
    flex-basis: 100%;
    font-size: 0.95rem;
  }
  .member-bar-actions {
    flex-basis: 100%;
  }
  .member-bar-actions .btn-primary,
  .member-bar-actions .btn-ghost {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    font-size: 0.85rem;
    line-height: 1.25;
    padding: 0.5rem 0.6rem;
  }
}

.event-modal {
  width: min(46rem, 92vw);
  max-height: 88vh;
  overflow-y: auto;
  border: 0;
  border-radius: 14px;
  padding: 1.25rem 1.4rem 1.6rem;
  background: #fff;
  color: #1a1a1a;
}
.event-modal::backdrop {
  background: rgb(0 0 0 / 0.5);
}
.event-modal h3 {
  margin: 0 0.5rem 0.25rem 0;
}
.event-modal-when {
  margin: 0 0 0.9rem;
  font-weight: 600;
}
.event-modal-close-form {
  float: right;
  margin: -0.4rem -0.5rem 0 0;
}
.event-modal-close {
  font: inherit;
  font-size: 1.5rem;
  line-height: 1;
  padding: 0.1rem 0.5rem;
  border: 0;
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
}
.event-modal-facts {
  margin: 0 0 1rem;
}
.event-modal-facts > div[hidden] {
  display: none;
}
.event-modal-facts > div {
  display: grid;
  grid-template-columns: 8rem 1fr;
  gap: 0.5rem;
  padding: 0.28rem 0;
  border-bottom: 1px solid #f0f0f0;
}
.event-modal-facts dt {
  font-weight: 600;
  margin: 0;
}
.event-modal-facts dd {
  margin: 0;
}
.event-modal-hero {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
  margin: 0 0 0.6rem;
}
/* the author display above beats the UA's [hidden], so the empty hero is restated hidden */
.event-modal-hero[hidden] {
  display: none;
}
.event-modal-collage {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 0.4rem;
}
.event-modal-collage img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 8px;
}
.event-modal-conduct {
  margin: 1rem 0 0.6rem;
  font-size: 0.9rem;
  color: #555;
}
.event-modal-book {
  margin: 0;
}
.modal-open,
.modal-open body {
  overflow: hidden;
}

/* section 3, the monthly special's badge and the venue's Maps link (main.css 1704, 1789, 3123) */
.regular-entry.is-monthly td {
  color: var(--color-monthly);
  font-weight: 700;
}
.badge-special {
  display: inline-block;
  background: var(--color-monthly);
  color: var(--color-bg);
  font-size: 0.7em;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1;
  padding: 0.28em 0.6em;
  border-radius: 999px;
  vertical-align: 0.12em;
  white-space: nowrap;
}
@media (max-width: 560px) {
  .regular-date .badge-special {
    display: block;
    width: fit-content;
    margin-top: 0.3em;
  }
}
.venue-link {
  text-decoration: underline;
}

/* section 5, the group-chat CTA */
.join-cta {
  margin-top: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-field-blush);
}

/* section 6, the plates and the matrix */
.ds-plate {
  margin: var(--space-4) 0;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: calc(var(--radius) + 2px);
  background: var(--plate-bg);
  color: var(--plate-ink);
}
.ds-plate.field-sky {
  background: var(--color-field-sky);
}
.ds-plate.field-butter {
  background: var(--color-field-butter);
}
.ds-plate h3.plate-title {
  font-family: var(--plate-font-display);
  font-size: 1.7rem;
  line-height: 1.25;
  margin: 0 0 0.35rem;
  text-wrap: balance;
  color: var(--plate-ink);
}
.ds-plate .plate-sub {
  color: var(--plate-muted);
  margin: 0 0 1.6rem;
  max-width: 62ch;
}
.mf-pm {
  border: 1px solid var(--plate-line-strong);
  border-radius: calc(var(--radius) + 2px);
  background: var(--plate-card);
  padding: 0.9rem 1.1rem;
  margin: 0 0 1.6rem;
}
.mf-pm-rows {
  display: grid;
  gap: 0.35rem;
  margin: 0;
}
.mf-pm-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 0.8rem;
  font-size: 0.85rem;
  align-items: baseline;
}
.mf-pm-row .mf-calc {
  color: var(--plate-muted);
  font-variant-numeric: tabular-nums;
}
.mf-pm-row .mf-amt {
  font-variant-numeric: tabular-nums;
  color: var(--plate-ink);
  min-width: 4.5rem;
  text-align: right;
}
.mf-pm-row.mf-gravy span {
  color: var(--plate-dim);
}
.mf-pm-row.mf-gravy .mf-calc {
  color: var(--plate-green);
}
.mf-take {
  margin: 0.7rem 0 0;
  padding-top: 0.6rem;
  border-top: 1px dashed var(--plate-line-strong);
  font-size: 0.85rem;
  color: var(--plate-accent);
  font-weight: 600;
}
.pricing-matrix table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.95rem;
}
.pricing-matrix th,
.pricing-matrix td {
  padding: 0.65rem 0.8rem;
  border-bottom: 1px solid var(--plate-line);
  text-align: center;
}
.pricing-matrix th[scope='row'],
.pricing-matrix thead th:first-child {
  text-align: left;
}
.pricing-matrix thead th {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--color-text);
  vertical-align: bottom;
}
.pricing-matrix thead .pm-price {
  display: block;
  font-size: 1.15rem;
  color: var(--color-text);
}
.pricing-matrix thead .pm-per {
  display: block;
  font-weight: 400;
  font-size: 0.75rem;
  color: var(--color-muted);
}
.pm-tick {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-accent);
}
/* The bring-a-friend matrix ticks in the Pair mark's blue (operator 2026-09-18: "instead of
   pink dots, can we use blue dots as per our logo colour?"); the memberships matrix keeps the
   accent. The token is the vendored brand's. */
.friend-matrix .pm-tick {
  background: var(--plate-blue);
}
.pm-no {
  color: var(--plate-dim);
}
/* The asterisk note under each matrix (operator 2026-09-18: "make this italic and smaller
   font"). */
.pm-footnote {
  margin: 0.5rem 0 0;
  font-size: 0.8rem;
  font-style: italic;
  color: var(--color-muted);
}
.pm-ticket-cell {
  font-size: 0.85rem;
  color: var(--color-muted);
}

/* app-owned: Book is a link here, and the app's own .btn spacing stays out of the pairs.
   The display rule would beat the UA's [hidden] rule, and the modal's Book is hidden for a
   sold-out night, so the hidden state is restated (the source does the same for .member-bar). */
a.btn-book {
  display: inline-block;
  text-decoration: none;
}
a.btn-book[hidden] {
  display: none;
}
.prose a.btn-book {
  color: #fff;
}
.member-bar-actions .btn + .btn,
.actions-buttons .btn + .btn {
  margin: 0;
}

/* app-owned: an event table shows four rows and folds the rest, ten in all, behind a control
   that says what it does (operator 2026-09-18, then 2026-09-21: "more than 4 events should be
   collapseable and uncollapseable, with max limit of 10 events"). A checkbox and its label, so
   it works with no script: the box sits before the table and the label after it, which is what
   the sibling selectors lean on. The label is an outlined pill like Log in (.btn.btn-ghost),
   centred under the table, its words and a chevron that turns when open; 44px tall for a thumb. */
.more-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.more-rows {
  display: none;
}
.more-toggle:checked ~ .table-wrap .more-rows {
  display: table-row-group;
}
.more-label {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: fit-content;
  min-height: 44px;
  margin: var(--space-2) auto 0;
  cursor: pointer;
}
.more-label::after {
  content: '';
  width: 0.55rem;
  height: 0.55rem;
  margin-top: -0.3rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.2s;
}
.more-toggle:checked ~ .more-label::after {
  margin-top: 0.3rem;
  transform: rotate(-135deg);
}
.more-toggle:checked ~ .more-label .more-text,
.more-toggle:not(:checked) ~ .more-label .less-text {
  display: none;
}
.more-toggle:focus-visible ~ .more-label {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* app-owned, /join: the membership picker as cards within a card (operator 2026-09-21: "card
   within card, so the background colour changes too, and it should say [Your selection]").
   The fieldset is the outer card, the blush field colour with no border, its legend floated so
   the colour covers it; each membership is a white card that is the radio's label, so a tap
   anywhere on it picks it. The picked card takes the pink wash and a pink border and its tag
   shows, off the radio's :checked through :has(), so there is no script; the radio stays in
   the card, so the keyboard works as it always did and a browser without :has() still shows
   the pick the plain way. */
fieldset.tier-picker {
  border: 0;
  background: var(--color-field-blush);
}
.tier-picker legend {
  float: left;
  width: 100%;
  padding: 0;
  margin: 0 0 var(--space-2);
}
.tier-cards {
  clear: both;
  display: grid;
  gap: var(--space-2);
}
label.tier-card {
  position: relative;
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  margin: 0;
  padding: var(--space-3);
  background: #fff;
  border: 2px solid var(--color-border);
  border-radius: var(--radius);
  cursor: pointer;
}
label.tier-card:hover {
  border-color: var(--color-accent);
}
label.tier-card:has(input:focus-visible) {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
label.tier-card:has(input:checked) {
  background: #fdf2f8;
  border-color: var(--color-accent);
}
.tier-body {
  display: grid;
  gap: 0.25rem;
}
.tier-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--space-2);
}
.tier-name {
  font-family: var(--font-display);
  font-size: 1.15rem;
}
.tier-price {
  color: var(--color-accent);
  font-weight: 600;
}
.tier-covers,
.tier-friend {
  font-size: 0.95rem;
}
.tier-picked {
  display: none;
  position: absolute;
  top: -0.75rem;
  right: var(--space-3);
  padding: 0.15rem 0.7rem;
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 600;
}
label.tier-card:has(input:checked) .tier-picked {
  display: inline-block;
}
