/* ==========================================================================
   FAU goes Downtown – stylesheet
   --------------------------------------------------------------------------
   Plain CSS. No build step, no framework. The whole site is two HTML pages
   plus this file.

   The look is a two-colour Riso print: fluorescent pink and blue on paper.
   Everything below is grouped under a banner comment. If you only want to
   change colours or sizes, stay in the "SETTINGS" block – you almost never
   need to touch anything after it.
   ========================================================================== */

/* ==========================================================================
   1. FONTS
   Archivo is the variable font that covers every weight and width used on
   the site. Anton is the poster face and is used for the big headline only –
   it is a plain font with one weight and no width axis, so it cannot be
   condensed or stretched with font-stretch. The 120 % of the printed posters
   is done with transform: scaleX() on .hero-title instead.
   ========================================================================== */

@font-face {
  font-family: "Archivo";
  src: url("../fonts/archivo-latin.woff2") format("woff2");
  font-weight: 400 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
  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: "Archivo";
  src: url("../fonts/archivo-latin-ext.woff2") format("woff2");
  font-weight: 400 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
  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: "Anton";
  src: url("../fonts/anton-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  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: "Anton";
  src: url("../fonts/anton-latin-ext.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  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;
}

/* ==========================================================================
   2. SETTINGS
   Colours, spacing and sizes. Change values here, not further down.
   ========================================================================== */

:root {
  color-scheme: light;

  /* The two printing inks and the paper they sit on.
     --paper and --ink swap over in dark mode; everything else here does not.
     A pink plate is pink on either stock. */
  --paper: #f4f3ef;
  --paper-shade: #e9e7e1;
  --ink: #141026; /* both inks overprinted – the "black" of the page */
  --pink: #ff3d97; /* fluorescent pink plate */
  --blue: #04316a; /* blue plate – FAU Blau, the university's own brand blue */
  --blue-ink: var(--blue); /* the blue plate used as small type on paper */
  /* The offset plate behind the headline. FAU Blau itself is almost the same
     value as the overprint ink (1.5:1), so the plate would vanish; this is the
     lighter step of FAU's own blue ladder, which separates properly. */
  --blue-plate: #0f63c0;
  --white: #ffffff;

  /* The overprint black as a physical ink, not as a role. Anything printed
     on top of a pink or blue flood uses this, so it stays dark on both
     stocks – a pink field never carries pale type. */
  --ink-fixed: #141026;

  /* The one solid dark block on the page: the footer. On white stock it is
     the overprint ink; on black stock it lifts a step off the sheet
     instead of dropping to a glaring white flood. */
  --slab: var(--ink);
  --on-slab: var(--paper);

  /* Text colours that pass contrast checks on each background. */
  --on-paper: var(--ink);
  --on-paper-quiet: #4a4363;
  --on-pink: var(--ink-fixed);
  --on-blue: var(--white);
  --on-blue-quiet: #d6ddff;
  --on-slab-quiet: #aba5c2;

  /* Rules and hairlines, in the same family as the ink. */
  --rule: color-mix(in srgb, var(--ink) 22%, transparent);
  --rule-strong: color-mix(in srgb, var(--ink) 65%, transparent);

  /* How the paper grain is laid down. Multiplied into white stock;
     screened onto black stock, where multiplying would show nothing. */
  --grain-blend: multiply;
  --grain-opacity: 0.35;

  /* Layout. */
  --sheet: 82rem; /* page width at its widest */
  --measure: 62ch; /* comfortable reading width for paragraphs */
  --gutter: clamp(1.25rem, 4vw, 3.5rem);

  /* Vertical rhythm. Section padding scales with the viewport. */
  --band: clamp(3.5rem, 8vw, 7rem);

  /* Typefaces. --face is the whole site, --face-display only the headline. */
  --face: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --face-display: "Anton", "Archivo", "Helvetica Neue", Arial, sans-serif;

  /* Paper grain, laid over the whole page. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)' opacity='0.5'/%3E%3C/svg%3E");

  /* Halftone dot screen, laid over every photograph. */
  --dots: radial-gradient(circle at center, #000 0.9px, transparent 1.1px);
}

/* --------------------------------------------------------------------------
   THE SAME PRINT ON BLACK STOCK
   Dark mode is not a second design. It is this flyer run on black paper:
   the same two inks, nudged only as far as they must be to stay readable on
   a dark sheet, and the same flat floods, rules and grain.

   Which stock is in the press is decided by assets/js/theme.js and written
   onto <html data-theme>. It follows the phone's own light/dark setting
   until the visitor presses the button in the masthead, and then remembers
   what they chose. With JavaScript switched off the site prints on white,
   which is its home stock.
   -------------------------------------------------------------------------- */

[data-theme="dunkel"] {
  color-scheme: dark;

  --paper: #100d18; /* black stock */
  --paper-shade: #1b1729;
  --ink: #efedf5; /* the ink that reads as "black" is now the light one */
  --pink: #ff5aa5; /* both inks step up: fluorescent ink is brighter on black */
  --blue: #0f63c0; /* FAU Blau lifted – the CD value is too dark on black */
  --blue-ink: #8ea0ff; /* the blue plate needs more lift to read as small type */
  --blue-plate: #3d8ce0; /* the plate lifted again to carry on black stock */

  --on-paper-quiet: #9b93b8;
  /* The blue flood is lifted on black stock, so the quiet type on it has to
     lift too: the white-stock value only reaches 4.39:1 against #0f63c0 and
     misses AA. This clears it at 4.80:1 and still reads a step quieter than
     the plain --on-blue white beside it. */
  --on-blue-quiet: #e2e7ff;

  --slab: #191428;
  --on-slab: var(--ink);
  --on-slab-quiet: #8d86a8;

  /* Black noise multiplied into a black sheet shows nothing, so on this
     stock the grain is screened on as light speckle instead. */
  --grain-blend: screen;
  --grain-opacity: 0.1;
}

/* ==========================================================================
   3. BASE
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  background: var(--paper);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-width: 20rem;
  background: var(--paper);
  color: var(--on-paper);
  font-family: var(--face);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.075rem);
  font-weight: 400;
  font-stretch: 100%;
  line-height: 1.62;
  overflow-x: hidden;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
}

/* The grain sits above everything and is never clickable. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  background-image: var(--grain);
  background-size: 140px 140px;
  mix-blend-mode: var(--grain-blend);
  opacity: var(--grain-opacity);
}

img {
  display: block;
  max-width: 100%;
}

/* Browser furniture themed from the palette, so nothing ships as a default. */
::selection {
  background: var(--pink);
  color: var(--on-pink);
}

:focus-visible {
  outline: 3px solid var(--blue-ink);
  outline-offset: 3px;
}

.section-invert :focus-visible {
  outline-color: var(--on-blue);
}

.tearoff :focus-visible,
.section-pink :focus-visible {
  outline-color: var(--on-pink);
}

.site-footer :focus-visible {
  outline-color: var(--on-slab);
}

/* Screen-reader-only text: present for assistive tech, invisible on screen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Skip link, visible only when focused by keyboard. */
.skip-link {
  position: absolute;
  z-index: 100;
  top: 0.75rem;
  left: 0.75rem;
  padding: 0.7rem 1.1rem;
  background: var(--ink);
  color: var(--paper);
  font-weight: 700;
  text-decoration: none;
  transform: translateY(-160%);
}

.skip-link:focus-visible {
  transform: none;
}

/* ==========================================================================
   4. TYPE
   Size and width do the work. Headings are always uppercase Archivo:
   condensed and heavy for display, normal width for running text.
   ========================================================================== */

h1,
h2,
h3 {
  margin: 0;
  font-weight: 900;
  font-stretch: 66%;
  line-height: 0.88;
  letter-spacing: -0.015em;
  /* condensed caps run their words together without this */
  word-spacing: 0.07em;
  text-transform: uppercase;
  text-wrap: balance;
}

h2 {
  font-size: clamp(2.1rem, 6vw, 4rem);
}

h3 {
  font-size: clamp(1.35rem, 2.6vw, 1.9rem);
  line-height: 0.95;
}

p {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration-thickness: 0.09em;
  text-underline-offset: 0.22em;
  text-decoration-color: var(--pink);
}

a:hover {
  text-decoration-thickness: 0.16em;
}

.lead {
  max-width: 44ch;
  font-size: clamp(1.2rem, 1rem + 0.7vw, 1.45rem);
  font-weight: 500;
  line-height: 1.35;
  text-wrap: balance;
}

/* ==========================================================================
   5. LAYOUT HELPERS
   ========================================================================== */

.sheet {
  width: min(100% - (2 * var(--gutter)), var(--sheet));
  margin-inline: auto;
}

.prose {
  max-width: var(--measure);
}

.prose p {
  margin: 0 0 1.4em;
}

.prose p:last-child {
  margin-bottom: 0;
}

.prose a {
  font-weight: 700;
}

.band {
  padding-block: var(--band);
}

/* A section printed as a solid ink flood instead of on bare paper. */
.section-invert {
  background: var(--blue);
  color: var(--on-blue);
}

.section-pink {
  background: var(--pink);
  color: var(--on-pink);
}

/* Hairline rule in the ink family, used to separate printed blocks. */
.rule {
  border: 0;
  border-top: 1px solid var(--rule-strong);
  margin: 0;
}

/* ==========================================================================
   6. PHOTOGRAPHS
   Every photo is printed in the two inks and screened with halftone dots, so
   the pictures belong to the same print as the type. The ink recipe itself
   lives in the small <svg> block at the top of the HTML – a colour ramp from
   deep overprint in the shadows, through pink in the midtones, to bare paper
   in the highlights.
   ========================================================================== */

.plate {
  position: relative;
  overflow: hidden;
  background: var(--paper);
}

.plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: url("#ink-duotone");
}

/* Dot screen: the printed texture of the photograph. */
.plate::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--dots);
  background-size: 3px 3px;
  mix-blend-mode: multiply;
  opacity: 0.35;
  pointer-events: none;
}

/* Variant printed with the blue plate leading instead of the pink. */
.plate-blue img {
  filter: url("#ink-duotone-blue");
}

/* ==========================================================================
   7. BUTTONS
   Two printed blocks: a solid pink one for the main action, an outlined one
   for everything else.
   ========================================================================== */

.button {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 3rem;
  padding: 0.8rem 1.25rem;
  border: 2px solid currentColor;
  background: var(--pink);
  color: var(--on-pink);
  font-size: 0.95rem;
  font-weight: 800;
  font-stretch: 100%;
  letter-spacing: 0.06em;
  line-height: 1.1;
  text-transform: uppercase;
  text-decoration: none;
  transition:
    background-color 120ms ease-out,
    color 120ms ease-out;
}

.button svg {
  flex: none;
  width: 1em;
  height: 1em;
}

/* The outlined block prints in whatever ink the surface around it uses:
   the stock's ink on paper, the knockout colour inside an ink flood. */
.button-outline {
  background: transparent;
  color: inherit;
}

/* Hover runs a second ink pass over the block rather than lifting it. */
@media (hover: hover) {
  .button:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--paper);
  }

  .section-invert .button:hover {
    background: var(--on-blue);
    border-color: var(--on-blue);
    color: var(--blue);
  }

  .section-pink .button:hover {
    background: var(--paper);
    border-color: var(--paper);
    color: var(--on-pink);
  }
}

.button:active {
  background: var(--blue);
  border-color: var(--blue);
  color: var(--on-blue);
}

/* ==========================================================================
   8. HEADER – the top of the flyer
   ========================================================================== */

.masthead {
  position: relative;
  padding-block: clamp(1rem, 2.5vw, 1.4rem) 0;
}

.masthead-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--rule-strong);
}

/* On the event page the hero photograph starts hard against the masthead and
   runs the full width of the window, so the rule above it stops short of the
   picture on both sides and reads as a scratch across it. The photograph is
   its own separator there; the rule is only needed on the Impressum, which
   has no picture. Browsers without :has() keep the rule, which is merely the
   older look rather than a broken one. */
.masthead:has(+ main > .hero) .masthead-bar {
  border-bottom: 0;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: inherit;
  font-size: 0.82rem;
  font-weight: 800;
  font-stretch: 105%;
  letter-spacing: 0.16em;
  line-height: 1.2;
  text-transform: uppercase;
  text-decoration: none;
}

.brand img {
  width: 2.6rem;
  height: 2.6rem;
}

/* Partner line and stock switch share the right-hand end of the bar. */
.masthead-side {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2.5vw, 1.25rem);
}

.masthead-note {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.35;
  text-align: right;
}

/* The stock switch: white paper or black paper. A printed block like every
   other control on the page – square, 2px border, fills with ink on hover. */
.theme-toggle {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 2px solid var(--ink);
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition:
    background-color 120ms ease-out,
    color 120ms ease-out;
}

.theme-toggle svg {
  width: 1.15rem;
  height: 1.15rem;
}

/* One icon at a time: on white stock the button offers the black one. */
.theme-toggle .icon-hell {
  display: none;
}

[data-theme="dunkel"] .theme-toggle .icon-dunkel {
  display: none;
}

[data-theme="dunkel"] .theme-toggle .icon-hell {
  display: block;
}

@media (hover: hover) {
  .theme-toggle:hover {
    background: var(--ink);
    color: var(--paper);
  }
}

.theme-toggle:active {
  background: var(--blue);
  color: var(--on-blue);
}

/* ==========================================================================
   9. HERO – headline, date, photograph, main actions
   ========================================================================== */

/* No padding at the top: the photograph starts hard against the masthead. */
.hero {
  position: relative;
  padding-block: 0 clamp(2rem, 4vw, 3rem);
}

.hero-grid {
  display: grid;
  gap: 1.25rem;
}

/* The line above the headline. It carries the one word the page has to say
   before anything else is read. It is printed as a solid blue label rather
   than as bare type, because it sits on the photograph (see .hero-photo
   below) where loose pink type would disappear into the pink ink. Blue and
   not pink so the "Event im E-Werk" button stays the one pink block on the
   first screen. --blue is already lifted on black stock, so one value carries
   both papers. */
.hero-kicker {
  display: inline-block;
  margin: 0 0 clamp(0.5rem, 1.2vw, 0.85rem);
  padding: 0.35rem 0.8rem 0.3rem;
  background: var(--blue);
  color: var(--on-blue);
  /* Small at the bottom end so the label stays clearly subordinate to the
     headline on a phone, and held to Section size at the top end: past that
     it prints half a headline wide and stops reading as a label. */
  font-size: clamp(0.95rem, 3.4vw, 1.6rem);
  font-weight: 800;
  font-stretch: 105%;
  letter-spacing: 0.16em;
  line-height: 1.2;
  text-transform: uppercase;
}

/* The headline. Two plates: the ink one you read, and a pink one behind it
   that is deliberately out of register – the signature of a Riso print. */
.hero-title {
  position: relative;
  isolation: isolate;
  margin: 0;
  /* Anton has one weight and no width axis, so font-stretch does nothing
     here. The 120 % of the printed posters is a horizontal scale, which is
     what scaleX below does. The type sizes are 20 % smaller than they look
     because that scale widens them again. */
  font-family: var(--face-display);
  font-weight: 400;
  font-size: clamp(2.7rem, 16vw, 13.6rem);
  line-height: 0.95;
  letter-spacing: -0.005em;
  text-wrap: balance;
  /* The box is laid out 1/1.2 narrower so that the scale below puts it back
     on exactly the column width. Without this the empty right edge of the
     headline sticks out past the page and the phone can scroll sideways. */
  width: calc(100% / 1.2);
  transform: scaleX(1.2);
  transform-origin: left center;
}

/* The offset plate, printed a hair out of register behind the readable one.
   This is where the FAU blue appears at full size. */
.hero-title .ink-offset {
  position: absolute;
  inset: 0;
  z-index: 0;
  color: var(--blue-plate);
  transform: translate(0.046em, 0.03em);
  animation: register 900ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

.hero-title .ink-main {
  position: relative;
  z-index: 1;
  display: block;
}

@keyframes register {
  from {
    transform: translate(0.25em, 0.16em);
    opacity: 0.35;
  }
}

.hero-title em {
  display: block;
  font-style: normal;
}

/* The date at display scale, with place and price as scannable facts. */
.hero-when {
  display: grid;
  gap: 1.25rem 2.5rem;
  padding-top: 1rem;
  border-top: 2px solid var(--ink);
}

.hero-date {
  margin: 0;
  font-size: clamp(1.9rem, 6.5vw, 3.75rem);
  font-weight: 900;
  font-stretch: 125%;
  line-height: 0.95;
  letter-spacing: -0.03em;
  word-spacing: 0.04em;
  text-transform: uppercase;
}

.hero-facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem 1.75rem;
  margin: 0;
  align-content: start;
}

.hero-facts dt {
  margin-bottom: 0.4rem;
  font-size: 0.82rem;
  font-weight: 700;
  font-stretch: 105%;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.hero-facts dd {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.35;
}

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

/* The photograph runs first and full-bleed, so a phone shows what the party
   looks like before anything has to be scrolled. The headline is then pulled
   back up over its foot, the way type overprints an image on a poster. */
.hero-photo {
  order: 1;
  aspect-ratio: 4 / 3;
  /* Capped so that on a tall tablet the 4:3 crop cannot eat the whole
     screen and push the date off it. */
  max-height: 60vh;
  margin-inline: calc(-1 * var(--gutter));
}

/* The foot of the photograph dissolves into the paper so the headline has
   something to sit on. This is the one gradient on the site: type over a
   hard-cropped photograph is either illegible or has to be knocked out into
   a panel, and the panel hides the overlap that makes the effect work.
   It fades to var(--paper), so it follows the stock into dark mode. */
.hero-photo::before {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  z-index: 1;
  height: 45%;
  background: linear-gradient(to bottom, transparent, var(--paper) 95%);
}

/* Lifted over the photograph and pulled up into it. The photograph is 4:3,
   so its height follows the width of the window; below a 390px phone the
   pull eases off with it, or the headline would cover the whole picture. */
.hero-head {
  order: 2;
  position: relative;
  z-index: 2;
  margin-top: max(-9.5rem, -39vw);
}

.hero-when {
  order: 3;
}

.hero-grid .lead {
  order: 4;
}

.hero-actions {
  order: 5;
}

/* The imprint line: who is actually behind the party. */
.imprint {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.75rem;
  margin: clamp(1.75rem, 3vw, 2.5rem) 0 0;
  padding: 1.1rem 0 0;
  border-top: 1px solid var(--rule-strong);
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--on-paper-quiet);
  list-style: none;
}

/* ==========================================================================
   10. TICKETS – the three ways to get in, printed as rows
   ========================================================================== */

.tickets-head {
  display: grid;
  gap: 1rem;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.ticket-list {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  border-top: 2px solid currentColor;
  list-style: none;
}

.ticket {
  display: grid;
  gap: 0.35rem 2rem;
  padding-block: clamp(1.5rem, 3vw, 2rem);
  border-bottom: 1px solid var(--on-blue-quiet);
}

.ticket-name {
  margin: 0;
  font-size: clamp(1.5rem, 3vw, 2.1rem);
}

.ticket-where {
  margin: 0;
  max-width: 40ch;
  line-height: 1.5;
  color: var(--on-blue-quiet);
}

.ticket-price {
  margin: 0;
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  font-weight: 900;
  font-stretch: 112%;
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

/* The service-fee line: a footnote under the price, in its own row so it
   does not make the price block taller and push the row apart. */
.ticket-fee {
  margin: 0;
  font-size: 0.82rem;
  font-weight: 600;
  font-stretch: 100%;
  letter-spacing: 0;
  line-height: 1.3;
  color: var(--on-blue-quiet);
}

/* Status stamp. Swap the class in the HTML when the online sale opens. */
.ticket-status {
  display: inline-block;
  align-self: start;
  padding: 0.3rem 0.6rem;
  border: 2px solid currentColor;
  font-size: 0.82rem;
  font-weight: 800;
  font-stretch: 105%;
  letter-spacing: 0.16em;
  line-height: 1.2;
  text-transform: uppercase;
  transform: rotate(-2deg);
}

.ticket-status-open {
  background: var(--pink);
  border-color: var(--on-pink);
  color: var(--on-pink);
}

/* ==========================================================================
   11. PROGRAMME – what happens on which floor
   ========================================================================== */

.programme-list {
  display: grid;
  gap: 0;
  margin: clamp(2rem, 4vw, 3rem) 0 0;
  padding: 0;
  border-top: 2px solid var(--ink);
  list-style: none;
}

.programme-item {
  display: grid;
  gap: 0.4rem 2rem;
  padding-block: clamp(1.4rem, 3vw, 1.9rem);
  border-bottom: 1px solid var(--rule);
}

/* On phones the floor name sits under its entry as a caption. Set above the
   heading it would read as an eyebrow, which this page does not use. */
.programme-index {
  order: 1;
}

.programme-item h3 {
  margin: 0;
}

.programme-item p {
  margin: 0;
  max-width: 46ch;
  color: var(--on-paper-quiet);
}

.programme-index {
  font-size: 0.82rem;
  font-weight: 800;
  font-stretch: 105%;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--blue-ink);
}

/* ==========================================================================
   12. STORY + QUOTE
   ========================================================================== */

.story {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
}

.story .prose {
  margin-top: 1.75rem;
}

.pull-quote {
  margin: 0;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border: 2px solid var(--ink);
  background: var(--paper-shade);
}

.pull-quote p {
  margin: 0 0 1rem;
  font-size: clamp(1.2rem, 1rem + 0.7vw, 1.45rem);
  font-weight: 500;
  line-height: 1.45;
}

.pull-quote p:last-of-type {
  margin-bottom: 1.25rem;
}

.pull-quote footer {
  font-size: 0.82rem;
  font-weight: 800;
  font-stretch: 105%;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* ==========================================================================
   13. GALLERY
   Nine photographs printed as an uneven sheet, not a tidy grid of thumbnails.
   ========================================================================== */

.gallery {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.5rem, 1.5vw, 1rem);
  margin-top: clamp(2rem, 4vw, 3rem);
}

.gallery .plate {
  aspect-ratio: 3 / 2;
}

.gallery .plate:first-child {
  grid-column: span 2;
  aspect-ratio: 2 / 1.1;
}

/* ==========================================================================
   14. PARTNERS – the cooperation, set as text
   ========================================================================== */

.partners {
  display: grid;
  margin: clamp(2rem, 4vw, 3rem) 0 0;
  padding: 0;
  border-top: 2px solid var(--ink);
  list-style: none;
}

.partners li {
  padding-block: clamp(1.25rem, 3vw, 1.75rem);
  border-bottom: 1px solid var(--rule);
}

.partners .partner-name {
  margin: 0;
  font-size: clamp(1.1rem, 2vw, 1.4rem);
  font-weight: 800;
  font-stretch: 96%;
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.partners .partner-role {
  margin: 0.5rem 0 0;
  line-height: 1.45;
  color: var(--on-paper-quiet);
}

/* ==========================================================================
   14b. THE CLOSE – last block before the footer
   ========================================================================== */

.closer .sheet {
  display: grid;
  gap: clamp(1.75rem, 4vw, 3rem);
}

.closer-date {
  font-size: clamp(3rem, 11vw, 6.5rem);
  font-stretch: 62%;
  line-height: 0.85;
}

.closer-side {
  display: grid;
  align-content: end;
  gap: 1.5rem;
}

.closer-note {
  margin: 0;
  max-width: 30ch;
  font-size: clamp(1.2rem, 1rem + 0.7vw, 1.45rem);
  font-weight: 500;
  line-height: 1.4;
}

.closer .button {
  background: transparent;
}

@media (hover: hover) {
  .closer .button:hover {
    background: var(--on-pink);
    color: var(--pink);
    border-color: var(--on-pink);
  }
}

/* ==========================================================================
   15. FOOTER
   ========================================================================== */

.site-footer {
  /* Its own, shorter rhythm: three small lines do not need a full band. */
  --footer-band: clamp(2.25rem, 4vw, 3.5rem);
  padding-block: var(--footer-band);
  padding-bottom: calc(var(--footer-band) + env(safe-area-inset-bottom));
  background: var(--slab);
  color: var(--on-slab);
}

.footer-grid {
  display: grid;
  gap: clamp(1.25rem, 2vw, 1.75rem) clamp(2rem, 4vw, 3rem);
}

.footer-brand {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  color: inherit;
  font-size: 0.95rem;
  font-weight: 900;
  font-stretch: 90%;
  letter-spacing: 0.02em;
  line-height: 1.05;
  text-transform: uppercase;
  text-decoration: none;
}

.footer-brand img {
  width: 3.25rem;
  height: 3.25rem;
}

.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
}

.footer-nav a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 2.75rem;
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  border-bottom: 2px solid transparent;
}

.footer-nav a:hover,
.footer-nav a[aria-current="page"] {
  border-bottom-color: var(--pink);
}

.footer-nav svg {
  width: 0.85em;
  height: 0.85em;
}

.footer-legal {
  margin: 0;
  font-size: 0.82rem;
  color: var(--on-slab-quiet);
}

/* ==========================================================================
   16. TEAR-OFF STRIP
   The bit you rip off a corkboard flyer. On phones it stays fixed to the
   bottom of the screen so the main action is always one thumb away.
   ========================================================================== */

.tearoff {
  /* Sticky, not fixed. iOS only repositions fixed elements once a scroll
     settles, so a fixed bar visibly lags during a flick; a sticky one rides
     the scroller instead. Being sticky it also takes real space at the end
     of the page, so nothing has to reserve room for it. */
  position: sticky;
  z-index: 80;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem var(--gutter);
  /* On an iPhone with a home indicator this inset is 0 while Safari's
     toolbar is open and about 34px once it collapses, so it changes mid
     scroll. max() takes the larger of the two instead of adding them, which
     halves how far the strip grows when that happens. */
  padding-bottom: max(0.7rem, env(safe-area-inset-bottom));
  background: var(--pink);
  color: var(--on-pink);
  /* the perforation you tear along */
  border-top: 2px dashed var(--on-pink);
}

.tearoff-text {
  min-width: 0;
  margin: 0;
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.3;
}

.tearoff .button {
  min-height: 2.6rem;
  padding: 0.6rem 0.9rem;
  background: var(--on-pink);
  border-color: var(--on-pink);
  color: var(--white);
  font-size: 0.82rem;
}

@media (hover: hover) {
  .tearoff .button:hover {
    background: var(--white);
    border-color: var(--white);
    color: var(--on-pink);
  }
}

/* ==========================================================================
   17. LEGAL PAGE (Impressum)
   ========================================================================== */

.legal {
  padding-block: var(--band);
}

.legal h1 {
  font-size: clamp(2.5rem, 8vw, 5rem);
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.legal h2 {
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 1rem;
  font-size: clamp(1.5rem, 3vw, 2.1rem);
}

.legal h3 {
  margin: 2.25rem 0 0.75rem;
  font-size: clamp(1.1rem, 2vw, 1.4rem);
  font-weight: 800;
  font-stretch: 96%;
  letter-spacing: -0.01em;
  text-transform: none;
}

.legal p {
  margin: 0 0 1.35em;
  max-width: var(--measure);
}

.legal address {
  margin: 0 0 1.5rem;
  font-style: normal;
  font-weight: 700;
}

.legal a {
  font-weight: 700;
}

/* ==========================================================================
   18. WIDER SCREENS
   Everything above is the phone layout. These rules rearrange it upwards.
   ========================================================================== */

@media (min-width: 46rem) {
  .ticket {
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: baseline;
  }

  .ticket-where {
    grid-column: 1;
  }

  .ticket-status {
    grid-row: 1;
    grid-column: 2;
    align-self: center;
  }

  .ticket-price {
    grid-row: 1;
    grid-column: 3;
    text-align: right;
  }

  .ticket-fee {
    grid-row: 2;
    grid-column: 2 / 4;
    text-align: right;
  }

  /* Wide enough for a label column: the floor name moves back to the left. */
  .programme-item {
    grid-template-columns: 9rem minmax(0, 1fr);
  }

  .programme-index {
    order: 0;
    grid-column: 1;
    grid-row: 1;
  }

  .programme-item > div {
    grid-column: 2;
    grid-row: 1;
  }

  .gallery {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* The lead photo runs two columns wide and two rows deep; the two next to
     it stack in the third column, and the remaining six fill two clean rows. */
  .gallery .plate:first-child {
    grid-column: span 2;
    grid-row: span 2;
    aspect-ratio: auto;
  }

  .partners {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: clamp(1.5rem, 3vw, 2.5rem);
  }

  .closer .sheet {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: end;
  }

  .footer-grid {
    grid-template-columns: auto 1fr;
    align-items: center;
  }

  .footer-nav {
    justify-content: flex-end;
  }

  .footer-legal {
    grid-column: 1 / -1;
  }
}

@media (min-width: 64rem) {
  .hero-grid {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    column-gap: clamp(2rem, 4vw, 3.5rem);
    row-gap: clamp(1.15rem, 1.7vw, 1.3rem);
  }

  /* The date sits under the headline, the standfirst beside it on the same
     baseline, and the buttons run under both. */
  .hero-grid .hero-when {
    grid-column: 1;
    grid-row: 3;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
  }

  .hero-grid .lead {
    grid-column: 2;
    grid-row: 3;
    align-self: end;
  }

  .hero-grid .hero-actions {
    grid-column: 1 / -1;
    grid-row: 4;
  }

  /* The photograph becomes a band across the full width of the window, with
     the headline pulled up over its foot – the same overprint as on a phone,
     at poster scale. */
  .hero-grid .hero-photo {
    grid-column: 1 / -1;
    grid-row: 1;
    aspect-ratio: auto;
    height: 46vh;
    min-height: 20rem;
    max-height: none;
    /* Pull past the sheet to both edges of the window – but stop growing
       beyond a 1920px window, or the photograph swallows the page. */
    margin-inline: calc(
      -1 * min(max(var(--gutter), (100vw - var(--sheet)) / 2), 19rem)
    );
  }

  /* Taken out of flow so the photograph fills the band, instead of its own
     proportions pushing the hero taller. */
  .hero-photo img {
    position: absolute;
    inset: 0;
  }

  /* A taller band needs a longer dissolve to reach paper under the type. */
  .hero-photo::before {
    height: 52%;
  }

  .hero-grid .hero-head {
    grid-column: 1 / -1;
    grid-row: 2;
    margin-top: -13rem;
  }

  .hero-kicker {
    margin-bottom: 0.7rem;
  }

  .story {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    align-items: start;
  }

  .tickets-head {
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
    align-items: end;
  }

  /* Past phone size the tear-off strip is not needed: the actions are
     already on screen. */
  .tearoff {
    display: none;
  }
}

/* ==========================================================================
   19. MOTION PREFERENCES
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .hero-title .ink-offset {
    animation: none;
  }

  .button,
  .theme-toggle {
    transition: none;
  }
}

/* ==========================================================================
   20. PRINT
   Someone will print this and pin it up. Make that version work.
   ========================================================================== */

@media print {
  /* Printing from the black stock would waste a cartridge and read badly.
     Paper is paper: force the light values back for the printer. */
  [data-theme="dunkel"] {
    color-scheme: light;
    --paper: #fff;
    --paper-shade: #fff;
    --ink: #000;
    --blue-ink: #000;
    --on-paper-quiet: #333;
    --slab: #fff;
    --on-slab: #000;
    --on-slab-quiet: #333;
  }

  body::after,
  .tearoff,
  .theme-toggle,
  .skip-link {
    display: none;
  }

  .section-invert,
  .section-pink {
    background: #fff;
    color: #000;
  }

  .plate img {
    filter: grayscale(1) contrast(1.1);
    mix-blend-mode: normal;
  }

  .plate::before,
  .plate::after {
    display: none;
  }
}
