/* The whole site's styles, in one file: the fonts and palette, the shell
   (marquee bands, masthead, menu), then each page's own rules.
   Follow DESIGN.md: no pure white, no shadows, no rounded corners, except
   where noted. */

/* Fonts ------------------------------------------------------------------ */

/* Fonts are served from our own origin, never a font host, so no visitor
   data leaves our server. Each comes in a Latin and a Latin Extended file;
   the browser loads only what a page's text needs. */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-display: swap;
  font-weight: 200 800;
  src: url("fonts/bricolage-grotesque-latin-ext-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-display: swap;
  font-weight: 200 800;
  src: url("fonts/bricolage-grotesque-latin-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url("fonts/ibm-plex-mono-latin-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url("fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: italic;
  font-display: swap;
  font-weight: 400;
  src: url("fonts/ibm-plex-mono-latin-ext-400-italic.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: italic;
  font-display: swap;
  font-weight: 400;
  src: url("fonts/ibm-plex-mono-latin-400-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-display: swap;
  font-weight: 600;
  src: url("fonts/ibm-plex-mono-latin-ext-600-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-display: swap;
  font-weight: 600;
  src: url("fonts/ibm-plex-mono-latin-600-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Palette and type -------------------------------------------------------- */

:root {
  /* The page keeps room for a scrollbar, shown or not, so going between a
     long page and a short one never moves the logo and the menu sideways. */
  scrollbar-gutter: stable;

  /* The palette: the logo's own yellow and black, cobalt and vermilion, on paper. */
  --logo-yellow: #eaea03;
  --ink: #000;
  --cobalt: #2340c8;
  --vermilion: #e0482a;
  --paper: #f6f3ec;

  --field: #fbf9f4;
  --muted: #5c5850;
  --rule: #cfc8b8;
  /* Vermilion darkened enough to read as text on paper. */
  --alert: #a3321f;

  --font-display: "Bricolage Grotesque", sans-serif;
  --font-text: "IBM Plex Mono", monospace;

  /* How wide the marquee's bands are. The page keeps clear of them. */
  --marquee-band: 36px;

  /* Easing: quick out of the start, well past the end, and back, for a
     press. */
  --bounce: cubic-bezier(0.3, 1.9, 0.55, 1);
  /* Slow at both ends, like a curtain pulled by hand. */
  --pulled: cubic-bezier(0.65, 0, 0.35, 1);
  /* Springs, sampled: a card opening (stiffness 26.7, damping 4.1, mass
     0.2), over 0.6s, held at its end rather than going past it, so the
     Poster swells and the details rise only as far as they rest: rising
     past the band would show a light line of the Poster under them; a
     menu bubble turning (damping ratio 0.5,
     overshooting by a sixth), over 0.7s; and the Season tabs' highlight
     (damping ratio 0.8, a fifth of a bounce), over 0.8s. */
  --spring-card: linear(0, 0.049, 0.16, 0.295, 0.43, 0.554, 0.661, 0.748, 0.818, 0.872, 0.913, 0.942, 0.963, 0.978, 0.988, 0.994, 0.998, 1, 1, 1, 1);
  --spring-bubble: linear(0, 0.086, 0.288, 0.53, 0.76, 0.946, 1.072, 1.142, 1.163, 1.151, 1.118, 1.079, 1.041, 1.01, 0.989, 0.977, 0.973, 0.975, 0.98, 0.987, 0.993, 0.998, 1.002, 1.004, 1.004, 1.004, 1.003, 1.002, 1);
  --spring-tab: linear(0, 0.077, 0.242, 0.428, 0.598, 0.737, 0.842, 0.916, 0.964, 0.992, 1.007, 1.014, 1.015, 1.014, 1.011, 1.008, 1.006, 1.004, 1.002, 1.001, 1);

  color-scheme: light;
  font-family: var(--font-text);
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
}

@media (max-width: 640px) {
  :root {
    --marquee-band: 24px;
  }
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: var(--marquee-band) 0;
  background: var(--paper);
}

a {
  color: inherit;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.2;
}

.logo {
  display: block;
  width: auto;
}

.muted {
  color: var(--muted);
}

.alert {
  color: var(--alert);
}

/* Forms and buttons ------------------------------------------------------- */

input,
textarea,
select,
button,
.button-link {
  font: inherit;
  color: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 0;
  padding: 0.4rem 0.6rem;
}

input,
textarea,
select {
  background: var(--field);
}

:is(input, textarea, select, button, .button-link):focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

:is(input, textarea)[aria-invalid="true"] {
  border-color: var(--alert);
  outline-color: var(--alert);
}

button,
.button-link {
  background: var(--ink);
  color: var(--paper);
  cursor: pointer;
}

/* A link that looks like the buttons. */
.button-link {
  display: inline-block;
  text-decoration: none;
}

button:disabled {
  cursor: default;
  opacity: 0.6;
}

/* Marquee bands ----------------------------------------------------------- */

/* Two ink bands, across the top and the bottom, in the logo's yellow, the
   top one travelling left and the bottom one right. */
/* Over everything: last in the page, the highest layer, and a layer of
   its own, so no clipping's video or the logo's paper is ever drawn over
   it. */
.marquee {
  position: fixed;
  left: 0;
  right: 0;
  z-index: 100;
  transform: translateZ(0);
  display: flex;
  align-items: center;
  height: var(--marquee-band);
  overflow: hidden;
  background: var(--ink);
  color: var(--logo-yellow);
  pointer-events: none;
}

.marquee--top {
  top: 0;
}

.marquee--bottom {
  bottom: 0;
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee 60s linear infinite;
}

.marquee--bottom .marquee-track {
  animation-direction: reverse;
}

@keyframes marquee {
  to {
    transform: translateX(-50%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
  }
}

.marquee-group {
  display: flex;
  flex: none;
  align-items: center;
  gap: calc(var(--marquee-band) / 2);
  padding-right: calc(var(--marquee-band) / 2);
}

.marquee-group img {
  height: calc(var(--marquee-band) * 2 / 3);
}

.marquee-slogan {
  font-family: var(--font-display);
  font-size: calc(var(--marquee-band) * 0.55);
  font-weight: 600;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

/* Masthead ---------------------------------------------------------------- */

/* The big logo, fitted 24px in from each side of its stage, with the soft
   black shadow it was drawn with. It turns in perspective to face the
   cursor on a spring (site.js sets --turn and --perspective), and so does
   its paper. */
.masthead {
  --masthead-height: clamp(10rem, 34vw, 18.5rem);

  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 48rem;
  height: var(--masthead-height);
  margin: 1rem auto 0;
}

/* The shadow is the logo's and its paper's together, not each one's:
   while the logo fades back over the paper, both show, and two shadows
   would darken. */
.masthead {
  filter: drop-shadow(0.35em 0.4em 0.25em rgb(0 0 0 / 80%));
  font-size: clamp(3px, 0.45vw, 6px);
}

/* Positioned, so the logo lies over its paper. */
.masthead a {
  position: relative;
  display: block;
}

.masthead .logo {
  width: min(100vw - 48px, 48rem - 48px, (var(--masthead-height) - 48px) * 2364 / 1076);
  height: auto;
}

.masthead :is(.logo, .paper) {
  transform: perspective(var(--perspective, 1200px)) rotateY(var(--turn, 0deg));
}

/* The logo's paper, which visitors can crumple (see crumple.js). It covers
   the masthead, centred on it as the logo is, so the two turn alike, and
   lies under the logo, where three.js draws the same logo in the same
   place. A grip swaps the logo for the paper at once, as the paper starts
   to move. Once it lies flat again, the logo fades back over it, and the
   paper hides only when the fade is over. */
.masthead .paper {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  transition: opacity 0s 0.3s;
}

.masthead .logo {
  transition: opacity 0.3s;
}

.masthead[data-flat="true"] .paper,
.masthead[data-flat="false"] .logo {
  opacity: 0;
}

.masthead[data-flat="false"] :is(.logo, .paper) {
  transition: none;
}

/* Once the paper is ready, pressing the logo grips it rather than
   following the link, and on touch screens dragging moves it rather than
   the page. */
.masthead[data-paper="ready"] a {
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

.masthead[data-paper="ready"][data-flat="false"] a {
  cursor: grabbing;
}

@media (prefers-reduced-motion: reduce) {
  .masthead :is(.logo, .paper) {
    transition: none;
  }
}

/* On phones the logo is smaller, with the menu clear below it. */
@media (max-width: 640px) {
  .masthead {
    --masthead-height: auto;

    margin-top: 0.75rem;
    padding: 0 0.75rem;
  }

  .masthead .logo {
    width: min(100vw - 4.5rem, 20rem);
  }
}

/* Menu -------------------------------------------------------------------- */

/* The sections as tilted bubbles, each its own size, shape and colour. On
   hover, and while you're on its page, a bubble takes its colour, and a
   press squashes it. The bubbles keep their
   round shapes and soft shadows: DESIGN.md's exception. */
/* Above the scrapbook's clippings, which may reach up under it, and a
   little clear of the logo's foot. */
.menu {
  position: relative;
  z-index: 30;
  margin-top: 0.5rem;
}

.menu ul {
  --bubble-unit: 1rem;

  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 1.5rem;
  max-width: 64rem;
  margin: 0 auto;
  padding: 0 1rem 1rem;
  list-style: none;
}

/* The link is the bubble's hit area, tilted and still; only its face
   turns and swells, so a pointer near an edge never loses the bubble as
   it moves, and the face springs back and forth (--spring-bubble). */
.bubble {
  --bubble-colour: var(--ink);
  --bubble-text: var(--paper);

  display: block;
  width: calc(var(--bubble-width) * var(--bubble-unit));
  height: calc(var(--bubble-height) * var(--bubble-unit));
  border-radius: 999px;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: calc(var(--bubble-font-size) * var(--bubble-unit));
  text-decoration: none;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-drag: none;
  transform: rotate(var(--bubble-tilt));
}

.bubble-face {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  background: var(--paper);
  box-shadow: 0 4px 14px rgb(0 0 0 / 10%);
  will-change: transform;
  transition:
    background 0.3s ease,
    color 0.3s ease,
    transform 0.7s var(--spring-bubble);
}

/* The section you're on takes its colour at once, and the one you leave
   loses it at once (site.js marks it data-left for that moment). */
.bubble[aria-current="page"] .bubble-face,
.bubble[data-left] .bubble-face {
  transition: transform 0.7s var(--spring-bubble);
}

.bubble[aria-current="page"] .bubble-face {
  background: var(--bubble-colour);
  color: var(--bubble-text);
}

/* Only a pointer that hovers turns a bubble the other way, from the link's
   own tilt to -0.6 of it: a tap would leave it turned. */
@media (hover: hover) {
  .bubble:hover .bubble-face {
    background: var(--bubble-colour);
    color: var(--bubble-text);
    transform: rotate(calc(var(--bubble-tilt) * -1.6)) scale(1.08);
  }
}

.bubble:active .bubble-face {
  transform: scale(0.9, 0.84);
  transition-duration: 0.1s;
}

.bubble:focus-visible {
  outline: none;
}

.bubble:focus-visible .bubble-face {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

/* Sizes are in --bubble-unit, picked by hand to look random, the same on
   every visit. */
.bubble--about {
  --bubble-width: 8.5;
  --bubble-height: 8.5;
  --bubble-font-size: 1.9;
  --bubble-tilt: -8deg;
  --bubble-colour: var(--logo-yellow);
  --bubble-text: var(--ink);
}

.bubble--programme {
  --bubble-width: 19;
  --bubble-height: 6;
  --bubble-font-size: 2.6;
  --bubble-tilt: 4deg;
  --bubble-colour: var(--cobalt);
}

.bubble--private {
  --bubble-width: 9;
  --bubble-height: 4.5;
  --bubble-font-size: 1.6;
  --bubble-tilt: 9deg;
}

/* Narrower screens: the same bubbles in one row, smaller. */
@media (max-width: 899px) {
  .menu ul {
    --bubble-unit: min(1rem, 2.35vw);

    flex-wrap: nowrap;
    gap: 0.4rem;
    padding: 0 0.5rem 0.75rem;
  }
}

@media (max-width: 640px) {
  .menu {
    margin-top: 0.5rem;
  }
}

/* Page -------------------------------------------------------------------- */

/* The Programme's cards take a wide page; every other page's text keeps to
   a column. */
.page {
  max-width: 90rem;
  margin: 0 auto;
  padding: 1.5rem 1rem 3rem;
}

.page > :not(.programme) {
  max-width: 44rem;
  margin-inline: auto;
}

section h2 {
  margin: 0 0 1rem;
  font-size: 1.6rem;
}

section p {
  max-width: 36rem;
}

/* A Season's years, beneath its number and title. */
.season-years {
  display: block;
  font-family: var(--font-text);
  font-size: 0.9rem;
  font-weight: 400;
  color: var(--muted);
}

/* Programme --------------------------------------------------------------- */

/* The Programme is centred: the Season tabs, the headings, and the cards,
   which keep their width however few there are. */
.programme {
  text-align: center;
}

.programme > section > h3 {
  margin: 2rem 0 0;
  font-size: 1.4rem;
}

.season-tabs ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.season-tabs a {
  display: block;
  padding: 0.4rem 0.9rem 0.5rem;
  border: 1px solid var(--ink);
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
}

/* The current Season's tab, and the one under the pointer, in ink. With
   site.js, one highlight slides between them instead (highlightTabs): the
   tabs' own backgrounds stay clear, and the tab it is on is lit. */
.season-tabs a:is(:hover, [aria-current="page"]) {
  background: var(--ink);
  color: var(--paper);
}

.season-tabs a:is(:hover, [aria-current="page"]) .season-years {
  color: var(--rule);
}

.season-tabs.is-highlighted,
.season-tabs.is-highlighted ul {
  position: relative;
}

.season-tabs.is-highlighted a {
  background: none;
  color: var(--ink);
  transition: color 0.3s ease;
}

.season-tabs.is-highlighted a .season-years {
  color: var(--muted);
  transition: color 0.3s ease;
}

.season-tabs.is-highlighted a[data-lit] {
  color: var(--paper);
}

.season-tabs.is-highlighted a[data-lit] .season-years {
  color: var(--rule);
}

.season-highlight {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
  background: var(--ink);
  transform-origin: 0 0;
  pointer-events: none;
}

.season-highlight.is-sliding {
  transition: transform 0.8s var(--spring-tab);
}

.season-tab-title {
  display: block;
}

/* On phones the three tabs fit one row. */
@media (max-width: 640px) {
  .season-tabs ul {
    flex-wrap: nowrap;
    gap: 0.3rem;
  }

  .season-tabs a {
    padding: 0.3rem 0.5rem 0.35rem;
    font-size: 0.85rem;
  }

  .season-tabs .season-years {
    font-size: 0.75rem;
  }
}

.month h4 {
  margin: 1.5rem 0 0.75rem;
  font-size: 1rem;
  font-weight: normal;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Up to three cards a row, centred, each at most 28rem wide. */
.programme-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 28rem));
  justify-content: center;
  gap: 0.5rem;
  align-items: start;
  max-width: 86rem;
  margin: 0 auto;
  padding: 0;
  list-style: none;
  text-align: left;
}

/* A Chapter, or a trio before the Chapters began, is a row of its own with
   a column for each of the Season's three Strands, so a column is always
   one programme, named in the legend over the rows. Narrower, the row is
   one column. */
.trio h4 {
  margin: 1.75rem 0 0.75rem;
  font-size: 1rem;
  font-weight: normal;
}

.trio-label {
  font-family: var(--font-display);
  font-size: 1.3rem;
  font-weight: 600;
}

.trio-dates {
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.trio-label + .trio-dates::before {
  content: "· ";
}

.strand-legend {
  display: none;
}

@media (min-width: 60rem) {
  .programme-trio {
    grid-template-columns: repeat(3, minmax(0, 28rem));
  }

  .strand-column-1 {
    grid-column: 1;
  }

  .strand-column-2 {
    grid-column: 2;
  }

  .strand-column-3 {
    grid-column: 3;
  }

  /* The legend's rules line up however long each Strand's name is. */
  .strand-legend {
    display: grid;
    align-items: stretch;
    margin-top: 1.5rem;
    text-align: center;
  }

  .strand-legend li {
    padding: 0.5rem 1rem;
    border-bottom: 2px solid var(--ink);
  }
}

.strand-title {
  display: block;
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 600;
}

.strand-subtitle {
  display: block;
  font-size: 0.9rem;
  color: var(--muted);
}

.programme-cell {
  padding: 0.5rem;
}

/* The card is a container, so the panel can be as tall as the Poster. Ink
   lies under it all, so where the Poster meets the band partway through a
   pixel, the seam blends into ink rather than showing the paper as a
   light line. */
.card {
  overflow: hidden;
  container-type: inline-size;
  background: var(--ink);
}

.poster {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--rule);
}

/* The Poster and the ink band under it open the card. */
.card-details {
  position: relative;
}

.card-summary {
  display: block;
  list-style: none;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.card-summary::-webkit-details-marker {
  display: none;
}

.card-summary:focus-visible {
  outline: none;
}

.card-summary:focus-visible .card-caption {
  outline: 2px solid var(--logo-yellow);
  outline-offset: -4px;
}

/* Opened, the Poster swells a little and its blurred copy fades in over
   it, on the card's spring. */
.card-poster {
  display: block;
  position: relative;
  overflow: hidden;
}

/* A Poster is a square with its 16:9 picture in the middle, on white, and
   shows cropped to the picture. Drawn smaller, the white just past the
   crop bleeds into the edge rows of pixels as a light line, which moves as
   the Poster swells. So the Poster is a little swollen even at rest, and
   its edges fall inside the picture. */
.card-poster img,
.poster-blurred {
  transform: scale(1.02);
  transition: transform 0.6s var(--spring-card), opacity 0.6s var(--spring-card);
}

.card-details[open] :is(.card-poster img, .poster-blurred) {
  transform: scale(1.1);
}

/* The blurred copy lies over the Poster, under the Film's details. */
.poster-blurred {
  position: absolute;
  inset: 0;
  height: 100%;
  filter: blur(3px);
}

@starting-style {
  .card-details[open] .poster-blurred {
    opacity: 0;
    transform: scale(1.02);
  }
}

.card-details:not([open]) .poster-blurred {
  opacity: 0;
}

/* The ink band: when on the left, the Film on the right, and the way to
   register under them; the Registration page's is the same. */
.card-caption,
.card-register-band,
.registration-band {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0.75rem;
  background: var(--ink);
  color: var(--paper);
}

.card-register-band {
  margin: 0;
  padding-top: 0;
}

/* The Registration page's Poster isn't swollen as a card's is (see
   .card-poster img), so its band overlaps the bottom row of pixels, where
   the white past the crop bleeds in. */
.registration-band {
  position: relative;
  margin-top: -1px;
}

.card-when,
.card-film {
  display: flex;
  flex-direction: column;
}

.card-when {
  flex: none;
}

/* A long title wraps inside the card instead of being cut off. */
.card-film {
  align-items: flex-end;
  min-width: 0;
  overflow-wrap: anywhere;
  text-align: right;
}

.card-title {
  font-family: var(--font-display);
  font-weight: 600;
}

.card-register {
  color: var(--logo-yellow);
  font-weight: 600;
}

.card-register:focus-visible {
  outline: 2px solid var(--logo-yellow);
  outline-offset: 2px;
}

/* Opened, the Film's details rise from the band over the Poster, never
   past 70% of its height, so its top stays in sight and closes the card
   again; a long description scrolls. They only slide and fade: the Poster
   clips them as they rise. */
.card-info {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: calc(100cqw * 9 / 16);
  overflow: hidden;
  pointer-events: none;
}

.card-info-body {
  position: relative;
  max-height: 70%;
  overflow-y: auto;
  /* Its foot is a border, which stays put as a long description scrolls,
     so the text is cut a little above the band rather than right on it. */
  padding: 0.6rem 0.75rem 0;
  border-bottom: 0.75rem solid var(--ink);
  pointer-events: auto;
  transition:
    transform 0.6s var(--spring-card),
    opacity 0.6s var(--spring-card);
}

/* What an opened card shows, on the card and the Registration page. */
.card-info-body,
.registration-about {
  background: var(--ink);
  color: var(--paper);
  font-size: 0.85rem;
}

:is(.card-info-body, .registration-about) p {
  margin: 0 0 0.5rem;
}

:is(.card-info-body, .registration-about) p:last-child {
  margin-bottom: 0;
}

.card-topic {
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.card-cities {
  color: var(--logo-yellow);
}

/* Where the browser can keep a closing card's content shown a little
   longer, the details sink back into the band as it closes. */
@starting-style {
  .card-details[open] .card-info-body {
    opacity: 0;
    transform: translateY(100%);
  }
}

.card-details:not([open]) .card-info-body {
  opacity: 0;
  transform: translateY(100%);
}

.card-details::details-content {
  transition: content-visibility 0.6s allow-discrete;
}

/* What is still to be made says TBA. */
.tba {
  font-family: var(--font-display);
  font-size: 2rem;
  color: var(--muted);
}

/* About ------------------------------------------------------------------- */

/* The club's text, centred on a sheet of paper above everything else, and
   the scrapbook's clippings: photos and videos in a paper border, each
   turned and sized at random. site.js
   scatters them over the whole page, under everything else, keeping the
   text, the logo and the menu's buttons clear; without it they sit in a
   row below. */
.scrapbook {
  max-width: 38rem;
  margin: 1rem auto 0;
}

.scrapbook-text {
  position: relative;
  z-index: 10;
  padding: 0.75rem 1.25rem;
  background: var(--paper);
  text-align: center;
}

.scrapbook-text p {
  margin: 0 auto;
}

/* Under the text, the club's name on Instagram and Telegram, and their
   marks in ink. */
.follow {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
  padding-top: 1rem;
}

.follow-handle {
  font-weight: 600;
}

.follow a {
  display: block;
  line-height: 0;
}

.follow svg {
  fill: currentColor;
}

.follow a:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.scrapbook-pile {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.5rem;
  margin-top: 2rem;
}

/* The masthead sits above the scattered clippings, as the menu does. */
.masthead {
  position: relative;
  z-index: 20;
}

.scrapbook-pile.scattered {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  display: block;
  width: 100%;
  margin: 0;
  overflow: hidden;
  pointer-events: none;
}

.scrapbook-pile.scattered .clipping {
  position: absolute;
  top: var(--top);
  left: var(--left);
  pointer-events: auto;
}

.clipping {
  --base-width: 15rem;

  position: relative;
  z-index: var(--layer);
  width: calc(var(--base-width) * var(--scale) / 100);
  padding: 0.45rem;
  border: 1px solid var(--rule);
  background: var(--field);
  transform: rotate(var(--tilt));
}

.clipping--portrait {
  --base-width: 11rem;
}

.clipping img,
.clipping video {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
}

@media (max-width: 640px) {
  .clipping {
    --base-width: 9rem;

    padding: 0.3rem;
  }

  .clipping--portrait {
    --base-width: 6.5rem;
  }

  .scrapbook-text p {
    font-size: 0.85rem;
    line-height: 1.45;
  }
}

/* Text only screen readers read. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.privacy h3 {
  margin: 1.5rem 0 0.5rem;
  font-size: 1.1rem;
}

/* Forms ------------------------------------------------------------------- */

form label {
  display: block;
  margin: 1rem 0 0.25rem;
}

form input:not([type="radio"], [type="checkbox"]),
form textarea {
  width: 100%;
}

form fieldset {
  margin: 1.25rem 0 0;
  padding: 0.25rem 1rem 1rem;
  border: 1px solid var(--rule);
}

form fieldset[aria-invalid="true"] {
  border-color: var(--alert);
}

form legend {
  padding: 0 0.25rem;
}

form .hint {
  margin: 0 0 0.25rem;
  font-size: 0.85rem;
}

form label.choice {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
}

form .alert {
  margin: 0.25rem 0 0;
}

form button[type="submit"] {
  margin-top: 1.5rem;
}

/* The field only bots see: off screen, out of the tab order. */
.honeypot {
  position: absolute;
  left: -100vw;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Registration ------------------------------------------------------------ */

/* The Screening as an opened card shows it, laid flat: beside the form on
   a wide screen, where it stays in view, and above it on a narrow one. */
.registration-screening {
  margin: 0 0 2rem;
}

/* Under the band, the rest of what an opened card shows. */
.registration-about {
  padding: 0 0.75rem 0.75rem;
}

/* On a wide screen the Screening stays in view beside the form. */
@media (min-width: 60rem) {
  .page > .registration {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 28rem);
    column-gap: 2.5rem;
    align-items: start;
    max-width: 64rem;
  }

  .registration > h2 {
    grid-column: 1 / -1;
  }

  .registration-screening {
    position: sticky;
    top: calc(var(--marquee-band) + 1rem);
  }
}

.registration-form {
  max-width: 28rem;
}

.registration-form .consent {
  margin: 1.5rem 0 0.5rem;
}

.registration-form .notice {
  margin-top: 1.5rem;
  font-size: 0.85rem;
}

/* Feedback ---------------------------------------------------------------- */

/* Pages people reach from a link have only the logo above them. */
.bare {
  padding: 0;
}

.wordmark {
  max-width: 32rem;
  margin: 0 auto;
  padding: 1.5rem 1rem 0;
}

.wordmark .logo {
  height: 2.25rem;
}

.bare .page > * {
  max-width: 32rem;
}

.feedback h1 {
  margin: 0 0 0.25rem;
  font-size: 1.6rem;
}

/* Each Score is a square to tap, with the radio button hidden but still
   reachable by keyboard and screen readers. */
form fieldset.scores {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 0.5rem;
  margin: 1.5rem 0 0;
  padding: 0;
  border: none;
}

.scores legend {
  margin-bottom: 0.5rem;
  padding: 0;
}

form .scores label {
  position: relative;
  margin: 0;
}

.scores input {
  position: absolute;
  opacity: 0;
}

.scores span {
  display: block;
  padding: 0.6rem 0;
  border: 1px solid var(--ink);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.scores input:checked + span {
  background: var(--ink);
  color: var(--paper);
}

.scores input:focus-visible + span {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.scores[aria-invalid="true"] span {
  border-color: var(--alert);
}

/* Player ------------------------------------------------------------------ */

/* While the device is locked, a closed vermilion curtain stands in front of
   the Player, with the Access password form on a paper sign. Unlocking
   parts it over the Player, and locking draws it closed again, in the page
   (site.js); a page loaded whole shows it as it is. */
.stage {
  position: relative;
}

.stage:has(> .curtain) {
  min-height: 28rem;
}

.curtain {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  padding: 1rem;
  overflow: hidden;
}

.curtain-half {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50%;
  /* Pleats: the vermilion folded into a slightly darker line. */
  background: repeating-linear-gradient(
    90deg,
    var(--vermilion) 0 2.25rem,
    color-mix(in srgb, var(--vermilion) 82%, var(--ink)) 2.25rem 2.5rem
  );
}

.curtain-left {
  left: 0;
}

.curtain-right {
  right: 0;
  border-left: 2px solid var(--ink);
}

/* Parting, the sign fades first, and the halves are drawn aside past the
   stage's edges, slow at both ends, like a curtain pulled by hand: past,
   since the pull is slowest at its end, which would leave a sliver of each
   half crawling along the sides. */
.curtain-half {
  transition: transform 1.2s var(--pulled);
}

.curtain.is-parting .curtain-sign {
  opacity: 0;
}

.curtain.is-parting .curtain-left {
  transform: translateX(-115%);
}

.curtain.is-parting .curtain-right {
  transform: translateX(115%);
}

/* Closing, the halves come in from the edges, so they are seen to move at
   once, as the sign fades in. */
@starting-style {
  .curtain.is-closing .curtain-left {
    transform: translateX(-100%);
  }

  .curtain.is-closing .curtain-right {
    transform: translateX(100%);
  }

  .curtain.is-closing .curtain-sign {
    opacity: 0;
  }
}

/* With reduced motion the curtain only fades. */
@media (prefers-reduced-motion: reduce) {
  .curtain-half {
    transition: opacity 0.4s ease;
  }

  .curtain.is-parting .curtain-half {
    transform: none;
    opacity: 0;
  }

  @starting-style {
    .curtain.is-closing :is(.curtain-left, .curtain-right) {
      transform: none;
      opacity: 0;
    }
  }
}

.curtain-sign {
  position: relative;
  width: min(100%, 24rem);
  padding: 1.25rem;
  border: 1px solid var(--ink);
  background: var(--paper);
  transition: opacity 0.4s ease;
}

.unlock p:first-child {
  margin-top: 0;
}

.unlock label {
  margin-top: 0;
}

.unlock-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

form .unlock-row input {
  flex: 1 1 10rem;
  width: auto;
  min-width: 0;
}

.unlock-row button[type="submit"] {
  margin-top: 0;
}

.lock {
  background: transparent;
  color: var(--ink);
}

.live {
  margin-bottom: 1.25rem;
}

.notice {
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--rule);
}

/* A 16:9 Poster beside the countdown, or above it on phones. */
.countdown {
  display: grid;
  grid-template-columns: 16rem 1fr;
  gap: 1rem;
  align-items: start;
  font-variant-numeric: tabular-nums;
}

.countdown h3 {
  margin: 0 0 0.5rem;
  font-size: 1.3rem;
  font-weight: normal;
}

.countdown p {
  margin: 0 0 0.25rem;
}

@media (max-width: 40rem) {
  .countdown {
    grid-template-columns: 1fr;
  }
}

/* The Film, 16:9 until it fills the screen, with the Live button in its
   top corner. */
.frame {
  position: relative;
  background: var(--ink);
}

.frame video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
}

.live-button {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  padding: 0.2rem 0.6rem;
  border-color: var(--paper);
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Following the Live edge, the button is lit, in vermilion. */
.live-button[aria-pressed="true"] {
  border-color: var(--vermilion);
  background: var(--vermilion);
}

.screen > .muted {
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

.feedback-link {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1rem;
  align-items: center;
  margin-bottom: 1rem;
  padding: 0.75rem;
  border: 1px solid var(--ink);
}

.feedback-link[hidden] {
  display: none;
}

.feedback-link img {
  display: block;
}

.feedback-link p {
  margin: 0 0 0.5rem;
}

.feedback-link a {
  overflow-wrap: anywhere;
}

@media (max-width: 30rem) {
  .feedback-link {
    grid-template-columns: 1fr;
  }
}

/* Motion between pages ---------------------------------------------------- */

/* Going to another page swaps the page at once, while the bands, the logo
   and the menu stay put. Between the pages in the menu's shell site.js
   swaps the page itself, so the bands and the logo never stop; loading a
   whole page, the marquee carries on where it was, by the clock the
   layout's inline script sets it by. */
@view-transition {
  navigation: auto;
}

.masthead {
  view-transition-name: masthead;
}

.menu {
  view-transition-name: menu;
}

.marquee--top {
  view-transition-name: marquee-top;
}

.marquee--bottom {
  view-transition-name: marquee-bottom;
}

/* The page passes under the bands. */
::view-transition-group(marquee-top),
::view-transition-group(marquee-bottom) {
  z-index: 1;
}

/* What stays shows only as it is now, live, not faded from a still of it
   as it was: the moving bands would show twice. Nor does it slide from
   where it was on the last page, as from a page scrolled down. */
::view-transition-group(masthead),
::view-transition-group(menu),
::view-transition-group(marquee-top),
::view-transition-group(marquee-bottom) {
  animation: none;
}

::view-transition-old(masthead),
::view-transition-old(menu),
::view-transition-old(marquee-top),
::view-transition-old(marquee-bottom) {
  display: none;
}

::view-transition-new(masthead),
::view-transition-new(menu),
::view-transition-new(marquee-top),
::view-transition-new(marquee-bottom) {
  animation: none;
}

/* The page isn't morphed or cross-faded: it swaps at once. */
::view-transition-group(root),
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
}

/* A chosen Score bounces. */
.scores input:checked + span {
  animation: press 0.5s var(--bounce);
}

@keyframes press {
  40% {
    transform: scale(0.85);
  }
}

/* With reduced motion nothing moves: pages and the curtain swap at once. */
@media (prefers-reduced-motion: reduce) {
  *,
  ::before,
  ::after {
    animation: none !important;
    transition: none !important;
  }

  @view-transition {
    navigation: none;
  }
}

/* Editor ------------------------------------------------------------------ */

/* Where Organisers edit the Programme and the Films: wider than the text
   column, for its tables, and plain. */
.page > .editor {
  max-width: 72rem;
}

.page > .editor-login {
  max-width: 24rem;
}

.editor h2 .season-years {
  display: inline;
}

.editor h3 {
  margin: 2.5rem 0 0.5rem;
  font-size: 1.25rem;
}

.editor-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-bottom: 1.5rem;
  padding-bottom: 0.75rem;
  border-bottom: 2px solid var(--ink);
}

.editor-bar nav {
  display: flex;
  gap: 1.25rem;
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 600;
}

.editor-bar nav a {
  text-decoration: none;
}

.editor-bar nav a[aria-current="page"] {
  text-decoration: underline;
  text-decoration-thickness: 3px;
  text-underline-offset: 0.3em;
}

.editor-bar form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.75rem;
  align-items: baseline;
}

/* Its figures keep their width, so the clock's line doesn't shift as the
   minutes turn. */
.editor-clock {
  font-variant-numeric: tabular-nums;
}

.link-button {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  text-decoration: underline;
}

.editor-notice {
  padding: 0.5rem 0.75rem;
  background: var(--logo-yellow);
}

.editor .season-tabs ul {
  justify-content: flex-start;
}

.editor-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  margin: 1.25rem 0;
}

.editor-actions form button[type="submit"] {
  margin: 0;
}

.editor-filter {
  flex: 1 1 14rem;
}

.editor-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.95rem;
}

.editor-table th,
.editor-table td {
  padding: 0.45rem 0.5rem;
  border-bottom: 1px solid var(--rule);
  text-align: left;
  vertical-align: top;
}

.editor-table th {
  border-bottom: 2px solid var(--ink);
  font-weight: 600;
  white-space: nowrap;
}

.editor-table tr.is-draft td {
  background: color-mix(in srgb, var(--rule) 35%, transparent);
}

.editor-table form button[type="submit"] {
  margin: 0;
}

/* Published or draft, as a switch: ink when published. */
.toggle {
  padding: 0.15rem 0.5rem;
  background: transparent;
  color: var(--ink);
  font-size: 0.85rem;
  white-space: nowrap;
}

.toggle.is-on {
  background: var(--ink);
  color: var(--paper);
}

.badge {
  display: inline-block;
  padding: 0 0.4rem;
  border: 1px solid var(--ink);
  font-size: 0.8rem;
  white-space: nowrap;
}

.badge--ready {
  background: var(--logo-yellow);
}

.badge--failed {
  border-color: var(--alert);
  color: var(--alert);
}

.badge--none {
  border-style: dashed;
  color: var(--muted);
}

/* A form whose fields sit in a row on wide screens: a Season's settings, a
   Chapter, a Series. */
.editor-inline {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.75rem;
  align-items: flex-end;
  margin: 0.5rem 0;
}

.editor-inline label {
  flex: 1 1 12rem;
  margin-top: 0.5rem;
}

.editor-inline label.narrow {
  flex: 0 0 6rem;
}

.editor-inline label.wide {
  flex: 3 1 18rem;
}

.editor-inline button[type="submit"] {
  margin-top: 0.5rem;
}

.editor-inline :is(input, select) {
  width: 100%;
}

.editor-add-row {
  padding-top: 0.5rem;
  border-top: 1px dashed var(--rule);
}

.editor-card {
  margin: 1rem 0;
  padding: 0.25rem 1rem 1rem;
  border: 1px solid var(--rule);
}

.editor-thumb {
  display: block;
  width: 12rem;
  margin: 1rem 0 0;
}

.editor-add summary {
  cursor: pointer;
  font-weight: 600;
}

.editor-form select {
  width: 100%;
  max-width: 100%;
}

.editor-form .editor-filter {
  width: 100%;
  margin-bottom: 0.25rem;
}

/* A City's Locations in a row, after its name. */
.editor-city {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.25rem;
  align-items: baseline;
  margin-top: 0.5rem;
}

.editor-city > span {
  flex: 0 0 7rem;
  font-weight: 600;
}

form .editor-city label.choice {
  margin: 0;
}

.editor-poster[hidden] {
  display: none;
}

.editor-scroll {
  overflow-x: auto;
}

.editor-poster {
  display: block;
  max-width: 20rem;
  width: 100%;
  margin: 0.5rem 0;
}

.editor-groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0 1rem;
}

.editor-danger button {
  margin-top: 2rem;
  background: var(--alert);
  border-color: var(--alert);
}

/* On phones the Screenings' table drops its Cities and what they are part
   of, and scrolls sideways if it must. */
@media (max-width: 640px) {
  .editor-screenings :is(th, td):is(:nth-child(3), :nth-child(4)) {
    display: none;
  }
}

/* A Screening's still and Poster, side by side where there is room. */
.editor-pictures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0 1.5rem;
}

/* Making a Poster: the controls beside the 16:9 stage, or above it on
   phones. A step, tool or preset that is on is inked; the others are only
   outlined. The handles are drawn on a canvas over the picture. */
.distort {
  display: grid;
  grid-template-columns: 15rem 1fr;
  gap: 1rem;
  align-items: start;
}

.distort-controls,
.distort-controls [data-for],
.distort-controls form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.distort-controls [hidden] {
  display: none;
}

.distort-controls .hint {
  margin: 0;
}

.distort-controls label {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.distort-controls input[type="range"] {
  flex: 1;
  min-width: 0;
  padding: 0;
}

.distort-modes,
.distort-print,
.distort-export {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.375rem;
}

.distort-tools,
.distort-presets,
.distort-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.375rem;
}

.distort-tools {
  grid-template-columns: 1fr 1fr;
}

.distort-export {
  grid-template-columns: 1fr;
}

.distort-controls :is(.distort-modes, .distort-print, .distort-tools, .distort-presets, .distort-row) button {
  padding-inline: 0.25rem;
}

.distort-controls button[aria-pressed="false"] {
  background: var(--field);
  color: var(--ink);
}

.distort-current {
  margin: 0;
}

.distort-stage {
  position: relative;
  width: min(100%, 75vh * 16 / 9);
  aspect-ratio: 16 / 9;
  border: 1px solid var(--rule);
}

.distort-stage canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.distort-handles {
  touch-action: none;
}

@media (max-width: 640px) {
  .distort {
    grid-template-columns: 1fr;
  }

  .distort-stage {
    width: 100%;
  }
}
