/* Design tokens: see DESIGN.md. Self-hosted variable fonts, no Google Fonts
   request at runtime. */

@font-face {
  font-family: 'Archivo';
  src: url('/fonts/archivo.woff2') format('woff2-variations');
  font-weight: 400 600;
  font-display: swap;
}

@font-face {
  font-family: 'Big Shoulders Display';
  src: url('/fonts/big-shoulders-display.woff2') format('woff2-variations');
  font-weight: 700 900;
  font-display: swap;
}

@font-face {
  font-family: 'Big Shoulders Stencil';
  src: url('/fonts/big-shoulders-stencil.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}

@font-face {
  /* The flyer engine's monospace face, PROJECT-C-EDM-FLYER-ENGINE-SPEC.md
     section 10. Only used inside generated flyer SVGs. */
  font-family: 'JetBrains Mono';
  src: url('/fonts/jetbrains-mono.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}

:root {
  /* Colour: see DESIGN.md */
  --wall-base: #2b2a27;
  --wall-patch: #403e39;
  --paper: #d9d8d2;
  --paper-faded: #bab8b0;
  --toner: #141312;
  --stamp-ink: #8f1d1d;
  --sodium: #b8722a;
  --focus-ring: #e8b04a;
  /* Matches .site-footer's own divider, so admin list dividers (section
     16) and other one-off separators use the same subtle line. */
  --border: rgba(217, 216, 210, 0.2);

  /* Type */
  --font-display: 'Big Shoulders Display', 'Arial Narrow', sans-serif;
  --font-stencil: 'Big Shoulders Stencil', 'Arial Narrow', sans-serif;
  --font-body: 'Archivo', Arial, sans-serif;

  --text-body: 16px;
  --text-small: 14px;
  --text-h3: 20px;
  --text-h2: 28px;
  --text-h1: clamp(15px, 1.7vw, 26px);

  /* Shape and depth */
  --radius: 0;
  --tape-width: 28px;

  /* Motion */
  --motion-interaction: 200ms ease-out;
}

* {
  box-sizing: border-box;
}

/* Only .site-nav and .board-column ul had ever reset list styling, so every
   other <ul> on the site (archive, crews, crew profiles, harm reduction,
   the calendar's day lists) rendered with the browser's default bullets
   and 40px indent -- and, since nothing gave their <li>s any spacing
   either, adjacent event cards butted up against each other with no gap.
   Resetting this globally, with a couple of small utility classes below
   for the spacing individual lists still need, is one fix instead of
   patching each page that happens to contain a <ul>. */
ul, ol {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The native hidden attribute is meant to always mean display: none, but
   any element that also sets its own display (grid, flex...) would
   otherwise win, since author styles beat the UA stylesheet regardless of
   specificity. This makes [hidden] reliable everywhere instead of
   special-casing it per component. */
[hidden] {
  display: none !important;
}

html {
  background: var(--wall-base) url('/textures/concrete-grain.svg') repeat;
}

body {
  margin: 0;
  background: var(--wall-base);
  background-image: url('/textures/concrete-grain.svg');
  background-repeat: repeat;
  color: var(--paper);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.5;
}

main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 1.25rem 3rem;
}

/* Every other page (submit, contact, crews, archive, event, admin...) is a
   single narrow column -- a form, a list, one card -- with nothing to fill
   the home page's wider 1100px, which just left it stranded against the
   left edge with a big gap on the right. The home page manages its own
   width above and is unaffected, since .page-home main is more specific. */
body:not(.page-home) main {
  max-width: 760px;
}

a {
  color: var(--paper);
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Header and slogan strip, section 13.3: the one loud element. */
.site-header {
  padding: 2.5rem 1.25rem 2rem;
  text-align: left;
}

.site-header .site-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-h2);
  margin: 0 0 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  display: inline-block;
  color: inherit;
  text-decoration: none;
  transition: transform var(--motion-interaction);
}

.site-header .site-name:hover,
.site-header .site-name:focus-visible {
  transform: rotate(-1.5deg) scale(1.04);
}

.hero-name-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem 1rem;
}

.hero-name-row .site-name {
  margin: 0;
  white-space: nowrap;
  font-size: clamp(28px, 5vw, 64px);
}

.slogan-strip {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--text-h1);
  line-height: 1.15;
  margin: 0;
  background: var(--paper);
  color: var(--toner);
  display: inline-block;
  padding: 0.35em 0.5em;
  transform: rotate(-1deg);
  flex: 0 1 auto;
}

/* Site nav: the actionable links, up top so people don't need to scroll
   the footer to find them. */
.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}

.site-nav a {
  font-weight: 600;
  text-decoration: none;
  border-bottom: 2px solid transparent;
}

.site-nav a:hover,
.site-nav a:focus-visible {
  border-bottom-color: var(--paper);
}

/* Paper scraps: event cards. Shape and rotation are set inline per event
   via scrapShapeFor(), see src/lib/scrapShape.js. */
.scrap {
  background: var(--paper);
  color: var(--toner);
  padding: 1rem 1.25rem;
  position: relative;
  border-radius: var(--radius);
}

/* The global `a { color: var(--paper) }` rule below is for the dark wall
   background -- on a scrap's own paper-coloured background it left every
   link (Tickets, Add to calendar, Something wrong with this listing?, Look
   after each other) the same colour as the card itself, invisible except
   when selected. .scrap-title already special-cased this; every other
   link inside a scrap needs the same fix. */
.scrap a {
  color: inherit;
}

.scrap--past {
  background: var(--paper-faded);
}

.scrap .scrap-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-h3);
  margin: 0 0 0.4rem;
  line-height: 1.2;
}

.scrap .scrap-title a {
  color: inherit;
  text-decoration: none;
}

.scrap .scrap-title a:hover {
  text-decoration: underline;
}

.scrap-meta {
  font-size: var(--text-small);
  margin: 0.15rem 0;
  color: #3a3835;
}

.scrap-tape {
  position: absolute;
  top: -10px;
  left: 50%;
  transform: translateX(-50%) rotate(-2deg);
  width: var(--tape-width);
  height: 18px;
  background: rgba(217, 216, 210, 0.6);
}

/* A generated flyer's inlined SVG has no width/height attribute (only a
   viewBox), so without this it renders at the SVG default of 300x150. */
.generated-flyer svg {
  width: 100%;
  height: auto;
  display: block;
}

/* Status stamps: real text, not images. Section 8.2. */
.stamp {
  display: inline-block;
  font-family: var(--font-stencil);
  font-weight: 700;
  color: var(--stamp-ink);
  border: 3px solid var(--stamp-ink);
  padding: 0.15em 0.5em;
  transform: rotate(-4deg);
  text-transform: uppercase;
  font-size: var(--text-small);
}

/* Board columns, section 7.1 */
.board {
  display: grid;
  gap: 1.5rem;
}

.board-column h2 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-h2);
  text-transform: uppercase;
}

/* A vertical list of event/crew scrap cards: the board columns, the
   archive, the crews directory, a crew's own upcoming/past lists. */
.board-column ul,
.card-list {
  display: grid;
  gap: 1.25rem;
}

/* A plain list of links or short text entries with no card of their own
   (archive's year index, the calendar's per-day event lists, harm
   reduction links): needs some breathing room, just less than a card
   list's. */
.link-list {
  display: grid;
  gap: 0.5rem;
}

@media (min-width: 1024px) {
  .slogan-strip {
    white-space: nowrap;
  }

  .board {
    grid-template-columns: 1fr 1fr;
  }

  /* Been and gone on the left, Coming up on the right. DOM order stays
     upcoming-first so mobile (no grid here) keeps Coming up on top. */
  .board-column:first-child {
    order: 2;
  }

  .board-column:last-child {
    order: 1;
  }

  .calendar-panel {
    position: sticky;
    top: 1.25rem;
  }

  /* Home page only, section 7.1: the calendar sits beside the slogan, in
     the page-level grid below, rather than under the board. main and
     .home-layout are promoted with display: contents so their children
     (the board and the calendar) become direct items of that grid,
     without changing the mobile layout (plain block flow, no grid here)
     or moving anything in the actual markup. */
  .page-home {
    display: grid;
    grid-template-columns: 2fr 1fr;
    column-gap: 2rem;
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 1.25rem 3rem;
  }

  .page-home main,
  .page-home .home-layout {
    display: contents;
  }

  /* The header stays a real sticky box (it can't also be display:
     contents -- that would remove the box there'd be nothing to stick).
     It occupies column 1 on its own row; the calendar (below) sits next
     to it in column 2. */
  .page-home .site-header {
    grid-column: 1;
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--wall-base);
    background-image: url('/textures/concrete-grain.svg');
    background-repeat: repeat;
    margin: 0 -1.25rem;
    padding: 2.5rem 1.25rem 2rem;
  }

  /* This nav has less room than on other pages (it shares the row with
     the site name instead of spanning full width), so tighten it enough
     to keep all the links on one row instead of wrapping. */
  .page-home .site-header .site-nav {
    gap: 0.4rem 0.9rem;
    font-size: 0.85rem;
  }

  .page-home .view-toggle {
    display: none;
  }

  .page-home [data-panel="board"] {
    grid-column: 1;
  }

  /* --header-height is set by header-height.js to the header's actual
     rendered height (it varies with viewport width, so a fixed guess would
     only be right sometimes -- see that file). Frozen alongside the
     header and the calendar; only the cards underneath actually scroll. */
  .page-home .board-column h2 {
    position: sticky;
    top: var(--header-height, 13rem);
    z-index: 10;
    margin: 0;
    padding: 0.75rem 0;
    background: var(--wall-base);
    background-image: url('/textures/concrete-grain.svg');
    background-repeat: repeat;
  }

  /* Spans both the header's row and the board's row, so this cell is as
     tall as the two of them combined -- giving the sticky calendar panel
     inside it (above) room to stay stuck for the board's full height,
     instead of running out of room and scrolling away after only the
     header's own short height. */
  .page-home [data-panel="calendar"] {
    grid-column: 2;
    grid-row: 1 / 3;
  }

  .page-home .site-footer {
    grid-column: 1 / -1;
  }
}

/* Mobile board/calendar toggle, section 7.2 */
.view-toggle {
  display: none;
  gap: 0.5rem;
  margin: 0 0 1rem;
}

.view-toggle button {
  font-family: var(--font-body);
  font-weight: 600;
  padding: 0.6rem 1rem;
  border: 2px solid var(--paper);
  background: transparent;
  color: var(--paper);
  min-height: 44px;
  min-width: 44px;
}

.view-toggle button[aria-pressed="true"] {
  background: var(--paper);
  color: var(--toner);
}

@media (max-width: 1023px) {
  .view-toggle {
    display: flex;
  }
}

/* Calendar grid, section 7.1 and 14 */
.calendar {
  background: var(--wall-patch);
  padding: 1rem;
}

.calendar table {
  width: 100%;
  /* Fixed so the 7 day columns always divide the table's own width evenly
     -- without this, the day boxes' own min-width below (set for a decent
     touch target) could force the table itself wider than its container
     on a narrow phone screen, pushing the last column or two off the
     right edge of the page (owner-reported bug). Fixed layout means a
     narrow viewport shrinks every column instead of overflowing. */
  table-layout: fixed;
  border-collapse: collapse;
}

.calendar th,
.calendar td {
  text-align: center;
  padding: 0.4rem;
  font-size: var(--text-small);
}

/* Every day gets the same size box, whether or not it links anywhere, so
   the grid reads as uniform rather than some days looking like buttons
   and others like plain text. width: 100% (not a fixed min-width) fills
   whatever the fixed table-layout above gives this column -- it can
   still shrink on a narrow screen instead of forcing the table wider
   than the page. */
.calendar td a,
.calendar td span {
  min-height: 44px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.calendar td a {
  background: var(--paper);
  color: var(--toner);
  text-decoration: none;
}

/* Today's date, section 7.1 */
.calendar td.is-today {
  outline: 2px solid var(--sodium);
  outline-offset: -2px;
}

.calendar td.is-today span {
  font-weight: 800;
  color: var(--sodium);
}

.calendar-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}

.calendar-nav a {
  min-height: 44px;
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.calendar-nav-label {
  font-family: var(--font-display);
  font-weight: 800;
}

/* Footer, section 6 */
.site-footer {
  border-top: 1px solid rgba(217, 216, 210, 0.2);
  padding: 2rem 1.25rem;
  font-size: var(--text-small);
  display: grid;
  gap: 0.5rem;
}

.site-footer a {
  color: var(--paper);
}

/* Empty state, section 7.3 */
.empty-scrap {
  background: var(--paper);
  color: var(--toner);
  padding: 1.5rem;
  transform: rotate(-1deg);
}

/* Forms: submit, edit, crew and contact pages. Sections 9, 10.4, 14. */
h1 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-h2);
  text-transform: uppercase;
}

h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-h3);
}

.field {
  margin-bottom: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  max-width: 40rem;
}

.field label {
  font-weight: 600;
}

input,
textarea,
select {
  font: inherit;
  font-family: var(--font-body);
  padding: 0.6rem 0.75rem;
  border: 2px solid var(--paper);
  background: var(--paper);
  color: var(--toner);
  min-height: 44px;
  border-radius: var(--radius);
}

textarea {
  min-height: 100px;
}

button,
.button {
  font: inherit;
  font-family: var(--font-body);
  font-weight: 600;
  padding: 0.6rem 1.25rem;
  min-height: 44px;
  border: 2px solid var(--paper);
  background: var(--paper);
  color: var(--toner);
  cursor: pointer;
  border-radius: var(--radius);
  display: inline-block;
  text-decoration: none;
}

button.secondary,
.button.secondary {
  background: transparent;
  color: var(--paper);
}

button.danger,
.button.danger {
  background: var(--stamp-ink);
  border-color: var(--stamp-ink);
  color: var(--paper);
}

.actions {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin: 0.75rem 0;
}

/* Step-by-step submission form, section 9.1. .form-wizard is the positioning
   context for its steps; only the active one takes up space and is
   reachable. visibility (rather than display) is deliberate: the Turnstile
   widget lives in the last step and needs real dimensions to render into
   even before that step is shown, which display: none would prevent. */
.step-progress {
  font-weight: 600;
  margin: 0 0 1rem;
}

.form-wizard {
  position: relative;
}

.form-step {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  visibility: hidden;
  pointer-events: none;
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.form-step.is-active {
  position: relative;
  visibility: visible;
  pointer-events: auto;
}

.form-step h2 {
  margin-top: 0;
}

.muted {
  color: #b5b3aa;
  font-size: var(--text-small);
}

.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;
}

.error {
  color: var(--stamp-ink);
  background: var(--paper);
  padding: 0.75rem 1rem;
  font-weight: 600;
}

details.field summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--paper);
}

/* Reduced motion and high contrast, sections 13.5 and 14 */
@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
    animation: none !important;
  }
}

@media (prefers-contrast: more) {
  body {
    background-image: none;
  }

  .scrap,
  .empty-scrap,
  .slogan-strip {
    clip-path: none !important;
    transform: none !important;
  }
}
