/* Base, page shell and the shared components every page builds on. Values come from tokens.css. */

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

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

body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  margin: 0;
  background-color: var(--table);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  overflow-wrap: break-word;
}

h1,
h2,
h3 {
  margin: 0 0 var(--space-3);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  text-wrap: balance;
}

h1 {
  font-size: var(--text-2xl);
}

h2 {
  font-size: var(--text-xl);
}

h3 {
  font-size: var(--text-lg);
}

p,
ul,
ol,
dl,
address {
  margin: 0 0 var(--space-4);
}

p {
  max-width: var(--measure);
  text-wrap: pretty;
}

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

a {
  color: var(--felt);
  text-decoration-thickness: var(--underline-thin);
  text-underline-offset: var(--underline-offset);
}

a:hover {
  color: var(--felt-deep);
  text-decoration-thickness: var(--underline-thick);
}

::selection {
  background-color: var(--gold);
  color: var(--ink);
}

/* Gold alone disappears on white, so a dark edge rings it: visible on the felt band and on paper. */
:focus-visible {
  outline: var(--focus-outline-width) solid var(--felt-deep);
  outline-offset: var(--focus-outline-offset);
  box-shadow: var(--focus-ring);
}

.visually-hidden,
.skip-link:not(:focus) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  z-index: var(--layer-skip-link);
  padding: var(--space-3) var(--space-4);
  background-color: var(--gold);
  color: var(--ink);
  font-weight: var(--weight-bold);
}

.skip-link:hover {
  color: var(--ink);
}

/* Shell: the felt band, the page column and the footer share one column width. */

.site-header__inner,
.page,
.site-footer__inner {
  width: 100%;
  max-width: var(--content-width);
  margin-inline: auto;
  padding-inline: var(--space-4);
}

.site-header {
  border-bottom: 4px solid var(--felt-deep);
  background-color: var(--felt);
}

.site-header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-5);
  padding-block: var(--space-2);
}

/* A thumb-sized target like the nav links. The padding gives the focus ring room around the
   letters; the negative margin keeps them on the column edge. */
.wordmark {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target);
  margin-inline: calc(-1 * var(--space-2));
  padding: var(--space-1) var(--space-2);
  color: var(--paper);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-heavy);
  line-height: var(--leading-tight);
  text-decoration: none;
}

.wordmark:hover {
  color: var(--paper);
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
}

.site-nav__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target);
  color: var(--paper);
  font-weight: var(--weight-bold);
  text-decoration: none;
}

.site-nav__link:hover {
  color: var(--paper);
  text-decoration: underline;
  text-decoration-thickness: var(--underline-thick);
}

.page {
  flex-grow: 1;
  padding-block: var(--space-6) var(--space-8);
}

.page-title {
  margin: 0 0 var(--space-4);
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--weight-heavy);
  line-height: var(--leading-tight);
}

.lede {
  max-width: var(--measure);
  margin: 0 0 var(--space-6);
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}

.site-footer {
  border-top: 1px solid var(--rule);
  color: var(--ink-soft);
  font-size: var(--text-sm);
}

.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-1) var(--space-5);
  padding-block: var(--space-5);
}

.site-footer__address,
.site-footer__note {
  margin: 0;
  font-style: normal;
}

/* On a narrow phone the address wraps after the store name, never inside the street. */
.site-footer__address > span {
  display: inline-block;
}

@media (min-width: 48rem) {
  .site-header__inner,
  .page,
  .site-footer__inner {
    padding-inline: var(--space-6);
  }

  .site-header__inner {
    padding-block: var(--space-3);
  }

  .wordmark {
    font-size: var(--text-2xl);
  }

  .page {
    padding-block-start: var(--space-7);
  }

  .page-title {
    font-size: var(--text-4xl);
  }
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-target);
  padding: var(--space-2) var(--space-5);
  border: 2px solid var(--felt);
  border-radius: var(--radius-sm);
  background-color: var(--felt);
  color: var(--paper);
  font: inherit;
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition-duration: var(--duration-quick);
  transition-property: background-color, border-color, color;
}

.button:hover {
  border-color: var(--felt-deep);
  background-color: var(--felt-deep);
  color: var(--paper);
}

.button--quiet {
  background-color: transparent;
  color: var(--felt);
}

.button--quiet:hover {
  background-color: var(--paper);
  color: var(--felt-deep);
}

/* The primary action in the felt band: a paper button, since felt on felt would vanish. */
.button--on-felt {
  border-color: var(--paper);
  background-color: var(--paper);
  color: var(--felt);
}

.button--on-felt:hover {
  border-color: var(--table);
  background-color: var(--table);
  color: var(--felt-deep);
}

/* Label, then hint and error, then the control: help is read out before anyone starts typing. */

.field {
  display: grid;
  gap: var(--space-1);
  max-width: var(--field-width);
  margin: 0 0 var(--space-5);
}

.field:has(.field__error) {
  padding-inline-start: var(--space-4);
  border-inline-start: 4px solid var(--stamp);
}

.field__label {
  font-weight: var(--weight-bold);
}

.field__hint {
  margin: 0;
  color: var(--ink-soft);
}

.field__error {
  margin: 0;
  color: var(--stamp);
  font-weight: var(--weight-bold);
}

.field__input {
  width: 100%;
  margin-block-start: var(--space-1);
  min-height: var(--touch-target);
  padding: var(--space-2) var(--space-3);
  border: 2px solid var(--control-border);
  border-radius: var(--radius-sm);
  background-color: var(--paper);
  color: var(--ink);
  font: inherit;
}

.field__input[aria-invalid="true"] {
  border-color: var(--stamp);
}

.error-summary {
  max-width: var(--measure);
  margin: 0 0 var(--space-6);
  padding: var(--space-4) var(--space-5);
  border: 3px solid var(--stamp);
  border-radius: var(--radius-sm);
  background-color: var(--paper);
}

.error-summary h2 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
}

.error-summary ul {
  margin: 0;
  padding-inline-start: var(--space-5);
}

.error-summary a,
.error-summary a:hover {
  color: var(--stamp);
  font-weight: var(--weight-bold);
}

/* A game's class from /games.css sets --game-color; without one the tint stays neutral. Badges
   and the calendar's event links share one edge and tint, so a game looks the same everywhere. */
.game-badge,
.calendar-event {
  border-inline-start: 4px solid var(--game-color);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background-color: color-mix(in srgb, var(--game-color) 12%, var(--paper));
  color: var(--ink);
}

.game-badge {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
}

.calendar-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4) var(--space-6);
  margin-block-end: var(--space-5);
}

.calendar-header .page-title {
  margin-block-end: var(--space-1);
}

.calendar-header__zone {
  margin: 0;
  color: var(--ink-soft);
}

.calendar-header__months {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.calendar-header__this-month {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target);
  margin-inline-end: var(--space-2);
  font-weight: var(--weight-bold);
}

.calendar-empty {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  margin-block-end: var(--space-5);
}

.calendar-empty__message {
  margin: 0;
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}

/* Both rows share one track definition and border box, so the headings sit over their days.
   The rule lines are the list's own background showing through the gaps. */
.calendar__weekdays,
.calendar__days {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--rule-width);
  border: var(--rule-width) solid transparent;
}

.calendar__weekdays {
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
}

.calendar__weekdays > span {
  padding: var(--space-1) var(--space-2);
}

.calendar__days {
  margin: 0;
  padding: 0;
  border-color: var(--rule);
  background-color: var(--rule);
  list-style: none;
}

.calendar-day {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-height: var(--day-min-height);
  padding: var(--space-2);
  background-color: var(--paper);
}

.calendar-day--outside {
  background-color: var(--table);
  color: var(--ink-soft);
}

.calendar-day__number {
  display: grid;
  place-items: center;
  width: var(--day-marker);
  height: var(--day-marker);
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-heavy);
  line-height: var(--leading-tight);
}

/* Keyed to aria-current, so the gold disc and what screen readers announce can't disagree. */
[aria-current="date"] .calendar-day__number {
  border-radius: var(--radius-round);
  background-color: var(--gold);
  color: var(--ink);
}

.calendar-day__events {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Time and seats share the top line, then the name and the game each get a full-width line.
   When a narrow cell can't fit both, the seats drop under the time, and a word longer than the
   cell is wide breaks rather than spilling into the next day. */
.calendar-event {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  column-gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  overflow-wrap: anywhere;
  text-decoration: none;
  transition-duration: var(--duration-quick);
  transition-property: background-color;
}

.calendar-event__time {
  font-weight: var(--weight-bold);
}

.calendar-event__seats {
  order: 1;
  color: var(--ink-soft);
}

.calendar-event__seats--full {
  color: var(--stamp);
  font-weight: var(--weight-bold);
}

.calendar-event__name {
  order: 2;
  flex-basis: 100%;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
}

/* The full game names run long, so on the grid they get the smallest text on the site. */
.calendar-event__game {
  order: 3;
  flex-basis: 100%;
  color: var(--ink-soft);
  font-size: var(--text-xs);
}

/* Any deeper and the stamp-red "Full" drops under 4.5:1 against the darker game colors. */
.calendar-event:hover {
  background-color: color-mix(in srgb, var(--game-color) 18%, var(--paper));
  color: var(--ink);
}

.calendar-event:hover .calendar-event__name {
  text-decoration: underline;
  text-decoration-thickness: var(--underline-thin);
}

/* Just above the phone layout a column holds only six to nine letters of an event name, so
   the cells give up some padding and long words break at a hyphen. */
@media (43.75rem <= width < 64rem) {
  .calendar__weekdays > span,
  .calendar-day {
    padding-inline: var(--space-1);
  }

  .calendar-event {
    padding-inline: var(--space-1);
    hyphens: auto;
  }
}

/* Seven columns don't fit a phone, so under 700px (43.75rem at the default text size) the
   month becomes an agenda: only the days with events, each under its full date. */
@media (width < 43.75rem) {
  .calendar__weekdays,
  .calendar-day,
  .calendar-day__number {
    display: none;
  }

  /* Two month names don't fit beside "This month" on a phone, so the pager gets its own row
     of equal halves. */
  .calendar-header__months {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    width: 100%;
  }

  .calendar-header__this-month {
    grid-column: 1 / -1;
    justify-self: start;
  }

  .calendar-header__months .button {
    padding-inline: var(--space-3);
  }

  .calendar__days {
    display: block;
    border: 0;
    background-color: transparent;
  }

  .calendar-day--has-events {
    display: block;
    min-height: 0;
    padding: 0;
    background-color: transparent;
  }

  .calendar-day--has-events ~ .calendar-day--has-events {
    margin-block-start: var(--space-5);
  }

  .calendar-day__date.visually-hidden {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }

  .calendar-day__date {
    margin: 0 0 var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: var(--weight-heavy);
    line-height: var(--leading-tight);
  }

  /* The agenda hides the day numbers, so today's gold disc sits beside its date instead. */
  [aria-current="date"] .calendar-day__date::before {
    content: "";
    display: inline-block;
    width: var(--today-dot);
    height: var(--today-dot);
    margin-inline-end: var(--space-2);
    border-radius: var(--radius-round);
    background-color: var(--gold);
  }

  .calendar-event {
    padding: var(--space-2) var(--space-3);
  }

  .calendar-event__game {
    font-size: var(--text-sm);
  }
}

/* Every transition takes its duration from this token, so zeroing it stops them all. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-quick: 0s;
  }
}

/* Create an event: the game picker's cards (Task 10). Each is framed in its game's color like
   a physical card's border; the art crops to one shared ratio so templates with different
   native art proportions still line up in the grid. */

.game-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--game-card-min-width), 1fr));
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.game-picker > li {
  display: flex;
}

.game-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  overflow: hidden;
  border: var(--game-card-border-width) solid var(--game-color);
  border-radius: var(--radius-md);
  background-color: var(--paper);
}

.game-card__art {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.game-card__body {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  gap: var(--space-3);
  padding: var(--space-5);
}

.game-card__logo {
  width: auto;
  max-width: 100%;
  height: var(--game-card-logo-height);
  object-fit: contain;
  object-position: left;
}

.game-card__description {
  margin: 0;
  color: var(--ink);
}

.game-card__facts {
  margin: 0 0 auto;
  color: var(--ink-soft);
  font-size: var(--text-sm);
}

/* Event page: the game's art, the facts and the sign-up sheet, with the registration panel in a
   column of its own on wide screens. The sheet is the one loud thing on the site, so everything
   around it stays plain. */

/* The facts also head the register and confirmation pages. Each fact is as wide as its text, so
   the address never breaks inside its ZIP code. */
.facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-7);
  margin-block-end: var(--space-5);
}

.facts dt {
  color: var(--ink-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
}

.facts dd {
  margin: 0;
}

.facts__full {
  color: var(--stamp);
  font-weight: var(--weight-bold);
}

.event {
  display: grid;
  gap: var(--space-6);
}

.event__art {
  width: 100%;
  aspect-ratio: var(--banner-ratio);
  margin-block-end: var(--space-5);
  border-block-end: 4px solid var(--game-color);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  object-fit: cover;
}

/* Every logo fits the same box, so a tall one isn't dwarfed by a wide one of the same height. */
.event__logo {
  width: auto;
  max-width: var(--logo-width);
  max-height: var(--logo-height);
  margin-block-end: var(--space-4);
}

.event__details > .game-badge {
  margin-block-end: var(--space-3);
}

.event__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
}

.next-step-note {
  margin: 0;
  font-weight: var(--weight-bold);
}

.event__actions > .next-step-note {
  flex-basis: 100%;
}

.event__subheading {
  margin-block: var(--space-6) var(--space-2);
  font-size: var(--text-lg);
}

/* The clipboard: a felt-green board with a clip at the top holding a sheet of paper. */
.sign-up-sheet {
  margin-block-start: var(--space-7);
  padding: var(--space-6) var(--space-3) var(--space-3);
  border-radius: var(--radius-md);
  background-color: var(--felt);
}

/* The clip stays in the flow, pulled up over the board's top edge. Absolutely positioned, it
   would stop axe from checking the contrast of the text on the sheet. */
.sign-up-sheet::before {
  content: "";
  display: block;
  width: var(--clip-width);
  height: var(--clip-height);
  margin: calc(-1 * (var(--space-6) + var(--space-2))) auto 0;
  border: var(--clip-edge) solid var(--felt-deep);
  border-radius: var(--clip-radius);
  background-color: var(--rule);
  background-image: var(--clip-hole);
}

.sign-up-sheet__paper {
  padding: var(--space-6) var(--space-5) var(--space-5);
  border-radius: var(--radius-sm);
  background-color: var(--paper);
}

/* The stamp shares the title's row, and drops under the title when the sheet is too narrow for
   both, so it never lands on a name. */
.sign-up-sheet__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  margin-block-end: var(--space-2);
}

.sign-up-sheet__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-heavy);
  line-height: var(--leading-tight);
}

.sign-up-sheet__stamp {
  margin: 0;
  margin-inline-start: auto;
  padding: 0 var(--space-3);
  border: var(--stamp-border) double var(--stamp);
  border-radius: var(--radius-md);
  color: var(--stamp);
  font-family: var(--font-display);
  font-size: var(--text-4xl);
  font-weight: var(--weight-heavy);
  line-height: var(--leading-snug);
  rotate: var(--stamp-tilt);
}

/* Native list numbers, not counters: Safari stops announcing a list once its markers go. The
   top padding sets each name on its ruled line, and an empty line's number lands in the same
   place. */
.sign-up-sheet__lines {
  margin: 0;
  padding-inline-start: var(--sheet-numbers);
}

.sign-up-sheet__line {
  min-height: var(--sheet-row);
  padding-block: calc(var(--sheet-row) - 1lh - var(--space-1)) var(--space-1);
  border-block-end: var(--sheet-line) solid var(--rule);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  line-height: var(--leading-snug);
}

.sign-up-sheet__line::marker {
  color: var(--ink-soft);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-heavy);
}

.registration-panel {
  padding: var(--space-5);
  border: var(--rule-width) solid var(--rule);
  border-radius: var(--radius-sm);
  background-color: var(--paper);
}

.registration-panel__title {
  font-size: var(--text-lg);
}

.registration-panel__qr {
  width: 100%;
  max-width: var(--qr-size-phone);
  margin-block-end: var(--space-3);
}

.registration-panel__link {
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}

.registration-panel .button {
  width: 100%;
}

@media (min-width: 48rem) {
  .event__art {
    aspect-ratio: var(--banner-ratio-wide);
  }

  .event__logo {
    max-width: var(--logo-width-wide);
    max-height: var(--logo-height-wide);
  }

  .sign-up-sheet__stamp {
    font-size: var(--text-5xl);
  }

  .registration-panel__qr {
    max-width: var(--qr-size);
  }
}

@media (width < 24rem) {
  .sign-up-sheet__stamp {
    font-size: var(--text-3xl);
  }
}

/* Until the panel gets its own column it comes after the whole sheet, so the next step shows
   under the needs line instead, where a player reads it before scrolling. */
@media (width < 60rem) {
  .registration-panel__next-step {
    display: none;
  }
}

/* A tablet has room to set the panel's words beside the code rather than under it. */
@media (48rem <= width < 60rem) {
  .registration-panel {
    display: flow-root;
  }

  .registration-panel__qr {
    float: inline-start;
    margin-block-end: 0;
    margin-inline-end: var(--space-5);
  }
}

/* Wide screens give the panel a column from the top, so the QR code is in view as soon as the
   page opens, and it stays in view while a long sheet scrolls past. */
@media (min-width: 60rem) {
  .event {
    grid-template-columns: minmax(0, 1fr) var(--panel-width);
    align-items: start;
  }

  .event__next-step {
    display: none;
  }

  .registration-panel {
    position: sticky;
    top: var(--space-5);
  }
}

/* Registration: phone-first, one field and one big button. Full and closed states drop the
   form for a plain explanation, so there is never more than one thing to do on this page. */
.register-form {
  max-width: var(--field-width);
}

.register-form__button {
  width: 100%;
}

.confirmation-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* Printed, the event page is a sheet for the counter or a flyer. The site links, the art and the
   buttons only work on screen, so they stay off the paper, and the QR code prints in one piece. */
@media print {
  body:has(.event) .site-header,
  .event__art,
  .event .button,
  .sign-up-sheet::before {
    display: none;
  }

  .sign-up-sheet {
    padding: 0;
  }

  .sign-up-sheet__line,
  .registration-panel {
    break-inside: avoid;
  }
}
