/* Malaysia Showtimes
   Dark-first palette: a "mild dark" of warm slate (never black) with a coral
   accent. The bright theme is warm off-white paper with ink-navy type, and the
   two are built to read as the same product at different brightness.

   Fonts are self-hosted, not linked from Google, so the page has no external
   dependency at runtime. Outfit carries display weight, Rubik carries body and
   the dense showtime data. */

@font-face {
  font-family: 'Outfit';
  src: url('fonts/Outfit.woff2') format('woff2');
  font-weight: 400 700;
  font-display: swap;
}
@font-face {
  font-family: 'Rubik';
  src: url('fonts/Rubik.woff2') format('woff2');
  font-weight: 300 600;
  font-display: swap;
}

:root {
  color-scheme: dark;
  --bg: #1b1c24;
  --bg-raised: #24252f;
  --bg-sunken: #15161d;
  --line: #383a47;
  --line-soft: #2c2e39;
  --text: #f3f2ef;
  --text-dim: #b3b6c2;
  --text-faint: #8b8fa0;
  --accent: #ff6b52;
  --accent-soft: #35251f;
  --accent-ink: #22110d;
  /* Accent text sitting on --accent-soft. On the dark tint the accent itself
     clears AA at 5.2:1, so this is the same colour; the bright theme needs a
     darker one (see below) and this token is what lets both use one rule. */
  --accent-strong: #ff6b52;
  --chain-gsc: #fb923c;
  --chain-tgv: #98a5ff;
  --chain-fst: #4ade80;
  --chain-amerin: #f9a8d4;
  --chain-mega: #67e8f9;
  --chain-paragon: #d8b4fe;
  --chain-tsr: #fda4af;
  --chain-default: #a8b0bd;
  --focus: #93b4ff;
  --shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 10px 24px rgba(0, 0, 0, .28);
  --shadow-lift: 0 2px 6px rgba(0, 0, 0, .4), 0 18px 40px rgba(0, 0, 0, .42);
  /* Geometry, not palette — the same in both themes, so it belongs on the base
     :root. Defining it only under [data-theme="light"] left the default dark
     theme with no corner radius and an uncapped column. */
  --radius: 14px;
  --radius-sm: 9px;
  --maxw: 1180px;
}

/* The bright theme: warm paper rather than clinical white.

   Dark is the default for everyone, and the OS preference is deliberately not
   consulted, so the site looks the same to every visitor until they choose
   otherwise. Bright is opt-in through the switch in the masthead. */
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f6f5f2;         /* warm paper, not clinical grey */
  --bg-raised: #ffffff;
  --bg-sunken: #eceae4;
  --line: #dcd8ce;
  --line-soft: #e9e6df;
  --text: #16182b;       /* ink navy, never pure black */
  --text-dim: #4d5266;   /* 8.0:1 on --bg-raised */
  --text-faint: #6a7086; /* 5.0:1 on --bg-raised */
  --accent: #d6321f;     /* one accent, locked across the whole site */
  --accent-soft: #fdece9;
  --accent-ink: #ffffff;
  /* The accent on its own tint is only 4.2:1 here, so selected filter chips get
     a darker shade of the same hue: 5.7:1 on --accent-soft, 6.0:1 on --bg. */
  --accent-strong: #b32717;
  /* Chain colours are darkened for the bright base so every badge clears
     WCAG AA on white. Ratios measured, not guessed. */
  --chain-gsc: #b8490b;
  --chain-tgv: #4a59d0;
  --chain-fst: #0e7f57;
  --chain-amerin: #bd3a76;
  --chain-mega: #0d7590;
  --chain-paragon: #8438cd;
  --chain-tsr: #b92742;
  --chain-default: #58616f;
  --focus: #1d4ed8;
  /* Shadows tinted to the paper hue, never pure black on a light ground. */
  --shadow: 0 1px 2px rgba(40, 34, 24, .05), 0 10px 24px rgba(40, 34, 24, .07);
  --shadow-lift: 0 2px 6px rgba(40, 34, 24, .07), 0 18px 40px rgba(40, 34, 24, .12);
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.55 Rubik, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Outfit carries anything that should feel like a title. */
h1, h2, h3, .brand-name, .movie-title, .grid-title, .date-head, .region-head,
.cinema-head h3, .summary b {
  font-family: Outfit, Rubik, system-ui, sans-serif;
  letter-spacing: -.015em;
}

/* Times, counts and dates are compared down columns, so they get tabular
   figures; prose does not, because it looks mechanical. */
.time, .datebtn span, .summary { font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 20px; }

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

:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 4px; }

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

.masthead {
  background: var(--bg-raised);
  border-bottom: 1px solid var(--line);
  position: relative;
}
/* One accent hairline across the top: the only pure decoration on the page,
   and it is what makes the bright palette read as deliberate rather than blank. */
.masthead::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--chain-gsc) 55%, var(--chain-tgv));
}

.masthead-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding-top: 18px; padding-bottom: 14px; flex-wrap: wrap;
}

.brand { display: flex; align-items: center; gap: 12px; }
.brand-mark {
  width: 38px; height: 38px; flex: 0 0 38px; display: block; padding: 7px;
  color: var(--accent-ink); background: var(--accent); border-radius: 11px;
}
.brand-name { margin: 0; font-size: 22px; letter-spacing: -.03em; font-weight: 700; }
.brand-sub { margin: 2px 0 0; font-size: 13px; color: var(--text-dim); }

.masthead-side { display: flex; align-items: center; justify-content: flex-end; }

/* Bright / dark switch. A two-state segmented control rather than a single
   cycling button: with two options the current state should be visible, not
   inferred from an icon that means "what you will get if you press me". */
.themeswitch {
  display: flex; gap: 2px; padding: 3px; flex: 0 0 auto;
  background: var(--bg-sunken); border: 1px solid var(--line);
  border-radius: 999px;
}
.themebtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 30px; padding: 0; cursor: pointer;
  background: none; border: 0; border-radius: 999px;
  /* --text-dim, not --text-faint: at faint the inactive icon sat at 4.08:1 on
     the bright strip. It is a UI glyph so 3:1 would pass, but the rest of the
     page holds 4.5 and this is free. */
  color: var(--text-dim);
  transition: background .18s ease, color .18s ease;
}
.themebtn svg { width: 16px; height: 16px; display: block; }
.themebtn:hover { color: var(--text); }
.themebtn.is-on {
  background: var(--accent); color: var(--accent-ink);
  box-shadow: var(--shadow);
}
.themebtn.is-on:hover { color: var(--accent-ink); }

/* ---------- site nav ---------- */

.sitenav { display: flex; gap: 4px; padding-bottom: 12px; overflow-x: auto; scrollbar-width: none; }
.sitenav::-webkit-scrollbar { display: none; }
.sitenav a {
  flex: 0 0 auto; padding: 8px 14px; border-radius: var(--radius-sm);
  color: var(--text-dim); text-decoration: none; font-size: 14px; font-weight: 600;
  border: 1px solid transparent; transition: color .15s, background .15s;
}
.sitenav a:hover { color: var(--text); background: var(--bg-sunken); }
.sitenav a.is-current {
  color: var(--accent-ink); background: var(--accent); border-color: var(--accent);
}
.sitenav a.is-current:hover { color: var(--accent-ink); background: var(--accent); }

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

/* ---------- date bar ---------- */

.datebar {
  display: flex; gap: 8px; overflow-x: auto; padding-bottom: 14px;
  scrollbar-width: none;
}
.datebar::-webkit-scrollbar { display: none; }

.datebtn {
  flex: 0 0 auto; min-width: 74px; padding: 8px 14px;
  background: var(--bg-raised); color: var(--text-dim);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  font: inherit; font-size: 13px; text-align: center; cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.datebtn span { display: block; font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .05em; }
.datebtn:hover { border-color: var(--text-faint); }
.datebtn:active { transform: scale(.97); }
.datebtn.is-active {
  background: var(--accent); color: var(--accent-ink);
  border-color: var(--accent); font-weight: 600; box-shadow: var(--shadow);
}
.datebtn.is-active span { color: var(--accent-ink); opacity: .72; }

/* ---------- toolbar ---------- */

.toolbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--line);
}

.toolbar-inner {
  display: flex; align-items: center; gap: 14px;
  padding-top: 10px; padding-bottom: 10px; flex-wrap: wrap;
}

.tabs { display: flex; background: var(--bg-sunken); border-radius: var(--radius-sm); padding: 3px; }
.tab {
  border: 0; background: none; color: var(--text-dim); cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 600; padding: 6px 14px;
  border-radius: 6px; white-space: nowrap;
}
.tab.is-active { background: var(--bg-raised); color: var(--text); box-shadow: var(--shadow); }

.search { position: relative; flex: 1 1 220px; min-width: 180px; }
.search svg {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; fill: none; stroke: var(--text-faint); stroke-width: 2;
  stroke-linecap: round; pointer-events: none;
}
.search input {
  width: 100%; padding: 8px 10px 8px 32px; font: inherit; font-size: 14px;
  color: var(--text); background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.search input::placeholder { color: var(--text-faint); }

.filters { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* Seven chains do not fit a phone, so the strip scrolls inside itself rather
   than pushing the page into a horizontal scroll. */
.chipset {
  display: flex; gap: 4px; background: var(--bg-sunken); padding: 3px;
  border-radius: var(--radius-sm); max-width: 100%;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.chipset::-webkit-scrollbar { display: none; }
.chip {
  flex: 0 0 auto;
  border: 0; background: none; color: var(--text-dim); cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 600; padding: 5px 11px; border-radius: 6px;
}
.chip.is-active { background: var(--bg-raised); color: var(--text); box-shadow: var(--shadow); }
/* --chain is set per element from the chain's slug, so one rule colours them all. */
.chip[data-chain].is-active { color: var(--chain); }

.select select, .toggle {
  font: inherit; font-size: 13px; color: var(--text-dim);
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: 7px 9px; max-width: 190px;
}
.select select { cursor: pointer; }
.toggle { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none; }
.toggle input { accent-color: var(--accent); margin: 0; }

/* ---------- faceted filters ----------

   Deliberately NOT the .chipset/.chip idiom above. That is a segmented control
   and reads as "pick one"; these are multi-select, so they take the filter-chip
   form instead: separate outlined pills that fill in when active. Selection is
   carried by fill, border and weight as well as colour, so it survives without
   colour perception, and by aria-pressed for screen readers.

   The bar sits below the sticky toolbar rather than inside it — expanded, four
   groups are far too tall to pin to the top of a phone. */

.facetbar { background: var(--bg); border-bottom: 1px solid var(--line); }
.facets { display: grid; gap: 5px; padding-top: 8px; padding-bottom: 10px; }

.facet-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--text-dim);
}
.facet-clear {
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  padding: 3px 9px; border-radius: 999px;
  color: var(--accent-strong); background: none;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  transition: background .18s ease;
}
.facet-clear:hover { background: var(--accent-soft); }

.facet { display: flex; align-items: flex-start; gap: 8px; }
.facet-label {
  flex: 0 0 64px; padding-top: 6px;
  font-size: 12px; font-weight: 600; color: var(--text-dim);
}
.facet-chips { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; flex: 1 1 0; min-width: 0; }

.fchip {
  display: inline-flex; align-items: center; gap: 5px;
  /* Never shrink and never wrap the label: inside the scrolling strip on a
     phone a shrunk chip breaks "Kids & Family" over two lines, which stretches
     every chip in the row to match. */
  flex: 0 0 auto; white-space: nowrap;
  min-height: 27px; padding: 3px 10px;
  font: inherit; font-size: 12px; font-weight: 600;
  color: var(--text-dim); background: var(--bg-raised);
  border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer;
  /* transform + colour only, so toggling a filter never reflows the bar */
  transition: background .18s ease, color .18s ease,
              border-color .18s ease, transform .12s ease;
}
.fchip:hover:not(:disabled) { color: var(--text); border-color: var(--text-faint); }
.fchip:active:not(:disabled) { transform: scale(.97); }
.fchip[aria-pressed="true"] {
  color: var(--accent-strong); background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  font-weight: 700;
}
/* A value that would return nothing stays visible but unusable, so the shape of
   the data is still legible instead of options silently vanishing. */
.fchip:disabled { opacity: .42; cursor: default; }

.fchip-n {
  font-size: 11px; font-weight: 600; opacity: .7;
  font-variant-numeric: tabular-nums;
}
.fchip-more { color: var(--text-faint); background: none; border-style: dashed; }

@media (max-width: 768px) {
  /* Wrapping four groups of chips ran the filter bar to about 330px on a
     phone — most of the screen before a single poster. Each group becomes a
     strip that scrolls inside itself instead, the same trick the chain chipset
     already uses, which puts the whole bar back under 150px. The chips keep a
     thumb-sized box; the saving comes from the layout, not from shrinking the
     targets. */
  .facets { gap: 2px; padding-top: 6px; padding-bottom: 7px; }
  .facet { align-items: center; gap: 8px; }
  .facet-label { flex: 0 0 56px; padding-top: 0; font-size: 11.5px; }
  .facet-chips {
    flex-wrap: nowrap; overflow-x: auto; gap: 6px;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
    padding: 2px 0;
  }
  .facet-chips::-webkit-scrollbar { display: none; }
  /* 34px rather than the 44px used for the page's primary controls. These are
     chips in a scrolling strip, which is the one control class Material sizes
     at 32dp, and they are wide enough that the real target area is comfortably
     past 44px across. */
  .fchip { min-height: 34px; padding: 6px 11px; }
  .facet-head { font-size: 11.5px; }
}

/* ---------- summary ---------- */

.summary {
  color: var(--text-dim); font-size: 14px; margin: 26px 0 16px;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.summary b {
  color: var(--text); font-weight: 700; font-size: 26px; letter-spacing: -.03em;
}
/* Hairline separators instead of a run of middle dots (taste skill 9.F). */
/* Cinema name as an in-page action. Styled like the link it replaced so the
   row does not change shape, but it is a button because it acts on this page
   rather than navigating away. */
.group-pivot {
  grid-column: 2; grid-row: 1;
  padding: 0; margin: 0; background: none; border: 0; cursor: pointer;
  font: inherit; font-weight: 600; font-size: 14px; text-align: left;
  color: var(--text); border-bottom: 1px solid transparent;
  transition: color .15s ease, border-color .15s ease;
}
.group-pivot:hover { color: var(--accent); border-bottom-color: var(--accent); }
.group-pivot:active { color: var(--accent); }

/* The pinned-cinema pill. A filter the reader cannot see is a filter that
   looks like missing data, so it sits at the front of the summary line. */
.pin {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 8px 5px 12px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--accent-ink); background: var(--accent); border: 0;
}
.pin svg {
  width: 13px; height: 13px; flex: 0 0 13px;
  fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round;
  opacity: .8;
}
.pin:hover svg { opacity: 1; }
.pin:active { transform: scale(.97); }

.summary .sep {
  width: 1px; height: 12px; background: var(--line);
  display: inline-block; flex: 0 0 1px;
}

/* ---------- movie card ---------- */

.card {
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: var(--radius); margin-bottom: 16px; overflow: hidden;
  box-shadow: var(--shadow);
  transition: box-shadow .25s ease, transform .25s ease;
}
.card:hover { box-shadow: var(--shadow-lift); }

.movie-head { display: flex; gap: 16px; padding: 16px; }

.poster {
  flex: 0 0 92px; width: 92px; aspect-ratio: 2 / 3; object-fit: cover;
  background: var(--bg-sunken); border-radius: var(--radius-sm); display: block;
}

.movie-meta { min-width: 0; flex: 1; }
.movie-title { margin: 0 0 6px; font-size: 18px; letter-spacing: -.01em; line-height: 1.25; }
.movie-facts { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 8px; }

.badge {
  font-size: 11px; font-weight: 700; letter-spacing: .03em;
  padding: 2px 7px; border-radius: 5px; border: 1px solid var(--line);
  color: var(--text-dim); background: var(--bg-sunken); white-space: nowrap;
}
.badge-rating { color: var(--text); border-color: var(--text-faint); }
.badge-chain {
  color: var(--chain);
  border-color: color-mix(in srgb, var(--chain) 45%, transparent);
  background: color-mix(in srgb, var(--chain) 12%, transparent);
}

.movie-sub { font-size: 13px; color: var(--text-dim); margin: 0 0 8px; }
.synopsis { font-size: 13.5px; color: var(--text-dim); line-height: 1.6; margin: 8px 0 0; }

.linkrow { display: flex; gap: 14px; flex-wrap: wrap; font-size: 13px; }
.linkrow a, .textbtn {
  color: var(--accent); text-decoration: none; background: none; border: 0;
  padding: 0; font: inherit; cursor: pointer;
}
.linkrow a:hover, .textbtn:hover { text-decoration: underline; }

/* ---------- showtime groups ---------- */

.groups { border-top: 1px solid var(--line-soft); }

.group {
  display: grid; grid-template-columns: minmax(190px, 250px) 1fr;
  gap: 14px; padding: 12px 16px; border-bottom: 1px solid var(--line-soft);
}
.group:last-child { border-bottom: 0; }

.group-name { min-width: 0; }
.group-name a { color: var(--text); text-decoration: none; font-weight: 600; font-size: 14px; }
.group-name a:hover { color: var(--accent); }
.group-sub { display: block; font-size: 12px; color: var(--text-faint); margin-top: 2px; }

.times { display: flex; flex-wrap: wrap; gap: 6px; align-content: flex-start; }

.time {
  display: inline-flex; align-items: baseline; gap: 5px;
  min-height: 34px; padding: 7px 10px; border-radius: 8px; text-decoration: none;
  background: var(--bg-sunken); border: 1px solid var(--line);
  color: var(--text); font-size: 14px; font-weight: 600;
  white-space: nowrap; cursor: pointer;
  transition: border-color .16s ease-out, background .16s ease-out;
}
.time:hover {
  border-color: var(--chain); background: var(--bg-raised);
  box-shadow: var(--shadow); transform: translateY(-1px);
}
/* Tactile press: the pill physically depresses (taste skill 4.5). */
.time:active { transform: translateY(0) scale(.97); box-shadow: none; }
.time em { font-style: normal; font-size: 10.5px; font-weight: 700; color: var(--text-faint); letter-spacing: .02em; }
/* The chain's colour rides the left edge of every session pill. */
.time[data-chain] { border-left: 3px solid var(--chain); }
.time.is-past { opacity: .38; }
.time.is-past:hover { opacity: .7; }

.showall {
  display: block; width: 100%; text-align: left; padding: 11px 16px;
  background: none; border: 0; border-top: 1px solid var(--line-soft);
  color: var(--accent); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.showall:hover { background: var(--bg-sunken); }

/* ---------- cinema view ---------- */

.region-head {
  margin: 30px 0 14px; font-size: 15px; font-weight: 700; color: var(--text);
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding-bottom: 9px; border-bottom: 2px solid var(--text);
}
.region-head .count {
  font-family: Rubik, sans-serif; font-size: 12px; font-weight: 500;
  color: var(--text-faint); letter-spacing: 0;
}
.region-head:first-child { margin-top: 6px; }
.region-head--fav { color: var(--accent); border-bottom-color: var(--accent); }
.region-head--near { color: var(--accent); border-bottom-color: var(--accent); }

.cinema-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--line-soft); flex-wrap: wrap;
}
.cinema-head h3 { margin: 0; font-size: 16px; letter-spacing: -.01em; }
.cinema-head h3 a { color: inherit; text-decoration: none; }
.cinema-head h3 a:hover { color: var(--accent); }
.cinema-addr { font-size: 12px; color: var(--text-faint); margin: 3px 0 0; max-width: 62ch; }

/* ---------- distance and directions ----------

   Distance is a fact about the row, so it sits with the address rather than
   competing with the cinema name. Directions is a link out to a maps app; it
   reads as a link, not a button, because that is what it is. */

.cinema-way {
  margin: 5px 0 0; display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; font-size: 12px;
}
.cinema-dist { color: var(--text-dim); font-weight: 600; font-variant-numeric: tabular-nums; }
.cinema-dir {
  color: var(--accent-strong); text-decoration: none; font-weight: 600;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
}
.cinema-dir:hover { border-bottom-color: var(--accent); }

/* In the by-movie view the cinema name, its state and its distance share one
   line, so the distance is the thing that has to stay scannable down the
   column: tabular figures, and the accent to separate it from the state. */
.group-dist {
  display: inline-block; margin-top: 2px; margin-left: 8px;
  font-size: 12px; font-weight: 600; color: var(--accent-strong);
  font-variant-numeric: tabular-nums;
}

.pin-icon {
  width: 15px; height: 15px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.toggle-btn.is-busy { opacity: .65; cursor: progress; }

/* The permission message sits with the control that caused it, not at the top
   of the page: an error the reader has to hunt for is an error they will read
   as the page being broken. */
.geonote {
  flex-basis: 100%; margin: 2px 0 0; font-size: 12.5px;
  color: var(--text-dim); max-width: 68ch;
}

/* ---------- server-rendered film list ----------

   Shown to anything that has not run movies.js yet, which is every AI crawler
   and Googlebot's first pass. It is real content, so it is styled to be
   readable rather than hidden: a reader who arrives before the script does
   sees a plain list of films, not a blank page. movies.js removes it the
   moment it has the grid ready. */

.prerendered { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.pre-item {
  display: grid; grid-template-columns: 56px 1fr; gap: 12px; align-items: start;
  padding-bottom: 14px; border-bottom: 1px solid var(--line-soft);
}
.pre-item img { width: 56px; height: auto; border-radius: var(--radius-sm); display: block; }
.pre-item a { color: var(--text); text-decoration: none; display: contents; }
.pre-name { font-family: Outfit, Rubik, sans-serif; font-weight: 600; font-size: 15px; }
.pre-meta { margin: 3px 0 0; grid-column: 2; font-size: 12.5px; color: var(--text-dim); }

/* ---------- film page ---------- */

.film { padding-top: 22px; padding-bottom: 40px; }
.crumb { font-size: 12.5px; color: var(--text-dim); margin-bottom: 16px; }
.crumb a { color: var(--text-dim); }
.crumb a:hover { color: var(--accent); }

.film-head { display: grid; grid-template-columns: 220px 1fr; gap: 26px; align-items: start; }
.film-head img, .film-poster-empty {
  width: 220px; border-radius: var(--radius); display: block;
  background: var(--bg-sunken); aspect-ratio: 2 / 3; object-fit: cover;
}
.film-meta h1 { margin: 0 0 6px; font-size: 30px; letter-spacing: -.03em; }
.film-facts { margin: 0 0 10px; color: var(--text-dim); font-size: 14px; }
.film-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.film-lede { margin: 0 0 12px; font-size: 15px; color: var(--text); font-weight: 600; }
.film-synopsis { margin: 0 0 18px; max-width: 68ch; color: var(--text-dim); line-height: 1.65; }
.film-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin: 0; }
.film-cta {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 18px;
  border-radius: 999px; background: var(--accent); color: var(--accent-ink);
  font-weight: 700; text-decoration: none;
}
.film-cta:hover { filter: brightness(1.06); }
.film-trailer { color: var(--accent-strong); font-weight: 600; }

.film-where { margin-top: 34px; }
.film-where h2 { font-size: 17px; margin: 0 0 12px; }
.where-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.where-list li {
  display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  padding: 10px 12px; background: var(--bg-raised); font-size: 13.5px;
}
.where-list li:first-child { border-radius: var(--radius-sm) var(--radius-sm) 0 0; }
.where-list li:last-child { border-radius: 0 0 var(--radius-sm) var(--radius-sm); }
.where-list span { color: var(--text-dim); }
.film-foot { margin-top: 30px; font-size: 13px; color: var(--text-faint); }

/* The route from a card to that film's own page. Small on purpose: the primary
   action is still the showtimes link beside it. */
.grid-detail {
  display: inline-block; margin-top: 6px; font-size: 12.5px; font-weight: 600;
  color: var(--text-dim); text-decoration: none;
}
.grid-detail:hover { color: var(--accent); }

@media (max-width: 720px) {
  .film-head { grid-template-columns: 1fr; gap: 16px; }
  .film-head img, .film-poster-empty { width: 150px; }
  .film-meta h1 { font-size: 23px; }
}

/* ---------- poster grid (Now Showing / Coming Soon) ---------- */

/* The poster is a link to the same place as the card's call to action. It is
   the most obviously clickable thing on the card, so leaving it inert made the
   tile feel broken. Kept out of the tab order and hidden from screen readers:
   the visible CTA below already goes to the same destination with a proper
   label, and two stops on the same target is noise, not access. */
.grid-postlink { display: block; text-decoration: none; }
.grid-postlink:focus-visible { outline: none; }

.grid {
  display: grid; gap: 16px; margin-bottom: 8px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}

.grid-card {
  display: flex; flex-direction: column;
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
}

.grid-poster {
  width: 100%; aspect-ratio: 2 / 3; object-fit: cover; display: block;
  background: var(--bg-sunken); border-radius: 0;
}
.grid-poster--empty { background: var(--bg-sunken); }

.grid-body { padding: 12px 13px 13px; display: flex; flex-direction: column; gap: 7px; flex: 1; }
.grid-title { margin: 0; font-size: 15px; line-height: 1.3; letter-spacing: -.01em; }
.grid-badges { display: flex; flex-wrap: wrap; gap: 5px; }
.grid-facts { margin: 0; font-size: 12.5px; color: var(--text-dim); line-height: 1.45; }
.grid-note { margin: 0; font-size: 12px; color: var(--text-faint); }

.grid-cta {
  margin-top: auto; padding-top: 9px; font-size: 13px; font-weight: 600;
  color: var(--accent); text-decoration: none; align-self: flex-start;
}
.grid-cta:hover { text-decoration: underline; }

.date-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  margin: 30px 0 14px; padding-bottom: 8px; border-bottom: 1px solid var(--line);
  font-size: 15px; font-weight: 700; letter-spacing: -.01em; flex-wrap: wrap;
}
.date-head:first-child { margin-top: 6px; }
.date-head span { font-size: 12px; font-weight: 600; color: var(--text-faint); }

/* ---------- favourite stars ---------- */

.star {
  flex: 0 0 auto; width: 30px; height: 30px; padding: 5px; margin: -5px 2px -5px -5px;
  background: none; border: 0; border-radius: 6px; cursor: pointer;
  color: var(--text-faint); line-height: 0;
}
.star svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; }
.star:hover { color: var(--accent); background: var(--bg-sunken); }
.star.is-on { color: var(--accent); }
.star.is-on svg { fill: currentColor; }

/* Grid, not flex: a long cinema name must wrap within its own column rather
   than pushing itself onto a line below the star. */
.group-name {
  display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 4px;
}
.group-name .star { grid-column: 1; grid-row: 1; }
.group-name a { grid-column: 2; grid-row: 1; }
.group-name .group-sub { grid-column: 2; grid-row: 2; margin-top: 0; }

.cinema-id { display: flex; align-items: flex-start; gap: 4px; min-width: 0; }

.region-head--fav { color: var(--accent); }

.toggle-btn {
  cursor: pointer; color: var(--text-dim); font-weight: 600;
  display: inline-flex; align-items: center; gap: 6px;
}
.toggle-btn .star-icon {
  width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8;
}
.toggle-btn.is-on { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.toggle-btn.is-on .star-icon { fill: currentColor; }

/* ---------- progressive loading ---------- */

.more {
  min-height: 1px; text-align: center; color: var(--text-faint);
  font-size: 12.5px; padding: 0;
}
.more:not(:empty) { padding: 22px 0 8px; }

/* ---------- states ---------- */

.state { text-align: center; padding: 70px 20px; color: var(--text-dim); }
.state h2 { margin: 0 0 6px; font-size: 17px; color: var(--text); }
.state p { margin: 0; font-size: 14px; }

/* ---------- loading skeleton ---------- */

.sk-card { padding-bottom: 12px; }
.sk-head { display: flex; gap: 16px; padding: 16px; }
.sk-lines { flex: 1; display: flex; flex-direction: column; gap: 10px; padding-top: 4px; }
.sk-row { display: flex; gap: 14px; padding: 12px 16px; border-top: 1px solid var(--line-soft); }
.sk-pills { display: flex; flex-wrap: wrap; gap: 6px; flex: 1; }

.sk { background: var(--bg-sunken); border-radius: 6px; animation: pulse 1.4s ease-in-out infinite; }
.sk-poster { width: 92px; height: 138px; flex: 0 0 92px; border-radius: var(--radius-sm); }
.sk-line { height: 12px; }
.sk-pill { width: 74px; height: 34px; border-radius: 8px; }
.w60 { width: 60%; } .w45 { width: 45%; } .w30 { width: 30%; } .w25 { width: 180px; }

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* ---------- prose (privacy) ---------- */

.prose { max-width: 760px; padding-top: 8px; padding-bottom: 8px; }
.prose-title { font-size: 34px; letter-spacing: -.03em; margin: 26px 0 6px; }
.prose h2 {
  font-size: 19px; margin: 34px 0 10px; letter-spacing: -.02em;
  padding-top: 18px; border-top: 1px solid var(--line);
}
.prose .panel h2 { border-top: 0; padding-top: 0; margin-top: 0; }
.prose h3 { font-size: 15px; margin: 0 0 3px; }
.prose p { color: var(--text-dim); line-height: 1.7; margin: 0 0 12px; max-width: 68ch; }
.prose ul { color: var(--text-dim); line-height: 1.7; padding-left: 20px; margin: 0 0 12px; }
.prose li { margin-bottom: 4px; }
.prose b { color: var(--text); font-weight: 600; }

.panel {
  background: var(--bg-raised); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px; margin: 20px 0 8px;
  box-shadow: var(--shadow);
}

.choice {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 16px 0; border-top: 1px solid var(--line-soft);
}
.choice-text { min-width: 0; }
.choice-text p { margin: 0; font-size: 13.5px; }
.choice-note { margin: 14px 0 0; font-size: 13px; color: var(--text-faint); min-height: 1em; }

/* Switch: a real checkbox with the box hidden, so keyboard and screen readers
   get the native control and the visual is only paint. */
.switch { position: relative; flex: 0 0 auto; cursor: pointer; display: block; }
.switch input {
  position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer;
}
.switch-track {
  display: block; width: 50px; height: 30px; border-radius: 999px;
  background: var(--bg-sunken); border: 1px solid var(--line);
  transition: background .2s ease, border-color .2s ease;
}
.switch-knob {
  display: block; width: 22px; height: 22px; margin: 3px; border-radius: 50%;
  background: var(--text-faint);
  transition: transform .2s ease, background .2s ease;
}
.switch input:checked + .switch-track {
  background: var(--accent); border-color: var(--accent);
}
.switch input:checked + .switch-track .switch-knob {
  transform: translateX(20px); background: var(--accent-ink);
}
.switch input:focus-visible + .switch-track {
  outline: 2px solid var(--focus); outline-offset: 2px;
}

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

.footer {
  margin: 44px auto 32px; padding-top: 22px; border-top: 1px solid var(--line);
  color: var(--text-faint); font-size: 12.5px; line-height: 1.65;
}
.footer p { margin: 0 0 6px; max-width: 76ch; }

.footnav { display: flex; flex-wrap: wrap; gap: 18px; }
.footnav a {
  color: var(--text-dim); text-decoration: none; font-size: 13.5px; font-weight: 500;
}
.footnav a:hover { color: var(--accent); }
.footnav a[aria-current] { color: var(--text); }

/* ---------- responsive ---------- */

@media (max-width: 1024px) {
  .group { grid-template-columns: minmax(160px, 200px) 1fr; }
}

@media (max-width: 768px) {
  /* The filter stack is ~180px tall here — pinning it would eat a quarter of
     the screen on every scroll, so let it scroll away. */
  .toolbar { position: static; backdrop-filter: none; }
  .masthead-inner { padding-top: 14px; }
  .toolbar-inner { gap: 10px; }
  .search { order: 3; flex-basis: 100%; }
  .filters { order: 4; width: 100%; }
  .select select { max-width: none; flex: 1; }
  .group { grid-template-columns: 1fr; gap: 8px; padding: 12px 14px; }
  .movie-head { padding: 14px; gap: 12px; }
  .poster { flex-basis: 76px; width: 76px; }
  .movie-title { font-size: 17px; }

  /* Touch targets: 44px minimum once there is no mouse to aim with. */
  .time { min-height: 44px; padding: 10px 12px; }
  .tab, .chip {
    min-height: 44px; padding: 10px 14px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .datebtn { min-height: 44px; padding: 8px 14px; }
  .filters { gap: 8px; }
  .chipset { width: 100%; }

  /* The chain strip already scrolls inside itself, so on the grid pages it does
     not need a row to itself: sharing one with the sort control removes a 44px
     band from the top of every phone screen.

     Scoped to the grid pages on purpose. They carry two controls; the showtimes
     page carries six, and forcing those onto one line overflowed the row by
     200px, squashing the chain strip to nothing and pushing Favourites and Near
     me off the side of the screen with no way to reach them. */
  body[data-page] .filters { flex-wrap: nowrap; }
  body[data-page] .chipset { flex: 1 1 0; min-width: 0; width: auto; }
  body[data-page] .filters .select { flex: 0 0 auto; }
  .select select, .toggle { min-height: 44px; }
  .search input { min-height: 44px; font-size: 16px; } /* 16px stops iOS zooming */
  .showall { padding: 14px 16px; }
  .sitenav a { min-height: 44px; display: inline-flex; align-items: center; }
  .themebtn { width: 44px; height: 40px; }
  .group-pivot { min-height: 32px; }
  .pin { min-height: 40px; }
  .choice { gap: 14px; }
  .switch-track { width: 54px; height: 32px; }
  .switch input:checked + .switch-track .switch-knob { transform: translateX(22px); }
  /* The star is a 30px glyph; pad its hit area out to 44px without
     changing how big it looks (taste skill 4.5 / Apple HIG). */
  .star { width: 44px; height: 44px; padding: 12px; margin: -7px 0 -7px -12px; }
  .grid-cta { min-height: 44px; display: inline-flex; align-items: center; }
}

/* ---------- phone density ----------

   A phone should show a lot at once, the way a native app does: the chrome
   shrinks, the type steps down, and the vertical rhythm tightens. What does NOT
   shrink is anything you touch — the 44px targets set above stand, and the
   search field stays at 16px because anything smaller makes iOS zoom the page
   on focus. The space comes from padding and from display type, not from the
   things that have to stay usable. */
@media (max-width: 768px) {
  .masthead-inner { padding-top: 10px; padding-bottom: 8px; gap: 10px; }
  .brand { gap: 9px; }
  .brand-mark { width: 30px; height: 30px; flex-basis: 30px; padding: 5px; border-radius: 9px; }
  .brand-name { font-size: 17px; }
  .brand-sub { font-size: 11.5px; margin-top: 1px; }
  .sitenav { padding-bottom: 8px; gap: 3px; }
  .sitenav a { padding: 6px 12px; font-size: 13px; }
  .datebar { gap: 6px; padding-bottom: 10px; }
  .datebtn { min-width: 62px; font-size: 12.5px; }
  .toolbar-inner { padding-top: 8px; padding-bottom: 8px; gap: 8px; }
  .summary { margin: 14px 0 10px; font-size: 12.5px; gap: 7px; }
  .summary b { font-size: 20px; }
  .date-head { font-size: 15px; }
  .grid-facts, .grid-note { font-size: 11.5px; }
  .badge { font-size: 10px; }
}

@media (max-width: 560px) {
  /* Two-up on a phone. At one column a 2:3 poster is ~560px tall and a single
     film fills the screen. */
  .grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
  .grid-title { font-size: 14px; }
  .grid-body { padding: 10px 11px 11px; gap: 6px; }
}

@media (max-width: 480px) {
  .wrap { padding: 0 12px; }
  .brand-name { font-size: 16px; }
  /* The strapline is decoration next to the nav on a small screen. */
  .brand-sub { display: none; }
  .grid { gap: 10px; }
  .grid-title { font-size: 13.5px; }
  .grid-body { padding: 9px 10px 10px; gap: 4px; }
  .grid-badges { gap: 3px; }
  .badge { font-size: 9.5px; padding: 1px 5px; }
  .grid-cta { font-size: 12.5px; }
  .summary b { font-size: 18px; }
  .poster { flex-basis: 64px; width: 64px; }
  .sk-poster { width: 64px; height: 96px; flex-basis: 64px; }
  .region-head { margin-top: 20px; }
}
