/* Mobile first: the moment this exists for is standing somewhere at six
   o'clock with a phone, asking what is on tonight. Wide screens get more
   columns; nothing depends on having them. */

:root {
  --bg: #ffffff; --fg: #14161a; --dim: #666e7a; --line: #e3e6ea;
  --card: #f7f8fa; --raised: #f4f6f9; --controls: #e8ecf2;
  --shadow: rgba(15, 20, 30, .13);
  --accent: #b0271f; --accent-fg: #ffffff;
  --good: #1c7c3c; --mixed: #b07d10; --bad: #b0271f;
  --free: #3d9970; --sold: #d3d7dd; --broken: #b8bcc4; --best: #b0271f;
  --goodpair: #7ecfa3;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14161a; --fg: #e8eaee; --dim: #98a0ac; --line: #2a2f37;
    --card: #1c2027; --raised: #191d24; --controls: #23282f;
    --shadow: rgba(0, 0, 0, .45);
    --accent: #e2564c; --accent-fg: #14161a;
    --good: #4ec97a; --mixed: #e0b13a; --bad: #e2564c;
    --free: #4ec97a; --sold: #363c46; --broken: #2a2f37; --best: #e2564c;
    --goodpair: #2f7a51;
  }
}

* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font: 15px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
}
main { padding: 0 .75rem 4rem; max-width: 68rem; margin: 0 auto; }
a { color: inherit; }
h1 { font-size: 1.35rem; margin: 1rem 0 .5rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .95rem; }
.meta, .note, .hint, .legend { color: var(--dim); font-size: .82rem; }
.note { margin: .25rem 0 .75rem; }
/* Deliberately NOT called .empty: that collided with the seat state class
   .seat.empty, whose rule sets no padding, so every free seat inherited 1.5rem
   of vertical padding and stretched into a rectangle. Generic utility names and
   semantic state names share one namespace in CSS. */
.no-results { color: var(--dim); padding: 1.5rem 0; }
.warn { color: var(--bad); }
.ok { color: var(--good); font-size: .82rem; }

/* --- chrome --- */
/* Both sticky bands span the window; their contents share one measure with the
   scrolling content, so nothing steps sideways as you scroll. A surface that
   stopped short of the window edges would read as a floating card rather than
   a fixed layer. */
.band-inner { max-width: 68rem; margin: 0 auto; padding: 0 .75rem;
              display: flex; gap: .75rem; align-items: center; }

.topbar {
  position: sticky; top: 0; z-index: 20; padding: .55rem 0;
  background: var(--raised);
}
.brand { font-weight: 700; text-decoration: none; letter-spacing: -.02em; }
.topbar nav { display: flex; gap: .75rem; margin-left: auto; }
.topbar nav a { text-decoration: none; color: var(--dim); font-size: .9rem; }
.topbar nav a.on { color: var(--fg); font-weight: 600; }

/* --- filters --- */
/* Sticky, so choosing what to look at does not require scrolling away from
   what you are looking at. Separation from the scrolling content is a raised
   surface and a soft shadow -- two stacked rules read as a boundary drawn
   twice, where one layer reads as what it actually is. */
.sticky-controls {
  position: sticky; top: 0; z-index: 15;
  background: var(--controls);
  box-shadow: 0 3px 10px -4px var(--shadow);
  padding: 0 0 .45rem;
}
.sticky-controls .band-inner { display: block; }
.sticky-controls h1 { margin: .5rem 0 .25rem; }
.filters {
  display: flex; flex-wrap: wrap; gap: .4rem; align-items: center;
  padding: .5rem 0 .1rem;
}
.filters select {
  font: inherit; font-size: .82rem; padding: .25rem .4rem; border-radius: .35rem;
  border: 1px solid var(--line); background: var(--bg); color: var(--fg);
}
.check { font-size: .82rem; color: var(--dim); display: flex; align-items: center; gap: .25rem; }

/* --- disclosures --- */
details > summary { cursor: pointer; font-size: .82rem; color: var(--dim);
                    padding: .3rem 0; }
details[open] > summary { color: var(--fg); }

.picker { position: relative; }
.picker > summary { border: 1px solid var(--line); background: var(--bg);
                    border-radius: .35rem; padding: .25rem .5rem; color: var(--fg);
                    list-style: none; white-space: nowrap; }
.picker > summary::-webkit-details-marker { display: none; }
.picker > summary::after { content: " ▾"; color: var(--dim); }
.picker > summary { display: inline-flex; align-items: center; gap: .4rem; }
.picker-label { flex: 0 0 auto; }
.preview { display: inline-flex; gap: 1.5px; align-items: flex-end; }
.pv { width: 4px; height: 11px; border-radius: 1px; background: var(--line);
      display: inline-block; }
.pv.has { background: var(--free); opacity: .55; }
.pv.none { background: var(--line); height: 5px; }
.pv.wk.has { opacity: .8; }
.pv.sel { background: var(--accent); opacity: 1; height: 13px; }
.picker-body { position: absolute; z-index: 20; top: 100%; left: 0; margin-top: .25rem;
               background: var(--bg); border: 1px solid var(--line);
               border-radius: .4rem; padding: .5rem; min-width: 14rem;
               box-shadow: 0 6px 20px rgba(0,0,0,.18); }
.picker-body .check { display: flex; padding: .15rem 0; white-space: nowrap; }
.picker-body .tier { margin-left: auto; padding-left: .75rem; font-size: .7rem;
                     color: var(--dim); }
.picker-body .hint { margin: .4rem 0 0; }
.picker-body.dates { display: grid; grid-template-columns: repeat(7, 1fr);
                     gap: .2rem; min-width: 15rem; }
.picker-body.dates .hint { grid-column: 1 / -1; }
.day-cell { display: flex; flex-direction: column; align-items: center;
            border: 1px solid var(--line); border-radius: .3rem; padding: .15rem 0;
            font-size: .7rem; cursor: pointer; }
.day-cell input { display: none; }
.day-cell .num { font-weight: 600; font-size: .8rem; }
.day-cell.empty-day { opacity: .35; }
.day-cell.is-today { border-color: var(--accent); }
.day-cell:has(input:checked) { background: var(--accent); color: var(--accent-fg);
                               border-color: var(--accent); }
.reset { font-size: .78rem; color: var(--dim); }

/* --- the posted-window strip --- */
.strip { padding: .25rem 0 .5rem; }
.strip-row { display: flex; align-items: center; gap: .5rem; margin: .2rem 0; font-size: .8rem; }
.strip-row .venue { flex: 0 0 8.5rem; color: var(--dim); }
.strip-row .venue.primary { color: var(--fg); font-weight: 600; }
.cells { display: flex; gap: 2px; flex: 1; }
.cell { width: 100%; max-width: 14px; height: 14px; border-radius: 2px; display: inline-block; }
.cell.programmed { background: var(--free); }
.cell.announced { background: var(--mixed); opacity: .75; }
.cell.not-posted { background: var(--line); }
.cell.unknown { background: var(--broken); }
.through { flex: 0 0 auto; color: var(--dim); font-variant-numeric: tabular-nums; }
.legend { display: flex; gap: .5rem; align-items: center; margin-top: .5rem; flex-wrap: wrap; }
.legend .cell, .legend .seat { max-width: 12px; width: 12px; height: 12px;
                               aspect-ratio: auto; --seat-size: 12px; }

/* --- days --- */
.day { border-top: 1px solid var(--line); padding-top: .6rem; margin-top: .8rem; }
.day.today h2 .dow { color: var(--accent); }
.day h2 { display: flex; gap: .45rem; align-items: baseline; margin: 0 0 .35rem; }
.day h2 .dow { font-weight: 700; }
.day h2 .date { color: var(--dim); font-weight: 400; }
.day h2 .count { margin-left: auto; font-size: .75rem; color: var(--dim); font-weight: 400; }
.tag { background: var(--accent); color: var(--accent-fg); border-radius: .25rem;
       padding: 0 .3rem; font-size: .65rem; text-transform: uppercase; }
.venue-block { margin: .5rem 0 .8rem; }
.venue-block h3 { margin: .3rem 0; color: var(--dim); font-size: .8rem;
                  text-transform: uppercase; letter-spacing: .04em; }
.venue-block h3.primary { color: var(--fg); }
.zone { font-size: .65rem; text-transform: uppercase; border-radius: .25rem;
        padding: .05rem .3rem; margin-left: .35rem; letter-spacing: .03em; }
.zone.announced { background: var(--mixed); color: var(--bg); }
.zone.unknown, .zone.gone { background: var(--sold); color: var(--dim); }
.zone.leaving { background: var(--bad); color: var(--bg); }

/* --- film rows: one film, its showings grouped per theater --- */
.film-row { display: flex; gap: .5rem; align-items: flex-start; padding: .5rem 0;
            border-bottom: 1px solid var(--line); }
.film-row.watched .title { text-decoration: line-through; opacity: .55; }
.film-main { flex: 1; min-width: 0; }
.title-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; }
.title-line .title { font-weight: 600; text-decoration: none; }
.film-main .meta { display: block; margin: .1rem 0 .2rem; }
.strand { border: 1px solid var(--line); border-radius: .25rem; padding: 0 .25rem;
          margin-right: .3rem; font-size: .72rem; }

.venue-times { display: flex; gap: .4rem; align-items: baseline; margin: .18rem 0;
               flex-wrap: wrap; }
.venue-name { flex: 0 0 auto; font-size: .72rem; color: var(--dim);
              text-transform: uppercase; letter-spacing: .03em; min-width: 8.5rem; }
.venue-name.primary { color: var(--fg); }
.times { display: flex; flex-wrap: wrap; gap: .25rem; }
.film-actions { flex: 0 0 auto; }

/* Showing kinds. Standard is the quiet baseline; every other colour marks a
   deliberate variation, and the title attribute carries the detail. */
.time { font-size: .78rem; padding: .1rem .35rem; border: 1px solid var(--line);
        border-radius: .25rem; text-decoration: none; font-variant-numeric: tabular-nums;
        border-left-width: 3px; }
/* One palette, three shapes wear it: a calendar showtime, a grid chip, and the
   key's own chips. Written once because a legend that drifts from the thing it
   explains teaches the reader the wrong colour. */
.kind-standard   { border-left-color: var(--line); }
.kind-film-print { border-left-color: var(--accent); }
.kind-special    { border-left-color: var(--mixed); }
.kind-party      { border-left-color: #a05ec9; }
.kind-live       { border-left-color: #2f8fd0; }
.kind-advance    { border-left-color: var(--good); }
.kind-captioned  { border-left-color: #6b7280; }
.kind-unreserved { border-left-color: #6b7280; border-left-style: dashed; }
.time.kind-soldout, .chip.kind-soldout { opacity: .4; text-decoration: line-through; }
.legend.kinds { gap: .75rem; margin: 1.5rem 0 0; }
.legend.kinds .time { font-style: normal; }

/* New / leaving, shown only on films you have marked. */
.flag { font-size: .62rem; text-transform: uppercase; letter-spacing: .04em;
        border-radius: .25rem; padding: .08rem .3rem; font-weight: 700; }
.flag.leaving  { background: var(--bad); color: #fff; }
.flag.new      { background: var(--good); color: #fff; }
.flag.announced{ background: var(--mixed); color: #fff; }

/* --- score badge --- */
.score { display: inline-flex; align-items: center; justify-content: center;
         min-width: 2rem; height: 1.6rem; border-radius: .3rem; font-weight: 700;
         font-size: .85rem; text-decoration: none; color: #fff; flex: 0 0 auto; }
.score.good { background: var(--good); }
.score.mixed { background: var(--mixed); }
.score.bad { background: var(--bad); }
.score.none, .score.missing { background: transparent; color: var(--dim);
                              border: 1px dashed var(--line); font-weight: 400; }
.score.unconfirmed { opacity: .55; border: 1px dashed currentColor; }

/* --- marks: interest and seen, together --- */
.marks { display: inline-flex; align-items: center; gap: .3rem; }
.interest { display: inline-flex; }
.interest button, .watched {
  font: inherit; font-size: .72rem; padding: .2rem .4rem; cursor: pointer;
  border: 1px solid var(--line); background: var(--card); color: var(--dim);
}
.interest button:first-child { border-radius: .3rem 0 0 .3rem; }
.interest button:last-child { border-radius: 0 .3rem .3rem 0; }
.interest button.on { background: var(--accent); color: var(--accent-fg);
                      border-color: var(--accent); }
.watched { border-radius: .3rem; }
.watched.on { background: var(--good); color: var(--bg); border-color: var(--good); }

/* --- film list --- */
.film-list { display: grid; gap: .6rem; }
@media (min-width: 40rem) { .film-list { grid-template-columns: 1fr 1fr; } }
.film-card { display: flex; gap: .6rem; background: var(--card); border-radius: .5rem;
             padding: .5rem; }

.poster { width: 3.5rem; height: 5.2rem; object-fit: cover; border-radius: .3rem;
          background: var(--line); flex: 0 0 auto; }
.poster.blank { display: block; }
.poster.big { width: 8rem; height: 12rem; }
.card-body { flex: 1; min-width: 0; }
.card-head { display: flex; gap: .4rem; align-items: center; }
.card-head .title { font-weight: 600; text-decoration: none; }
.card-actions { margin-top: .4rem; display: flex; align-items: center; }

/* --- detail --- */
.detail header { display: flex; gap: 1rem; flex-wrap: wrap; align-items: flex-start; }
.detail h1 { margin-top: 0; }
.synopsis { color: var(--dim); font-size: .9rem; max-width: 44rem; }
.synopsis p { margin: .5rem 0; }
.states { list-style: none; padding: 0; }
.states li { padding: .3rem 0; border-bottom: 1px solid var(--line); font-size: .88rem; }
.showings { width: 100%; border-collapse: collapse; font-size: .85rem; }
.showings td { padding: .3rem .4rem .3rem 0; border-bottom: 1px solid var(--line); }
.showings .avail { text-align: right; }
.seats { color: var(--good); }
.sold { color: var(--dim); }
.sold.big { font-size: 1.1rem; }
.pin { display: flex; gap: .3rem; margin: .4rem 0; flex-wrap: wrap; }
.pin input { flex: 1; min-width: 14rem; font: inherit; font-size: .8rem;
             padding: .25rem .4rem; border: 1px solid var(--line);
             border-radius: .3rem; background: var(--bg); color: var(--fg); }
.pin button { font: inherit; font-size: .8rem; padding: .25rem .6rem; cursor: pointer;
              border-radius: .3rem; border: 1px solid var(--line); background: var(--card);
              color: var(--fg); }
.pin-status { font-size: .78rem; color: var(--dim); align-self: center; }

/* --- changes --- */
.run { border-top: 1px solid var(--line); padding-top: .6rem; margin-top: .9rem; }
.run h3 { margin: .6rem 0 .2rem; font-size: .78rem; text-transform: uppercase;
          letter-spacing: .04em; }
.run h3.new { color: var(--good); }
.run h3.leaving { color: var(--bad); }
.run h3.announced { color: var(--mixed); }
.extension { background: var(--card); border-left: 3px solid var(--good);
             padding: .5rem .6rem; border-radius: .3rem; margin: .4rem 0; font-size: .88rem; }
.extension .must { display: block; color: var(--accent); font-weight: 600; }
.extension .maybe { display: block; color: var(--dim); }
.change-list { list-style: none; padding: 0; margin: 0; }
.change-list li { display: flex; gap: .45rem; align-items: center; padding: .2rem 0; }

/* --- seat map --- */
.screen { background: var(--line); color: var(--dim); text-align: center;
          border-radius: 50% / 0 0 100% 100%; font-size: .7rem; letter-spacing: .3em;
          padding: .3rem 0 .5rem; margin: .8rem 0 .6rem; }
/* A 23-seat row does not fit a 375px phone at a comfortable seat size, so the
   seat size is derived from the auditorium's width and the space available.
   --cols is set per area by the template. The map still scrolls if the
   arithmetic runs out of room on a very wide house. */
.area { margin-bottom: .8rem; overflow-x: auto; }
/* Sized from the viewport rather than from a percentage. A custom property is
   substituted textually, so a percentage inside one resolves against whichever
   axis it lands in -- which made `height` resolve against the parent's height
   and stretched every seat into a rectangle. Viewport units are unambiguous,
   and aspect-ratio keeps the seat square without naming a height at all. */
.seat-row {
  display: flex; gap: var(--seat-gap); align-items: center; margin: 3px 0;
  line-height: 0;
  --seat-gap: 2px;
  --seat-size: clamp(
     6px,
     calc((min(100vw, 68rem) - 3.6rem) / var(--cols) - var(--seat-gap)),
     1.05rem);
}
.seat-row.aisle { height: .35rem; margin: 0; }
.row-label { flex: 0 0 1.4rem; font-size: .65rem; line-height: 1; color: var(--dim);
             text-align: right; margin-right: .2rem; }
/* Height is stated as well as the aspect ratio, and align-self pins it: a flex
   item with only an aspect ratio still stretches to the line's height. Now that
   --seat-size carries no percentage, a height built from it resolves against
   the right axis. */
.seat { width: var(--seat-size, 1.05rem); height: var(--seat-size, 1.05rem);
        aspect-ratio: 1; align-self: center; padding: 0; border-radius: .18rem;
        flex: 0 0 auto; display: inline-block; background: var(--sold); }
.seat.gap { background: transparent; }
.seat.empty { background: var(--free); opacity: .45; }
.seat.good { background: var(--goodpair); opacity: 1; }
.seat.best { background: var(--best); }
.seat.sold { background: var(--sold); }
.seat.broken { background: var(--broken); }
.summary { margin: .5rem 0; }
.good-pair { color: var(--good); }
.no-pair { color: var(--dim); }

.flash-ok { outline: 2px solid var(--good); outline-offset: 2px; }
.flash-bad { outline: 2px solid var(--bad); outline-offset: 2px; }
/* A row that no longer matches the active filter leaves visibly, so it is
   clear the mark took effect rather than the row simply disappearing. */
.retiring { opacity: 0; transform: translateX(1.5rem);
            transition: opacity .35s ease, transform .35s ease; }

/* --- sign in --- */
.signin { max-width: 20rem; margin: 3rem auto; }
.signin form { display: flex; flex-direction: column; gap: .6rem; margin-top: 1rem; }
.signin label { display: flex; flex-direction: column; gap: .2rem; font-size: .82rem;
                color: var(--dim); }
.signin input { font: inherit; padding: .45rem .5rem; border-radius: .35rem;
                border: 1px solid var(--line); background: var(--bg); color: var(--fg); }
.signin button { font: inherit; padding: .5rem; border-radius: .35rem; cursor: pointer;
                 border: none; background: var(--accent); color: var(--accent-fg);
                 font-weight: 600; }
.signin .warn { background: var(--card); border-left: 3px solid var(--bad);
                padding: .5rem .6rem; border-radius: .3rem; font-size: .88rem; }
.topbar .signout { margin-left: .25rem; }

/* --- what you already know about a film --- */
.yours .ticket { border-left: 3px solid var(--good); background: var(--card);
                 padding: .5rem .6rem; border-radius: .3rem; margin: .4rem 0; }
.yours .ticket.uncertain { border-left-color: var(--mixed); }
.yours .line { margin: 0; font-size: .9rem; }
.yours .line .meta { margin-left: .4rem; }
.candidates { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .4rem; }
.candidate { font: inherit; font-size: .78rem; padding: .25rem .5rem; cursor: pointer;
             border: 1px solid var(--line); border-radius: .3rem;
             background: var(--bg); color: var(--fg); }
.candidate.dismiss { color: var(--dim); }
.credits { font-size: .85rem; color: var(--dim); margin: .2rem 0 .4rem; }
.credits .by { display: block; color: var(--fg); }
.seat-actions { display: flex; gap: .5rem; align-items: center; margin: .5rem 0; }
#seat-refresh { font: inherit; font-size: .8rem; padding: .3rem .6rem; cursor: pointer;
                border: 1px solid var(--line); border-radius: .3rem;
                background: var(--card); color: var(--fg); }
.refresh-status { font-size: .8rem; color: var(--dim); }

/* A value that came from the second-choice source, marked quietly rather than
   presented as though the theater had said it. */
.from-elsewhere { border-bottom: 1px dotted var(--line); cursor: help; }

#seat-watch { font: inherit; font-size: .8rem; padding: .3rem .6rem; cursor: pointer;
              border: 1px solid var(--line); border-radius: .3rem;
              background: var(--card); color: var(--fg); }
#seat-watch.on { background: var(--accent); color: var(--accent-fg);
                 border-color: var(--accent); }

/* Links that leave for Alamo, where the ticket is actually bought. */
.alamo { text-decoration: none; border-bottom: 1px dotted currentColor; }
.venue-name .alamo { color: inherit; }

/* A showing under a seat watch, flagged wherever it appears: a standing
   intention you should not have to open a seat map to remember. */
.time.watched-seats, a.watched-seats { border-color: var(--accent); }
.eye { color: var(--accent); font-size: .6em; vertical-align: super;
       margin-left: .15rem; }

/* A row whose mark no longer matches the filter: set aside rather than removed,
   because a list that rearranges itself under your hand loses your place. */
.filtered-out { opacity: .45; }
.filtered-out::after { content: " — filtered out"; font-size: .72rem;
                       color: var(--dim); font-style: italic; }

/* The showing-kind key, which is also the filter. */
.kind-key { display: flex; flex-wrap: wrap; gap: .25rem; flex-basis: 100%;
            margin-top: .35rem; }
.kind-chip { font-size: .7rem; padding: .1rem .4rem; border-radius: .25rem;
             border: 1px solid var(--line); border-left-width: 3px;
             background: var(--bg); color: var(--dim); cursor: pointer;
             user-select: none; }
.kind-chip input { display: none; }
.kind-chip.on { color: var(--fg); font-weight: 600; background: var(--card);
                box-shadow: inset 0 0 0 1px var(--line); }
.kind-chip.kind-soldout { border-left-color: var(--dim); text-decoration: line-through; }

/* A film with one showing and no next Tuesday. */
.flag.single { background: var(--fg); color: var(--bg); }

.watch-list { list-style: none; padding: 0; }
.watch-list li { padding: .4rem 0; border-bottom: 1px solid var(--line);
                 display: flex; gap: .4rem; align-items: baseline;
                 flex-wrap: wrap; }
.strand-grid { display: flex; flex-wrap: wrap; gap: .35rem; margin: .5rem 0; }
.strand { font: inherit; font-size: .8rem; padding: .3rem .55rem; cursor: pointer;
          border: 1px solid var(--line); border-radius: .35rem;
          background: var(--card); color: var(--fg); display: inline-flex;
          gap: .35rem; align-items: baseline; }
.strand.on { background: var(--accent); color: var(--accent-fg);
             border-color: var(--accent); }
.strand.on .meta { color: var(--accent-fg); opacity: .8; }
.unwatch { font: inherit; font-size: .72rem; padding: .1rem .4rem; cursor: pointer;
           border: 1px solid var(--line); border-radius: .25rem;
           background: var(--bg); color: var(--dim); margin-left: auto; }
.add-watch { display: flex; gap: .3rem; margin-top: .6rem; }
.add-watch input { flex: 1; max-width: 24rem; font: inherit; font-size: .82rem;
                   padding: .3rem .5rem; border: 1px solid var(--line);
                   border-radius: .3rem; background: var(--bg); color: var(--fg); }
.add-watch button { font: inherit; font-size: .82rem; padding: .3rem .7rem;
                    cursor: pointer; border: 1px solid var(--line);
                    border-radius: .3rem; background: var(--card); color: var(--fg); }

/* --- the grid: dates across, films down ---------------------------------- */
/* Scrolls inside its own box. A table this wide making the whole page scroll
   sideways would take the sticky control band with it. */
/* The table is its own scroll region, in both directions, with its labels
   frozen. A sticky row cannot escape an overflow container, so a table that
   scrolls sideways inside a box while the page scrolls vertically outside it
   can never have a fixed header -- the two axes belong to different scrollers.
   Giving the box both makes it one, which is also the right mental model: a
   sheet you scroll around inside, with the dates and the titles pinned. */
.grid-scroll { overflow: auto; margin: .75rem 0;
               max-height: calc(100vh - var(--band-h, 9rem) - 3rem); }
/* Fixed columns, and the table as wide as they sum to; the wrapper scrolls.
   Neither automatic width works here: at 100% the browser squeezes the day
   columns until the times go one per line, and at max-content it widens them
   until a single day fills the screen. A day is worth a fixed amount of room. */
table.grid { border-collapse: collapse; table-layout: fixed; width: max-content;
             font-size: .82rem; }
table.grid th, table.grid td {
  border: 1px solid var(--line); vertical-align: top; padding: .35rem;
}
table.grid thead th {
  position: sticky; top: 0; z-index: 2; background: var(--card);
  text-align: center; white-space: nowrap; padding: .3rem .4rem;
}
table.grid thead th.today { background: var(--accent); color: var(--accent-fg); }
table.grid thead th.empty-day { color: var(--dim); }
table.grid .dow { display: block; font-size: .7rem; text-transform: uppercase;
                  letter-spacing: .04em; }
table.grid .dom { display: block; font-size: 1rem; font-weight: 600; }

/* The film column is the one thing you need while scrolled sideways. */
table.grid th.film-col {
  position: sticky; left: 0; z-index: 1; background: var(--bg);
  text-align: left; font-weight: normal; width: 17rem;
}
table.grid thead th.film-col { z-index: 3; background: var(--card); }
.film-head { display: flex; gap: .4rem; align-items: baseline; }
.film-head .title { font-weight: 600; }
.film-meta { display: flex; flex-wrap: wrap; gap: .3rem; align-items: baseline;
             color: var(--dim); font-size: .74rem; margin: .15rem 0; }
.film-meta .by { color: var(--fg); }
.strand-tag { font-size: .68rem; text-transform: uppercase;
              letter-spacing: .04em; color: var(--dim); }
table.grid .marks { font-size: .7rem; }

/* Wide enough for two times side by side. A cell one chip wide turns twenty
   showings into twenty lines. */
table.grid td, table.grid thead th:not(.film-col) { width: 9.5rem; }
table.grid td > * { display: inline-block; }
table.grid td.today { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.chip { margin: 0 .18rem .18rem 0; padding: .12rem .3rem;
        border: 1px solid var(--line); border-left-width: 3px;
        border-radius: .25rem; text-decoration: none; white-space: nowrap;
        font-variant-numeric: tabular-nums; }
.chip.watched-seats { box-shadow: inset 0 0 0 1px var(--accent); }
.chip .at { margin-left: .25rem; font-size: .68rem; opacity: .75; }
.chip.more { border-left-color: var(--dim); color: var(--dim); font-size: .72rem; }
.legend b { font-family: inherit; }

/* --- film page: showings grouped by date --------------------------------- */
.day-group { margin: .8rem 0; }
.day-group h3 { font-size: .82rem; margin: 0 0 .2rem; font-weight: 600;
                display: flex; gap: .4rem; align-items: baseline; }
.day-group.today h3 { color: var(--accent); }
.day-group table.showings { margin: 0; }
td.kind-cell { width: 1rem; padding-right: .2rem; }
/* The calendar's palette, as a dot: the row already carries time and theatre,
   and a coloured border on a table cell reads as a table rule. */
.kind-dot { display: inline-block; width: .5rem; height: .5rem; border-radius: 50%;
            background: var(--line); border-left: 0; vertical-align: middle; }
.kind-dot.kind-film-print { background: var(--accent); }
.kind-dot.kind-special    { background: var(--mixed); }
.kind-dot.kind-party      { background: #a05ec9; }
.kind-dot.kind-live       { background: #2f8fd0; }
.kind-dot.kind-advance    { background: var(--good); }
.kind-dot.kind-captioned  { background: #6b7280; }
.kind-dot.kind-unreserved { background: transparent; box-shadow: inset 0 0 0 1px #6b7280; }
.kind-dot.kind-soldout    { background: var(--dim); opacity: .5; }

/* "All scheduled" sits above the day grid and spans it. */
.span-all { grid-column: 1 / -1; font-size: .8rem; display: flex; gap: .35rem;
            align-items: center; padding: .2rem 0 .4rem; color: var(--fg);
            border-bottom: 1px solid var(--line); margin-bottom: .4rem; }
