/* =========================================================
   KAFKA MODULAR POSTER
   Everything except assets/kafka.png and assets/circle.jpg is HTML/CSS.
   Edit the variables below to reposition or recolor the design.
   ========================================================= */

:root {
  --bg: #0b0d0e;
  --bg-soft: #151617;
  --paper: #f2efe9;
  --muted: #c8c5c2;
  --accent: #7a174d;
  --accent-2: #a42c6d;

  /* Motion — the single place every duration and curve on the site is timed.
     Nothing animates without them, and the one ambient cue is capped at
     --dur-ambience so "finite" is a number rather than a promise. */
  --ease-out: cubic-bezier(.22, .61, .36, 1);
  --ease-soft: cubic-bezier(.32, 0, .16, 1);
  --dur-quick: .28s;
  --dur-base: .55s;
  --dur-slow: .95s;
  --dur-ambience: 4.2s;

  /* Layout dials the two hero layers and the bottom band are tuned from. */
  --band-h: max(128px, 15vh);
  --hero-opacity: 1;
  --sig-opacity: .47;

  --hero-right: 10vw;
  /* How far Kafka's feet sit below the frame edge. Negative = she bleeds off
     the bottom; more negative drops her further. */
  --hero-bottom: -11vh;
  --hero-height: 103vh;

  --ghost-left: 20vw;
  --ghost-top: 5vh;
  --ghost-height: 76vh;
  --ghost-width: 55vw;
  --ghost-opacity: 0.12;

  /* Desktop compact scale — the one dial for "everything reads a touch large
     at 100% browser zoom". From 901px up the whole page is scaled once on the
     root (see the DESKTOP COMPACT SCALE block in the responsive section), which
     is the same result as zooming the browser to 80%, and the user can still
     zoom further on top of it. The two viewport-tall frames divide by this so
     they still fill the screen exactly. Set it to 1 to get the original 1:1
     desktop sizing back, whole. */
  --desktop-scale: .8;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100%;
  background: #050607;
}

body {
  color: var(--paper);
  font-family: Georgia, "Times New Roman", serif;
  overflow-x: hidden;
}

::selection {
  background: var(--accent-2);
  color: #fff;
}

/* Keep the title/player and band in flow so short viewports and error messages
   grow the frame instead of pushing controls under the band. */
.poster {
  position: relative;
  width: 100%;
  min-height: 100svh;
  overflow: hidden;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-bottom: 0;
  background:
    radial-gradient(circle at 52% 38%, rgba(255,255,255,.035), transparent 28%),
    linear-gradient(115deg, #161819 0%, #0a0c0d 58%, #101112 100%);
}

/* One magenta bloom that opens the frame on load and then rests. It sits at
   z-index 2 — above the grayscale ghost, below the character (4), the magenta
   band (3) and the type (7) — so it lights the poster without ever tinting a
   word or washing the hero. */
.poster::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: radial-gradient(circle at 63% 44%, rgba(164, 44, 109, .2), transparent 58%);
}

/* ---------- BACKGROUND / DECORATION ---------- */

.background,
.grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.background {
  z-index: -5;
}

.grain {
  opacity: 0.18;
  background:
    repeating-linear-gradient(
      13deg,
      transparent 0 4px,
      rgba(255,255,255,.012) 4px 5px
    ),
    repeating-linear-gradient(
      91deg,
      transparent 0 9px,
      rgba(255,255,255,.01) 9px 10px
    );
  mix-blend-mode: screen;
}

.arcs {
  position: absolute;
  inset: 0;
  /* The rings are nudged down and right to sit around Kafka. translate comes
     before rotate on purpose: transforms apply right-to-left, so the ring is
     rotated first and the shift then stays on the page's own axes instead of
     sliding along the rotated ones. */
  transform: translate(5vw, 6vh) rotate(60deg);
  transform-origin: 50% 50%;
  pointer-events: none;
}

.arc {
  position: absolute;
  border: 1px solid rgba(236,236,232,.55);
  border-radius: 50%;
  pointer-events: none;
}

.arc--1 {
  width: 96vw;
  height: 96vw;
  left: 38vw;
  top: -47vw;
  transform: rotate(-6deg);
}

.arc--2 {
  width: 79vw;
  height: 79vw;
  left: 42vw;
  top: -36vw;
  opacity: .65;
}

.arc--3 {
  width: 62vw;
  height: 62vw;
  left: 46vw;
  top: -25vw;
  opacity: .35;
}

.signature {
  position: absolute;
  /* The signature hangs off the right edge, so a larger right pulls it further
     left across the poster. */
  right: 6vw;
  top: 50vh;
  font-family: "Brush Script MT", "Segoe Script", cursive;
  font-size: clamp(9rem, 24vw, 26rem);
  line-height: .8;
  font-style: italic;
  color: var(--accent);
  opacity: var(--sig-opacity);
  transform: rotate(-7deg);
  white-space: nowrap;
}

/* ---------- CHARACTER LAYERS ---------- */

.hero-character,
.ghost-character {
  position: absolute;
  display: block;
  user-select: none;
  pointer-events: none;
}

.hero-character {
  z-index: 4;
  right: var(--hero-right);
  bottom: var(--hero-bottom);
  height: var(--hero-height);
  max-width: var(--hero-width);
  object-fit: contain;
  opacity: var(--hero-opacity);
  filter:
    drop-shadow(0 18px 28px rgba(0,0,0,.55))
    drop-shadow(0 0 22px rgba(122,23,77,.18));
}

.ghost-character {
  z-index: -2;
  left: var(--ghost-left);
  top: var(--ghost-top);
  height: var(--ghost-height);
  max-width: var(--ghost-width);
  opacity: var(--ghost-opacity);
  filter: grayscale(1) contrast(.9) brightness(.85);
  transform: rotate(-3deg);
  transform-origin: center;
  mask-image: linear-gradient(to bottom, #000 0 72%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0 72%, transparent 100%);
}

/* ---------- NAVBAR ---------- */
/* Slim fixed masthead layered over the poster (z-index 20 clears the
   highest existing layer, .title-block at 7). It is built only from the
   existing vocabulary: solid magenta square-cornered blocks (echoes
   .mini-label), 1px white hairlines, uppercase Arial labels with tight
   tracking, and magenta glow picked up from --accent / --accent-2. */

.navbar {
  position: fixed;
  z-index: 20;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: clamp(3.5rem, 1rem + 0.9vh, 4.2rem);
  padding-inline: clamp(1.1rem, 3.4rem + 1.4vw, 5.6rem);
  background: rgba(11, 13, 14, .62);
  -webkit-backdrop-filter: blur(.5rem);
  backdrop-filter: blur(.5rem);
  border-bottom: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 .6rem 1.6rem -1.2rem rgba(0, 0, 0, .9);
}

.navbar__nav {
  display: flex;
  align-items: center;
  gap: clamp(.9rem, 2.4vw, 2.4rem);
}

.navbar__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .42em;
  min-height: 2.5rem;
  padding: 0 clamp(.72rem, 1.3vw, 1.05rem);
  background: transparent;
  color: var(--paper);
  opacity: .62;
  text-decoration: none;
  text-transform: uppercase;
  text-shadow: 0 1px 6px rgba(0, 0, 0, .65);
  font-family: Arial, Helvetica, sans-serif;
  font-size: clamp(.66rem, .92vw, .84rem);
  font-weight: 700;
  letter-spacing: .14em;
  line-height: 1;
  transition:
    color .34s cubic-bezier(.22, .61, .36, 1),
    opacity .34s cubic-bezier(.22, .61, .36, 1),
    background-color .34s cubic-bezier(.22, .61, .36, 1),
    box-shadow .34s cubic-bezier(.22, .61, .36, 1),
    text-shadow .34s cubic-bezier(.22, .61, .36, 1);
}

/* Hairline underline that slides in from the left edge of the link. */
.navbar__link::after {
  content: "";
  position: absolute;
  left: clamp(.72rem, 1.3vw, 1.05rem);
  right: clamp(.72rem, 1.3vw, 1.05rem);
  bottom: .3rem;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .38s cubic-bezier(.22, .61, .36, 1);
}

/* Idle -> hover / focus: ink warms toward the magenta accent, glow blooms,
   underline wipes in from the left. */
.navbar__link:hover,
.navbar__link:focus-visible {
  color: color-mix(in oklab, var(--accent-2) 34%, var(--paper));
  opacity: 1;
  text-shadow: 0 0 .85rem rgba(164, 44, 109, .8), 0 1px 6px rgba(0, 0, 0, .65);
}

.navbar__link:hover::after,
.navbar__link:focus-visible::after {
  transform: scaleX(1);
}

.navbar__link:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 3px;
}

/* Current page: filled in, like a solid magenta .mini-label block. */
.navbar__link.is-active,
.navbar__link[aria-current="page"] {
  color: white;
  opacity: 1;
  background: var(--accent);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .16);
  text-shadow: none;
}

.navbar__link.is-active::after,
.navbar__link[aria-current="page"]::after {
  transform: scaleX(0);
}

.navbar__dropdown {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.navbar__dropdown > summary {
  list-style: none;
  cursor: pointer;
}

.navbar__dropdown > summary::-webkit-details-marker { display: none; }

.navbar__chevron {
  width: .38em;
  height: .38em;
  margin: -.12em 0 0 .12em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform .28s cubic-bezier(.22, .61, .36, 1);
}

.navbar__dropdown[open] > summary .navbar__chevron {
  transform: rotate(225deg);
}

.navbar__dropdown[open] > summary,
.navbar__dropdown[data-current] > summary {
  color: #fff;
  opacity: 1;
  background: var(--accent);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .16);
  text-shadow: none;
}

.navbar__dropdown[open] > summary::after,
.navbar__dropdown[data-current] > summary::after {
  transform: scaleX(0);
}

.navbar__menu {
  position: absolute;
  z-index: 1;
  top: calc(100% + .55rem);
  left: 0;
  display: grid;
  gap: .15rem;
  width: max-content;
  min-width: 11.5rem;
  max-width: calc(100vw - 2rem);
  padding: .4rem;
  border: 1px solid rgba(255, 255, 255, .14);
  background: rgba(16, 17, 18, .97);
  box-shadow: 0 1.5rem 3.5rem -1rem rgba(0, 0, 0, .9);
  -webkit-backdrop-filter: blur(.65rem);
  backdrop-filter: blur(.65rem);
}

.navbar__dropdown[data-nav-group="info"] .navbar__menu {
  right: 0;
  left: auto;
}

.navbar__dropdown:not([open]) > .navbar__menu,
.navbar__menu[hidden] {
  display: none;
}

.navbar__menu-link {
  display: flex;
  align-items: center;
  min-height: 2.65rem;
  padding: .65rem .8rem;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  color: var(--paper);
  font-family: Arial, Helvetica, sans-serif;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .12em;
  line-height: 1.2;
  text-decoration: none;
  text-transform: uppercase;
  transition: color .25s cubic-bezier(.22, .61, .36, 1), background-color .25s cubic-bezier(.22, .61, .36, 1);
}

.navbar__menu-link:last-child { border-bottom: 0; }

.navbar__menu-link:hover,
.navbar__menu-link:focus-visible,
.navbar__menu-link.is-active {
  color: #fff;
  background: rgba(122, 23, 77, .48);
}

.navbar__menu-link:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
  .navbar__link,
  .navbar__link::after,
  .navbar__chevron,
  .navbar__menu-link {
    transition: none;
  }
}
.info-section#admin {
  min-height: auto;
  padding-block: clamp(4rem, 2rem + 4vh, 6rem);
}

.info-section#admin .approval-list {
  margin-top: 1.5rem;
}

.info-section#admin .approval-row {
  padding: 1.25rem 1.5rem;
}
/* The `hidden` attribute must win over our display: flex rules. */
.info-section[hidden],
.navbar__menu-link[hidden],
.approval-empty[hidden],
.approval-status[hidden] {
  display: none !important;
}

.approval-status {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  margin: 0 0 .9rem;
  padding: .35rem .75rem;
  border: 1px solid rgba(255, 255, 255, .12);
  background: rgba(255, 255, 255, .04);
  color: var(--muted);
  font-family: Arial, Helvetica, sans-serif;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.approval-status:empty { display: none; }

.approval-status[data-pending='true'] {
  color: #f0d08a;
  border-color: rgba(240, 208, 138, .35);
  background: rgba(240, 208, 138, .08);
}

.approval-list {
  list-style: none;
  padding: 0;
  margin: 1.5rem 0 0;
  display: grid;
  gap: 1rem;
  max-width: 60rem;
}

.approval-row {
  flex-direction: column;
  align-items: stretch;
  gap: 1.25rem;
  padding: 1.5rem 1.75rem;
  border: 1px solid rgba(255, 255, 255, .12);
  border-left: 4px solid rgba(240, 208, 138, .6);
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .015));
  box-shadow: 0 1rem 2.5rem -1.5rem rgba(0, 0, 0, .6);
  transition: border-color .2s, background-color .2s, transform .12s, box-shadow .2s;
}

.approval-row__avatar {
  width: 3rem;
  height: 3rem;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(240, 208, 138, .4);
  background: rgba(240, 208, 138, .1);
  color: #f0d08a;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: 0;
}

.approval-row:hover {
  border-color: rgba(255, 255, 255, .2);
  border-left-color: rgba(240, 208, 138, .85);
  background: linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .02));
  transform: translateY(-1px);
}

.approval-row__top {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.approval-row__identity {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  min-width: 0;
  flex: 1;
}

.approval-row__name {
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-size: .82rem;
  color: var(--paper);
  word-break: break-word;
}

.approval-row__time {
  color: var(--muted);
  font-size: .7rem;
  letter-spacing: .02em;
}

.approval-row__actions {
  display: flex;
  gap: .5rem;
  flex-shrink: 0;
}

.approval-row__button {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .55rem .95rem;
  border: 1px solid rgba(255, 255, 255, .18);
  background: rgba(255, 255, 255, .03);
  color: var(--paper);
  font-family: Arial, Helvetica, sans-serif;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color .2s, color .2s, border-color .2s, transform .12s;
}

.approval-row__glyph {
  font-size: 1rem;
  line-height: 1;
}

.approval-row__label {
  line-height: 1;
}

.approval-row__button:disabled {
  opacity: .4;
  cursor: wait;
  transform: none;
}

.approval-row__button--approve:hover,
.approval-row__button--approve:focus-visible {
  background: rgba(70, 180, 110, .26);
  border-color: rgba(70, 180, 110, .6);
  color: #b9f0c6;
  transform: translateY(-1px);
}

.approval-row__button--reject:hover,
.approval-row__button--reject:focus-visible {
  background: rgba(200, 60, 80, .26);
  border-color: rgba(200, 60, 80, .6);
  color: #f5b0b8;
  transform: translateY(-1px);
}

.approval-row__button:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: -2px;
}

.approval-empty {
  margin: .5rem 0 0;
  padding: 1.6rem 1rem;
  text-align: center;
  color: var(--muted);
  font-style: italic;
  font-size: .85rem;
  border: 1px dashed rgba(255, 255, 255, .12);
  background: rgba(255, 255, 255, .02);
}

@media (max-width: 560px) {
  .approval-row {
    flex-direction: column;
    align-items: stretch;
    gap: 1rem;
  }
  .approval-row__actions {
    justify-content: flex-end;
  }
}


/* ---------- SIGN IN ---------- */
/* Sits on the right end of the navbar, where the decorative mark used to be.
   Idle it is identical to a .navbar__link: grey, no fill, hairline underline
   that wipes in on hover/focus. The filled magenta block is the pressed state
   only, never the resting one. */
.navbar__signin {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 2.5rem;
  padding: 0 clamp(.72rem, 1.3vw, 1.05rem);
  border: 0;
  background: transparent;
  color: var(--paper);
  cursor: pointer;
  opacity: .62;
  text-decoration: none;
  text-transform: uppercase;
  text-shadow: 0 1px 6px rgba(0, 0, 0, .65);
  font-family: Arial, Helvetica, sans-serif;
  font-size: clamp(.66rem, .92vw, .84rem);
  font-weight: 700;
  letter-spacing: .14em;
  line-height: 1;
  transition:
    color .34s cubic-bezier(.22, .61, .36, 1),
    opacity .34s cubic-bezier(.22, .61, .36, 1),
    background-color .34s cubic-bezier(.22, .61, .36, 1),
    box-shadow .34s cubic-bezier(.22, .61, .36, 1),
    text-shadow .34s cubic-bezier(.22, .61, .36, 1);
}

.navbar__signin::after {
  content: "";
  position: absolute;
  left: clamp(.72rem, 1.3vw, 1.05rem);
  right: clamp(.72rem, 1.3vw, 1.05rem);
  bottom: .3rem;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .38s cubic-bezier(.22, .61, .36, 1);
}

.navbar__signin:hover,
.navbar__signin:focus-visible {
  color: color-mix(in oklab, var(--accent-2) 34%, var(--paper));
  opacity: 1;
  text-shadow: 0 0 .85rem rgba(164, 44, 109, .8), 0 1px 6px rgba(0, 0, 0, .65);
}

.navbar__signin:hover::after,
.navbar__signin:focus-visible::after {
  transform: scaleX(1);
}

.navbar__signin:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 3px;
}

/* While the dialog is open the button reads as pressed. It sits behind the
   backdrop while that is up, so this is mostly for the moment the dialog
   starts to close — but it is the honest state, and it is what a screen
   reader announces via aria-expanded. */
.navbar__signin[aria-expanded="true"] {
  color: #fff;
  opacity: 1;
  background: var(--accent);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .16);
  text-shadow: none;
}

.navbar__signin[aria-expanded="true"]::after {
  transform: scaleX(0);
}

.auth {
  width: min(26rem, calc(100vw - 2.5rem));
  max-height: calc(100dvh - 3rem);
  margin: auto;
  padding: 0;
  border: 0;
  overflow: auto;
  background: #101112;
  color: var(--paper);
  box-shadow: 0 2rem 5rem -1rem rgba(0, 0, 0, .9), 0 0 0 1px rgba(255, 255, 255, .14);
  /* Opening is a keyframe (a short, one-shot rise); closing is a transition off
     the same start values, which is why overlay/display are transitioned with
     allow-discrete. Browsers without discrete transitions still close cleanly,
     they just do it instantly. */
  opacity: 0;
  transform: translateY(1.1rem) scale(.965);
  transition:
    opacity var(--dur-quick) var(--ease-out),
    transform var(--dur-quick) var(--ease-out),
    overlay var(--dur-quick) allow-discrete,
    display var(--dur-quick) allow-discrete;
}

.auth[open] {
  /* The end state is a plain rule, not only a keyframe: if the animation never
     runs — reduced motion, an old engine — the dialog still has to be visible. */
  opacity: 1;
  transform: none;
  animation: dialog-rise .42s var(--ease-out) both;
}

/* Start state for the opening frame. */
@starting-style {
  .auth[open] {
    opacity: 0;
    transform: translateY(1.1rem) scale(.965);
  }
}

.auth::backdrop {
  background: rgba(5, 6, 7, .78);
  -webkit-backdrop-filter: blur(.25rem);
  backdrop-filter: blur(.25rem);
  animation: backdrop-in .3s var(--ease-out) both;
}

.auth__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem 1.25rem;
  border-bottom: 1px solid rgba(255, 255, 255, .12);
}

.auth__title {
  margin: 0;
  text-transform: uppercase;
  font-family: Arial, Helvetica, sans-serif;
  font-size: .95rem;
  font-weight: 700;
  letter-spacing: .18em;
}

.auth__close {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  border: 1px solid rgba(255, 255, 255, .2);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font-size: 1.15rem;
  line-height: 1;
}

.auth__close:hover {
  color: #fff;
  border-color: rgba(255, 255, 255, .5);
}

.auth__close:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

.auth__tabs {
  display: flex;
  border-bottom: 1px solid rgba(255, 255, 255, .12);
}

.auth__tabs[hidden] { display: none; }

.auth__tab {
  flex: 1;
  padding: .8rem .5rem;
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  text-transform: uppercase;
  font-family: Arial, Helvetica, sans-serif;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .16em;
}

.auth__tab:hover {
  color: var(--paper);
}

.auth__tab.is-on {
  color: #fff;
  border-bottom-color: var(--accent-2);
}

.auth__tab:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: -2px;
}

.auth__form {
  display: grid;
  gap: .85rem;
  padding: 1.25rem;
}

/* [hidden] has to win over the grid above, otherwise the inactive panel stays
   on screen: the UA rule for [hidden] is display:none, which loses to any
   author display declaration. */
.auth__form[hidden] {
  display: none;
}

.auth__field {
  display: grid;
  gap: .35rem;
}

.auth__field span {
  color: var(--muted);
  text-transform: uppercase;
  font-family: Arial, Helvetica, sans-serif;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .18em;
}

.auth__field input {
  padding: .65rem .7rem;
  border: 1px solid rgba(255, 255, 255, .18);
  background: rgba(255, 255, 255, .04);
  color: var(--paper);
  font-family: Arial, Helvetica, sans-serif;
  font-size: .85rem;
}

.auth__field input:focus-visible {
  border-color: transparent;
  outline: 2px solid var(--accent-2);
  outline-offset: 1px;
}

/* The username rules live outside the <label> so they are not read as part of
   the field's accessible name (the input points here with aria-describedby).
   The negative top margin tucks the hint against the input it describes
   instead of leaving it floating in the form's .85rem gap. */
.auth__hint {
  margin: -.45rem 0 0;
  color: var(--muted);
  font-family: Arial, Helvetica, sans-serif;
  font-size: .7rem;
  line-height: 1.45;
}

.auth__submit {
  margin-top: .3rem;
  padding: .8rem 1rem;
  border: 0;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  text-transform: uppercase;
  font-family: Arial, Helvetica, sans-serif;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .16em;
}

.auth__submit:hover {
  background: var(--accent-2);
}

.auth__submit:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

.auth__note {
  margin: 0;
  padding: .1rem 1.25rem 1.25rem;
  border-left: 2px solid var(--accent-2);
  color: var(--muted);
  font-family: Arial, Helvetica, sans-serif;
  font-size: .75rem;
  line-height: 1.5;
}

/* The script moves focus here after a submit, so the outcome is announced
   rather than just appearing. The magenta rule is the focus affordance. */
.auth__note:focus {
  outline: none;
  background: rgba(164, 44, 109, .18);
}

/* ---------- NAV: IN-PAGE TARGETS ---------- */
/* The poster stays a locked 100svh canvas with overflow:hidden; the fixed
   navbar sits outside it so disclosure panels are not clipped. INFO and the
   menu destinations live below the poster, so their anchors are real scrolls. */

html {
  scroll-behavior: smooth;
  /* A classic scrollbar reserves ~15px of the layout viewport. The poster sizes
     itself in vw units, so the gutter that only exists once the document
     scrolls would reflow the locked frame. Suppressing it keeps the poster
     pixel-identical; wheel, keyboard and anchor scrolling are untouched. */
  scrollbar-width: none;
}

html::-webkit-scrollbar {
  width: 0;
  height: 0;
}

#top,
#schedule,
#inventory,
#calendar {
  scroll-margin-top: clamp(3.5rem, 1rem + 0.9vh, 4.2rem);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

/* ---------- TOP LABELS ---------- */

.topbar {
  position: absolute;
  z-index: 6;
  top: clamp(4.4rem, 1.5rem + 5vh, 6.5rem);
  left: 5.8vw;
  right: 5.2vw;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

.brand {
  /* One source of truth so Iallis and E-pal can never drift apart in size. */
  --brand-size: clamp(.85rem, 1.35vw, 1.6rem);
  display: flex;
  align-items: baseline;
  gap: .7rem;
  text-shadow: 0 2px 10px rgba(0,0,0,.5);
}

.brand strong {
  font-size: var(--brand-size);
  letter-spacing: -.02em;
}

/* Same size as the wordmark and on the same baseline. The row is baseline-
   aligned, so the divider needs align-self: an empty inline block would
   otherwise align by its bottom edge and hang below the text. flex-start plus
   the original -.2rem nudge puts it back where it was before. */
.brand small {
  font-size: var(--brand-size);
  line-height: 1.16;
  font-weight: 700;
}

.brand--right {
  flex-direction: column;
  gap: 0;
  align-items: flex-end;
  text-align: right;
}

.divider {
  display: inline-block;
  align-self: flex-start;
  width: 1px;
  height: 2.4rem;
  margin-top: -.2rem;
  background: rgba(255,255,255,.8);
}

/* ---------- MAIN TITLE ---------- */

.title-block {
  position: relative;
  z-index: 7;
  /* In the flow of .poster, offset by margins instead of top/left. Same clamp
     and same width as the absolute layout it replaces, so the column still
     starts in the same place and the h1's 19vh cap still steps the display
     type down on very wide, very short windows. flex: 0 0 auto so the box is
     never compressed to fit — if the column outgrows the viewport, the poster
     grows around it. */
  flex: 0 0 auto;
  margin: clamp(9.8rem, 27vh, 22rem) 0 1.5rem 5.2vw;
  width: min(44vw, 780px);
}

.title-block h1,
.title-block h2,
.title-block p {
  margin: 0;
}

/* The h1 runs at line-height .72, which is tighter than the glyphs themselves,
   so the tail of the Q and the descender of the p in "Queue Up" both fall well
   outside the box — measured, the ink reaches 41px past the bottom of a 107px
   box. A .34em margin buys that ink its room back without loosening the
   display type, and because it is in em it scales with the clamp()'d size. */
.title-block h1 {
  font-size: min(clamp(4.8rem, 11.1vw, 12.4rem), 20.5vh);
  line-height: .72;
  font-weight: 400;
  letter-spacing: -.065em;
  margin-bottom: .34em;
  text-shadow: 0 4px 20px rgba(0,0,0,.25);
}

/* "with" and the name sit next to each other on one shared baseline, the same
   trick the topbar uses for Iallis | E-pal. inline-flex so the row still
   shrink-wraps instead of claiming the full 44vw of the title block. */
.title-row {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: .55rem;
  margin-top: .3rem;
}

.title-with {
  color: var(--muted);
  font-family: Arial, Helvetica, sans-serif;
  font-size: clamp(.72rem, 1.35vw, 1.3rem);
  font-style: italic;
  letter-spacing: .1em;
}

.title-row h2 {
  font-size: clamp(2.45rem, 4.8vw, 5.6rem);
  line-height: .9;
  font-style: italic;
  font-weight: 400;
  white-space: nowrap;
}

.title-rule {
  width: 80%;
  height: 2px;
  margin-top: .7rem;
  background: rgba(245,245,241,.88);
  /* The load animation wipes this rule in from the left, so it has to grow
     from its own start edge. */
  transform-origin: left center;
}

.title-copy {
  margin-top: .8rem !important;
  margin-left: 54%;
  color: var(--muted);
  font-size: min(clamp(.78rem, 1.5vw, .95rem), 2.2vh);
  line-height: 1.55;
}

/* ---------- HERO CALLS TO ACTION ---------- */
/* The poster had no way into the INFO block beyond the nav, which is easy to
   miss on a phone. These two buttons live under the copy, aligned to the same
   left edge as "Queue Up", and are built from the vocabulary already in the
   sheet: square-cornered magenta blocks, 1px paper hairlines, uppercase Arial
   with tight tracking, and the magenta glow off --accent / --accent-2. */

.title-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(.55rem, 1.2vw, .95rem);
  margin-top: clamp(.85rem, .4rem + 1vw, 1.5rem);
}

.cta {
  display: inline-flex;
  align-items: center;
  gap: .55em;
  min-height: 2.35rem;
  padding: 0 clamp(.9rem, 1.4vw, 1.15rem);
  border: 1px solid transparent;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  text-decoration: none;
  text-transform: uppercase;
  font-family: Arial, Helvetica, sans-serif;
  font-size: clamp(.6rem, .74vw, .7rem);
  font-weight: 700;
  letter-spacing: .16em;
  line-height: 1;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .12);
  transition:
    background-color var(--dur-quick) var(--ease-out),
    box-shadow var(--dur-quick) var(--ease-out),
    transform var(--dur-quick) var(--ease-out);
}

/* The second button is the hairline twin: transparent until it is wanted, then
   it fills from the accent so the pair reads as one family. */
.cta--ghost {
  background: rgba(255, 255, 255, .03);
  border-color: rgba(245, 241, 233, .38);
  box-shadow: none;
}

.cta__arrow {
  transition: transform var(--dur-quick) var(--ease-out);
}

.cta:hover,
.cta:focus-visible {
  background: var(--accent-2);
  border-color: rgba(245, 241, 233, .7);
  transform: translateY(-2px);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .2),
    0 .7rem 1.4rem -.7rem rgba(164, 44, 109, .85);
}

.cta:hover .cta__arrow,
.cta:focus-visible .cta__arrow {
  transform: translateX(3px);
}

.cta:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {

  .cta,
  .cta__arrow {
    transition: none;
  }

  .cta:hover,
  .cta:focus-visible {
    transform: none;
  }
}

/* ---------- MUSIC PLAYER ---------- */
/* The one local file on the site, in the hero column under the CTAs. Built only
   from vocabulary already in the sheet — a magenta block like .cta, 1px paper
   hairlines, uppercase Arial with tight tracking, glow off --accent/-accent-2,
   44px targets like the navbar links — and kept narrow (min(100%, 30rem)) so
   it never reaches the character on the right. On a phone it simply follows
   the copy and the CTAs into the poster's stacked column.

   Two faces, one audio element. The native <audio controls> is the whole
   player until player.js reports in, because only that script sets
   data-mp="custom" and hides it, so a missing or blocked file leaves a working
   native player behind. The custom panel ships hidden and is revealed by the
   same script, which is why nothing in it — including the seek range — is live
   before that point. */

.music-player-native {
  display: block;
  width: min(100%, 30rem);
  margin-top: 1rem;
  accent-color: var(--accent-2);
}

html[data-mp="custom"] .music-player-native { display: none; }

.music-player {
  width: min(100%, 30rem);
  margin: 1rem 0 0;
  padding: .82rem 1rem;
  display: flex;
  flex-direction: column;
  gap: .7rem;
  border: 1px solid rgba(245, 241, 233, .18);
  border-radius: 6px;
  background: rgba(10, 10, 14, .74);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 1.3rem 2.6rem -1.4rem rgba(0, 0, 0, .9);
  transition: border-color var(--dur-quick) var(--ease-out), box-shadow var(--dur-quick) var(--ease-out);
}

/* display: flex would otherwise beat the UA [hidden] rule. */
.music-player[hidden] { display: none; }

/* Set by the media element's own play event, never by the click. */
.music-player.is-playing {
  border-color: rgba(164, 44, 109, .55);
  box-shadow: 0 0 0 1px rgba(164, 44, 109, .26), 0 1.3rem 2.6rem -1.4rem rgba(0, 0, 0, .9);
}

.music-player__head {
  display: flex;
  align-items: center;
  gap: .55rem;
}

.music-player__meta {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.music-player__title,
.music-player__sub {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.music-player__title {
  font-family: Arial, Helvetica, sans-serif;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .16em;
  line-height: 1.15;
  text-transform: uppercase;
}

.music-player__sub {
  color: var(--muted);
  font-size: .62rem;
  line-height: 1.35;
}

.music-player__time {
  flex: 0 0 auto;
  color: var(--muted);
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: .62rem;
  font-variant-numeric: tabular-nums;
}

/* Three bars that move only while audio is actually playing: the class comes
   from the play/pause events, so there is never a pulsing idle player. */
.music-player__bars {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: flex-end;
  gap: 2px;
  height: 13px;
  opacity: .38;
  transition: opacity var(--dur-quick) var(--ease-out);
}

.music-player__bars i {
  width: 2px;
  height: 100%;
  background: var(--accent-2);
  transform: scaleY(.3);
  transform-origin: bottom;
}

.music-player.is-playing .music-player__bars { opacity: 1; }
.music-player.is-playing .music-player__bars i { animation: mp-eq 1.05s var(--ease-soft) infinite alternate; }
.music-player.is-playing .music-player__bars i:nth-child(2) { animation-delay: .16s; }
.music-player.is-playing .music-player__bars i:nth-child(3) { animation-delay: .32s; }

@keyframes mp-eq {
  from { transform: scaleY(.22); }
  to { transform: scaleY(1); }
}

.music-player__controls {
  display: flex;
  align-items: center;
  gap: .6rem;
}

.music-player__play {
  flex: 0 0 auto;
  min-width: 44px;
  min-height: 44px;
  padding: 0 1rem;
  border: 1px solid transparent;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  text-transform: uppercase;
  font-family: Arial, Helvetica, sans-serif;
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .16em;
  line-height: 1;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .12);
  transition: background-color var(--dur-quick) var(--ease-out),
              box-shadow var(--dur-quick) var(--ease-out),
              transform var(--dur-quick) var(--ease-out);
}

.music-player__play:hover,
.music-player__play:focus-visible {
  background: var(--accent-2);
  transform: translateY(-1px);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .2), 0 .5rem 1.1rem -.6rem rgba(164, 44, 109, .85);
}

.music-player__play:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 3px;
}

.music-player__play[disabled] {
  opacity: .45;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.music-player__label {
  flex: 0 0 auto;
  color: var(--muted);
  font-family: Arial, Helvetica, sans-serif;
  font-size: .52rem;
  font-weight: 700;
  letter-spacing: .14em;
  line-height: 1;
  text-transform: uppercase;
}

/* Label and range share one line, the same way the reference player seats VOL
   beside its slider — stacking them instead would make the control row 57px
   and push the whole panel into the magenta band on a 900px-tall window. */
.music-player__seek,
.music-player__vol {
  display: flex;
  align-items: center;
  gap: .4rem;
}

.music-player__seek {
  flex: 1 1 auto;
  min-width: 0;
}

.music-player__vol {
  flex: 0 0 auto;
}

/* The visible track is 4px but the control is 44px tall, so the whole band is
   the hit area and the keyboard target is real. --val (0..1) is the only thing
   JS writes here; Firefox paints the fill with ::-moz-range-progress instead.

   flex-basis 0 rather than a width: a range's intrinsic width is far wider
   than the space it should share, so a percentage width here would overflow
   the label instead of shrinking, and min-width 0 is what lets the seek track
   go all the way down to a 320px screen. */
.music-player__range {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  flex: 1 1 0;
  min-width: 0;
  height: 44px;
  margin: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
}

.music-player__vol .music-player__range { flex: 0 0 4.5rem; }

.music-player__range::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-2) 0 calc(var(--val, 0) * 100%),
              rgba(245, 241, 233, .18) calc(var(--val, 0) * 100%) 100%);
}

/* Webkit and Mozilla pseudo-elements are deliberately never grouped into one
   selector list: a browser that does not know one of them drops the whole
   rule, not just the half it cannot parse. */

.music-player__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  margin-top: -4px;
  border: 0;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: 0 0 0 1px rgba(122, 23, 77, .9), 0 0 .6rem rgba(164, 44, 109, .8);
}

.music-player__range::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: 0 0 0 1px rgba(122, 23, 77, .9), 0 0 .6rem rgba(164, 44, 109, .8);
}

.music-player__range[disabled]::-webkit-slider-thumb { background: var(--muted); box-shadow: none; }
.music-player__range[disabled]::-moz-range-thumb { background: var(--muted); box-shadow: none; }

.music-player__range::-moz-range-track {
  height: 4px;
  border-radius: 999px;
  background: rgba(245, 241, 233, .18);
}

.music-player__range::-moz-range-progress {
  height: 4px;
  border-radius: 999px;
  background: var(--accent-2);
}

.music-player__range:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
  border-radius: 999px;
}

.music-player__range[disabled] { cursor: not-allowed; }

/* Empty until something has actually gone wrong, so the panel keeps its height
   when there is nothing to say. */
.music-player__status {
  margin: 0;
  color: color-mix(in oklab, var(--accent-2) 40%, var(--paper));
  font-size: .6rem;
  line-height: 1.4;
}

.music-player__status:empty { display: none; }

@media (prefers-reduced-motion: reduce) {

  .music-player,
  .music-player__bars,
  .music-player__play { transition: none; }

  .music-player__play:hover,
  .music-player__play:focus-visible { transform: none; }

  .music-player.is-playing .music-player__bars i {
    animation: none;
    transform: scaleY(.55);
  }
}

@media (max-width: 900px) {

  .music-player,
  .music-player-native { width: min(100%, 26rem); }
}

/* Phones run the poster as a stacked column, so the player just joins the copy
   and the CTAs above the character. Over 480px the three controls share one
   line; under it the seek takes its own full-width line with play and volume
   either side of the one below, so nothing is crushed at 320px. */
@media (max-width: 620px) {

  .music-player,
  .music-player-native {
    width: 100%;
    margin-top: .9rem;
  }

  .music-player {
    padding: .75rem .85rem;
    gap: .55rem;
  }
}

@media (max-width: 480px) {

  .music-player__controls {
    flex-wrap: wrap;
    row-gap: .35rem;
  }

  .music-player__seek {
    order: -1;
    flex: 1 0 100%;
  }

  .music-player__vol { margin-left: auto; }
}

/* =========================================================
   MOTION
   Every animation on the page is automatic, and there is exactly one switch:
   prefers-reduced-motion. Inside no-preference the entrance pass and the scroll
   reveals play on every load; outside it the reduced-motion rules further down
   leave every element in its resting state instead. There is no in-page switch
   and nothing is remembered between visits.
   Below the gate: transform and opacity only, so nothing is laid out twice,
   and nothing is driven by a rAF loop or a timer. The one ambient cue — the
   bloom, the arcs — is finite: it plays once, then rests forever.
   ========================================================= */

@keyframes nav-drop {
  from {
    opacity: 0;
    transform: translateY(-100%);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(1.15rem);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
}

@keyframes rule-draw {
  from {
    transform: scaleX(0);
  }
}

/* The character walks in from below the frame. Its end opacity reads the same
   dial the static styles use, so a viewport that dims it (mobile) stays dim. */
@keyframes character-in {
  from {
    opacity: 0;
    transform: translateY(2.2vh) scale(.985);
  }

  to {
    opacity: var(--hero-opacity);
    transform: none;
  }
}

/* The grayscale ghost gets its own entrance rather than the shared fade: it
   drifts in from the left and rights itself from -5deg to its resting -3deg.
   Both keyframe ends are written out instead of being left implicit, so the
   fill-mode never has to guess the dials off the base rule. */
@keyframes ghost-settle {
  from {
    opacity: 0;
    transform: translate(-25px, 0) rotate(-5deg);
  }

  to {
    opacity: var(--ghost-opacity);
    transform: translate(0, 0) rotate(-3deg);
  }
}

@keyframes band-in {
  from {
    transform: translateY(101%);
  }
}

@keyframes ring-in {
  from {
    opacity: 0;
    scale: .8;
    rotate: -14deg;
  }
}

/* scale/rotate are used as independent properties here so the hover transform
   on the same element still composes instead of fighting the keyframe. */
@keyframes ring-settle {
  from {
    opacity: 0;
    scale: .9;
  }
}

@keyframes signature-settle {
  from {
    opacity: 0;
    transform: translateY(-2.5rem) rotate(-12deg);
  }

  to {
    opacity: var(--sig-opacity);
    transform: rotate(-7deg);
  }
}

@keyframes bloom-in {
  from {
    opacity: 0;
    scale: 1.06;
  }

  to {
    opacity: 1;
    scale: 1;
  }
}

@keyframes dialog-rise {
  from {
    opacity: 0;
    transform: translateY(1.1rem) scale(.965);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes backdrop-in {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: no-preference) {

  /* ---- Entrance: one staggered pass, ~1.5s from the first frame ---- */

  .navbar {
    animation: nav-drop var(--dur-base) var(--ease-out) both;
  }

  .topbar {
    animation: fade-in var(--dur-slow) var(--ease-out) .08s both;
  }

  .ghost-character {
    animation: ghost-settle 1.5s var(--ease-soft) .05s both;
  }

  .signature {
    animation: signature-settle 1.6s var(--ease-soft) .18s both;
  }

  .hero-character {
    animation: character-in 1.3s var(--ease-out) .12s both;
  }

  .title-block h1 {
    animation: rise-in var(--dur-slow) var(--ease-out) .2s both;
  }

  .title-row {
    animation: rise-in var(--dur-slow) var(--ease-out) .34s both;
  }

  .title-rule {
    animation: rule-draw var(--dur-slow) var(--ease-out) .46s both;
  }

  .title-copy {
    animation: fade-in var(--dur-slow) var(--ease-out) .56s both;
  }

  .title-cta .cta:first-child {
    animation: rise-in var(--dur-slow) var(--ease-out) .64s both;
  }

  .title-cta .cta:last-child {
    animation: rise-in var(--dur-slow) var(--ease-out) .74s both;
  }

  /* Opacity only, and no transform in the keyframe, so the fill can never sit
     on top of the button's own hover transform inside the panel. */
  .music-player {
    animation: fade-in var(--dur-slow) var(--ease-out) .84s both;
  }

  .bottom-band {
    animation: band-in var(--dur-slow) var(--ease-out) .3s both;
  }

  .bottom-content .circle-mark {
    animation: ring-in var(--dur-slow) var(--ease-out) .52s both;
  }

  /* ---- Atmosphere: finite, once, then still for the rest of the visit ----
     The arcs breathe out to their resting scale and opacity (an omitted
     to-frame resolves to the element's own values) and the bloom settles;
     total run is under --dur-ambience plus its stagger. */
  .arc--1 {
    animation: ring-settle var(--dur-ambience) var(--ease-soft) .15s both;
  }

  .arc--2 {
    animation: ring-settle var(--dur-ambience) var(--ease-soft) .35s both;
  }

  .arc--3 {
    animation: ring-settle var(--dur-ambience) var(--ease-soft) .55s both;
  }

  .poster::after {
    animation: bloom-in 3.6s var(--ease-soft) .15s both;
  }

  /* ---- Scroll reveals --------------------------------------------
     The hidden start state is behind html[data-js="on"] as well, so if the
     script never runs — no JS, blocked, or an IntersectionObserver too old
     to exist — the copy is simply already on screen. */
  html[data-js="on"] .reveal {
    opacity: 0;
    transform: translateY(1.4rem);
    transition:
      opacity var(--dur-slow) var(--ease-out) var(--d, 0s),
      transform var(--dur-slow) var(--ease-out) var(--d, 0s);
  }

  html[data-js="on"] .reveal.is-in {
    opacity: 1;
    transform: none;
  }

}

@media (prefers-reduced-motion: reduce) {

  .auth,
  .auth[open],
  .auth::backdrop {
    animation: none;
    transition: none;
  }
}

/* ---------- SECTION LABELS ---------- */

.mini-label {
  display: inline-block;
  min-width: 8.5rem;
  padding: .2rem .7rem .24rem;
  background: var(--accent);
  font-size: clamp(.68rem, .8vw, .92rem);
  font-weight: 700;
  line-height: 1;
}

.mini-label--small {
  min-width: 5rem;
  margin-top: .55rem;
}

.info-section__title {
  margin: .55rem 0 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(2.5rem, 6.2vw, 6.4rem);
  font-weight: 400;
  line-height: .98;
  letter-spacing: -.02em;
  text-shadow: 0 4px 20px rgba(0, 0, 0, .25);
}

.info-section__copy {
  margin: .4rem 0 0;
  max-width: 34rem;
  color: #d5d2cf;
  font-size: min(clamp(.88rem, 1vw, 1.05rem), 2.4vh);
  line-height: 1.55;
}

/* ---------- FLOW SECTIONS ---------- */
/* Schedule and Inventory share the poster's dark gradient, framed texture and
   square-cornered magenta labels. */

.info-section {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  min-height: 100svh;
  padding-block: clamp(4.5rem, 3rem + 6vh, 9rem);
  padding-inline: 5.7vw;
  border-top: 1px solid rgba(255, 255, 255, .08);
  background:
    radial-gradient(circle at 74% 32%, rgba(255, 255, 255, .03), transparent 26%),
    linear-gradient(115deg, #161819 0%, #0a0c0d 58%, #101112 100%);
}

.info-section__grain {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  opacity: .12;
  background:
    repeating-linear-gradient(
      13deg,
      transparent 0 4px,
      rgba(255,255,255,.012) 4px 5px
    ),
    repeating-linear-gradient(
      91deg,
      transparent 0 9px,
      rgba(255,255,255,.01) 9px 10px
    );
  mix-blend-mode: screen;
}

.nav-destination__inner {
  grid-template-columns: minmax(0, 1fr);
  max-width: min(88vw, 56rem);
  margin-inline: auto;
}

.schedule-calendar {
  min-width: 0;
  margin-top: clamp(1.2rem, 2vw, 1.8rem);
  padding: clamp(.7rem, 1.5vw, 1.25rem);
  border: 1px solid rgba(255, 255, 255, .14);
  background: rgba(11, 13, 14, .56);
  scroll-margin-top: clamp(3.5rem, 1rem + .9vh, 4.2rem);
}

.schedule-calendar__toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: .85rem;
  border-bottom: 1px solid rgba(255, 255, 255, .12);
}

.schedule-calendar__month {
  margin: 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(1.15rem, 2vw, 1.7rem);
  font-weight: 400;
}

.schedule-calendar__navigation {
  display: flex;
  align-items: center;
  gap: .4rem;
}

.schedule-calendar__nav,
.schedule-admin__cancel {
  min-height: 2.35rem;
  padding: .45rem .7rem;
  border: 1px solid rgba(255, 255, 255, .2);
  background: rgba(255, 255, 255, .035);
  color: var(--paper);
  cursor: pointer;
  font: 700 .65rem/1 Arial, Helvetica, sans-serif;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.schedule-calendar__nav:hover,
.schedule-admin__cancel:hover {
  border-color: var(--accent-2);
  background: rgba(122, 23, 77, .35);
}

.schedule-calendar__nav:focus-visible,
.schedule-admin__cancel:focus-visible,
.schedule-admin__submit:focus-visible,
.schedule-calendar__add:focus-visible,
.schedule-event__action:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 2px;
}

.event-dialog { width: min(36rem, calc(100% - 2rem)); max-height: calc(100svh - 2rem); padding: clamp(1.25rem, 4vw, 2rem); overflow-y: auto; border: 1px solid rgba(255,255,255,.25); border-top: 2px solid var(--accent-2); background: #101112; color: var(--paper); color-scheme: dark; }
.event-dialog::backdrop { background: rgba(0,0,0,.78); backdrop-filter: blur(5px); }
.event-dialog h2 { margin: 1rem 0; font-size: 2rem; font-weight: 400; }
.event-dialog p { color: var(--muted); font-size: .95rem; line-height: 1.6; overflow-wrap: anywhere; }
.event-dialog .event-dialog__event { font-size: 1.3rem; color: var(--paper); }
.event-dialog__field { display: flex; flex-direction: column; gap: .65rem; margin-top: 1.5rem; }
.event-dialog__field span { font: .85rem/1.4 Arial, sans-serif; color: var(--muted); }
.event-dialog__field input { min-width: 0; width: 100%; min-height: 44px; padding: .8rem; border: 1px solid rgba(255,255,255,.3); border-radius: 0; background: #080a0b; color: var(--paper); font: 1rem/1.4 Georgia, serif; }
.event-dialog__actions { display: flex; flex-wrap: wrap; gap: .65rem; margin: 1rem 0; }
.event-button { min-height: 44px; padding: .7rem 1rem; border: 1px solid rgba(255,255,255,.3); border-radius: 0; background: #151617; color: var(--paper); cursor: pointer; font: .8rem/1.3 Arial, sans-serif; }
.event-button:hover { background: #321325; border-color: #d879ad; }
.event-button--primary { background: var(--accent); border-color: var(--accent-2); }
.event-button:disabled { opacity: .55; cursor: not-allowed; }
.event-button:focus-visible, .event-dialog input:focus-visible { outline: 2px solid #eb8fbd; outline-offset: 3px; }
.event-dialog [hidden] { display: none !important; }
.event-dialog__status { min-height: 1.5em; }
.event-dialog__status[data-error="true"] { color: #ffb7ce; }
.event-attendee-list { list-style: none; margin: 1rem 0; padding: 0; }
.event-attendee-list li { padding: 1rem 0; border-top: 1px solid rgba(255,255,255,.15); overflow-wrap: anywhere; }
.event-attendee-list time { display: block; margin-top: .5rem; color: var(--muted); font: .8rem/1.5 Arial, sans-serif; }

.schedule-calendar__status {
  margin: .9rem 0 0;
  color: var(--muted);
  font: .75rem/1.45 Arial, Helvetica, sans-serif;
}

.schedule-calendar__status[data-error="true"] {
  color: #f3a5c9;
}

.schedule-calendar__table {
  width: 100%;
  margin-top: .9rem;
  border-collapse: collapse;
  table-layout: fixed;
}

.schedule-calendar__table th {
  padding: .5rem .2rem;
  border-bottom: 1px solid rgba(255, 255, 255, .14);
  color: var(--muted);
  font: 700 .62rem/1 Arial, Helvetica, sans-serif;
  letter-spacing: .1em;
  text-align: left;
  text-transform: uppercase;
}

.schedule-calendar__table td {
  width: 14.285%;
  height: 7.25rem;
  padding: .25rem;
  border: 1px solid rgba(255, 255, 255, .1);
  vertical-align: top;
}

.schedule-calendar__day {
  position: relative;
  min-height: 6.65rem;
  padding: .25rem;
}

.schedule-calendar__day--outside { opacity: .42; }

.schedule-calendar__day--today {
  background: rgba(122, 23, 77, .18);
  box-shadow: inset 0 0 0 1px rgba(196, 62, 138, .55);
}

.schedule-calendar__date {
  display: block;
  font: 700 .68rem/1 Arial, Helvetica, sans-serif;
}

.schedule-calendar__events {
  display: grid;
  gap: .2rem;
  margin: .35rem 0 0;
  padding: 0;
  list-style: none;
}

.schedule-event {
  min-width: 0;
  padding: .25rem .3rem;
  border-left: 2px solid var(--accent-2);
  background: rgba(122, 23, 77, .28);
  overflow-wrap: anywhere;
}

.schedule-event__title {
  display: block;
  color: var(--paper);
  font: 700 .61rem/1.25 Arial, Helvetica, sans-serif;
}

.schedule-event__time,
.schedule-event__location,
.schedule-event__description {
  display: block;
  margin-top: .12rem;
  color: var(--muted);
  font: .55rem/1.3 Arial, Helvetica, sans-serif;
}

.schedule-event__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .2rem;
  margin-top: .3rem;
}

.schedule-event__action,
.schedule-calendar__add {
  padding: .2rem .3rem;
  border: 1px solid rgba(255, 255, 255, .2);
  background: rgba(5, 6, 7, .55);
  color: var(--paper);
  cursor: pointer;
  font: 700 .52rem/1.2 Arial, Helvetica, sans-serif;
  text-transform: uppercase;
}

.schedule-event__action:hover,
.schedule-calendar__add:hover {
  border-color: var(--accent-2);
  color: #fff;
}

.schedule-calendar__add {
  margin-top: .35rem;
  color: var(--muted);
}

.schedule-agenda { display: none; }

.schedule-agenda__title {
  margin: 0 0 .65rem;
  font: 700 .68rem/1.2 Arial, Helvetica, sans-serif;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.schedule-agenda__list {
  display: grid;
  gap: .55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.schedule-agenda__empty {
  margin: 0;
  color: var(--muted);
  font: .75rem/1.45 Arial, Helvetica, sans-serif;
}

.schedule-agenda__item {
  padding: .65rem;
  border: 1px solid rgba(255, 255, 255, .12);
  border-left: 2px solid var(--accent-2);
  background: rgba(255, 255, 255, .025);
}

.schedule-agenda__item .schedule-event__title { font-size: .72rem; }

.schedule-agenda__item .schedule-event__time,
.schedule-agenda__item .schedule-event__location,
.schedule-agenda__item .schedule-event__description {
  font-size: .65rem;
}

.schedule-admin {
  display: grid;
  gap: .8rem;
  margin-top: 1.2rem;
  padding: clamp(.8rem, 1.4vw, 1.2rem);
  border-top: 2px solid var(--accent);
  background: rgba(255, 255, 255, .025);
}

.schedule-admin[hidden],
.auth__account[hidden] {
  display: none;
}

.schedule-admin__title {
  margin: 0;
  font: 700 .75rem/1.2 Arial, Helvetica, sans-serif;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.schedule-admin__form {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .75rem;
}

.schedule-admin__field {
  display: grid;
  min-width: 0;
  gap: .35rem;
}

.schedule-admin__field--wide { grid-column: 1 / -1; }

.schedule-admin__field > span {
  color: var(--muted);
  font: 700 .6rem/1.2 Arial, Helvetica, sans-serif;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.schedule-admin__field input,
.schedule-admin__field textarea {
  width: 100%;
  min-width: 0;
  padding: .55rem .6rem;
  border: 1px solid rgba(255, 255, 255, .18);
  background: rgba(255, 255, 255, .04);
  color: var(--paper);
  font: .78rem/1.35 Arial, Helvetica, sans-serif;
}

.schedule-admin__field textarea { resize: vertical; }

.schedule-admin__field input:focus-visible,
.schedule-admin__field textarea:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 1px;
}

.schedule-admin__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .55rem;
}

.schedule-admin__submit {
  min-height: 2.4rem;
  padding: .65rem .85rem;
  border: 0;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  font: 700 .63rem/1 Arial, Helvetica, sans-serif;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.schedule-admin__submit:hover { background: var(--accent-2); }

.schedule-admin__submit:disabled {
  cursor: wait;
  opacity: .65;
}

.auth__account {
  display: grid;
  gap: .65rem;
  padding: 1.25rem;
}

.auth__account-email,
.auth__account-role {
  margin: 0;
  color: var(--muted);
  font: .8rem/1.45 Arial, Helvetica, sans-serif;
  overflow-wrap: anywhere;
}

.account-access { margin-top: 3rem; padding-top: 2rem; border-top: 1px solid rgba(255,255,255,.2); }
.account-access[hidden] { display: none !important; }
.account-access h3 { margin: 1rem 0; font-size: clamp(1.7rem, 3vw, 2.2rem); font-weight: 400; }
.account-access > p, .account-access__row p, .account-access__row small { color: var(--muted); line-height: 1.6; }
.account-access__toolbar { display: flex; align-items: end; flex-wrap: wrap; gap: 1rem; margin: 1.5rem 0; }
.account-access__toolbar label { min-width: 12rem; }
.account-access__list { list-style: none; padding: 0; margin: 1.5rem 0; }
.account-access__row { display: flex; justify-content: space-between; align-items: center; gap: 1.5rem; padding: 1.3rem 0; border-top: 1px solid rgba(255,255,255,.15); overflow-wrap: anywhere; }
.account-access__row > div { min-width: 0; }
.account-access__row h4 { margin: 0; font-size: 1.2rem; font-weight: 400; }
.account-access__row p { margin: .5rem 0; font-size: .85rem; text-transform: capitalize; }
.account-access__actions { display: flex; flex-wrap: wrap; gap: .6rem; flex-shrink: 0; }
.account-access__retained { color: var(--muted); font-size: .85rem; }
.account-access :is(button, select):focus-visible { outline: 2px solid #eb8fbd; outline-offset: 4px; }
@media (max-width: 600px) { .account-access__row { align-items: stretch; flex-direction: column; gap: .8rem; } .account-access__actions { flex-shrink: 1; } }

.inventory-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(.75rem, 1.5vw, 1.25rem);
  margin-top: clamp(1.2rem, 2vw, 1.8rem);
}

.inventory-card {
  min-width: 0;
  min-height: 12rem;
  padding: clamp(.9rem, 1.5vw, 1.4rem);
  border: 1px solid rgba(255, 255, 255, .14);
  border-left: 2px solid var(--accent-2);
  background: rgba(11, 13, 14, .5);
}

.inventory-card h3 {
  margin: .9rem 0 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(1.05rem, 1.55vw, 1.5rem);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -.015em;
}

.inventory-card p {
  margin: .7rem 0 0;
  color: var(--muted);
  font-size: clamp(.78rem, .9vw, .9rem);
  line-height: 1.45;
}

/* Private inventory follows the poster's hairlines, ink panels and magenta labels. */
#inventory [hidden] { display: none !important; }
.inventory-heading { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: 2rem; }
.inventory-heading h3 { margin: 0; font-size: 1.35rem; font-weight: 400; }
.inventory-status, .inventory-admin > p { color: var(--muted); font: .9rem/1.6 Georgia, serif; }
.inventory-status { min-height: 1.5em; }
.inventory-status[data-error="true"] { color: #ffb7ce; }
.inventory-button { min-height: 44px; padding: .65rem 1rem; border: 1px solid rgba(255,255,255,.3); border-radius: 0; background: #151617; color: var(--paper); font: .78rem/1.3 Arial, sans-serif; cursor: pointer; transition: background var(--dur-quick), border-color var(--dur-quick); }
.inventory-button:hover { border-color: #ce659c; background: #321325; }
.inventory-button--primary { background: var(--accent); border-color: var(--accent-2); }
.inventory-button:disabled { cursor: not-allowed; opacity: .5; }
#inventory :is(button, input, select, textarea):focus-visible { outline: 2px solid #eb8fbd; outline-offset: 4px; }
.inventory-list { padding: 0; margin: 1.2rem 0 0; list-style: none; }
.inventory-entry { min-width: 0; padding: 1.2rem 0; border-top: 1px solid rgba(255,255,255,.14); overflow-wrap: anywhere; }
.inventory-entry :is(h4, h5) { margin: 0 0 .55rem; font-size: 1.15rem; font-weight: 400; line-height: 1.35; }
.inventory-entry time { color: #e9a4c9; font: .82rem/1.5 Arial, sans-serif; }
.inventory-entry p { white-space: pre-wrap; color: var(--muted); font-size: .95rem; line-height: 1.6; }
.inventory-entry__kind { display: block; color: #d993b8; margin-bottom: .65rem; font: .65rem/1.4 Arial, sans-serif; text-transform: uppercase; letter-spacing: .12em; }
.inventory-admin { margin-top: 2.5rem; padding: clamp(1rem, 3vw, 2rem); border: 1px solid rgba(255,255,255,.18); border-top: 2px solid var(--accent-2); background: linear-gradient(125deg, rgba(122,23,77,.12), rgba(11,13,14,.8) 60%); }
.inventory-admin h3 { font-size: clamp(1.4rem, 2vw, 1.8rem); font-weight: 400; margin: 1rem 0; }
.inventory-admin h4 { font-size: 1.25rem; font-weight: 400; overflow-wrap: anywhere; }
.inventory-chooser { display: grid; grid-template-columns: 1fr 1fr auto; align-items: end; gap: 1rem; margin-top: 1.5rem; }
.inventory-field { display: flex; flex-direction: column; gap: .6rem; min-width: 0; }
.inventory-field > span { color: var(--muted); font: .78rem/1.5 Arial, sans-serif; }
.inventory-field :is(input, select, textarea) { width: 100%; min-width: 0; min-height: 44px; padding: .75rem; color: var(--paper); background: #0b0d0e; border: 1px solid rgba(255,255,255,.28); border-radius: 0; color-scheme: dark; font: 1rem/1.4 Georgia, serif; }
.inventory-field textarea { resize: vertical; }
.inventory-form { margin-top: 2rem; }
.inventory-form fieldset { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; border: 0; border-top: 1px solid rgba(255,255,255,.18); padding: 1.5rem 0 0; margin: 0; min-width: 0; }
.inventory-form legend { padding: 0 1rem 0 0; font-size: 1.2rem; }
.inventory-field--wide, .inventory-form .inventory-actions { grid-column: 1 / -1; }
.inventory-actions { display: flex; flex-wrap: wrap; gap: .65rem; margin-top: 1rem; }
.inventory-managed-list { display: grid; grid-template-columns: 1fr 1fr; column-gap: 2rem; }
@media (max-width: 700px) {
  .inventory-chooser, .inventory-form fieldset, .inventory-managed-list { grid-template-columns: minmax(0, 1fr); }
  .inventory-field--wide, .inventory-form .inventory-actions { grid-column: auto; }
}

.info-section__rule {
  width: min(100%, 26rem);
  height: 2px;
  margin-top: .85rem;
  background: rgba(245,245,241,.88);
}

/* ---------- BOTTOM BAND ---------- */

.bottom-band {
  position: relative;
  z-index: 3;
  width: 100%;
  flex: 0 0 auto;
  margin-top: auto;
  /* In flow so the avatar, text and player can grow without overlapping. */
  display: flex;
  align-items: center;
  min-height: var(--band-h);
  /* Clean magenta only. The diagonal white hairlines that used to cross this
     bar are gone on purpose: the ::after layer with the two bright diagonals
     was deleted, and the faint repeating-linear-gradient stripes that sat
     underneath the fill (invisible, 95% covered) went with it. */
  background: linear-gradient(90deg, rgba(131,32,87,.97), rgba(106,25,74,.91));
  border-top: 1px solid rgba(255,255,255,.1);
}

.bottom-content {
  position: relative;
  z-index: 2;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: clamp(.9rem, 1.8vw, 1.4rem);
  padding-inline: 3.4vw;
  padding-block: clamp(.7rem, 1.2vh, 1.1rem);
}

.circle-mark {
  width: clamp(66px, 8vw, 135px);
  aspect-ratio: 1;
  flex: 0 0 auto;
  border: 3px solid white;
  border-radius: 50%;
  background: rgba(255,255,255,.02);
}

/* The JPEG has no alpha channel — its corners are pure white — so it is
   clipped to the ring instead of laid in as a square. Decorative, hence
   the empty alt on the img and aria-hidden on the wrapper. */
.circle-mark img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  user-select: none;
}

/* The avatar turns very slightly on hover — a single, non-looping touch. */
.circle-mark {
  transition:
    transform var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out);
}

.circle-mark:hover {
  transform: rotate(7deg) scale(1.03);
}

@media (prefers-reduced-motion: reduce) {

  .circle-mark {
    transition: none;
  }
}

.symbols {
  display: flex;
  gap: .15rem;
  align-items: center;
  font-family: Arial, Helvetica, sans-serif;
  font-size: clamp(1.25rem, 2vw, 2.2rem);
}

/* The glyphs tick over one at a time on hover, without ever looping. */
.symbols span {
  display: inline-block;
  transition: transform var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}

.symbols:hover span:nth-child(1) { transform: rotate(-14deg) translateY(-3px); }
.symbols:hover span:nth-child(2) { transform: rotate(10deg) translateY(-6px); transition-delay: .05s; }
.symbols:hover span:nth-child(3) { transform: rotate(16deg) translateY(-2px); transition-delay: .1s; }

@media (prefers-reduced-motion: reduce) {

  .symbols span {
    transition: none;
  }
}

.bottom-copy {
  width: min(30vw, 26rem);
  align-self: center;
}

.bottom-copy p {
  margin: .55rem 0 0;
  color: rgba(255,255,255,.92);
  font-size: clamp(.66rem, .78vw, .78rem);
  line-height: 1.5;
}

.pill {
  display: inline-block;
  padding: .18rem .8rem .2rem;
  border-radius: 999px;
  background: rgba(245,238,239,.92);
  color: #6a204a;
  font-size: clamp(.6rem, .7vw, .78rem);
  font-style: italic;
  font-weight: 700;
  letter-spacing: .03em;
}

/* ---------- RESPONSIVE ---------- */

/* No short-window rule any more, and none is needed. The hero column is in
   normal flow inside .poster, so a window too short for the frame grows it by
   exactly the amount the copy is missing rather than by a guessed constant. */

/* ---------- DESKTOP COMPACT SCALE ---------- */
/* The poster was drawn to be read from a chair, so on a large monitor at 100%
   zoom the type, the nav, the player and Kafka all read a shade large. Rather
   than re-tune ~120 viewport units down to a second desktop breakpoint, the
   entire desktop frame is scaled once, on the root element, by
   --desktop-scale. Scaling the root (not a wrapper) is what keeps this honest:
   the fixed masthead stays fixed and still spans the full width, the poster
   keeps filling the viewport because its width comes from the ICB, the
   full-bleed gradients never grow a seam, and the browser's own Ctrl+ - / +
   zoom still works on top of it, because nothing here touches
   user-scalable, maximum-scale or any script.
   901px and up only: the tablet/phone layout below is untouched and keeps its
   native sizes, where larger relative type is the right call anyway.
   Inside @supports so a browser without zoom simply keeps today's 1:1 desktop
   instead of losing the compensated frame heights. */

@media (min-width: 901px) {
  @supports (zoom: 1) {
    html {
      zoom: var(--desktop-scale);
    }

    /* Pull the lower white strokes left across the purple band while keeping
       the rings low and slightly enlarged around Kafka. */
    .arcs {
      transform: translate(6vw, 30vh) rotate(60deg) scale(1.10);
    }

    /* Zoom lays the page out at full size and paints it smaller, so a
       100svh min-height would leave the bottom fifth of the first screen
       empty. Dividing by the scale puts the physical frame back at exactly
       one viewport tall. min-height (not height) is kept on purpose: the
       poster is still a flex column with the band on margin-top:auto, so
       copy that needs more room grows the frame instead of being clipped —
       and at 80% the column needs less room than it did, not more. */
    .poster {
      min-height: calc(100svh / var(--desktop-scale));
    }

    /* Restore Kafka against the page's compact scale, then make the requested
       one-sixteenth reduction. Raise --hero-height / --hero-width to enlarge. */
    .hero-character {
      height: calc(var(--hero-height) * .9375 / var(--desktop-scale));
      max-width: calc(var(--hero-width) / var(--desktop-scale));
    }

    /* The ghost stays compensated to the full desktop scale behind Kafka. */
    .ghost-character {
      height: calc(var(--ghost-height) / var(--desktop-scale));
      max-width: calc(var(--ghost-width) / var(--desktop-scale));
    }

    /* Compensate root scaling so every flow section still fills one viewport.
       after the root applies the desktop compact scale. */
    .info-section {
      min-height: calc(100svh / var(--desktop-scale));
    }

    /* The fixed masthead shrinks with the page, so anchor offsets divide by the
       same factor to keep each destination from landing underneath it. */
    #top,
    #schedule,
    #inventory,
    #calendar {
      scroll-margin-top: calc(clamp(3.5rem, 1rem + 0.9vh, 4.2rem) / var(--desktop-scale));
    }
  }
}

@media (max-width: 900px) {
  :root {
    /* Only a small bleed here: at 768px an -18vw offset ate a quarter of the
       figure. The bottom is measured from the band, not the viewport, so the
       image always stops where the band starts instead of hiding behind it. */
    --hero-right: -5vw;
    --hero-bottom: var(--band-h);
    --hero-height: 76vh;
    --ghost-left: -3vw;
    --ghost-top: 11vh;
    --ghost-height: 56vh;
  }

  .title-block {
    margin-top: 24vh;
    width: 68vw;
  }

  .title-block h1 {
    font-size: min(clamp(4rem, 15vw, 7rem), 17vh);
  }

  .title-row h2 {
    font-size: clamp(2rem, 7vw, 3.7rem);
  }

  /* The copy used to disappear here, which left the whole pitch in a 5px
     sliver of the desktop indent. It stays on tablet and phone — the 54%
     indent is dropped for a plain left column with a magenta rule, so the
     lines have room to breathe. */
  .title-copy {
    display: block;
    margin-left: 0;
    max-width: 30ch;
    padding-left: clamp(.7rem, 1.6vw, 1rem);
    border-left: 2px solid var(--accent);
    font-size: min(clamp(.78rem, 2.1vw, .95rem), 2.2vh);
  }

  .title-cta {
    margin-top: clamp(.8rem, .4rem + 1.2vw, 1.2rem);
  }

  .info-section {
    padding-inline: 4.5vw;
  }

  .inventory-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .schedule-admin__form {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .brand--right {
    display: none;
  }

  .signature {
    top: 45vh;
    right: -20vw;
    font-size: 35vw;
  }

  .navbar {
    height: 3.5rem;
    padding-inline: clamp(1.1rem, 4.6vw, 2.4rem);
  }

  .navbar__nav {
    gap: clamp(.85rem, 3.4vw, 1.6rem);
  }

  .navbar__link {
    min-height: 2.75rem;
    letter-spacing: .12em;
  }

  .bottom-band {
    padding-inline: 0;
  }

  .bottom-content {
    padding-inline: 4.5vw;
  }

  .bottom-copy {
    width: min(42vw, 22rem);
  }

  .schedule-calendar__table th {
    padding-inline: .1rem;
    font-size: .55rem;
    letter-spacing: .04em;
  }

  .schedule-calendar__table td {
    height: 5.5rem;
    padding: .12rem;
  }

  .schedule-calendar__day {
    min-height: 5rem;
    padding: .18rem;
  }

  .schedule-calendar__date { font-size: .58rem; }

  .schedule-event { padding: .18rem; }

  .schedule-event__title { font-size: .52rem; }

  .schedule-event__time,
  .schedule-event__location,
  .schedule-event__description {
    font-size: .48rem;
  }

  .schedule-calendar__add {
    padding: .16rem .2rem;
    font-size: .46rem;
  }

  .schedule-admin__form {
    grid-template-columns: minmax(0, 1fr);
  }

  .schedule-admin__field--wide { grid-column: auto; }

  .schedule-agenda {
    display: grid;
    gap: .6rem;
    margin-top: 1rem;
  }

  .schedule-calendar__events {
    display: flex;
    flex-wrap: wrap;
    gap: .12rem;
  }

  .schedule-calendar__events .schedule-event {
    flex: 0 0 .32rem;
    width: .32rem;
    height: .32rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--accent-2);
    overflow: hidden;
  }

  .schedule-calendar__events .schedule-event > * { display: none; }
}

@media (max-width: 620px) {
  /* The locked absolute frame cannot survive a 320px phone: at this width the
     poster becomes a stacked column — topbar, title, character, magenta band —
     in the same left edge, same magenta, same type. The character drops into
     the flow, right-aligned, so it is never half off-screen, and the band is
     pushed to the bottom edge with margin-top:auto. If the stack ends up taller
     than the viewport the poster simply grows; nothing is clipped. */
  :root {
    --band-h: 124px;
  }

  .poster {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: 100svh;
    padding-top: 7.2rem;
    /* The band is in the flow here with margin-top:auto, so it needs no
       clearance of its own and must not inherit the desktop reserved gap. */
    padding-bottom: 0;
  }

  .topbar {
    top: 4.4rem;
    left: 24px;
    right: 24px;
  }

  .title-block {
    position: relative;
    top: auto;
    left: auto;
    width: auto;
    /* The shorthand, not margin-inline: the desktop margin-top has to go too,
       since the 7.2rem on the poster above does the spacing here. */
    margin: 0 24px;
  }

  .title-block h1 {
    font-size: clamp(3.4rem, 17.5vw, 6.4rem);
  }

  .title-row h2 {
    font-size: clamp(1.9rem, 8.6vw, 3.4rem);
  }

  .title-copy {
    max-width: 32ch;
  }

  .title-cta {
    gap: .5rem;
  }

  .cta {
    min-height: 2.5rem;
    padding-inline: .9rem;
    font-size: .64rem;
    letter-spacing: .12em;
  }

  .hero-character {
    /* right/bottom are relative offsets on a positioned element, so they have
       to be cleared before the image can sit in the flow. */
    position: relative;
    right: auto;
    bottom: auto;
    align-self: flex-end;
    width: clamp(10.5rem, 56vw, 19rem);
    max-width: 78%;
    height: auto;
    margin-top: clamp(.4rem, 2.4vh, 1.5rem);
  }

  .ghost-character {
    left: -120px;
    top: 100px;
    height: 430px;
  }

  .info-section {
    padding-block: clamp(3.2rem, 11vh, 5rem);
    padding-inline: 25px;
  }

  .info-section__title {
    font-size: clamp(2.1rem, 11.5vw, 3.4rem);
  }

  .info-section__rule {
    margin-top: .7rem;
  }

  .bottom-band {
    position: relative;
    bottom: auto;
    margin-top: auto;
  }

  .bottom-content {
    gap: .7rem;
    padding-inline: 18px;
  }

  .circle-mark {
    width: clamp(48px, 15vw, 66px);
    border-width: 2px;
  }

  .bottom-copy {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
  }

  .symbols {
    display: none;
  }

  .navbar {
    height: 3.5rem;
    padding-inline: 1.1rem;
  }

  .navbar__nav {
    gap: .8rem;
  }

  .navbar__link {
    min-height: 2.75rem;
    padding-inline: .6rem;
    font-size: .64rem;
    letter-spacing: .1em;
  }

  .navbar__link::after {
    left: .6rem;
    right: .6rem;
  }
}

/* 320px and under: the nav is the tightest thing in the layout, so the
   top-level labels and sign-in button use tighter tracking. */
@media (max-width: 400px) {
  .navbar__link,
  .navbar__signin {
    padding-inline: .5rem;
    font-size: .6rem;
    letter-spacing: .06em;
  }

  .navbar__link::after,
  .navbar__signin::after {
    left: .5rem;
    right: .5rem;
  }

  .title-copy {
    max-width: 28ch;
  }
}
