/* Heat Parties — site stylesheet
   Built from dev/design_brief.png, dev/CSS styles.txt, and the reference comps. */

/* ---------- Fonts ---------- */
@font-face {
  font-family: "Bethany Elingston";
  src: url("../fonts/BethanyElingston.50f7ec533a08.otf") format("opentype");
  font-weight: normal;
  font-display: swap;
}
@font-face {
  font-family: "Casablanca";
  src: url("../fonts/Casablanca.450d9e58ce06.ttf") format("truetype");
  font-weight: normal;
  font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  --hp-black: #000000;
  --hp-ink: #0a0708;
  --hp-red: #ff0000;
  --hp-red-deep: #980000;
  --hp-red-dark: #6d0000;
  --hp-orange: #c4711a;
  /* The orange of "Parties" in logo.png, sampled from the artwork. */
  --hp-orange-brand: #d16200;
  --hp-orange-deep: #a3560d;
  --hp-cream: #ece29b;
  /* A signal yellow, not the soft parchment of --hp-cream: this is the one
     word on the site that has to read as a light being on. */
  --hp-yellow: #ffd21c;
  --hp-white: #ffffff;
  --hp-smoke: rgba(255, 255, 255, 0.62);
  --hp-line: rgba(236, 226, 155, 0.22);

  --font-display: "Casablanca", "Brush Script MT", cursive;
  --font-body: "Bethany Elingston", "Playfair Display", Georgia, "Times New Roman", serif;

  /* Bethany Elingston sets very tight, so every run of it is tracked out.
     One value drives the whole site -- change it here to taste. Rules that
     already declare their own letter-spacing (nav, headings, buttons, table
     headers) keep theirs. */
  --tracking-body: 0.045em;

  --shell: 1180px;
  --radius: 10px;
}

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

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

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--hp-black);
  color: var(--hp-white);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  letter-spacing: var(--tracking-body);
}

a { text-decoration: none; color: var(--hp-cream); }
a:hover { color: var(--hp-white); }

img { max-width: 100%; height: auto; display: block; }

h1, h2, h3 { margin: 0 0 0.5em; }

/* Casablanca is a joined script -- spacing it apart breaks the letterforms,
   so everything set in the display face opts out of the body tracking. */
h1,
.tile .tile-value,
.tier .tier-name,
.page-art-caption,
.heat-tagline .script,
.countdown-name,
.coming-soon-lead { letter-spacing: normal; }

h1 {
  font-family: var(--font-display);
  color: var(--hp-red);
  font-size: clamp(2.6rem, 6vw, 4.2rem);
  font-weight: 400;
  line-height: 1.1;
}

h2 {
  font-family: var(--font-body);
  color: var(--hp-red);
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.5rem;
  font-size: clamp(1rem, 2vw, 1.3rem);
}

h3 {
  font-family: var(--font-body);
  color: var(--hp-cream);
  text-transform: uppercase;
  letter-spacing: 0.22rem;
  font-size: 0.95rem;
}

/* ---------- Header ----------
   Centred wordmark over the tagline, exactly as every comp opens. */
.site-header {
  position: relative;
  z-index: 2;
  padding: 2.6rem 1.5rem 0;
  text-align: center;
}

.site-header .logo {
  margin: 0 auto;
  width: min(600px, 46vw);
  min-width: 260px;
}

.tagline {
  color: var(--hp-cream);
  font-size: clamp(1rem, 2.2vw, 1.4rem);
  margin: 0.4rem 0 0;
}

/* ---------- Navigation ----------
   Primary links centred in the bar, account links pinned right. */
.nav {
  position: relative;
  /* Above .messages, .nav-staff and .shell (all 1-2). `.nav` establishes a
     stacking context, so the Media dropdown inside it can never out-rank a
     later sibling on its own -- the whole nav layer has to sit higher, or the
     flash-message strip paints straight over the open menu. */
  z-index: 20;
  /* Wider than the content shell, so the account links reach the page edge
     the way they do in the comps. */
  max-width: min(1520px, 95vw);
  margin: 1.7rem auto 0;
  padding: 0 1.5rem 0.4rem;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: clamp(1.5rem, 5vw, 4.5rem);
}

.nav-primary {
  display: flex;
  /* One row, never two. Where the row stops fitting, the Menu button takes
     over instead -- see the 1000px query under Responsive. */
  flex-wrap: nowrap;
  justify-content: center;
  gap: 0.9rem clamp(1.1rem, 2.6vw, 2.7rem);
}

.nav a {
  font-family: var(--font-body);
  font-size: clamp(13px, 0.92vw, 16px);
  color: var(--hp-white);
  text-transform: uppercase;
  letter-spacing: 0.12rem;
  white-space: nowrap;
}
.nav a:hover { color: var(--hp-cream); }
/* The page you are on: cream, and underlined so it reads as current even
   where the colour difference is subtle. The offset keeps the rule clear of
   the uppercase letterforms. */
/* "Media" holds Gallery and Videos. Built on <details> so it opens on click
   and on keyboard without JavaScript; hover is layered on for pointers only,
   so it never traps a touch user who cannot hover. */
.nav-group { position: relative; }
.nav-group > summary {
  font-family: var(--font-body);
  font-size: clamp(13px, 0.92vw, 16px);
  color: var(--hp-white);
  text-transform: uppercase;
  letter-spacing: 0.12rem;
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}
.nav-group > summary::-webkit-details-marker { display: none; }
.nav-group > summary::after {
  content: " \25BE";     /* U+25BE caret, so it reads as a menu */
  font-size: 0.8em;
}
.nav-group > summary:hover { color: var(--hp-cream); }
.nav-group > summary:focus-visible {
  outline: 2px solid var(--hp-cream);
  outline-offset: 4px;
}
.nav-group-menu {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: calc(100% + 0.55rem);
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 0.8rem 1.1rem;
  background: var(--hp-black);
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.6);
}
@media (hover: hover) {
  .nav-group:hover > .nav-group-menu { display: flex; }
  .nav-group:hover > summary { color: var(--hp-cream); }
}

.nav a.is-current,
.nav-staff a.is-current {
  color: var(--hp-cream);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.42em;
}
.nav-staff a.is-current { color: var(--hp-white); }
.nav-group > summary.is-current {
  color: var(--hp-cream);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.42em;
}

.nav .nav-account {
  display: flex;
  gap: 1.4rem;
  align-items: center;
}

/* Hamburger. Hidden until the bar runs out of room. */
.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--hp-line);
  border-radius: 6px;
  color: var(--hp-cream);
  font-family: var(--font-body);
  text-transform: uppercase;
  letter-spacing: 0.18rem;
  font-size: 13px;
  padding: 0.5rem 0.9rem;
  cursor: pointer;
}

.nav-act-log {
  font-family: var(--font-body);
  font-size: 15px;
  color: var(--hp-cream);
  text-transform: uppercase;
  letter-spacing: 0.12rem;
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
}
.nav-act-log:hover { color: var(--hp-white); }
/* Outranks `.nav a` so the link and the button stay the same size. */
.nav a.nav-act-log,
.nav button.nav-act-log { font-size: 15px; }

/* Back-of-house strip, only rendered for staff roles.

   One row at every width. It runs as wide as the main nav rather than the
   content shell -- at the shell's width a Site Manager's eight links wrapped
   even on a wide screen -- and the gaps close up as the window narrows. When
   that is still not enough, the strip moves sideways instead of breaking onto
   a second line.

   No scrollbar, at the user's request. A fade marks each edge where links run
   on, and heat.js lets a mouse wheel move the strip and brings the page you
   are on into view. Touch and trackpads swipe it without help. */
.nav-staff {
  position: relative;   /* keep it above the page art */
  z-index: 2;
  max-width: min(1520px, 95vw);
  margin: 0 auto;
  padding: 0.8rem 1.5rem;
  display: flex;
  flex-wrap: nowrap;
  gap: clamp(1rem, 1.9vw, 1.8rem);
  overflow-x: auto;
  scrollbar-width: none;                       /* Firefox, Chrome and Edge */
  background: linear-gradient(90deg, var(--hp-red-dark), transparent 70%);
  border-bottom: 1px solid var(--hp-line);
}
.nav-staff::-webkit-scrollbar { display: none; }   /* Safari */
/* heat.js sets these only while links are cut off at that edge. A mask
   rather than an overlay, because the strip's own background is a gradient
   that no single overlay colour would match. */
.nav-staff.is-clipped-end {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 3rem), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 3rem), transparent);
}
.nav-staff.is-clipped-start {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 3rem);
  mask-image: linear-gradient(90deg, transparent, #000 3rem);
}
.nav-staff.is-clipped-start.is-clipped-end {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 3rem, #000 calc(100% - 3rem), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 3rem, #000 calc(100% - 3rem), transparent);
}
.nav-staff a {
  flex: none;
  white-space: nowrap;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  color: var(--hp-cream);
}
.nav-staff a:hover { color: var(--hp-white); }

/* ---------- Layout ---------- */
.shell {
  position: relative;
  z-index: 1;
  flex: 1 0 auto;
  width: 100%;
  max-width: var(--shell);
  margin: 0 auto;
  padding: 2.4rem 1.5rem 4rem;
}

.shell.is-narrow { max-width: 720px; }
.prose { max-width: 62ch; }
.prose.is-centered { margin: 0 auto; text-align: center; }

/* Body copy is justified. Set on the container rather than on `p`, so
   anything that declares its own alignment -- the page heading, section
   headings, the tagline, the rules list and the note under it -- simply keeps
   what it has, instead of needing an exception that has to out-specify this
   rule. Centred prose is excluded: justify would override the centring. */
.prose:not(.is-centered),
.page-section { text-align: justify; }
.page-section h3 { text-align: left; }
/* Centred as a block, but the text itself stays ranged left -- long
   paragraphs are hard to read centred. */
.prose.is-column { margin: 0 auto; }

.site-footer {
  flex-shrink: 0;
  padding: 2rem 1.5rem 2.6rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
}
.footer-links { display: flex; justify-content: center; gap: 2.2rem; }

/* Deliberately sans, where the rest of the site is serif: this is a legal
   notice rather than part of the voice, and it should read as fine print. */
.copyright {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  color: var(--hp-smoke);
}
.site-footer a {
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.16rem;
  color: var(--hp-cream);
}

/* ---------- Buttons ---------- */
.button,
button.button {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: bold;
  text-transform: uppercase;
  border-radius: var(--radius);
  /* The brief specifies .8rem; dialled back so short labels stay readable. */
  letter-spacing: 0.35rem;
  padding: 0.75rem 1.9rem 0.75rem 2.25rem;
  border: 0;
  cursor: pointer;
  font-size: 0.95rem;
  color: var(--hp-cream);
  transition: transform 0.12s ease, background-color 0.12s ease;
}
.button:hover { transform: translateY(-1px); color: var(--hp-white); }

.button1 { background-color: var(--hp-black); border: 1px solid var(--hp-cream); }
.button1:hover { background-color: #1a1a1a; }

.button2 { background-color: var(--hp-red-deep); color: var(--hp-white); }
.button2:hover { background-color: #b30000; }

/* Named for <button> as well, because button.button above resets the border to
   nothing and outranks a bare .button-quiet -- which left a quiet <button>
   looking like stray text beside the identical-looking links. */
.button-quiet,
button.button-quiet {
  background: none;
  border: 1px solid var(--hp-line);
  color: var(--hp-cream);
}

/* ---------- Cards & panels ---------- */
.card {
  background: var(--hp-red-deep);
  border-radius: var(--radius);
  padding: 2rem 2.2rem 2.4rem;
}
.card h1 { color: var(--hp-white); text-align: center; }

.panel {
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  padding: 1.5rem 1.7rem;
}

/* ---------- Forms ---------- */
.form-row { margin-bottom: 1.1rem; }

.form-row label {
  display: block;
  color: var(--hp-cream);
  margin-bottom: 0.35rem;
  font-size: 1rem;
}

.card .form-row label { color: var(--hp-cream); }

/* Every text-like control, whatever its type. This used to enumerate types,
   which meant each new one -- search, url, number, time -- silently fell back
   to the browser default and sat at a different height from the selects beside
   it. Excluding the handful that must stay native is the durable way round. */
input:not([type="checkbox"], [type="radio"], [type="file"], [type="submit"],
          [type="button"], [type="reset"], [type="image"], [type="hidden"],
          [type="range"], [type="color"]),
select,
textarea {
  width: 100%;
  padding: 0.7rem 0.8rem;
  border: 0;
  border-radius: 4px;
  background: var(--hp-white);
  color: var(--hp-ink);
  font-family: var(--font-body);
  font-size: 1rem;
  /* Without this, an input and a select fall back to their own intrinsic
     line-heights and end up a couple of pixels apart. */
  line-height: 1.4;
}
input:disabled, textarea:disabled, select:disabled {
  background: #d8d5d5;
  color: #555;
  cursor: not-allowed;
}
textarea { resize: vertical; }

.form-help { display: block; font-size: 0.85rem; color: var(--hp-smoke); margin-top: 0.3rem; }
.form-checkbox { display: flex; gap: 0.6rem; align-items: flex-start; }
.form-checkbox input { width: auto; margin-top: 0.35rem; }

.errorlist {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0;
  color: var(--hp-cream);
  font-size: 0.88rem;
}
.errorlist li::before { content: "— "; }

/* ---------- Messages ---------- */
.messages {
  position: relative;
  z-index: 2;
  max-width: var(--shell);
  margin: 1.4rem auto 0;
  padding: 0 1.5rem;
  list-style: none;
}
.messages li {
  border-left: 3px solid var(--hp-red);
  background: rgba(152, 0, 0, 0.2);
  padding: 0.7rem 1rem;
  margin-bottom: 0.6rem;
  border-radius: 0 4px 4px 0;
}
.messages li.success { border-left-color: var(--hp-cream); }
.messages li.warning { border-left-color: var(--hp-orange); }

/* ---------- Tiles (dashboards) ---------- */
.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.1rem;
  margin: 2rem 0;
}
.tile {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  padding: 1.3rem 1.4rem;
}
.tile .tile-value {
  font-family: var(--font-display);
  font-size: 2.8rem;
  color: var(--hp-red);
  line-height: 1;
}
.tile .tile-label {
  text-transform: uppercase;
  letter-spacing: 0.16rem;
  font-size: 0.8rem;
  color: var(--hp-cream);
  margin-top: 0.5rem;
}
.tile .tile-note { font-size: 0.85rem; color: var(--hp-smoke); }

/* ---------- Staff lists (Executive Dashboard) ----------
   The to-do list, the supply list, and notes, beneath the tiles. The two lists
   reuse the door's tick, sized down: the door's is a large tap target for a
   phone at the entrance, and at that size these lists read as padded rather
   than compact (user, 2026-09-14). */
.list-panel { padding: 1.1rem 1.4rem; }
.list-panel + .list-panel { margin-top: 1rem; }
.list-panel h3 { margin-bottom: 0.6rem; }
.list-add { margin-bottom: 0.4rem; }
.list-add .form-row { margin-bottom: 0.5rem; }
.list-add .form-row label { margin-bottom: 0.15rem; font-size: 0.9rem; }
.list-add-submit { display: flex; align-items: flex-end; }
.list-add textarea { min-height: 4.2rem; }
.staff-list { list-style: none; margin: 0; padding: 0; }
.staff-list-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.8rem;
  padding: 0.3rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.staff-list-item:last-child { border-bottom: none; }
.staff-list-item .tick { min-height: 36px; padding: 0.2rem; gap: 0.4rem; }
.staff-list-item .tick-box { width: 26px; height: 26px; font-size: 1rem; }
.staff-list-item span.tick,
.staff-list-item span.tick:hover { cursor: default; border-color: var(--hp-line); }
.staff-list-item span.tick.is-on { color: var(--hp-cream); }
.staff-list-item span.tick.is-on .tick-box {
  border-color: var(--hp-cream);
  background: var(--hp-cream);
  color: var(--hp-ink);
}
.list-body { flex: 1 1 0; min-width: 0; }
/* A supply has two ticks as well as Delete, so on a narrow screen its name
   takes a row of its own and the ticks wrap beneath it. */
.supply-item .list-body { flex-basis: 12rem; }
.list-title { display: block; color: var(--hp-white); overflow-wrap: break-word; line-height: 1.3; }
.list-meta { display: block; font-size: 0.8rem; color: var(--hp-smoke); line-height: 1.3; }
.list-meta > span + span::before { content: " \00b7  "; }
.staff-list-item.is-overdue .todo-due { color: var(--hp-orange); font-weight: bold; }
.staff-list-item.is-done .list-title { color: var(--hp-smoke); text-decoration: line-through; }
.list-subhead {
  margin: 0.8rem 0 0.1rem;
  font-size: 0.78rem;
  font-weight: normal;
  color: var(--hp-smoke);
  text-transform: uppercase;
  letter-spacing: 0.16rem;
}
.list-empty { padding: 0.3rem 0; }
.list-delete .button { white-space: nowrap; }
.list-actions { display: flex; align-items: center; gap: 0.4rem; }
.list-actions .button { white-space: nowrap; }
/* Row buttons stay small at every width. The site-wide button spacing made
   Delete wider than the text beside it, and on a phone squeezed a title into
   a column one word wide. */
.list-delete .button,
.list-actions .button,
.list-edit .button {
  padding: 0.25rem 0.6rem;
  font-size: 0.7rem;
  letter-spacing: 0.08rem;
}

/* A supply or a note open for editing: a text box, then Save and Cancel. */
.list-edit {
  display: flex;
  flex: 1 1 100%;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.list-edit input[type="text"] { flex: 1 1 14rem; width: auto; }
.note-edit textarea { flex: 1 1 100%; width: 100%; min-height: 5rem; }
.list-edit .button { white-space: nowrap; }
.supply-ticks { display: flex; gap: 0.4rem; }
.supply-ticks .tick { padding: 0.2rem 0.6rem 0.2rem 0.2rem; }

/* A note: its text as typed, line breaks kept, and any address a link. A long
   address breaks anywhere rather than widening the panel. */
.note-body { color: var(--hp-white); line-height: 1.4; overflow-wrap: anywhere; }
/* On a narrow screen the note takes a row of its own, with Edit and Delete
   beneath it, rather than being squeezed into a column beside them. */
.note-item .list-body { flex-basis: 14rem; }

/* Clearing a list: the summary opens the question, and only its button
   deletes. */
.list-clear { margin-top: 0.6rem; }
.list-clear summary { display: inline-block; list-style: none; cursor: pointer; }
.list-clear summary::-webkit-details-marker { display: none; }
.list-clear[open] summary { margin-bottom: 0.5rem; }
.list-clear p { margin: 0 0 0.5rem; font-size: 0.9rem; }

/* On a phone: a little less panel padding, and the ticks back up to a size a
   thumb can hit. */
@media (max-width: 640px) {
  .list-panel { padding: 1rem; }
  .staff-list-item { gap: 0.35rem 0.6rem; }
  .staff-list-item .tick { min-height: 42px; }
}

/* ---------- Filter bars (staff tables) ---------- */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  align-items: center;
  margin: 1.6rem 0 1rem;
}
.filter-bar input[type="search"],
.filter-bar select {
  width: auto;
  min-width: 12rem;
  flex: 0 1 auto;
}
.filter-bar .button { padding: 0.6rem 1.2rem; letter-spacing: 0.16rem; }

/* ---------- Tables ---------- */
.table-wrap { overflow-x: auto; }
table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.95rem;
}
table.data th {
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  font-size: 0.76rem;
  color: var(--hp-cream);
  padding: 0.7rem 0.8rem;
  border-bottom: 1px solid var(--hp-line);
  white-space: nowrap;
}
table.data td {
  padding: 0.75rem 0.8rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
table.data tr:hover td { background: rgba(152, 0, 0, 0.14); }

/* The RSVP List reads as a grid of short values -- names, dates, one-word
   admissions, ticks -- so centring keeps the columns legible. Opt-in, because
   the wordier tables elsewhere still read better ranged left. */
table.data.data-center th,
table.data.data-center td { text-align: center; }

/* The People column: the number carries the column, and the word under it says
   what the number makes them -- "2 / Couple" -- so neither has to be guessed
   from the donation type beside it. */
.rsvp-composition {
  display: block;
  font-size: 0.75rem;
  margin-top: 0.1rem;
}

/* The walk-in form sits above the door list and is worked one-handed on a
   phone, so the submit lines up with the fields rather than dropping below. */
.walk-in { margin-bottom: 2rem; }
.walk-in-submit { display: flex; align-items: flex-end; }
.walk-in-submit .button { white-space: nowrap; }

/* A row action has to sit inside a table cell without setting the row height. */
.button-small {
  padding: 0.35rem 0.9rem;
  font-size: 0.75rem;
  letter-spacing: 0.16rem;
}

/* Destructive actions get their own block, away from the save button. */
.danger-zone { margin-top: 2.5rem; border-top: 1px solid var(--hp-line); padding-top: 1.5rem; }
.danger-zone h3 { color: var(--hp-red); }

/* A support ticket is one long page of separate sections: the ticket, the
   conversation under it, and where it stands below the reply box. Nothing
   spaced them, so each heading sat against the box or button above it. They
   break the way the danger zone does -- a gap, then a line. */
.ticket-thread-heading,
.ticket-status { margin-top: 2.5rem; border-top: 1px solid var(--hp-line); padding-top: 1.5rem; }

/* ---------- Badges ---------- */
.badge {
  display: inline-block;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.12rem;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  border: 1px solid currentColor;
}
.badge-silver { color: #c9c9c9; }
.badge-gold { color: var(--hp-cream); }
.badge-platinum { color: var(--hp-orange); }
.badge-diamond { color: var(--hp-red); }
.badge-active { color: var(--hp-cream); }
.badge-suspended { color: var(--hp-orange); }
.badge-blacklisted { color: var(--hp-red); }

/* ---------- Door check-in ----------
   Worked one-handed on a phone in a dark doorway: big tap targets, high
   contrast, and no reliance on JavaScript to tick someone off. */
.door-tally {
  font-size: 1.05rem;
  margin: 0.4rem 0 1.2rem;
}
.door-tally strong { color: var(--hp-cream); }
.door-owing { color: var(--hp-orange); }
.door-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin: 0.4rem 0 1.4rem;
}
/* Two of these actions are POSTs, so they are buttons inside forms rather than
   links. The wrapper form would otherwise be the flex item and break the row;
   display:contents hands its place to the button itself. */
.door-actions form { display: contents; }

.door-table td { vertical-align: middle; }
.door-name {
  display: block;
  font-size: 1.15rem;
  color: var(--hp-white);
}
.door-meta,
.door-note {
  display: block;
  font-size: 0.8rem;
  color: var(--hp-smoke);
  margin-top: 0.15rem;
}
.door-note { font-style: italic; }

.pay-yes { color: var(--hp-cream); }
.pay-no {
  color: var(--hp-orange);
  font-weight: bold;
}

.door-tick-col {
  width: 1%;
  text-align: right;
  white-space: nowrap;
}

/* The tick is a button, not a checkbox: one press is one recorded arrival,
   with no second "save" step and nothing to lose if JavaScript is off. */
/* A plain "yes" in a table cell. Distinct from .tick below, which is the
   interactive check-in control and carries a border and hover state. */
.yes-mark {
  color: var(--hp-cream);
  font-size: 1.15rem;
  line-height: 1;
}

.tick {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 48px;
  padding: 0.4rem 0.9rem 0.4rem 0.5rem;
  background: none;
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  color: var(--hp-smoke);
  font-family: inherit;
  font-size: 0.85rem;
  cursor: pointer;
}
.tick:hover { border-color: var(--hp-cream); color: var(--hp-white); }
.tick:focus-visible { outline: 2px solid var(--hp-cream); outline-offset: 2px; }

.tick-box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 2px solid var(--hp-line);
  border-radius: 6px;
  font-size: 1.3rem;
  line-height: 1;
}
.tick[aria-checked="true"] { color: var(--hp-cream); border-color: transparent; }
.tick[aria-checked="true"] .tick-box {
  border-color: var(--hp-cream);
  background: var(--hp-cream);
  color: var(--hp-ink);
}

/* How many people one row is. Built on .tick for the tap target, but it is a
   number rather than a yes/no, so the box holds a digit and never fills in --
   a filled box down this column would read as "ticked" and mean nothing. */
.size-tick .tick-box {
  font-size: 1rem;
  font-weight: bold;
  color: var(--hp-cream);
}
/* A party of three or more was set deliberately on the RSVP List, so the door
   shows it rather than offering to halve it with one press. */
.size-fixed { color: var(--hp-cream); font-size: 0.85rem; }

/* An arrived guest recedes so the ones still to come stand out. */
.door-table tr.is-arrived .door-name { color: var(--hp-smoke); }
.door-table tr.is-arrived td { background: rgba(236, 226, 155, 0.05); }

/* A no-show is struck through; Interested says so, quietly, beside the name. */
.door-table tr.is-no-show .door-name {
  color: var(--hp-smoke);
  text-decoration: line-through;
}

/* Someone who has gone home. Dimmer than an arrival and without its highlight,
   because the highlight means "in the room" -- which is the one thing this row
   no longer is. Not struck through: they came, unlike a no-show. */
.door-table tr.is-departed .door-name,
.door-table tr.is-departed .door-meta { opacity: 0.55; }
.badge-interested { color: var(--hp-smoke); }

.door-footnote { margin-top: 1.4rem; font-size: 0.8rem; }

/* What to collect at the door, for whoever takes cash. */
.door-rates { margin: 0 0 1.6rem; }
.door-rates h3 { margin: 0 0 0.5rem; }
.door-rate-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.6rem;
}
.door-rates strong { color: var(--hp-cream); }
.door-rate-special { margin: 0.6rem 0 0; }

/* Sorting. The column headers are the control on a wide screen; a phone hides
   the header row, so the same choices come back as a dropdown there. */
.filter-bar .door-sort { display: none; }
.sort-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: inherit;
}
.sort-link:hover { color: var(--hp-white); }
.sort-arrow { font-size: 0.6rem; }
.sort-arrow.is-idle { opacity: 0.4; }

/* Words a phone needs because it has no header row to say them. */
.door-mobile-label { display: none; }

/* On a phone the seven columns will not fit side by side, and the ticks are the
   one thing that must never be off-screen -- so each guest becomes a block:
   name; payment, party size, and the left/no-show tick on one row; then ID,
   waiver, and check-in, check-in pinned right. The header row goes, so the sort
   moves into the filter bar. */
@media (max-width: 640px) {
  .filter-bar .door-sort { display: block; }

  .door-table thead { display: none; }
  .door-table,
  .door-table tbody,
  .door-table tr,
  .door-table td { display: block; width: auto; }
  .door-table tr {
    display: grid;
    grid-template-columns: auto auto 1fr;
    grid-template-areas: "name name name" "paid people noshow" "id waiver tick";
    align-items: center;
    gap: 0.15rem 0.5rem;
    padding: 0.7rem 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  }
  /* table.data td outranks .door-table td, so these name both. Without that
     every cell keeps its own rule and one guest reads as three rows. */
  table.data.door-table td { border: none; padding: 0 0.2rem; }
  table.data.door-table td.door-tick-col { padding-top: 0.45rem; }
  .door-table tr.is-arrived { background: rgba(236, 226, 155, 0.05); }
  .door-table tr.is-arrived td { background: none; }
  .door-mobile-label { display: inline; }
  .door-table td:nth-child(1) { grid-area: name; }
  .door-table td:nth-child(2) { grid-area: paid; }
  .door-table td:nth-child(3) { grid-area: people; text-align: center; }
  .door-table td:nth-child(4) { grid-area: id; }
  .door-table td:nth-child(5) { grid-area: waiver; }
  .door-table td:nth-child(6) { grid-area: tick; text-align: right; }
  .door-table td:nth-child(7) { grid-area: noshow; text-align: right; }

  /* The page's own buttons stay small, so the list starts near the top. */
  .door-actions { gap: 0.5rem; }
  .door-actions .button {
    padding: 0.5rem 0.9rem;
    font-size: 0.72rem;
    letter-spacing: 0.1rem;
  }
  .door-table td[colspan] { grid-column: 1 / -1; }

  .tick-text { font-size: 0.75rem; }
  .tick { padding: 0.4rem 0.6rem 0.4rem 0.4rem; gap: 0.4rem; }
  .door-table .tick-box { width: 30px; height: 30px; font-size: 1.15rem; }
}

/* ---------- Split hero (login, signup, age gate) ---------- */
.split {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  min-height: 68vh;
  align-items: center;
  gap: 2rem;
}
.split-art {
  height: 100%;
  min-height: 60vh;
  background-size: cover;
  background-position: center;
  border-radius: var(--radius);
}
.split-body { max-width: 460px; margin: 0 auto; width: 100%; }

/* ---------- Locked / teaser states ---------- */
.locked {
  text-align: center;
  max-width: 640px;
  margin: 0 auto;
  padding: 3rem 1rem;
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  background: radial-gradient(ellipse at top, rgba(152, 0, 0, 0.28), transparent 70%);
}
.locked h1 { margin-bottom: 0.2rem; }
/* Casablanca draws its capitals tall and wide, so an all-caps acronym set in
   it towers over the words either side. Scaled down to sit level with them,
   wherever a display heading contains one -- "VIP Video Library", "RSVP List",
   "VIP List". */
h1 .acronym { font-size: 0.7em; }
.locked .locked-actions { margin-top: 1.8rem; display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }

.tier-grid {
  display: grid;
  /* Fixed at two columns rather than auto-fit, which packed three across and
     left Diamond stranded on its own row. Two rows of two: Silver and Gold
     above, Platinum and Diamond beneath, following the DOM order. */
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
  margin: 2rem 0 0;
  text-align: left;
}
.tier {
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
}
.tier .tier-name {
  font-family: var(--font-display);
  font-size: 1.9rem;
  color: var(--hp-red);
}
.tier .tier-length { color: var(--hp-cream); font-size: 0.9rem; }

/* ---------- Definition list (account settings) ---------- */
dl.detail { margin: 0; }
dl.detail dt {
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  font-size: 0.75rem;
  color: var(--hp-cream);
  margin-top: 1.1rem;
}
dl.detail dd { margin: 0.15rem 0 0; font-size: 1.05rem; }

.muted { color: var(--hp-smoke); }
.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;
}
.stack > * + * { margin-top: 1.4rem; }
.row-actions { display: flex; gap: 1rem; flex-wrap: wrap; align-items: center; margin-top: 2rem; }

/* ---------- Page art ----------
   The signature device in the comps: a tall image bleeding off the left edge,
   fading into the black page, with an optional script caption over it. It sits
   behind the content, so it never intercepts a click. */
.page-art {
  position: fixed;
  left: 0;
  top: 0;
  width: clamp(210px, 25vw, 400px);
  height: 100vh;
  background-size: cover;
  background-position: center;
  z-index: 0;
  pointer-events: none;
}
.page-art::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(0,0,0,0.28) 0%, rgba(0,0,0,0) 30%,
                    rgba(0,0,0,0.72) 78%, var(--hp-black) 100%),
    linear-gradient(180deg, rgba(0,0,0,0.55) 0%, transparent 22%,
                    transparent 78%, rgba(0,0,0,0.55) 100%);
}
.page-art-caption {
  position: absolute;
  left: 1.6rem;
  right: 1.2rem;
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 2.4vw, 2.6rem);
  line-height: 1;
  color: var(--hp-cream);
  z-index: 1;
}
.page-art-caption.at-bottom { bottom: 12vh; }
.page-art-caption.at-top { top: 34vh; }
.page-art-caption.is-rose { color: #e79a9a; }

/* ---------- Homepage slider ----------
   Card geometry measured off s1-s3: 1160 x 545 at a 2.132 ratio. */
.slider {
  position: relative;
  max-width: 1160px;
  margin: 0 auto;
}

.slides {
  position: relative;
  aspect-ratio: 1163 / 542;
  border-radius: 16px;
  overflow: hidden;
  background: var(--hp-ink);
}

.slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.75s ease;
}
.slide.is-active { opacity: 1; visibility: visible; }

/* No JS, no problem: the first slide still shows. */
.no-js .slide:first-child { opacity: 1; visibility: visible; }

/* The wording lives in the slide artwork now, so the whole slide is the link
   and the accessible name comes from .sr-only text inside it. The arrows and
   dots are later siblings of .slides, so they still paint above this and keep
   their own clicks. Inactive slides are `visibility: hidden`, which already
   keeps their links out of the tab order. */
.slide-link {
  position: absolute;
  inset: 0;
  display: block;
  text-decoration: none;
}
.slide-link:focus-visible {
  outline: 2px solid var(--hp-cream);
  outline-offset: -8px;
  border-radius: 10px;
}

/* Slider controls */
.slider-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  background: rgba(0, 0, 0, 0.42);
  border: 1px solid var(--hp-line);
  color: var(--hp-cream);
  border-radius: 999px;
  width: 44px;
  height: 44px;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s ease, background-color 0.2s ease;
}
.slider:hover .slider-arrow,
.slider-arrow:focus-visible { opacity: 1; }
.slider-arrow:hover { background: rgba(152, 0, 0, 0.8); color: var(--hp-white); }
.slider-arrow.is-prev { left: 1rem; }
.slider-arrow.is-next { right: 1rem; }

.slider-dots {
  display: flex;
  justify-content: center;
  gap: 0.7rem;
  margin-top: 1.4rem;
}
.slider-dot {
  width: 11px;
  height: 11px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--hp-cream);
  background: none;
  cursor: pointer;
  transition: background-color 0.2s ease;
}
.slider-dot[aria-selected="true"] { background: var(--hp-red); border-color: var(--hp-red); }

/* ---------- Events calendar ----------
   The cream month panel from calendar_pg.png. */
.calendar-panel {
  background: #fdf9e3;
  color: var(--hp-ink);
  border-radius: 14px;
  padding: 1.8rem clamp(1rem, 3vw, 2.4rem) 2.2rem;
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.55);
}
.calendar-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.4rem;
  margin-bottom: 1.4rem;
}
.calendar-month {
  font-family: var(--font-body);
  color: var(--hp-red-deep);
  font-size: clamp(1.6rem, 3.2vw, 2.3rem);
  margin: 0;
  text-transform: none;
  letter-spacing: 0;
}
.calendar-nav {
  background: none;
  border: 0;
  color: var(--hp-red-deep);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.2rem 0.5rem;
  border-radius: 6px;
}
.calendar-nav:hover { background: rgba(152, 0, 0, 0.1); }

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}
.calendar-dow {
  text-align: center;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  color: rgba(10, 7, 8, 0.55);
  padding-bottom: 0.4rem;
}
.calendar-cell {
  min-height: 78px;
  border-radius: 6px;
  background: rgba(10, 7, 8, 0.045);
  padding: 0.4rem 0.5rem;
  font-size: 0.85rem;
}
.calendar-cell.is-empty { background: none; }
.calendar-cell.is-today { outline: 2px solid var(--hp-red-deep); }
.calendar-day { color: rgba(10, 7, 8, 0.65); }
.calendar-event {
  display: block;
  margin-top: 0.25rem;
  background: var(--hp-red-deep);
  color: var(--hp-white);
  border-radius: 4px;
  padding: 0.15rem 0.35rem;
  font-size: 0.74rem;
}

/* ---------- Event detail & listings ---------- */
.back-link { margin: 0 0 1.2rem; }
.back-link a { font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.14rem; }

.notice-strip {
  border-left: 3px solid var(--hp-orange);
  background: rgba(196, 113, 26, 0.14);
  padding: 0.7rem 1rem;
  border-radius: 0 4px 4px 0;
  margin: 0 0 1.4rem;
}

/* The cover graphic is shown whole. `max-height` plus `object-fit: cover` used
   to crop it to a 380px band, cutting the top and bottom off whatever was
   uploaded. Now it keeps its own proportions, scaling down to fit the column
   but never being cropped and never upscaled past its real size. */
.event-header {
  max-width: 100%;
  height: auto;
  margin: 0 auto 1.6rem;
  border-radius: var(--radius);
}

.event-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem 3rem;
  justify-content: center;
  margin: 0 0 2rem;
}
.event-facts dt {
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  font-size: 0.72rem;
  color: var(--hp-cream);
}
.event-facts dd { margin: 0.2rem 0 0; font-size: 1.05rem; }

.event-description { margin: 0 auto 2.4rem; }

.admission-heading { text-align: center; margin: 2.6rem 0 1.4rem; }

.tier-buy { display: block; margin-top: 0.9rem; text-align: center; }
.tier-grid .tier { text-align: center; }

.calendar-event.is-draft {
  background: none;
  border: 1px dashed var(--hp-red-deep);
  color: var(--hp-red-deep);
}

.upcoming { display: flex; flex-direction: column; gap: 0.5rem; }
.upcoming-row {
  display: grid;
  grid-template-columns: 8rem 1fr auto;
  gap: 1rem;
  align-items: baseline;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  color: var(--hp-white);
}
.upcoming-row:hover { background: rgba(152, 0, 0, 0.18); }
.upcoming-date {
  text-transform: uppercase;
  letter-spacing: 0.12rem;
  font-size: 0.8rem;
  color: var(--hp-cream);
}
.upcoming-where { color: var(--hp-smoke); font-size: 0.9rem; }

/* ---------- RSVP form on an event page ---------- */
.rsvp-form {
  margin-top: 2.4rem;
  padding: 1.4rem 1.5rem 1.6rem;
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  max-width: 520px;
}
.rsvp-form h3 { margin-bottom: 1rem; }
.rsvp-tiers { border: 0; padding: 0; margin: 0 0 1.1rem; }
.rsvp-tiers legend {
  padding: 0;
  color: var(--hp-cream);
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  font-size: 0.76rem;
  margin-bottom: 0.5rem;
}
.rsvp-tiers ul { list-style: none; padding: 0; margin: 0; }
.rsvp-tiers li { margin-bottom: 0.35rem; }
.rsvp-tiers label { display: flex; align-items: center; gap: 0.6rem; cursor: pointer; }
.rsvp-tiers input[type="radio"] { width: auto; margin: 0; }

.rsvp-check {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1.1rem;
  cursor: pointer;
}
.rsvp-check input { width: auto; margin: 0; }

.rsvp-actions { margin-top: 1.2rem; }
.rsvp-cancel { margin-top: 0.9rem; }
.rsvp-closed { margin-top: 2rem; }

/* ---------- Moderation ---------- */
.mod-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin: 1.6rem 0 0.4rem;
}
.mod-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.4rem, 3vw, 2.6rem);
  align-items: start;
  margin-top: 1.6rem;
}
.mod-form h3, .mod-current h3 { margin-bottom: 1rem; }
.mod-form.is-standalone { max-width: 620px; margin-top: 1.6rem; }

.mod-item {
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  padding: 0.9rem 1rem;
  margin-bottom: 0.8rem;
}
.mod-item-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  margin-bottom: 0.4rem;
}
.mod-item-name { font-size: 1.05rem; color: var(--hp-white); }
.mod-item-reason { margin: 0 0 0.35rem; }
.mod-item-meta { margin: 0 0 0.7rem; font-size: 0.78rem; color: var(--hp-smoke); }

/* ---------- Report queue ---------- */
.report {
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  margin-bottom: 1rem;
}
.report-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
}
.report-summary { font-size: 1.1rem; color: var(--hp-white); }
.report-meta { margin: 0.3rem 0 0.7rem; font-size: 0.8rem; color: var(--hp-smoke); }
.report-body { margin: 0 0 0.9rem; }
.report-review {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  align-items: flex-start;
  padding-top: 0.9rem;
  border-top: 1px solid var(--hp-line);
}
.report-review select { width: auto; min-width: 12rem; }
.report-review textarea { flex: 1 1 16rem; min-height: 2.8rem; }
.report-outcome { margin: 0; font-size: 0.85rem; color: var(--hp-smoke); }
.report-outcome-note { display: block; color: var(--hp-white); margin-top: 0.25rem; }

/* ---------- Paying: VIP membership and event admission ----------
   Two processors are offered everywhere money changes hands, so the same
   button row serves the VIP page, an event's admission grid, and the prepay
   panel on a member's own RSVP. */

/* The price is what someone is comparing, so it outranks the tier's name for
   weight. Cream, not red: the name above it is already red, and two reds
   stacked on one small card read as a single block of colour. */
.tier .tier-price {
  font-size: 1.35rem;
  color: var(--hp-cream);
  margin-top: 0.1rem;
}

/* Side by side, wrapping to a stack rather than shrinking -- a pay button
   squeezed narrow stops looking like one. */
/* .join-actions is the same row of buttons pointing at signup rather than a
   processor -- shared so the two cannot drift out of step visually. */
.pay-row,
.join-actions {
  display: flex;
  gap: 0.9rem;
  flex-wrap: wrap;
  margin-top: 1.1rem;
}
.pay-row .button,
.join-actions .button {
  flex: 1 1 13rem;
  text-align: center;
  /* The base button is padded asymmetrically to sit the tracked-out capitals
     optically centred. Centred text in a stretched flex item does not need it,
     and the lopsided padding shows at this width. */
  padding-left: 1.9rem;
}

.pay-note { font-size: 0.9rem; margin-top: 1.1rem; }

/* The special rate graphic on the Mischief After Dark pay page. It is square,
   so it is held narrower than the text column rather than towering over it. */
.promo-graphic { width: 100%; max-width: 26rem; margin: 0 auto 1.6rem; border-radius: 8px; }

.prepay-panel { margin-bottom: 1.8rem; }
.prepay-panel h3 { margin-bottom: 0.4rem; }

/* Shown to a visitor where a member gets the RSVP form, so it sits where the
   form would have and keeps the page from ending on a dead stop. */
.rsvp-join { margin-top: 2.4rem; }
.rsvp-join h3 { margin-bottom: 0.4rem; }

/* ---------- Homepage countdown ----------
   Only on screen in the last week before a party, so it can afford to sit
   above the slider and be noticed. Centred lines: the party's name, how long
   is left, the head count once the doors open, and the way in.

   Sized to its contents rather than to a shape. It was a square for a day
   (2026-09-16): at 320px across, aspect-ratio fixed the height at 320px too,
   which left 90px of dead air above and below four short lines. The ratio
   came back off and the padding sets the vertical instead (user, 2026-09-17).
   The banner gains and loses the eyebrow and the head count over the course
   of a party, and it is allowed to change height with them. */
.countdown {
  display: grid;
  place-content: center;
  /* Width is still fixed, so the lines break in the same places whatever is
     inside -- it is the height that follows the contents, not the measure. */
  width: min(20rem, 86vw);
  margin: 0 auto 1.6rem;
  /* Tighter top and bottom than the sides: the space either end was the
     square's doing, and without it 1.25rem all round reads as slack. */
  padding: 1rem 1.25rem;
  text-align: center;
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  /* Two layers, both restrained enough to read as depth rather than as
     decoration: a warm glow spilling in from above the top edge, over a
     diagonal wash that is deepest at the corners. Colours are the tokens
     written out, since a custom property cannot be used inside rgba(). */
  background:
    radial-gradient(ellipse at 50% -20%,
      rgba(209, 98, 0, 0.16) 0%,           /* --hp-orange-brand */
      transparent 60%),
    linear-gradient(165deg,
      rgba(152, 0, 0, 0.32) 0%,            /* --hp-red-deep */
      rgba(152, 0, 0, 0.10) 50%,
      rgba(109, 0, 0, 0.26) 100%);         /* --hp-red-dark */
  color: var(--hp-cream);
  font-size: 0.92rem;
}

/* An author display rule outranks the browser's own [hidden] styling, so the
   block above would keep the banner on screen after the script hides it. */
.countdown[hidden] { display: none; }

/* A label for the name beneath it, so it is set small and tracked out rather
   than competing with it. */
.countdown-eyebrow {
  display: block;
  color: var(--hp-white);
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.22rem;
  font-size: 0.78rem;
  /* Casablanca below carries tall ascenders that reach well above its line
     box, so the two collide on a default gap. This is set against the script,
     not against the label's own size. */
  margin-bottom: 0.6rem;
}

/* Same trap as the banner itself: the display rule above outranks the
   browser's own [hidden] styling, so without this the label survives being
   hidden when the party starts. */
.countdown-eyebrow[hidden] { display: none; }

/* The name, in the display face. Not uppercased and not tracked out:
   Casablanca is a joined script and both break the letterforms. */
.countdown-name {
  display: block;
  font-family: var(--font-display);
  color: var(--hp-red);
  font-size: clamp(1.8rem, 4.5vw, 2.4rem);
  line-height: 1.15;
}

/* The number people actually came for, so it outweighs everything around it. */
.countdown-left {
  display: block;
  margin-top: 0.15rem;
  color: var(--hp-white);
  font-size: 1.15rem;
  font-weight: bold;
  /* Stops the line shuffling sideways as digits of different widths tick. */
  font-variant-numeric: tabular-nums;
}

.countdown-cta {
  display: block;
  margin-top: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.18rem;
  font-size: 0.8rem;
}
.countdown-cta a { color: var(--hp-cream); }
.countdown-cta a:hover { color: var(--hp-white); text-decoration: underline; }

/* Four strokes, inheriting the line's colour, so it follows the live state
   without a second copy. Sized in em to track the text beside it. */
.countdown-icon {
  display: inline-block;
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.25em;
  margin-right: 0.45em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The doors are open. The one moment this banner should be loud -- loud in
   the deep reds of the brand rather than the bright one, which at full width
   read as an alert rather than as an invitation (user's call, 2026-09-16). */
.countdown.is-live {
  /* Same two layers, opaque and turned up -- it should look lit from within
     on the one night it is on screen. The glow is what carries that now, so
     it sits deeper into the panel than the bright version needed to. */
  background:
    radial-gradient(ellipse at 50% -20%,
      rgba(152, 0, 0, 0.55) 0%,            /* --hp-red-deep */
      transparent 68%),
    linear-gradient(165deg,
      var(--hp-red-deep) 0%,
      var(--hp-red-dark) 55%,
      #4d0000 100%);
  border-color: var(--hp-red-deep);
  color: var(--hp-white);
}
/* Red on red is invisible: the name takes the cream it can be read in. */
.countdown.is-live .countdown-name { color: var(--hp-cream); }
.countdown.is-live .countdown-cta a { color: var(--hp-white); }

/* ---------- Live head count ----------
   Inside the banner, on screen only while the doors are open and somebody is
   through them. Three stacked lines: the status, the number, and what the
   number counts. */
.attendance {
  display: block;
  margin-top: 0.9rem;
  /* A hairline rather than a box of its own: the banner around it is already
     the frame, and a tile inside a tile is one frame too many. */
  padding-top: 0.8rem;
  border-top: 1px solid rgba(255, 255, 255, 0.28);
}

/* The same trap as the banner and its eyebrow: the display rule above
   outranks the browser's own [hidden] styling, so without this the badge
   survives being hidden before the first guest arrives. */
.attendance[hidden] { display: none; }

/* Small and tracked out, so it reads as a status light rather than a heading
   competing with the party's name above it. */
.attendance-tag {
  display: block;
  /* Clear of the number beneath it: tracked-out caps sat straight on top of a
     40px numeral read as one stack rather than two things. */
  margin-bottom: 0.5rem;
  color: var(--hp-yellow);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.3rem;
  font-size: 0.95rem;
  /* Letter-spacing is applied to the right of the last letter too, which
     leaves the word sitting half a space left of centre without this. */
  text-indent: 0.3rem;
}

/* The dot that says this is happening now rather than being a total from
   last time. */
.attendance-tag::before {
  content: "";
  display: inline-block;
  width: 0.7em;
  height: 0.7em;
  margin-right: 0.5em;
  /* Nudged off the baseline to sit against the cap height of the word. Less
     of a lift than the small dot needed -- a bigger circle centres lower. */
  vertical-align: 0.01em;
  border-radius: 50%;
  background: var(--hp-white);
  animation: attendance-pulse 2s ease-in-out infinite;
}

@keyframes attendance-pulse {
  50% { opacity: 0.25; }
}

/* The number, and the one thing here that should carry across a room. The
   body face rather than the display one: Casablanca is a joined script, and
   its digits read as decoration at a glance -- which is the only way this is
   ever read. .countdown-left sets its number the same way, for the same
   reason. */
.attendance-count {
  display: block;
  color: var(--hp-cream);
  /* The floor matters more than the ceiling here: on a narrow phone the
     square is only as tall as it is wide, and this is the line with the room
     to give. Too large a minimum and the live state outgrows its own shape. */
  font-size: clamp(2.1rem, 6.5vw, 3.6rem);
  font-weight: bold;
  line-height: 1.1;
  /* The digits set tight in this face at display size -- "15" reads as one
     glyph without this. In em so it holds as the number scales down the
     clamp above. */
  letter-spacing: 0.1em;
  /* The tracking is applied to the right of the last digit too, which leaves
     the number sitting half a space left of centre; this puts it back. */
  text-indent: 0.1em;
  /* Stops the badge shuffling sideways as the count crosses 9 and 99. */
  font-variant-numeric: tabular-nums;
}

.attendance-phrase {
  display: block;
  margin-top: 0.1rem;
  color: var(--hp-white);
  font-weight: bold;
  font-size: 0.95rem;
}

/* ---------- Venue pages ----------
   The public "Our Venue" page, and the Places Nearby list that staff build
   on it. Reuses .event-header, .prose and .panel; only what is new is here. */

/* Everything down this page used to share the reading column .prose sets,
   ranged left. It runs the full width of the shell now and is centred in it
   (user, 2026-09-17): the venue is a page people scan for one fact at a time
   -- where is it, what is there, where do I park -- rather than read through,
   and the column was holding the map down to half the room it wanted.

   Centring is set once here and inherited, so a section added later is
   centred without a rule of its own. */
.venue-body { text-align: center; }
.venue-event,
.venue-address,
.venue-map-actions,
.nearby-list,
.venue-prose { max-width: none; }

/* The event this venue belongs to, set quietly under the heading -- it is a
   way back to the party, not a second title. */
.venue-event {
  margin: 0 0 1.4rem;
  color: var(--hp-cream);
}

.venue-event-when {
  display: block;
  color: var(--hp-smoke);
  font-size: 0.9rem;
}

.venue-header { margin-bottom: 1.6rem; }

/* The address is a heading in the structure the user asked for, so it is set
   as one -- but as an address rather than a shout, so it keeps its case. */
.venue-address {
  text-transform: none;
  letter-spacing: normal;
  color: var(--hp-cream);
  margin-bottom: 0.9rem;
}

/* The label the user asked for in front of the address. Set quieter than what
   it introduces, so the address is still the thing the eye lands on. */
.venue-address-label {
  color: var(--hp-smoke);
  font-weight: normal;
}

/* A fixed ratio rather than a fixed height: the frame has to hold its shape
   from a phone to a desktop, and a map squeezed into 200px on a wide screen
   is no use to anyone. */
.venue-map {
  position: relative;
  aspect-ratio: 16 / 10;
  /* Centred in the full-width page rather than filling it, and the two caps
     are kept in step -- 56rem across is 35rem tall at 16/10, so the frame
     reaches its largest with the ratio still honoured instead of flattening
     into a strip when one cap bites before the other. */
  max-width: 56rem;
  max-height: 35rem;
  margin: 0 auto 1rem;
  overflow: hidden;
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  /* Something to look at while Google's frame is still loading, instead of a
     white rectangle on a black page. */
  background: var(--hp-ink);
}

.venue-map iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.venue-map-actions { margin: 0 0 2rem; }

.venue-prose { margin-bottom: 2rem; }

/* Places nearby, as read by a guest: a name and whatever was written under
   it. A definition list because that is what this is -- a term and its
   details -- and the grouping divs keep each pair together. */
/* One place per row, each the full width of the page (user, 2026-09-18).
   These were side by side in capped cards for a day, and the cap was doing
   the damage: 24rem is narrow enough that a detail of any length wrapped two
   or three times and broke inside "check-out", which reads as a typesetting
   accident rather than as a line. Given the width, most details fit on one
   line and the rest break where they should. */
.nearby-list {
  margin: 0 0 2rem;
  display: grid;
  gap: 1.1rem;
}

.nearby-item {
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.03);
}

.nearby-item dt {
  color: var(--hp-cream);
  font-weight: bold;
  font-size: 1.05rem;
}

.nearby-item dd {
  margin: 0.3rem 0 0;
  color: var(--hp-smoke);
}

.nearby-item dd p { margin: 0 0 0.4rem; }
.nearby-item dd p:last-child { margin-bottom: 0; }

.venue-staff-actions { margin-top: 2.4rem; }

/* The staff side: the editor's own list, and the form that adds to it. */
.venue-places {
  margin-top: 2.6rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--hp-line);
}

/* Line breaks in the details are kept, so the row grows to fit rather than
   running the address and the phone numbers together on one line. */
.nearby-admin .nearby-details {
  display: block;
  white-space: normal;
  line-height: 1.5;
}

.nearby-add { margin-top: 1.4rem; }

/* ---------- Archive ---------- */

.archive-note { margin-bottom: 1.4rem; }

.archive-date { white-space: nowrap; }

/* Two links per row, stacked on a phone rather than wrapping mid-phrase. */
.archive-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1rem;
}

/* The denominator is context, not data: it should not compete with the count
   in front of it. */
.archive-of {
  display: block;
  color: var(--hp-smoke);
  font-size: 0.82rem;
  white-space: nowrap;
}

.prepay-note {
  font-size: 0.88rem;
  text-align: center;
  max-width: 46rem;
  margin: 1.3rem auto 0;
}

/* An admission card carries a button per processor now rather than one, so
   the pair stacks with a gap of its own instead of each keeping the margin
   that used to separate a single button from the price above it. */
.tier-buy + .tier-buy { margin-top: 0.5rem; }

/* What VIP gets you: term and explanation, read top to bottom rather than
   packed into a grid -- there are only three, and each needs a sentence. */
.perks { margin: 0; }
.perks dt {
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  font-size: 0.78rem;
  color: var(--hp-cream);
  margin-top: 1.2rem;
}
.perks dd { margin: 0.25rem 0 0; }

@media (max-width: 900px) {
  .mod-layout { grid-template-columns: 1fr; }
}

/* ---------- Party Management ----------
   Form on the left, every event listed beside it, so a party you just made is
   visible without leaving the page. */
.party-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: clamp(1.4rem, 3vw, 2.6rem);
  align-items: start;
  margin-top: 1.6rem;
}

.party-form h3,
.party-side h3 {
  margin-bottom: 1rem;
}
.party-form .costs-heading { margin-top: 2.2rem; }

/* Fields that sit together on one line, collapsing when there is no room. */
.field-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1rem;
}
.field-row .form-row { flex: 1 1 8rem; }
.field-row .form-row.is-wide { flex: 2 1 14rem; }

.costs-table { margin-top: 0.6rem; max-width: 460px; }
.costs-table td { vertical-align: middle; }
.costs-price input { width: 8rem; }
.costs-link input { width: 100%; min-width: 10rem; }
.costs-table { max-width: none; }
.costs-available { text-align: center; }
.costs-available input { width: auto; }

.cover-preview {
  max-width: 260px;
  border-radius: 8px;
  margin-bottom: 0.6rem;
}

.party-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-top: 1.8rem;
}

/* The side list */
.party-side {
  border-left: 1px solid var(--hp-line);
  padding-left: clamp(1rem, 2vw, 1.6rem);
}
.party-item {
  display: block;
  padding: 0.7rem 0.8rem;
  margin-bottom: 0.5rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--hp-white);
}
.party-item:hover { background: rgba(152, 0, 0, 0.18); color: var(--hp-white); }
.party-item.is-current {
  border-color: var(--hp-cream);
  background: rgba(152, 0, 0, 0.22);
}
.party-item-date {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12rem;
  color: var(--hp-cream);
}
.party-item-title { display: block; font-size: 1.05rem; }
.party-item-meta {
  display: block;
  font-size: 0.78rem;
  color: var(--hp-smoke);
}
.party-item-draft { color: var(--hp-orange); }

/* The private pay link, above the event list for staff to copy. The address
   ends in one long unbroken token, so it wraps anywhere rather than pushing
   the sidebar wider. */
.private-link { margin-bottom: 2rem; }
.private-link p { font-size: 0.85rem; margin: 0 0 0.5rem; }
.private-link a { overflow-wrap: anywhere; font-size: 0.9rem; }

@media (max-width: 900px) {
  .party-layout { grid-template-columns: 1fr; }
  .party-side {
    border-left: 0;
    border-top: 1px solid var(--hp-line);
    padding-left: 0;
    padding-top: 1.4rem;
  }
}

/* ---------- Party Management hub ----------
   The tiles that open the pages this page used to hold, and the list of what
   is still to come underneath them. .tile further up is a dashboard
   statistic -- a big number and a label; these are navigation, so they are
   their own thing rather than a variant of it. They reuse .tile-grid, which
   is only the grid. */
.nav-tiles { margin-bottom: 1.8rem; }
.nav-tile {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--hp-line);
  border-radius: var(--radius);
  padding: 1.3rem 1.4rem;
  color: var(--hp-white);
}
.nav-tile:hover,
.nav-tile:focus-visible {
  background: rgba(152, 0, 0, 0.18);
  border-color: var(--hp-cream);
  color: var(--hp-white);
}
/* Four strokes each, inheriting colour through currentColor so they follow
   the tile's hover without a second rule per icon. */
.nav-tile-icon {
  width: 30px;
  height: 30px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--hp-red);
}
.nav-tile:hover .nav-tile-icon,
.nav-tile:focus-visible .nav-tile-icon { color: var(--hp-cream); }
/* The display script is the site's voice for a page title, but these are
   three words that have to be read at a glance and "Archive" in it is barely
   a word. They take the dashboard tile's label treatment instead. */
.nav-tile-name {
  text-transform: uppercase;
  letter-spacing: 0.14rem;
  font-size: 0.95rem;
  color: var(--hp-cream);
}
.nav-tile-note { font-size: 0.85rem; color: var(--hp-smoke); }

/* The active list runs full width under the tiles rather than sitting in a
   sidebar, so its rows carry a visible edge the side list does without. */
.party-active { margin-bottom: 2rem; }
.party-active .form-help { margin-bottom: 0.9rem; }
.party-active .party-item { border-color: var(--hp-line); }

/* One row per party on the venue picker: the party on the left, the button
   that opens its venue page on the right. The whole row cannot be one link,
   because it contains a link. */
.venue-pick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--hp-line);
}
.venue-pick:last-child { border-bottom: 0; }
.venue-pick-main { min-width: 0; }
.venue-pick-go { flex: 0 0 auto; }

/* ---------- Gallery grid ---------- */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(0.8rem, 1.8vw, 1.5rem);
  max-width: 620px;
  margin: 0 auto;
}
.gallery-tile {
  aspect-ratio: 1;
  border-radius: 12px;
  background: #8a5252;
  background-size: cover;
  background-position: center;
  overflow: hidden;
}
/* Kept deliberately: currently unused, since the empty gallery shows a message
   instead of waiting tiles, but this is the comp's tile treatment and is what
   a placeholder tile should look like if they are ever wanted back. */
.gallery-tile.is-empty {
  background: linear-gradient(160deg, #8a5252, #6d3a3a);
}

/* Staff upload panels above the gallery and video grids. */
.upload-form { max-width: 560px; margin: 0 auto 2.2rem; }
.upload-form h3 { margin-bottom: 1rem; }

/* Tools sit on the tile itself, so a hidden or unwanted image can be dealt
   with where it is rather than in a separate management screen. */
.gallery-tile { position: relative; }
.gallery-tile.is-hidden,
.video-card.is-hidden { opacity: 0.55; }
.tile-tools {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.tile-flag {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.1rem;
  color: var(--hp-orange);
  background: rgba(0, 0, 0, 0.7);
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
}
.tile-remove {
  width: 28px;
  height: 28px;
  border-radius: 999px;
  border: 1px solid var(--hp-line);
  background: rgba(0, 0, 0, 0.65);
  color: var(--hp-cream);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.tile-remove:hover { background: var(--hp-red-deep); color: var(--hp-white); }

.video-card {
  border: 1px solid var(--hp-line);
  border-radius: 12px;
  padding: 0.9rem;
}
.video-player,
.video-embed img { width: 100%; border-radius: 8px; display: block; }
.video-embed {
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
  background: linear-gradient(160deg, #6d3a3a, #2a1013);
  color: var(--hp-cream);
  position: relative;
}
.video-embed img { position: absolute; inset: 0; height: 100%; object-fit: cover; opacity: 0.55; }
.video-embed span { position: relative; text-transform: uppercase; letter-spacing: 0.16rem; }
.video-title { margin: 0.7rem 0 0.2rem; }
.video-desc { margin: 0; font-size: 0.9rem; color: var(--hp-smoke); }
.video-tools { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.8rem; }

/* Empty state for a section with nothing published yet. Deliberately separate
   from the grid rules above, which stay exactly as they are for real images. */
.coming-soon {
  max-width: 620px;
  margin: 0 auto;
  padding: clamp(2.6rem, 6vw, 4.2rem) 1.5rem;
  text-align: center;
  border: 1px dashed var(--hp-line);
  border-radius: 12px;
}
.coming-soon p { margin: 0; color: var(--hp-smoke); }
/* Two classes, so it beats `.coming-soon p` above no matter the order --
   that rule would otherwise repaint the lead in the muted body colour. */
.coming-soon .coming-soon-lead {
  font-family: var(--font-display);
  color: var(--hp-red);
  font-size: clamp(1.9rem, 4.2vw, 3rem);
  line-height: 1;
  margin: 0 0 0.7rem;
}

.video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1.4rem;
}
.video-tile {
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  background: linear-gradient(160deg, #6d3a3a, #2a1013);
  display: grid;
  place-items: center;
  color: var(--hp-smoke);
}

/* ---------- Auth pages ----------
   login.png drops the nav entirely and floats the card on a full-bleed photo. */
.auth-body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-image:
    linear-gradient(180deg, rgba(0,0,0,0.55), rgba(0,0,0,0.35) 40%, rgba(0,0,0,0.75)),
    var(--auth-bg);
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
}
.auth-main {
  flex: 1 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1.5rem 3rem;
}
.auth-card {
  background: var(--hp-red-deep);
  border-radius: 12px;
  padding: 1.5rem clamp(1.4rem, 4vw, 2.4rem) 2rem;
  width: 100%;
  max-width: 430px;
  box-shadow: 0 22px 70px rgba(0, 0, 0, 0.6);
}
.auth-card h1 {
  font-family: var(--font-display);
  color: var(--hp-white);
  font-size: clamp(2rem, 4vw, 2.7rem);
  text-align: center;
  margin-bottom: 1rem;
}
.auth-card .form-row label {
  text-align: center;
  font-size: 1.05rem;
}
.auth-card .button { display: block; margin: 1.5rem auto 0; }
.auth-aside {
  text-align: center;
  margin-top: 1.1rem;
  color: var(--hp-cream);
}
.auth-aside a { text-decoration: underline; }

/* Links inside the card have to announce themselves: site links carry no
   underline, so on the red card the rules link was indistinguishable from the
   label text wrapped around it. Nobody agrees to something they cannot tell is
   clickable. */
.auth-card .form-checkbox a {
  color: var(--hp-white);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.auth-card .form-checkbox a:hover { color: var(--hp-cream); }

/* ---------- Section heading over a page ---------- */
.page-heading { text-align: center; margin-bottom: 1.8rem; }

/* Two-line tagline under a page heading: body face in white, the one loaded
   word in the display script and red. The script sits larger because
   Casablanca reads smaller than Bethany Elingston at the same point size. */
.heat-tagline {
  text-align: center;
  margin: -0.6rem 0 2.4rem;
  color: var(--hp-white);
  font-size: clamp(0.95rem, 1.7vw, 1.35rem);
  line-height: 1.4;
}
.heat-tagline p { margin: 0; }
.heat-tagline .script {
  font-family: var(--font-display);
  color: var(--hp-red);
  font-size: 2.2em;
  /* Casablanca ships one weight. Asking for bold makes the browser synthesise
     it, which thickens the thin script strokes until the word closes up and
     stops being readable. Pinned to normal so the script survives even if the
     tagline is set bold again. */
  font-weight: normal;
  line-height: 0.8;
  display: inline-block;
  vertical-align: -0.1em;
  /* The script's opening flourish crowds the word before it. Measured in the
     script's own em, so it scales with the word rather than the line. */
  margin-left: 0.2em;
}
.heat-tagline .script.is-brand { color: var(--hp-orange-brand); }

/* ---------- Sectioned prose pages (About our Parties) ---------- */
.page-section { margin-top: 2.8rem; }
.page-section:first-of-type { margin-top: 0; }
.page-section > h2 { margin-bottom: 1.1rem; text-align: center; }
/* Each subheader sits directly on its paragraph, with the breathing room moved
   above it -- so the header reads as belonging to the text below, not floating
   between two blocks. */
.page-section h3 { margin-top: 2.4rem; margin-bottom: 0.15rem; }
.page-section h3 + p { margin-top: 0; }

/* The rules read as a list, so they are left-aligned even on a centred page:
   a numbered clause centred on itself is hard to scan. */
.rules {
  text-align: left;
  list-style: none;
  counter-reset: rule;
  padding: 0;
  margin: 0 auto;
  max-width: 52ch;
}
.rules li {
  counter-increment: rule;
  position: relative;
  padding-left: 2.6rem;
  margin-bottom: 1.1rem;
  line-height: 1.6;
}
.rules li::before {
  content: counter(rule) ")";
  position: absolute;
  left: 0;
  top: 0;
  color: var(--hp-red);
  font-weight: bold;
}
.rules strong { color: var(--hp-cream); }

/* Guidance, not a rule -- set apart from the numbered list so it cannot be
   read as one, but not buried either. */
/* Legal page. The draft banner is staff-only, so members never see it, but
   whoever runs the site is reminded every time they look at the page. */
.legal-draft {
  border: 1px dashed var(--hp-orange);
  border-radius: var(--radius);
  padding: 0.8rem 1rem;
  color: var(--hp-orange);
  font-size: 0.9rem;
  text-align: left;
}
.legal-updated { color: var(--hp-smoke); font-size: 0.85rem; }
.legal-list { padding-left: 1.2rem; }
.legal-list li { margin-bottom: 0.6rem; }
.legal-list strong { color: var(--hp-cream); }
code {
  font-family: Consolas, "SFMono-Regular", monospace;
  font-size: 0.9em;
  color: var(--hp-cream);
}

.rules-note {
  text-align: left;
  max-width: 52ch;
  margin: 2.2rem auto 0;
  padding: 0.2rem 0 0.2rem 1.1rem;
  border-left: 2px solid var(--hp-cream);
  color: var(--hp-smoke);
  font-size: 0.95rem;
}

/* ---------- Responsive ---------- */
/* Tighter tracking on the staff strip, so it stays a single row without
   scrolling for longer: a Site Manager's eight links on a 1366px laptop, and
   an Executive's six down to about 950px. */
@media (max-width: 1400px) {
  .nav-staff a { letter-spacing: 0.1rem; }
}

@media (max-width: 1100px) {
  .page-art { display: none; }
}

/* The main nav swaps to the Menu button here, ahead of the 860px layout
   change. Signed in -- the widest version, with Your Account and Logout --
   the links stop fitting on one row just under 980px, and between there and
   860px they used to break onto a second line. Measured in Chrome with the
   real fonts. Add a link to PRIMARY_NAV and this needs measuring again. */
@media (max-width: 1000px) {
  .nav {
    grid-template-columns: 1fr;
    justify-items: center;
    padding-bottom: 0.8rem;
  }
  .nav-toggle { display: inline-block; }
  .nav-primary {
    display: none;
    width: 100%;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    margin-top: 1rem;
  }
  .nav-primary.is-open { display: flex; }
  .nav-group-menu {
    position: static;
    transform: none;
    align-items: center;
    background: none;
    border: 0;
    box-shadow: none;
    padding: 0.6rem 0 0;
  }
  .nav .nav-account { margin-top: 0.9rem; }
  .nav a { font-size: 15px; }
}

@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; }
  .split-art { min-height: 220px; }

  h2 { letter-spacing: 0.3rem; }
  .button, button.button { letter-spacing: 0.22rem; padding-left: 1.6rem; }

  .slides { border-radius: 12px; }
  .slider-arrow { opacity: 1; width: 38px; height: 38px; }

  .calendar-cell { min-height: 46px; font-size: 0.75rem; }
  .calendar-event { font-size: 0.65rem; }
  .gallery-grid { grid-template-columns: repeat(2, 1fr); }
  .event-facts { gap: 1rem 1.8rem; }
  .upcoming-row { grid-template-columns: 1fr; gap: 0.2rem; }
}

@media (max-width: 520px) {
  .site-header .logo { width: 82vw; }
  .tier-grid { grid-template-columns: 1fr; }   /* two 170px columns will not fit */
  .calendar-grid { gap: 2px; }
  .calendar-cell { min-height: 38px; padding: 0.2rem 0.25rem; }
}

/* Anyone who asked the OS to stop animations gets a static slider. */
@media (prefers-reduced-motion: reduce) {
  .slide { transition: none; }
  .button { transition: none; }
  /* A steady dot still says "live"; it just stops blinking to say it. */
  .attendance-tag::before { animation: none; }
}
