/* DAILY DOVER: bright, mobile-first. Base rules are the phone layout; the
   desktop frame layers on at the bottom. Every spatial value is a token off
   the 4px grid (playbook: one base unit, clean ratios). */

:root {
  /* grid */
  --u: 4px;
  --s1: 4px;   /* 1u */
  --s2: 8px;   /* 2u */
  --s3: 12px;  /* 3u */
  --s4: 16px;  /* 4u */
  --s6: 24px;  /* 6u */
  --s8: 32px;  /* 8u */
  --s12: 48px; /* 12u */
  /* One horizontal measure for the whole page: text sits --gutter in from the
     window edge and never runs wider than --measure. These are tokens because
     the day bands deliberately opt OUT of the inset so their wash and rule
     reach the window edges, and both halves have to agree on the number. */
  --measure: 1200px;
  --gutter: var(--s4);
  /* type: an editorial serif for display, the platform's best sans for text.
     system-ui first picks up SF / Segoe UI Variable / Roboto properly. */
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, Charter, Georgia, serif;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --f-xs: 12px;
  --f-sm: 14px;
  --f-md: 16px;
  --f-lg: 20px;
  --f-xl: 28px;
  --f-hero: 40px;
  /* radii (nested corners stay concentric: inner + padding = outer) */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  /* the bright palette: warm paper, soft ink */
  --paper: oklch(97.5% 0.012 85);
  --card: oklch(99.4% 0.004 85);
  --ink: oklch(28% 0.02 60);
  --ink-soft: oklch(45% 0.02 60);
  --ink-faint: oklch(58% 0.015 60);
  --line: oklch(90% 0.015 85);
  /* motion: one pair */
  --t-fast: 120ms ease-out;
  --t-slow: 240ms ease-out;
  /* depth: one soft step for cards, one for lifted chips */
  --shadow-card: 0 1px 2px oklch(30% 0.02 60 / 0.06), 0 4px 12px oklch(30% 0.02 60 / 0.05);
  --shadow-lift: 0 2px 8px oklch(30% 0.02 60 / 0.12);
}

* { box-sizing: border-box; }

/* The hidden attribute hides an element through a UA-stylesheet rule, which any
   author `display` declaration silently outranks. `.card` sets display:flex, so
   `card.hidden = true` from app.js did nothing at all and venue filtering only
   appeared to work (empty day sections disappeared, because `.day` sets no
   display, while the surviving sections still showed every venue). Declare it
   here, once, for everything the frontend hides. */
[hidden] { display: none !important; }

/* Per-venue accents derive from the --hue each chip/card sets inline. These
   must be declared HERE, not on :root: a custom property resolves its var()
   references where it is declared, so putting these on :root would freeze
   every venue at the fallback hue. */
.chip, .card {
  --accent: oklch(46% 0.11 var(--hue, 60));
  --accent-soft: oklch(94% 0.045 var(--hue, 60));
  --accent-line: oklch(80% 0.08 var(--hue, 60));
}

html { background: var(--paper); }

/* The body spans the window and holds no horizontal inset of its own. The
   width limit lives on the blocks below instead, so a full-bleed element is
   simply one that does not take the inset: nothing has to bleed back out with
   negative margins, and nothing is measured against a wrapper that stops
   short of the glass. */
body {
  margin: 0;
  padding: var(--s4) 0 calc(var(--s8) + env(safe-area-inset-bottom));
  font: var(--f-md)/1.55 var(--font-body);
  color: var(--ink);
  -webkit-text-size-adjust: 100%;
}

/* The shared inset. Each of these is a full-width block, so 100% is the window
   and the padding both centres the column and holds the gutter on a phone
   (where the second term goes negative and max() falls back to --gutter).
   `.day` is absent on purpose: its wash and its rule run the full width, and
   `.day-head` and `.cards` re-inset the contents inside it. */
.masthead, .venues, .searchbar, .day-head, .cards, .empty-note, .footer {
  padding-inline: max(var(--gutter), calc((100% - var(--measure)) / 2));
}

/* ---- masthead ---- */

.masthead { padding-block: var(--s4) var(--s3); }

.wordmark {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--f-hero);
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.05;
}

.tagline {
  margin: var(--s2) 0 0;
  color: var(--ink-soft);
  font-size: var(--f-md);
  font-weight: 500;
  letter-spacing: 0.01em;
}

/* ---- venue chip rail ---- */

/* Phone: three rows that scroll sideways together (column-flow grid packs
   the chips top-to-bottom, then left-to-right). Desktop swaps to a wrap. */
.venues {
  display: grid;
  grid-template-rows: repeat(3, auto);
  grid-auto-flow: column;
  justify-content: start;
  gap: var(--s2);
  overflow-x: auto;
  /* The shared inset doubles as the rail's scroll gutter, so the first and
     last chip clear the window edge at both ends of the swipe. */
  padding-block: var(--s3);
  margin: 0;
  scrollbar-width: none;
}
.venues::-webkit-scrollbar { display: none; }

.chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  white-space: nowrap;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--ink-faint);
  font-size: var(--f-sm);
  line-height: 1.2;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}

.chip.is-on {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent);
}

/* Select all / Clear all performs an action rather than reporting a venue's
   state, so it stays visually distinct at all times and its label says what
   the next click will do. */
.chip-all {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
  font-weight: 600;
}

.chip-count {
  font-size: var(--f-xs);
  opacity: 0.75;
}

.chip:focus-visible, #search:focus-visible, .card a:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* ---- search ---- */

.searchbar { padding-block: 0 var(--s6); }

#search {
  width: 100%;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--card);
  color: var(--ink);
  font-size: var(--f-md); /* 16px on purpose: smaller triggers iOS focus zoom */
}
#search::placeholder { color: var(--ink-faint); }

/* ---- day sections ---- */

/* Each section carries its own pale wash, one step of hue apart (see
   render.go's sectionHue), so a quick scroll registers a new section as a
   colour change rather than a line to hunt for. The band takes no horizontal
   inset, so the wash and the rule above it run right to the window edges at
   every width; --tint is declared here, on the element that also carries
   --section-hue, so it resolves per section and children inherit the resolved
   colour. */
/* Sections abut: any vertical margin between them would let the body's paper
   show through as a stray band, so all the breathing room is padding inside
   the tint and the rule is the only edge between two washes. */
.day {
  --tint: oklch(97.4% 0.024 var(--section-hue, 85));
  margin: 0;
  padding-block: 0 var(--s8);
  background: var(--tint);
}

/* The heading sticks to the top of the viewport for as long as its own day is
   on screen, so scrolling never loses track of which day you are reading. The
   element runs the full width (its rule and its wash reach the glass) while
   the shared inset holds the words on the page's column; it is fully opaque so
   cards pass under it. */
.day-head {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s2) var(--s3);
  margin-block: 0 var(--s4);
  padding-block: var(--s4) var(--s3);
  border-top: 2px solid var(--ink);
  background: var(--tint);
  font-family: var(--font-display);
  font-size: var(--f-xl);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: 0.01em;
}

/* A soft fade below the bar hides the hard edge of a card sliding under it. */
.day-head::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: var(--s3);
  background: linear-gradient(var(--tint), transparent);
  pointer-events: none;
}

.day-sub {
  font-family: var(--font-body);
  font-size: var(--f-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px var(--s2);
}

/* Today earns the loudest label on the page. */
.day-sub-today {
  color: var(--paper);
  background: var(--ink);
  border-color: var(--ink);
}

.cards {
  display: grid;
  /* minmax(0, …): grid items min-width auto would let long content blow the
     track wider than the viewport and clip. Two-across is the phone layout. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s3);
}

/* ---- cards ---- */

.card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow-wrap: break-word;
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent-line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.card-art { display: block; background: var(--accent-soft); }

.card-art img {
  display: block;
  width: 100%;
  max-width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.card-body { padding: var(--s3); }

/* The venue tag gets its own line: venue names run long ("Kent, CT Community
   Calendar") and a two-across phone card is narrow, so sharing a row with the
   date made the pill break mid-phrase on some font stacks. */
.card-venue { margin: 0; }

/* A rounded rectangle, not a pill: venue names wrap to two lines in a narrow
   card ("Kent, CT Community Calendar"), and a stadium radius around two lines
   reads as an oval blob. The single-line chips and badges stay pills. */
.venue-tag {
  display: inline-block;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-sm);
  padding: 3px var(--s2);
  font-size: var(--f-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.35;
}

.card-when {
  margin: var(--s2) 0 0;
  font-size: var(--f-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
}

/* Middots between whichever of date, time, and price the event has. */
.card-when span + span::before {
  content: "·";
  margin: 0 var(--s1);
  color: var(--ink-faint);
  font-weight: 400;
}

.price { font-weight: 400; }

.card-title {
  margin: var(--s2) 0 0;
  font-family: var(--font-display);
  font-size: var(--f-lg);
  line-height: 1.2;
  font-weight: 700;
  letter-spacing: 0.01em;
}

.card-title a { color: inherit; text-decoration: none; }
.card-title a:hover { color: var(--accent); }

.card-place {
  margin: var(--s1) 0 0;
  font-size: var(--f-sm);
  color: var(--ink-faint);
}

.card-desc {
  margin: var(--s2) 0 0;
  font-size: var(--f-sm);
  color: var(--ink-soft);
  white-space: pre-line;
  /* Narrow phone columns clamp long prose; desktop unclamps below. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
  overflow: hidden;
}

/* ---- footer ---- */

.empty-note { margin: var(--s8) 0; color: var(--ink-faint); text-align: center; }

.footer {
  margin-top: var(--s12);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
  font-size: var(--f-sm);
  color: var(--ink-soft);
}

.footnote { color: var(--ink-faint); font-size: var(--f-xs); }

/* ---- desktop enhancement ---- */

@media (min-width: 720px) {
  /* One token widens every gutter on the page at once. */
  :root { --gutter: var(--s8); }
  .venues {
    display: flex;
    flex-wrap: wrap;
  }
  .cards { gap: var(--s4); }
  .card-body { padding: var(--s4); }
  .card-title { font-size: var(--f-xl); }
  .card-desc { display: block; -webkit-line-clamp: unset; overflow: visible; }
}

@media (min-width: 1080px) {
  .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
  .chip { transition: none; }
}
